Skip to content

About

C++ library for CAPWAP protocol packet definitions (RFC 5415/5416)

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

vi-capwap-protocol

C++17 library for CAPWAP protocol (Control and Provisioning of Wireless Access Points) packet definitions according to RFC 5415 and RFC 5416.

This repository is designed to be included as a git submodule in other projects.

Structure

src/
├── *.h, *.cpp          # CAPWAP message types (DiscoveryRequest, JoinRequest, etc.)
└── elements/           # CAPWAP message elements
    ├── *.h, *.cpp      # Generic elements (ACDescriptor, WTPDescriptor, etc.)
    └── IEEE80211/      # IEEE 802.11 binding elements (RFC 5416)
tests/
├── unit_tests/         # Unit tests
└── benchmarks/         # Performance benchmarks
docs/
├── rfc5415.txt         # CAPWAP Protocol Specification
└── rfc5416.txt         # CAPWAP Binding for IEEE 802.11

Usage as Submodule

git submodule add <repository-url> path/to/vi-capwap-protocol
git submodule update --init --recursive

Then include the necessary headers in your project:

#include "vi-capwap-protocol/src/DiscoveryRequest.h"
#include "vi-capwap-protocol/src/elements/ACDescriptor.h"

Data Lifetime Management

Important: This library is designed for zero-copy operation. CAPWAP messages and elements do not take ownership of the data passed to them.

When passing data via nonstd::span<const uint8_t> to writable arrays (e.g., WritableRateSetArray, WritableStationArray), the caller must ensure that the referenced data remains valid until Serialize() is called.

Example - Correct Usage

std::vector<uint8_t> rate_set_data = { 0x82, 0x84, 0x8B, 0x96 };

WritableRateSetArray rate_sets;
rate_sets.Add(1, rate_set_data);  // span references rate_set_data
rate_sets.Serialize(&raw_data);   // rate_set_data must still be valid here

Example - Incorrect Usage

WritableRateSetArray rate_sets;
{
    std::vector<uint8_t> rate_set_data = { 0x82, 0x84, 0x8B, 0x96 };
    rate_sets.Add(1, rate_set_data);
}  // rate_set_data destroyed - span now points to invalid memory!
rate_sets.Serialize(&raw_data);  // Undefined behavior

Dependencies

Required for standalone builds (unit tests and benchmarks). When used as a git submodule, the parent project provides its own logging backend.

spdlog

  • Debian/Ubuntu: sudo apt install libspdlog-dev

fmt (transitive dependency of system spdlog)

  • Debian/Ubuntu: sudo apt install libfmt-dev

Building Tests

# Build and run unit tests
make build_tests
./output/tests/unit_tests/vi-capwap-tests

# Build and run benchmarks
make build_benchmarks
./output/tests/benchmarks/vi-capwap-benchmarks

Byte Order

The library builds for both little-endian (x86, ARM) and big-endian (MIPS) targets. The byte order is detected from the compiler via __BYTE_ORDER__. If a toolchain does not define it, the build fails with an explicit error rather than guessing — override it manually in that case:

-DVI_CAPWAP_BIG_ENDIAN=1   # or 0

Writing byte order safe code

  • Multi-byte protocol fields must use NetworkU16, NetworkU32 or NetworkS16 (src/Helpers.h). They are built and read byte by byte, so they carry no byte order assumption. Never put a raw uint16_t/uint32_t in a packed structure.
  • Protocol constants stored raw in packed structures (message and element types, result codes) must be wrapped in ToNetworkOrder16() / ToNetworkOrder32(), which spell them in the target's byte order at compile time.
  • Comparing such a constant needs no conversion: equality does not depend on the representation. Only ordering comparisons (<, >, ranges) require ToHostOrder*, because byte swapping does not preserve order.
  • Bit fields in packed structures are allocated from the most significant bit on big-endian targets. Every such structure declares both orders behind #if VI_CAPWAP_BIG_ENDIAN, mirrored within each octet, and constructor member init lists follow the same split. A bit field must never cross an octet boundary.
  • IPv4 address fields are raw uint32_t holding values in network byte order, as returned by inet_addr() / inet_pton(). They are stored as-is and need no conversion on either target.

Verifying on a big-endian target

The unit tests compare serialized output against literal wire bytes, so running the suite on a big-endian target verifies the byte order handling end to end.

sudo apt install g++-mips-linux-gnu qemu-user-static

make run_tests_be     # cross build for MIPS and run under qemu
make clean_tests_be

Cross targets have no system spdlog, so run_tests_be compiles logging out (LOG_LEVEL=LOG_LEVEL_NONE). The compiler, sysroot and emulator can be overridden through BE_CXX, BE_SYSROOT and BE_QEMU.

Code Quality

# Check code formatting
make check_format

# Apply code formatting
make apply_format

# Static analysis
make code_check

RFC Compliance

  • RFC 5415 - CAPWAP Protocol Specification
  • RFC 5416 - CAPWAP Binding for IEEE 802.11

Radio Information Requirements

When constructing CAPWAP messages with radio information, the following constraints must be satisfied:

  1. Maximum radios constraint: max_radios >= radios_in_use

    • The maximum number of radios supported by WTP must be greater than or equal to the number of radios currently in use
  2. Radio info array size: radios_in_use <= wtp_radio_info.size()

    • The wtp_radio_info array must contain at least radios_in_use elements

These requirements are enforced by runtime assertions in the library.

Radio ID Extension

RFC 5415/5416 specify that Radio ID must be in the range 1-31. This implementation extends the valid range to 0-31 to support special cases or vendor-specific requirements.

Standard Range (RFC): 1-31 Implementation Range: 0-31

This extension is intentional and does not affect interoperability with RFC-compliant implementations, as Radio ID 0 is simply an additional option that can be used or avoided as needed.

Vendor-Specific Result Codes

RFC 5415 assigns Result Codes 0-22. This implementation adds ten codes for vendor-defined conditions, placed well above the standard block so they cannot collide with future assignments by the RFC.

Standard Range (RFC): 0-22 Vendor-Specific Range: 0xF000-0xF009 (ResultCode::VendorSpecific_1 … VendorSpecific_10)

WritableResultCode result{ ResultCode::Type::VendorSpecific_1 };

ResultCode::Validate() accepts both ranges and rejects everything else, so a peer that does not know these codes simply fails to parse the element rather than misinterpreting it.

These codes are meaningful only between endpoints that agree on them. An RFC-compliant AC or WTP will reject them, so they must not be used where interoperability with third-party implementations is required.

RFC 5416 Implementation Status

This library implements IEEE 802.11 binding for CAPWAP (RFC 5416) with the following coverage:

Implemented CAPWAP Control Messages (10/13)

✓ Fully Implemented:

  • Discovery Request/Response (Section 5.1, 5.2)
  • Join Request/Response (Section 5.5, 5.6)
  • Configuration Status Request/Response (Section 5.7, 5.8)
  • Configuration Update Request/Response (Section 5.9)
  • Change State Event Request/Response (Section 5.11)
  • WTP Event Request/Response (Section 5.12)
  • WLAN Configuration Request/Response (Section 3.1, 3.2)

Not Implemented (Optional):

  • Primary Discovery Request/Response (Section 5.3, 5.4) - optional per RFC 5415
  • Station Configuration Request/Response (Section 5.10) - optional, but individual elements are implemented

IEEE 802.11 Elements (25/25)

All 25 IEEE 802.11-specific message elements from RFC 5416 Section 6 are fully implemented:

  • Add/Delete/Update WLAN management
  • Radio configuration (Antenna, Direct Sequence, OFDM, TX Power, etc.)
  • Station management (Station, Session Key, QoS Profile)
  • Information Elements and Statistics
  • All elements have comprehensive unit test coverage

This implementation provides complete functionality for managing WTP radios and WLANs in production environments.

Element Classification

This section describes how CAPWAP protocol elements are organized by their structure and usage patterns.

CAPWAP Core Elements (RFC 5415)

Elements are grouped based on their structural characteristics and how they appear in messages.

Group 1: Complex Elements with Sub-elements (Single Instance)

Single-occurrence elements containing multiple fields, where the last field is an array of nested sub-elements.

Group 2: Simple Value Lists (Single Instance)

Single-occurrence elements consisting exclusively of an array of uniform fields.

Group 3: Variable-Length Single Fields (Single Instance)

Single-occurrence elements whose body consists entirely of one dynamically-sized field.

Group 4: Structures with Dynamic Tail (Array in Message)

Elements that can appear multiple times in a message. Consist of static fields and end with a variable-length field.

Group 5: Static Structures (Single Instance)

Single-occurrence elements with strictly fixed size.

Group 6: Structures with Dynamic Tail (Single Instance)

Single-occurrence elements in a message. Have several static fields and end with a variable-length field.

Group 8: Static Structures (Array in Message)

Strictly fixed-size elements that can appear multiple times in a message.

IEEE 802.11 Binding Elements (RFC 5416)

Elements specific to IEEE 802.11 wireless binding, grouped by structure.

Group 1: Structures with Dynamic Field in the Middle (Array in Message)

Elements that can appear multiple times in a message, containing a variable-length field in the middle (whose length is specified by a preceding field) and ending with other static or dynamic fields.

Group 2: Static Structures (Array in Message)

Strictly fixed-size elements that can appear multiple times in a message (typically for each Radio ID, WLAN ID, or Station MAC).

Group 3: Structures with Dynamic Tail (Array in Message)

Elements that can appear multiple times in a message. Consist of initial static fields and end with a variable-length field (array of values, string, or raw data).

About

C++ library for CAPWAP protocol packet definitions (RFC 5415/5416)

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages