Merged VHT patch. Removed mutable global variables. #340

This commit is contained in:
Vasily Evseenko 2024-05-09 18:39:34 +03:00
parent ecfdfae823
commit 674c2d6526
4 changed files with 125 additions and 21 deletions

View File

@ -43,10 +43,11 @@ extern "C"
#include "fec.h"
}
using namespace std;
#include "wifibroadcast.hpp"
#include "tx.hpp"
using namespace std;
Transmitter::Transmitter(int k, int n, const string &keypair, uint64_t epoch, uint32_t channel_id) : \
fec_k(k), fec_n(n), block_idx(0),
@ -124,11 +125,15 @@ void Transmitter::make_session_key(void)
}
}
RawSocketTransmitter::RawSocketTransmitter(int k, int n, const string &keypair, uint64_t epoch, uint32_t channel_id, const vector<string> &wlans) : \
RawSocketTransmitter::RawSocketTransmitter(int k, int n, const string &keypair, uint64_t epoch, uint32_t channel_id, const vector<string> &wlans,
shared_ptr<uint8_t[]> radiotap_header, size_t radiotap_header_len, uint8_t frame_type) : \
Transmitter(k, n, keypair, epoch, channel_id),
channel_id(channel_id),
current_output(0),
ieee80211_seq(0)
ieee80211_seq(0),
radiotap_header(radiotap_header),
radiotap_header_len(radiotap_header_len),
frame_type(frame_type)
{
for(auto it=wlans.begin(); it!=wlans.end(); it++)
{
@ -174,10 +179,14 @@ RawSocketTransmitter::RawSocketTransmitter(int k, int n, const string &keypair,
void RawSocketTransmitter::inject_packet(const uint8_t *buf, size_t size)
{
assert(size <= MAX_FORWARDER_PACKET_SIZE);
uint8_t ieee_hdr[sizeof(ieee80211_header)];
// fill default values
memcpy(ieee_hdr, ieee80211_header, sizeof(ieee80211_header));
// frame_type
ieee_hdr[0] = frame_type;
// channel_id
uint32_t channel_id_be = htobe32(channel_id);
memcpy(ieee_hdr + SRC_MAC_THIRD_BYTE, &channel_id_be, sizeof(uint32_t));
@ -191,8 +200,8 @@ void RawSocketTransmitter::inject_packet(const uint8_t *buf, size_t size)
struct iovec iov[3] = \
{
// radiotap header
{ .iov_base = (void*)radiotap_header,
.iov_len = sizeof(radiotap_header)
{ .iov_base = (void*)radiotap_header.get(),
.iov_len = radiotap_header_len
},
// ieee80211 header
{ .iov_base = (void*)ieee_hdr,
@ -553,13 +562,18 @@ int main(int argc, char * const *argv)
int stbc = 0;
int ldpc = 0;
int mcs_index = 1;
int vht_nss = 1;
int debug_port = 0;
int fec_timeout = 0;
int rcv_buf = 0;
bool mirror = false;
bool vht_mode = false;
string keypair = "tx.key";
shared_ptr<uint8_t[]> radiotap_header = NULL;
size_t radiotap_header_len = 0;
uint8_t frame_type = FRAME_TYPE_DATA;
while ((opt = getopt(argc, argv, "K:k:n:u:p:l:B:G:S:L:M:D:T:i:e:R:f:m")) != -1) {
while ((opt = getopt(argc, argv, "K:k:n:u:p:l:B:G:S:L:M:N:D:T:i:e:R:f:m")) != -1) {
switch (opt) {
case 'K':
keypair = optarg;
@ -594,6 +608,9 @@ int main(int argc, char * const *argv)
case 'M':
mcs_index = atoi(optarg);
break;
case 'N':
vht_nss = atoi(optarg);
break;
case 'D':
debug_port = atoi(optarg);
break;
@ -616,12 +633,12 @@ int main(int argc, char * const *argv)
if (strcmp(optarg, "data") == 0)
{
fprintf(stderr, "Using data frames\n");
ieee80211_header[0] = FRAME_TYPE_DATA;
frame_type = FRAME_TYPE_DATA;
}
else if (strcmp(optarg, "rts") == 0)
{
fprintf(stderr, "Using rts frames\n");
ieee80211_header[0] = FRAME_TYPE_RTS;
frame_type = FRAME_TYPE_RTS;
}
else
{
@ -631,10 +648,10 @@ int main(int argc, char * const *argv)
break;
default: /* '?' */
show_usage:
fprintf(stderr, "Usage: %s [-K tx_key] [-k RS_K] [-n RS_N] [-u udp_port] [-R rcv_buf] [-p radio_port] [-B bandwidth] [-G guard_interval] [-S stbc] [-L ldpc] [-M mcs_index] [-T fec_timeout] [-l log_interval] [-e epoch] [-i link_id] [-f { data | rts }] [ -m ] interface1 [interface2] ...\n",
fprintf(stderr, "Usage: %s [-K tx_key] [-k RS_K] [-n RS_N] [-u udp_port] [-R rcv_buf] [-p radio_port] [-B bandwidth] [-G guard_interval] [-S stbc] [-L ldpc] [-M mcs_index] [-N VHT_NSS] [-T fec_timeout] [-l log_interval] [-e epoch] [-i link_id] [-f { data | rts }] [ -m ] interface1 [interface2] ...\n",
argv[0]);
fprintf(stderr, "Default: K='%s', k=%d, n=%d, udp_port=%d, link_id=0x%06x, radio_port=%u, epoch=%" PRIu64 ", bandwidth=%d guard_interval=%s stbc=%d ldpc=%d mcs_index=%d, fec_timeout=%d, log_interval=%d, rcv_buf=system_default, frame_type=data, mirror=false\n",
keypair.c_str(), k, n, udp_port, link_id, radio_port, epoch, bandwidth, short_gi ? "short" : "long", stbc, ldpc, mcs_index, fec_timeout, log_interval);
fprintf(stderr, "Default: K='%s', k=%d, n=%d, udp_port=%d, link_id=0x%06x, radio_port=%u, epoch=%" PRIu64 ", bandwidth=%d guard_interval=%s stbc=%d ldpc=%d mcs_index=%d vht_nss=%d, fec_timeout=%d, log_interval=%d, rcv_buf=system_default, frame_type=data, mirror=false\n",
keypair.c_str(), k, n, udp_port, link_id, radio_port, epoch, bandwidth, short_gi ? "short" : "long", stbc, ldpc, mcs_index, vht_nss, fec_timeout, log_interval);
fprintf(stderr, "Radio MTU: %lu\n", (unsigned long)MAX_PAYLOAD_SIZE);
fprintf(stderr, "WFB-ng version " WFB_VERSION "\n");
fprintf(stderr, "WFB-ng home page: <http://wfb-ng.org>\n");
@ -646,9 +663,16 @@ int main(int argc, char * const *argv)
goto show_usage;
}
// Set flags in radiotap header
// Only use VHT when BW set to 80 or higher
if (bandwidth >= 80) {
vht_mode = true;
}
if (!vht_mode)
{
// Set flags in HT radiotap header
uint8_t flags = 0;
switch(bandwidth) {
case 20:
flags |= IEEE80211_RADIOTAP_MCS_BW_20;
@ -688,9 +712,52 @@ int main(int argc, char * const *argv)
flags |= IEEE80211_RADIOTAP_MCS_FEC_LDPC;
}
radiotap_header_len = sizeof(radiotap_header_ht);
radiotap_header = shared_ptr<uint8_t[]>(new uint8_t[radiotap_header_len]);
memcpy(radiotap_header.get(), radiotap_header_ht, radiotap_header_len);
radiotap_header[MCS_FLAGS_OFF] = flags;
radiotap_header[MCS_IDX_OFF] = mcs_index;
}
else
{
// Set flags in VHT radiotap header
uint8_t flags = 0;
radiotap_header_len = sizeof(radiotap_header_vht);
radiotap_header = shared_ptr<uint8_t[]>(new uint8_t[radiotap_header_len]);
memcpy(radiotap_header.get(), radiotap_header_vht, radiotap_header_len);
if (short_gi)
{
flags |= IEEE80211_RADIOTAP_VHT_FLAG_SGI;
}
if (stbc)
{
flags |= IEEE80211_RADIOTAP_VHT_FLAG_STBC;
}
switch(bandwidth) {
case 80:
radiotap_header[VHT_BW_OFF] = IEEE80211_RADIOTAP_VHT_BW_80M;
break;
case 160:
radiotap_header[VHT_BW_OFF] = IEEE80211_RADIOTAP_VHT_BW_160M;
break;
default:
fprintf(stderr, "Unsupported bandwidth: %d\n", bandwidth);
exit(1);
}
if (ldpc)
{
radiotap_header[VHT_CODING_OFF] = IEEE80211_RADIOTAP_VHT_CODING_LDPC_USER0;
}
radiotap_header[VHT_FLAGS_OFF] = flags;
radiotap_header[VHT_MCSNSS0_OFF] |= ((mcs_index<<IEEE80211_RADIOTAP_VHT_MCS_SHIFT) & IEEE80211_RADIOTAP_VHT_MCS_MASK);
radiotap_header[VHT_MCSNSS0_OFF] |= ((vht_nss<<IEEE80211_RADIOTAP_VHT_NSS_SHIFT) & IEEE80211_RADIOTAP_VHT_NSS_MASK);
}
{
int fd;
@ -754,7 +821,8 @@ int main(int argc, char * const *argv)
fprintf(stderr, "Using %zu ports from %d for wlan emulation\n", wlans.size(), debug_port);
t = shared_ptr<UdpTransmitter>(new UdpTransmitter(k, n, keypair, "127.0.0.1", debug_port, epoch, channel_id));
} else {
t = shared_ptr<RawSocketTransmitter>(new RawSocketTransmitter(k, n, keypair, epoch, channel_id, wlans));
t = shared_ptr<RawSocketTransmitter>(new RawSocketTransmitter(k, n, keypair, epoch, channel_id, wlans,
radiotap_header, radiotap_header_len, frame_type));
}
data_source(t, rx_fd, fec_timeout, mirror, log_interval);

View File

@ -96,7 +96,7 @@ typedef std::unordered_map<uint64_t, txAntennaItem> tx_antenna_stat_t;
class RawSocketTransmitter : public Transmitter
{
public:
RawSocketTransmitter(int k, int m, const std::string &keypair, uint64_t epoch, uint32_t channel_id, const std::vector<std::string> &wlans);
RawSocketTransmitter(int k, int m, const std::string &keypair, uint64_t epoch, uint32_t channel_id, const std::vector<std::string> &wlans, shared_ptr<uint8_t[]> radiotap_header, size_t radiotap_header_len, uint8_t frame_type);
virtual ~RawSocketTransmitter();
virtual void select_output(int idx) { current_output = idx; }
virtual void dump_stats(FILE *fp, uint64_t ts, uint32_t &injected, uint32_t &dropped);
@ -107,6 +107,9 @@ private:
uint16_t ieee80211_seq;
std::vector<int> sockfds;
tx_antenna_stat_t antenna_stat;
shared_ptr<uint8_t[]> radiotap_header;
size_t radiotap_header_len;
uint8_t frame_type;
};

View File

@ -62,9 +62,20 @@ extern std::string string_format(const char *format, ...);
#define IEEE80211_RADIOTAP_MCS_STBC_3 3
#define IEEE80211_RADIOTAP_MCS_STBC_SHIFT 5
#define IEEE80211_RADIOTAP_VHT_FLAG_STBC 0x01
#define IEEE80211_RADIOTAP_VHT_FLAG_SGI 0x04
#define IEEE80211_RADIOTAP_VHT_MCS_MASK 0xF0
#define IEEE80211_RADIOTAP_VHT_NSS_MASK 0x0F
#define IEEE80211_RADIOTAP_VHT_MCS_SHIFT 4
#define IEEE80211_RADIOTAP_VHT_NSS_SHIFT 0
#define IEEE80211_RADIOTAP_VHT_BW_80M 0x04
#define IEEE80211_RADIOTAP_VHT_BW_160M 0x0B
#define IEEE80211_RADIOTAP_VHT_CODING_LDPC_USER0 0x01
#define MCS_KNOWN (IEEE80211_RADIOTAP_MCS_HAVE_MCS | IEEE80211_RADIOTAP_MCS_HAVE_BW | IEEE80211_RADIOTAP_MCS_HAVE_GI | IEEE80211_RADIOTAP_MCS_HAVE_STBC | IEEE80211_RADIOTAP_MCS_HAVE_FEC)
static uint8_t radiotap_header[] __attribute__((unused)) = {
static const uint8_t radiotap_header_ht[] __attribute__((unused)) = {
0x00, 0x00, // <-- radiotap version
0x0d, 0x00, // <- radiotap header length
0x00, 0x80, 0x08, 0x00, // <-- radiotap present flags: RADIOTAP_TX_FLAGS + RADIOTAP_MCS
@ -72,6 +83,19 @@ static uint8_t radiotap_header[] __attribute__((unused)) = {
MCS_KNOWN , 0x00, 0x00 // bitmap, flags, mcs_index
};
static const uint8_t radiotap_header_vht[] __attribute__((unused)) = {
0x00, 0x00, // <-- radiotap version
0x14, 0x00, // <- radiotap header length
0x00, 0x00, 0x20, 0x00, // <-- radiotap present flags: VHT Information
0x45, 0x00, // Known VHT information: 0000 0000 0100 0101, BW, GI, STBC
0x00, // Flags, BIT(0)=STBC, BIT(2)=GI
0x04, // BW, 0:20M, 1:40M, 4:80, 11:160
0x00, 0x00, 0x00, 0x00, // MCS_NSS[0:3]
0x00, // Coding[3:0], BCC/LDPC
0x00, // Group ID, not used
0x00, 0x00 // Partial AID, not used
};
#define WIFI_MTU 1500 // WiFi interface mtu. You can increase it if your card allow larger packets,
// but this can lead to interoperability issues and/or kernel crashes.
// If you use non-default MTU then you need to configure proper MTU on WiFi cards manually.
@ -81,13 +105,18 @@ static uint8_t radiotap_header[] __attribute__((unused)) = {
#define PACKET_INJECTION_TIMEOUT_MS 5
// Radiotap header will be discarded after injection so we can ingnore it in MTU calculations
#define MAX_PACKET_SIZE (WIFI_MTU + sizeof(radiotap_header))
#define MAX_RX_INTERFACES 8
// offset of MCS_FLAGS and MCS index
#define MCS_FLAGS_OFF 11
#define MCS_IDX_OFF 12
// offset of VHT information
#define VHT_FLAGS_OFF 10
#define VHT_BW_OFF 11
#define VHT_MCSNSS0_OFF 12
#define VHT_CODING_OFF 16
//the last four bytes used for channel_id
#define SRC_MAC_THIRD_BYTE 12
#define DST_MAC_THIRD_BYTE 18
@ -102,7 +131,7 @@ static uint8_t radiotap_header[] __attribute__((unused)) = {
// First address byte 'W'(0x57) has two lower bits set that means that address is multicast and locally administred
// See https://en.wikipedia.org/wiki/MAC_address for reference
static uint8_t ieee80211_header[] __attribute__((unused)) = {
static const uint8_t ieee80211_header[] __attribute__((unused)) = {
0x08, 0x01, 0x00, 0x00, // data frame, not protected, from STA to DS via an AP, duration not set
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // receiver is broadcast
0x57, 0x42, 0xaa, 0xbb, 0xcc, 0xdd, // last four bytes will be replaced by channel_id
@ -186,9 +215,9 @@ typedef struct {
uint16_t packet_size; // big endian
} __attribute__ ((packed)) wpacket_hdr_t;
#define MAX_PAYLOAD_SIZE (MAX_PACKET_SIZE - sizeof(radiotap_header) - sizeof(ieee80211_header) - sizeof(wblock_hdr_t) - crypto_aead_chacha20poly1305_ABYTES - sizeof(wpacket_hdr_t))
#define MAX_FEC_PAYLOAD (MAX_PACKET_SIZE - sizeof(radiotap_header) - sizeof(ieee80211_header) - sizeof(wblock_hdr_t) - crypto_aead_chacha20poly1305_ABYTES)
#define MAX_FORWARDER_PACKET_SIZE (MAX_PACKET_SIZE - sizeof(radiotap_header) - sizeof(ieee80211_header))
#define MAX_PAYLOAD_SIZE (WIFI_MTU - sizeof(ieee80211_header) - sizeof(wblock_hdr_t) - crypto_aead_chacha20poly1305_ABYTES - sizeof(wpacket_hdr_t))
#define MAX_FEC_PAYLOAD (WIFI_MTU - sizeof(ieee80211_header) - sizeof(wblock_hdr_t) - crypto_aead_chacha20poly1305_ABYTES)
#define MAX_FORWARDER_PACKET_SIZE (WIFI_MTU - sizeof(ieee80211_header))
int open_udp_socket_for_rx(int port, int rcv_buf_size);
uint64_t get_time_ms(void);

View File

@ -420,6 +420,10 @@ def init_wlans(max_bw, wlans):
ht_mode = 'HT20'
elif max_bw == 40:
ht_mode = 'HT40+'
elif max_bw == 80:
ht_mode = '80MHz'
elif max_bw == 160:
ht_mode = '160MHz'
else:
raise Exception('Unsupported bandwith %d MHz' % (max_bw,))