Expand description
Pure LLDP (IEEE 802.1AB) frame codec.
Everything in this file is a pure function over plain values: it opens no socket, reads
no configuration and touches no global state. That is deliberate. The LLDP transport is raw
Ethernet and needs CAP_NET_RAW / /dev/bpf*, which no test in this repository has, so the
transport can never be executed here — but the frame format can be, and is, checked against
literal bytes from the specification and from a real capture
(tests/server/lldp/codec_test.rs).
This is the bluetooth_ble_beacon split the root CLAUDE.md describes: payload construction
is pure and exhaustively tested; the platform transport is a thin layer over it that has
never run. metadata().notes says both.
§Frame layout
| dst MAC (6) | src MAC (6) | 0x88CC (2) | LLDPDU ... |An LLDPDU is a sequence of TLVs. Each TLV starts with two octets holding a 7-bit type and a 9-bit length:
0 1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| type (7) | length (9) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+IEEE 802.1AB-2016 §8.5 requires the first three TLVs, in this order: Chassis ID (1), Port ID (2), Time To Live (3). Optional TLVs follow, and End Of LLDPDU (type 0, length 0) terminates. Chassis ID and Port ID each carry a leading subtype octet that decides how the rest of the value is read — a MAC address, a network address or text — and getting that wrong is the classic way to produce a frame a neighbour silently discards.
§No bytes cross the LLM boundary
Every identifier is carried in and out of here as a string in its natural notation —
"00:01:30:f9:ad:a0" for a MAC, "192.0.2.1" for an address, "1/1" for an interface
name — and every subtype and capability as a name. Models cannot reliably produce or
read a TLV blob, and a tlv_hex parameter would defeat the entire point of the protocol
(see the action & event design rules in the root CLAUDE.md).
Structs§
- Advertisement
Request - What a
send_lldp_advertisementaction asks for, once validated. - Lldp
Frame - A full LLDP Ethernet frame, decoded.
- Lldpdu
- A decoded LLDPDU: the three mandatory TLVs plus whichever optional ones were present.
- Management
Address - One management address, as carried by TLV type 8.
Enums§
- IdKind
- Which side of the frame an identifier belongs to. The two use different subtype numbers for the same thing, so the value encoder has to know which table it is reading.
Constants§
- CHASSIS_
ID_ SUBTYPES - Chassis ID subtypes, 802.1AB-2016 Table 8-2.
- ETHERNET_
HEADER_ LEN - Destination MAC | source MAC | EtherType.
- LLDP_
ETHERTYPE - EtherType assigned to LLDP (IEEE 802.1AB §8.1).
- LLDP_
MULTICAST_ MAC - The nearest-bridge group address every LLDP agent transmits to (802.1AB Table 7-1).
- PORT_
ID_ SUBTYPES - Port ID subtypes, 802.1AB-2016 Table 8-3. Not the same numbering as Chassis ID — a MAC address is 4 for a chassis and 3 for a port, which is the single easiest thing to get wrong in this protocol.
- SYSTEM_
CAPABILITIES - System capability bits, 802.1AB-2016 Table 8-4.
- TLV_
CHASSIS_ ID - TLV_
END_ OF_ LLDPDU - TLV_
MANAGEMENT_ ADDRESS - TLV_
PORT_ DESCRIPTION - TLV_
PORT_ ID - TLV_
SYSTEM_ CAPABILITIES - TLV_
SYSTEM_ DESCRIPTION - TLV_
SYSTEM_ NAME - TLV_
TIME_ TO_ LIVE
Functions§
- capability_
bits - Turn capability names back into a bitmask. An unrecognised name is an error, not a silently
dropped bit: a model that asks to advertise
"swtich"must be told, or it will believe it claimed to be a bridge. - capability_
names - Split a capability bitmask into names. Bits with no assigned meaning are reported as
reserved_bit_<n>rather than dropped — a neighbour that sets one is telling us something, even if the spec has not named it yet. - decode_
frame - Parse an Ethernet frame carrying an LLDPDU.
- encode_
frame - Wrap an LLDPDU in its Ethernet header.
- format_
mac - Render six octets as lowercase colon-separated hex.
- parse_
mac - Parse
aa:bb:cc:dd:ee:ff(or the-/.-free spellings) into six octets. - subtype_
code - Look a subtype name up in the relevant table.
- subtype_
name - Render a subtype number as its name, or
"reserved_<n>"for one the spec does not define.