1. UDP 数据包格式

1.1 Radiotap Header (可选前缀)

来自无线网卡的原始数据包包含 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[] |
+----+-----+---------+

加密流程:

  1. 计算 session_hash = BLAKE2B(session_nonce || ciphertext)
  2. 使用 X25519(tx_publickey, rx_secretkey) 生成共享密钥
  3. 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 包,不转发到输出

加密流程:

  1. AEAD nonce = data_nonce (8 bytes)
  2. AAD = wblock_hdr_t (type + data_nonce, 9 bytes)
  3. 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 # 项目说明