1. UDP 数据包格式
来自无线网卡的原始数据包包含 radiotap header,携带物理层元数据:
1 2 3 4
| +--------+--------+----------+-----------+------------------+ | version| padding| it_len | it_present| payload fields | | (1B) | (3B) | (2B LE) | (4B LE +)| (variable) | +--------+--------+----------+-----------+------------------+
|
常用字段:
IEEE80211_RADIOTAP_CHANNEL (bit 5): 信道频率 + 标志(FHSS/Turbo/CR/CCK/OFDM/GHz2/GHz5/no-CK)
IEEE80211_RADIOTAP_DBM_ANTSIGNAL (bit 6): RSSI,有符号 int8_t(如 -65 dBm)
IEEE80211_RADIOTAP_DBM_ANTNOISE (bit 7): 噪声底,有符号 int8_t
IEEE80211_RADIOTAP_MCS (bit 32): MCS 信息(known/Padding/GF/Flags/MCS index)
IEEE80211_RADIOTAP_VHT (bit 34): VHT-MCS、VHT-NSS、带宽
1.2 WFB Session Packet (会话包)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| +--------+------------------+------------------------------------------+ | type | session_nonce | encrypted(wsession_data_t + TLV tags) | | 0x80 | (8B BE) | XSalsa20-Poly1305 ciphertext | +--------+------------------+------------------------------------------+
wsession_data_t: +-----------+-------------+----------+-----+-----+---------------+ | epoch | channel_id | fec_type | k | n | session_key[32]| | (8B BE) | (4B BE) | (1B) | (1B) | (1B) | (32B) | +-----------+-------------+----------+-----+-----+---------------+
TLV Tags (可选): +----+-----+---------+ | id | len | value[] | +----+-----+---------+
|
加密流程:
- 计算 session_hash = BLAKE2B(session_nonce || ciphertext)
- 使用 X25519(tx_publickey, rx_secretkey) 生成共享密钥
- crypto_box_open_easy() 解密 wsession_data_t
1.3 WFB Data Packet (数据包)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| +--------+-------------+----------------------------------+ | type | data_nonce | encrypted(wpacket_hdr_t + payload)| | 0x81 | (8B BE) | ChaCha20-Poly1305 AEAD ciphertext | +--------+-------------+----------------------------------+
data_nonce = (block_idx << 8) | fragment_idx - block_idx: 64位数据块序号(高56位) - fragment_idx: 分片索引(低8位,范围 [0, N-1])
wpacket_hdr_t: +-------+-------------+ | flags | packet_size | | (1B) | (2B BE) | +-------+-------------+
flags: bit 0: WFB_PACKET_FEC_ONLY (0x01) - FEC-only 包,不转发到输出
|
加密流程:
- AEAD nonce = data_nonce (8 bytes)
- AAD = wblock_hdr_t (type + data_nonce, 9 bytes)
- crypto_aead_chacha20poly1305_decrypt() 解密
1.4 完整数据包布局示例
1 2 3 4 5 6 7 8 9 10 11 12 13
| UDP Payload: |<-- radiotap header (variable) -->|<-- WFB packet -->|
Example (data packet): Offset Size Field ------ ---- ----- 0 ~20 radiotap header (channel, RSSI, MCS, etc.) ~20 1 type = 0x81 (WFB_PACKET_DATA) ~21 8 data_nonce (BE uint64) ~29 N ChaCha20-Poly1305 ciphertext (包含 wpacket_hdr_t + payload + auth tag)
Max UDP packet size: MAX_FORWARDER_PACKET_SIZE = 1500 bytes
|
2. FEC 编码规范
2.1 Reed-Solomon over GF(2^8)
参数:
- 字段: GF(2^8),生成元 g=0x1d
- 矩阵类型: Vandermonde
- SIMD 对齐: ZFEX_SIMD_ALIGNMENT (通常 32 bytes)
2.2 编码过程
1 2 3 4 5 6 7 8 9 10
| 输入: K 个数据块 [P0, P1, ..., P(K-1)],每块最大 MAX_FEC_PAYLOAD 字节
步骤 1: 构建 Vandermonde 矩阵 E[N][K] E[i][j] = g^(i*j) for i in [0,N), j in [0,K)
步骤 2: 计算校验块 C[K..N-1] C[m] = XOR(E[m][0]*P[0], E[m][1]*P[1], ..., E[m][K-1]*P[K-1]) 其中 * 为 GF(2^8) 乘法
输出: N 个块 [P0, P1, ..., P(K-1), C(K), ..., C(N-1)]
|
2.3 解码过程
1 2 3 4 5 6 7 8
| 输入: 任意 K 个块(可以是数据块或校验块的组合)
步骤 1: 构建子矩阵 G[K][K],行索引为可用块的编号 步骤 2: 计算 G_inv = inverse(G) over GF(2^8) 步骤 3: 恢复缺失的数据块 P_missing = G_inv * available_blocks
输出: K 个恢复后的数据块 [P0, P1, ..., P(K-1)]
|
2.4 FEC 参数推荐表
| Profile |
K (数据) |
N (总) |
冗余% |
最大容忍丢包% |
带宽开销 |
| Low |
8 |
10 |
25% |
20% |
1.33x |
| Default |
8 |
12 |
33% |
33% |
1.5x |
| Medium |
16 |
24 |
33% |
33% |
1.5x |
| High |
16 |
32 |
50% |
50% |
2.0x |
| Extreme |
8 |
24 |
67% |
67% |
3.0x |
3. 加密规范
3.1 密钥派生链
1 2 3 4 5 6 7 8 9 10 11 12 13
| Level 0: X25519 长期密钥对 ├── tx_publickey[32] (发射端公钥) └── rx_secretkey[32] (接收端私钥)
Level 1: Session Key (通过 crypto_box 交换) ├── shared_key = X25519(tx_public, rx_secret) ├── session_nonce[8] (随机生成) └── session_key[32] (加密传输的 ChaCha20-Poly1305 密钥)
Level 2: Data Encryption (ChaCha20-Poly1305 AEAD) ├── nonce = data_nonce (8 bytes, from block_idx + fragment_idx) ├── aad = wblock_hdr_t (9 bytes) └── ciphertext = encrypt(session_key, nonce, aad, plaintext)
|
3.2 NaCl/libsodium API 映射
| WFB-ng 操作 |
libsodium API |
| 生成密钥对 |
crypto_box_keypair() |
| 加密 session key |
crypto_box_easy() |
| 解密 session key |
crypto_box_open_easy() |
| 加密数据块 |
crypto_aead_chacha20poly1305_encrypt() |
| 解密数据块 |
crypto_aead_chacha20poly1305_decrypt() |
| Session hash |
crypto_generichash() (BLAKE2B) |
3.3 Epoch 机制
- epoch: 64位计数器,每次会话更新时递增
- channel_id: 32位通道标识符,用于多通道隔离
- 接收端拒绝 epoch < current_epoch 的会话包
- 发射端在以下情况生成新 session key:
- 启动时
- epoch 手动刷新
- channel_id 变化
4. IPC 消息协议
4.1 wfb_rx -> 监控工具 (Unix Socket)
1 2 3 4 5 6 7 8 9 10
| 格式: <timestamp_ms>\t<type>\t<data>\n
PKT 消息: <ms>\tPKT\t<count_all>:<bytes_all>:<dec_err>:<session>:<data>:<uniq>:<fec_recov>:<lost>:<bad>:<out_p>:<out_b>
SESSION 消息: <ms>\tSESSION\t<epoch>:<fec_type>:<k>:<n>
RSSI 消息: <ms>\tRSSI\t<addr>:<wlan_idx>:<antenna_id>:<rssi_min>:<rssi_avg>:<rssi_max>:<noise_min>:<noise_avg>:<noise_max>:<freq>:<mcs>:<bw>
|
4.2 tx_cmd -> wfb_tx (UDP Control)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| 请求: +---------+--------+------------------+ | req_id | cmd_id | payload | | (4B BE) | (1B) | (variable) | +---------+--------+------------------+
响应: +---------+------+------------------+ | req_id | rc | payload | | (4B BE) |(4B BE)| (variable) | +---------+------+------------------+
cmd_id 值: 1 = CMD_SET_FEC 2 = CMD_SET_RADIO 3 = CMD_GET_FEC 4 = CMD_GET_RADIO
|
5. 命令行接口参考
5.1 wfb_tx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| wfb_tx [OPTIONS]
必需参数: -d, --device <dev> 无线网卡设备名 (如 wlan0) -k, --keypair <file> X25519 密钥对文件路径
可选参数: --tx-iface <iface> 发射接口(默认与 -d 相同) --channel <chan> WiFi 信道号 (1-14 / 36-165) --bandwidth <bw> 带宽: 20, 40, 80, 160 MHz (默认 20) --mcs-index <idx> MCS index (0-77, 默认 1) --stbc <0|1> STBC 空间时间块编码 (默认 0) --ldpc <0|1> LDPC 编码 (默认 0) --short-gi <0|1> 短保护间隔 (默认 0) --vht-mode <0|1> VHT (802.11ac) 模式 (默认 0) --vht-nss <nss> VHT 空间流数 (默认 1)
FEC 参数: -k, --fec-k <k> FEC 数据块数 (默认 8) -n, --fec-n <n> FEC 总块数 (默认 12)
网络参数: --listen <addr:port> UDP 监听地址和端口 --client <addr:port> 客户端连接地址(用于 TUN 模式) --snd-buf-size <bytes> 发送缓冲区大小
控制通道: --control-port <port> tx_cmd 控制端口 (默认 2700)
其他: --genkeypair 生成新的密钥对并输出到 stdout -v, --verbose 详细日志
|
5.2 wfb_rx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| wfb_rx [OPTIONS]
必需参数: -d, --device <dev> 无线网卡设备名,多个用逗号分隔 (如 wlan1,wlan2) -k, --keypair <file> X25519 密钥对文件路径
可选参数: --rx-iface <iface> 接收接口列表(默认与 -d 相同)
输出目标: --output <type>:<params> 输出类型和参数: tun:<name> TUN 设备 (如 tun:wfb-rx) udp:<addr>:<port> UDP socket (如 udp:10.5.0.3:5800)
网络参数: --listen <addr:port> UDP 监听地址和端口 --rcv-buf-size <bytes> 接收缓冲区大小
其他: -v, --verbose 详细日志
|
5.3 wfb_tun
1 2 3 4 5 6 7 8 9
| wfb_tun [OPTIONS]
参数: -t, --tun-name <name> TUN 设备名称 (默认 "wfb-tun") -a, --tun-addr <addr> TUN 设备 IP/掩码 (默认 "10.5.0.2/24") -c, --peer-addr <addr> wfb_tx/rx 地址 (默认 "127.0.0.1") -u, --peer-port <port> wfb_tx/rx 端口 (默认 5801) -l, --listen-port <port> 监听 UDP 端口 (默认 5800) -T, --agg-timeout <ms> 聚合超时毫秒数 (默认 5)
|
5.4 tx_cmd
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| tx_cmd <port> <command> [OPTIONS]
命令: set_fec [-k K] [-n N] 设置 FEC 参数 get_fec 查询 FEC 参数 set_radio [-B bw] [-G GI] [-S stbc] [-L ldpc] [-M mcs] [-N nss] [-V] 设置射频参数 get_radio 查询射频参数
示例: tx_cmd 2700 set_fec -k 16 -n 32 tx_cmd 2700 set_radio -B 40 -M 5 -G s -S 1 tx_cmd 2700 get_fec tx_cmd 2700 get_radio
|
6. 文件结构总结
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| wfb-ng/ ├── src/ │ ├── common.h # 公共定义、协议常量、数据结构 │ ├── ieee80211_radiotap.h# Radiotap header 定义 │ │ │ ├── tx.cpp # 发射端: Transmitter 类 │ ├── rx.cpp # 接收端: Aggregator 类 │ │ │ ├── wfb_tun.c # TUN 代理: libevent 驱动的双向桥接 │ ├── tx_cmd.c # 控制工具: UDP 命令客户端 │ ├── tx_cmd.h # 控制协议定义 │ │ │ ├── radiotap.c # Radiotap header 解析器 │ │ │ ├── zfex.c # FEC Reed-Solomon 编解码 (SIMD) │ ├── zfex.h # FEC API │ ├── zfex_bytemask.h # GF(2^8) 字节掩码表 │ ├── zfex_macros.h # SIMD 宏定义 │ ├── zfex_pp.h # 预处理辅助 │ │ │ └── rtsp_server.c # RTSP/RTP 服务器 (GStreamer) │ ├── CMakeLists.txt # 构建系统 ├── LICENSE.txt # GPL-3.0 └── README.md # 项目说明
|