add udp socket support

This commit is contained in:
Miroslav Hutár 2024-02-15 15:53:57 +01:00
parent 23c6aaee25
commit f628479edb
22 changed files with 828 additions and 509 deletions

1
.env Normal file
View File

@ -0,0 +1 @@
FEITCSI_VERSION=1.1.0

View File

@ -1,3 +1,8 @@
include .env
# Variables
CDEFS += -DFEITCSI_VERSION="\"${FEITCSI_VERSION}"\"
# Target # Target
BIN_DIR = bin BIN_DIR = bin
BIN = $(BIN_DIR)/app BIN = $(BIN_DIR)/app
@ -19,7 +24,7 @@ INCLUDE_LIB_DIRS =
INCLUDE_LIB = $(foreach includedir,$(INCLUDE_LIB_DIRS),-L$(includedir)) INCLUDE_LIB = $(foreach includedir,$(INCLUDE_LIB_DIRS),-L$(includedir))
# Set compiler, preprocesor and linker flags # Set compiler, preprocesor and linker flags
CXXFLAGS += -g -O3 -Wall -std=c++17 $(INCLUDE) CXXFLAGS += -g -O3 -Wall -std=c++17 $(CDEFS) $(INCLUDE)
CPPFLAGS += `pkg-config --cflags gtkmm-3.0 libnl-3.0 libnl-genl-3.0 libpcap` CPPFLAGS += `pkg-config --cflags gtkmm-3.0 libnl-3.0 libnl-genl-3.0 libpcap`
LDFLAGS += $(INCLUDE_LIB) LDFLAGS += $(INCLUDE_LIB)
LDLIBS += `pkg-config --libs gtkmm-3.0 libnl-3.0 libnl-genl-3.0 libpcap` LDLIBS += `pkg-config --libs gtkmm-3.0 libnl-3.0 libnl-genl-3.0 libpcap`

98
include/Arguments.h Normal file
View File

@ -0,0 +1,98 @@
/*
* FeitCSI is the tool for extracting CSI information from supported intel NICs.
* Copyright (C) 2024 Miroslav Hutar.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ARGUMENTS_PARSER_H
#define ARGUMENTS_PARSER_H
#include <string>
#include <cstdint>
#include <map>
#include <argp.h>
#include "main.h"
struct Args
{
bool verbose;
uint16_t frequency;
bool gui = false;
bool udpSocket = false;
bool plot = false;
std::string bandwidth;
std::string outputFile;
uint8_t mcs;
uint16_t channelWidth;
uint8_t spatialStreams;
uint8_t txPower;
uint32_t antenna;
uint16_t guardInterval;
uint32_t injectDelay;
uint32_t injectRepeat;
std::string coding;
std::string format;
bool inject;
bool measure;
std::string mode;
std::string ltf;
std::string inputFile;
std::map<enum processor, bool> processors;
};
class Arguments
{
public:
inline static struct Args arguments;
static void init();
static void parse(int argc, char *argv[]);
static error_t parse_opt(int key, char *arg, argp_state *state);
private:
/* Program documentation. */
inline static char doc[] =
"FeitCSI - FeitCSI, the tool that enables CSI extraction and injection IEEE 802.11 frames";
/* A description of the arguments we accept. */
inline static char args_doc[] = "ARG1 ARG2";
/* The options we understand. */
inline static struct argp_option options[] = {
{"frequency", 'f', "FREQUENCY", 0, "Frequency to measure/inject CSI"},
{"channel-width", 'w', "CHANNELWIDTH", 0, "Channel width to measure/inject CSI. Possible values [20|40|HT40-|80|160]"},
{"output-file", 'o', "FILE", 0, "Output file where measurements should be stored."},
{"mcs", 'm', "MCS", 0, "Mcs index [0-11]"},
{"format", 'r', "FORMAT", 0, "Data frame format [NOHT|HT|VHT|HESU]"},
{"spatial-streams", 's', "SPATIALSTREAMS", 0, "Number of spatial streams [1|2]"},
{"guard-interval", 'g', "GUARDINTERVAL", 0, "Guard interval in ns [400|800]"},
{"ltf", 'l', "LTF", 0, "HE LTF [2xLTF+0.8|2xLTF+1.6|4xLTF+3.2|4xLTF+0.8]"},
{"coding", 'c', "CODING", 0, "Coding scheme [LDPC|BCC]"},
{"tx-power", 't', "TXPOWER", 0, "TX power of antenna in dBm [1-22]"},
{"antenna", 'a', "ANTENNA", 0, "Transmitting antenna 1, 2 or 12 for both"},
{"mode", 'i', "MODE", 0, "Mode of program[measure|inject|measureinject]"},
{"inject-delay", 'd', "INJECTDELAY", 0, "Delay between frame injections is us"},
{"inject-repeat", 'j', "INJECTREPEAT", 0, "How many times inject frame"},
{"verbose", 'v', 0, OPTION_ARG_OPTIONAL, "Produce verbose output"},
{"plot", 'p', 0, OPTION_ARG_OPTIONAL, "Plot CSI data"},
{"gui", 'x', 0, OPTION_ARG_OPTIONAL, "Run application in GUI"},
{"udp-socket", 'u', 0, OPTION_ARG_OPTIONAL, "Run application and listen to UDP"},
{0}};
};
#endif

View File

@ -1,6 +1,6 @@
/* /*
* FeitCSI is the tool for extracting CSI information from supported intel NICs. * FeitCSI is the tool for extracting CSI information from supported intel NICs.
* Copyright (C) 2023 Miroslav Hutar. * Copyright (C) 2023-2024 Miroslav Hutar.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -23,6 +23,7 @@
#include <string> #include <string>
#include <complex> #include <complex>
#include <vector> #include <vector>
#include "UdpSocket.h"
#define CSI_HEADER_LENGTH 272 #define CSI_HEADER_LENGTH 272
@ -56,6 +57,7 @@ public:
void loadFromMemory(uint8_t *pHeader, uint8_t *rawCsiData); void loadFromMemory(uint8_t *pHeader, uint8_t *rawCsiData);
void loadFromMemory(uint8_t *rawData); void loadFromMemory(uint8_t *rawData);
void save(); void save();
void sendUDP(UdpSocket *udpSocket);
void backup(); void backup();
void restore(); void restore();
void magnitudePhaseToComplex(); void magnitudePhaseToComplex();

View File

@ -1,6 +1,6 @@
/* /*
* FeitCSI is the tool for extracting CSI information from supported intel NICs. * FeitCSI is the tool for extracting CSI information from supported intel NICs.
* Copyright (C) 2023 Miroslav Hutar. * Copyright (C) 2023-2024 Miroslav Hutar.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -23,18 +23,20 @@
#include "WiFIController.h" #include "WiFIController.h"
#include "PacketInjector.h" #include "PacketInjector.h"
#include "gui/MainWindow.h" #include "gui/MainWindow.h"
#include "UdpSocket.h"
#include <thread> #include <thread>
class MainController class MainController
{ {
public: public:
static MainController *getInstance(); inline static UdpSocket *udpSocket = nullptr;
static MainController *getInstance();
static void deleteInstance(); static void deleteInstance();
void runNoGui(); void runNoGui(bool detach = false);
void measureCsi(bool stop = false); void measureCsi(bool stop = false);
@ -42,7 +44,12 @@ public:
void runGui(); void runGui();
void runUdpSocket();
void initInterface(); void initInterface();
void restoreState();
~MainController(); ~MainController();
private: private:
@ -62,14 +69,12 @@ private:
std::vector<InterfaceInfo> bkpInterfaces; std::vector<InterfaceInfo> bkpInterfaces;
static void *measureCsi(void *arg); static void *measureCsi(void *arg);
static void intHandler(int dummy); static void intHandler(int dummy);
static void *injectPackets(void *arg); static void *injectPackets(void *arg);
void restoreState();
}; };
#endif #endif

View File

@ -1,6 +1,6 @@
/* /*
* FeitCSI is the tool for extracting CSI information from supported intel NICs. * FeitCSI is the tool for extracting CSI information from supported intel NICs.
* Copyright (C) 2023 Miroslav Hutar. * Copyright (C) 2023-2024 Miroslav Hutar.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -22,6 +22,7 @@
#include <stdint.h> #include <stdint.h>
#include "ieee80211_radiotap.h" #include "ieee80211_radiotap.h"
#include "rs.h" #include "rs.h"
#include <pcap.h>
#define BIT(n) (0x1U << (n)) #define BIT(n) (0x1U << (n))
@ -38,6 +39,7 @@ public:
private: private:
void send(uint32_t rateNFlags); void send(uint32_t rateNFlags);
pcap_t *ppcap = nullptr;
}; };
#endif #endif

39
include/UdpSocket.h Normal file
View File

@ -0,0 +1,39 @@
/*
* FeitCSI is the tool for extracting CSI information from supported intel NICs.
* Copyright (C) 2024 Miroslav Hutar.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef UDP_SOCKET_H
#define UDP_SOCKET_H
#include <sys/socket.h>
class UdpSocket
{
public:
void init();
void send(char *buf, int size);
private:
int sfd;
bool running = false;
struct sockaddr_storage peer_addr;
socklen_t peer_addr_len;
};
#endif

View File

@ -1,6 +1,6 @@
/* /*
* FeitCSI is the tool for extracting CSI information from supported intel NICs. * FeitCSI is the tool for extracting CSI information from supported intel NICs.
* Copyright (C) 2023 Miroslav Hutar. * Copyright (C) 2023-2024 Miroslav Hutar.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -39,6 +39,7 @@ public:
private: private:
static int listenToCsiHandler(nl80211_state *state, nl_msg *msg, void *arg); static int listenToCsiHandler(nl80211_state *state, nl_msg *msg, void *arg);
static int processListenToCsiHandler(nl_msg *msg, void *arg); static int processListenToCsiHandler(nl_msg *msg, void *arg);
static void printDetail(Csi &c);
GnuPlot gnuPlot; GnuPlot gnuPlot;
}; };

View File

@ -1,6 +1,6 @@
/* /*
* FeitCSI is the tool for extracting CSI information from supported intel NICs. * FeitCSI is the tool for extracting CSI information from supported intel NICs.
* Copyright (C) 2023 Miroslav Hutar. * Copyright (C) 2023-2024 Miroslav Hutar.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -19,10 +19,6 @@
#ifndef MAIN_H #ifndef MAIN_H
#define MAIN_H #define MAIN_H
#include <string>
#include <cstdint>
#include <map>
#define MONITOR_INTERFACE_NAME "mon0" #define MONITOR_INTERFACE_NAME "mon0"
enum processor enum processor
@ -33,34 +29,4 @@ enum processor
phaseCalibrationLinearTransform, phaseCalibrationLinearTransform,
}; };
struct Arguments
{
bool verbose;
uint16_t frequency;
bool gui = false;
bool plot = false;
std::string bandwidth;
std::string outputFile;
uint8_t mcs;
uint16_t channelWidth;
uint8_t spatialStreams;
uint8_t txPower;
uint32_t antenna;
uint16_t guardInterval;
uint32_t injectDelay;
uint32_t injectRepeat;
std::string coding;
std::string format;
bool inject;
bool measure;
std::string mode;
std::string ltf;
std::string inputFile;
std::map<enum processor, bool> processors;
};
/* Get the input argument from argp_parse, which we
know is a pointer to our arguments structure. */
extern struct Arguments arguments;
#endif #endif

View File

@ -41,7 +41,7 @@ citations to the FeitCSI project:
## Competition ## Competition
There are some platforms, that are used to extract CSI from commodity hardware. However, they don't support current standards or injection packets. The only one competition is PicoScenes. It is a robust and good platform but FeitCSI has several advantages against it: There are some platforms, that are used to extract CSI from commodity hardware. However, they don't support current standards or injection packets. The only one competition is PicoScenes. It is a robust and good platform but FeitCSI has several advantages against it:
* **All for free without limits** (Some of the functionality (full 6GHz spectrum, packet injection in 11ac/ax format with 80/160MHz channel bandwidth, ...) are allowed after payment for the license in PicoScenes) * **All for free without limits**
* **No restriction to specific version of Linux OS and computer architecture** (PicoScenes work only on CPU with SSE4.2 or AVX2 and you need to have Ubuntu 20.04 LTS or its variants. **FeitCSI will work on every computer architecture** where can be installed Linux (e.g. x86-64, ARM). But of course, you have to plug NICs via PCI.) * **No restriction to specific version of Linux OS and computer architecture** (PicoScenes work only on CPU with SSE4.2 or AVX2 and you need to have Ubuntu 20.04 LTS or its variants. **FeitCSI will work on every computer architecture** where can be installed Linux (e.g. x86-64, ARM). But of course, you have to plug NICs via PCI.)
* **Support virtual environment** (If you don't want to install software on your computer or you have trouble, just download our prepared image of FeitCSI and enjoy FeitCSI in the virtual environment. Follow the steps in [Getting started - Virtual environment](https://feitcsi.kuskosoft.com/getting_started/#virtual-environment)) * **Support virtual environment** (If you don't want to install software on your computer or you have trouble, just download our prepared image of FeitCSI and enjoy FeitCSI in the virtual environment. Follow the steps in [Getting started - Virtual environment](https://feitcsi.kuskosoft.com/getting_started/#virtual-environment))
* **Live medium** (Our image can be also used in live medium (e.g. USB), not only in the virtual environment) * **Live medium** (Our image can be also used in live medium (e.g. USB), not only in the virtual environment)

273
src/Arguments.cpp Normal file
View File

@ -0,0 +1,273 @@
/*
* FeitCSI is the tool for extracting CSI information from supported intel NICs.
* Copyright (C) 2024 Miroslav Hutar.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Arguments.h"
#include "WiFIController.h"
#include "rs.h"
const std::string VERSION = (std::string("FeitCSI ") + FEITCSI_VERSION);
const char *argp_program_version = VERSION.c_str();
const char *argp_program_bug_address = "https://github.com/KuskoSoft/FeitCSI/issues";
void Arguments::init()
{
Arguments::arguments = {
.verbose = false,
.frequency = 2412,
.gui = false,
.udpSocket = false,
.plot = false,
.bandwidth = "20",
.mcs = 0,
.channelWidth = 20,
.spatialStreams = 1,
.txPower = 10,
.antenna = RATE_MCS_ANT_A_MSK,
.guardInterval = 400,
.injectDelay = 100000,
.injectRepeat = 0,
.coding = "LDPC",
.format = "NOHT",
.inject = false,
.measure = true,
.mode = "measure",
.ltf = "1xLTF+0.8",
};
}
void Arguments::parse(int argc, char *argv[])
{
static struct argp argp = {options, parse_opt, args_doc, doc};
argp_parse(&argp, argc, argv, 0, 0, &arguments);
}
error_t Arguments::parse_opt(int key, char *arg, struct argp_state *state)
{
/* Get the input argument from argp_parse, which we
know is a pointer to our arguments structure. */
struct Args *args = (struct Args *)state->input;
switch (key)
{
case 'v':
args->verbose = true;
break;
case 'x':
args->gui = true;
break;
case 'u':
args->udpSocket = true;
break;
case 'p':
args->plot = true;
break;
case 'i':
{
args->mode.assign(arg);
if (args->mode == "measure")
{
args->measure = true;
}
else if (args->mode == "inject")
{
args->inject = true;
args->measure = false;
}
else if (args->mode == "measureinject")
{
args->measure = true;
args->inject = true;
}
else
{
argp_failure(state, 1, 0, "Bad mode. Possible values [measure|inject|measureinject]");
exit(ARGP_ERR_UNKNOWN);
}
break;
}
case 'm':
{
int mcs = std::atoi(arg);
if (mcs < 0 || mcs > 11)
{
argp_failure(state, 1, 0, "Bad MCS index. Possible values [0-11]");
exit(ARGP_ERR_UNKNOWN);
}
args->mcs = (uint8_t)mcs;
break;
}
case 'r':
{
args->format.assign(arg);
if (args->format == "NOHT" || args->format == "HT" || args->format == "VHT" || args->format == "HESU")
{
}
else
{
argp_failure(state, 1, 0, "Bad format. Possible values [NOHT|HT|VHT|HESU]");
exit(ARGP_ERR_UNKNOWN);
}
break;
}
case 'c':
{
args->coding.assign(arg);
if (args->coding == "LDPC" || args->coding == "BCC")
{
}
else
{
argp_failure(state, 1, 0, "Bad coding. Possible values [LDPC|BCC]");
exit(ARGP_ERR_UNKNOWN);
}
break;
}
case 'l':
{
args->ltf.assign(arg);
if (args->ltf == "1xLTF+0.8" || args->ltf == "2xLTF+0.8" || args->ltf == "2xLTF+1.6" || args->ltf == "4xLTF+3.2" || args->ltf == "4xLTF+0.8")
{
}
else
{
argp_failure(state, 1, 0, "Bad LTF. Possible values [2xLTF+0.8|2xLTF+1.6|4xLTF+3.2|4xLTF+0.8]");
exit(ARGP_ERR_UNKNOWN);
}
break;
}
case 'g':
{
int gi = std::atoi(arg);
if (gi == 400 || gi == 800)
{
args->guardInterval = (uint16_t)gi;
}
else
{
argp_failure(state, 1, 0, "Bad guard interval. Possible values [400|800]");
exit(ARGP_ERR_UNKNOWN);
}
break;
}
case 'd':
{
int injd = std::atoi(arg);
if (injd <= 0)
{
argp_failure(state, 1, 0, "Inject delay is not correct number");
exit(ARGP_ERR_UNKNOWN);
}
args->injectDelay = (uint32_t)injd;
break;
}
case 'j':
{
int injr = std::atoi(arg);
if (injr <= 0)
{
argp_failure(state, 1, 0, "Inject repeat is not correct number");
exit(ARGP_ERR_UNKNOWN);
}
args->injectRepeat = (uint32_t)injr;
break;
}
case 's':
{
int ss = std::atoi(arg);
if (ss < 1 || ss > 2)
{
argp_failure(state, 1, 0, "Bad spatial stream. Possible values [1|2]");
exit(ARGP_ERR_UNKNOWN);
}
args->spatialStreams = (uint8_t)ss;
break;
}
case 't':
{
int tx = std::atoi(arg);
if (tx < 1 || tx > 22)
{
argp_failure(state, 1, 0, "Bad tx power. Possible values [1-22]");
exit(ARGP_ERR_UNKNOWN);
}
args->txPower = (uint8_t)tx;
break;
}
case 'a':
{
int a = std::atoi(arg);
if (a == 1)
{
args->antenna = RATE_MCS_ANT_A_MSK;
}
else if (a == 2)
{
args->antenna = RATE_MCS_ANT_B_MSK;
}
else if (a == 12)
{
args->antenna = RATE_MCS_ANT_AB_MSK;
}
else
{
argp_failure(state, 1, 0, "Bad transmitting antenna value. Possible values 1, 2 or 12 for both");
exit(ARGP_ERR_UNKNOWN);
}
break;
}
case 'f':
{
int f = std::atoi(arg);
if (f <= 0)
{
argp_failure(state, 1, 0, "Frequency is not correct");
exit(ARGP_ERR_UNKNOWN);
}
args->frequency = (uint16_t)f;
break;
}
case 'w':
{
struct ChanMode chMode = WiFIController::getChanMode(arg);
if (chMode.width == 0)
{
argp_failure(state, 1, 0, "Bad bandwidth. Possible values of bandwidth are [20|40|HT40-|80|160]");
exit(ARGP_ERR_UNKNOWN);
}
args->bandwidth = arg;
args->channelWidth = WiFIController::chanModeToWidth(chMode);
break;
}
case 'o':
args->outputFile = arg;
break;
case ARGP_KEY_ARG:
case ARGP_KEY_END:
if (args->frequency == 0 ||
args->bandwidth.empty())
{
argp_failure(state, 1, 0, "Fill required arguments -f -b . See --help for more information");
exit(ARGP_ERR_UNKNOWN);
}
return 0;
default:
return ARGP_ERR_UNKNOWN;
}
return 0;
}

View File

@ -1,6 +1,6 @@
/* /*
* FeitCSI is the tool for extracting CSI information from supported intel NICs. * FeitCSI is the tool for extracting CSI information from supported intel NICs.
* Copyright (C) 2023 Miroslav Hutar. * Copyright (C) 2023-2024 Miroslav Hutar.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -24,9 +24,9 @@
#include <vector> #include <vector>
#include <iostream> #include <iostream>
#include <filesystem> #include <filesystem>
#include "main.h"
#include "rs.h" #include "rs.h"
#include "Logger.h" #include "Logger.h"
#include "Arguments.h"
Csi::Csi() Csi::Csi()
{ {
@ -73,7 +73,7 @@ void Csi::loadFromMemory(uint8_t *rawData)
void Csi::save() void Csi::save()
{ {
std::ofstream outfile; std::ofstream outfile;
outfile.open(arguments.outputFile, std::ios_base::app | std::ios::binary); outfile.open(Arguments::arguments.outputFile, std::ios_base::app | std::ios::binary);
if (outfile.fail()) if (outfile.fail())
{ {
throw std::ios_base::failure("Open file failed: " + std::string(std::strerror(errno))); throw std::ios_base::failure("Open file failed: " + std::string(std::strerror(errno)));
@ -81,7 +81,16 @@ void Csi::save()
outfile.write(reinterpret_cast<char *>(&this->rawHeaderData), sizeof(RawHeaderData)); outfile.write(reinterpret_cast<char *>(&this->rawHeaderData), sizeof(RawHeaderData));
outfile.write(reinterpret_cast<char *>(this->rawCsiData), this->rawHeaderData.csiDataSize); outfile.write(reinterpret_cast<char *>(this->rawCsiData), this->rawHeaderData.csiDataSize);
outfile.close(); outfile.close();
std::filesystem::permissions(arguments.outputFile, std::filesystem::perms::all & ~(std::filesystem::perms::owner_exec | std::filesystem::perms::group_exec | std::filesystem::perms::others_exec), std::filesystem::perm_options::add); std::filesystem::permissions(Arguments::arguments.outputFile, std::filesystem::perms::all & ~(std::filesystem::perms::owner_exec | std::filesystem::perms::group_exec | std::filesystem::perms::others_exec), std::filesystem::perm_options::add);
}
void Csi::sendUDP(UdpSocket *udpSocket)
{
int size = CSI_HEADER_LENGTH + this->rawHeaderData.csiDataSize;
char data[size];
memcpy(data, &this->rawHeaderData, CSI_HEADER_LENGTH);
memcpy(&data[CSI_HEADER_LENGTH], this->rawCsiData, this->rawHeaderData.csiDataSize);
udpSocket->send(data, size);
} }
void Csi::fixCsiBug() void Csi::fixCsiBug()
@ -196,57 +205,6 @@ void Csi::processRawCsi()
this->magnitude.push_back(std::abs(c)); this->magnitude.push_back(std::abs(c));
this->phase.push_back(std::arg(c)); this->phase.push_back(std::arg(c));
} }
//this->unwrapPhase();
if (arguments.verbose)
{
Logger::log(info) << "Subcarrier count: " << this->rawHeaderData.numSubCarriers << ", ";
Logger::log(info, true) << "RX: " << +this->rawHeaderData.numRx << ", ";
Logger::log(info, true) << "TX: " << +this->rawHeaderData.numTx << ", ";
switch (channelWidth)
{
case RATE_MCS_CHAN_WIDTH_20:
Logger::log(info, true) << "Channel width: 20, ";
break;
case RATE_MCS_CHAN_WIDTH_40:
Logger::log(info, true) << "Channel width: 40, ";
break;
case RATE_MCS_CHAN_WIDTH_80:
Logger::log(info, true) << "Channel width: 80, ";
break;
case RATE_MCS_CHAN_WIDTH_160:
Logger::log(info, true) << "Channel width: 160, ";
break;
}
switch (format)
{
case RATE_MCS_CCK_MSK: // VERY OLD FORMAT
Logger::log(info, true) << "Format: CCK\n";
break;
case RATE_MCS_LEGACY_OFDM_MSK:
Logger::log(info, true) << "Format: LEGACY_OFDM\n";
break;
break;
case RATE_MCS_HT_MSK:
Logger::log(info, true) << "Format: HT\n";
break;
break;
case RATE_MCS_VHT_MSK:
Logger::log(info, true) << "Format: VHT\n";
break;
break;
case RATE_MCS_HE_MSK:
Logger::log(info, true) << "Format: HE\n";
break;
break;
case RATE_MCS_EHT_MSK:
Logger::log(info, true) << "Format: EHT\n";
break;
break;
}
}
} }
void Csi::backup() void Csi::backup()

View File

@ -21,6 +21,7 @@
#include "Logger.h" #include "Logger.h"
#include "GnuPlot.h" #include "GnuPlot.h"
#include "interpolation.h" #include "interpolation.h"
#include "Arguments.h"
#include <fstream> #include <fstream>
#include <numeric> #include <numeric>
@ -30,7 +31,7 @@
bool CsiProcessor::loadCsi() bool CsiProcessor::loadCsi()
{ {
this->clearState(); this->clearState();
std::ifstream ifs(arguments.inputFile, std::ios::binary); std::ifstream ifs(Arguments::arguments.inputFile, std::ios::binary);
ifs.seekg (0, ifs.end); ifs.seekg (0, ifs.end);
int length = ifs.tellg(); int length = ifs.tellg();
@ -60,7 +61,7 @@ bool CsiProcessor::loadCsi()
void CsiProcessor::saveCsi() void CsiProcessor::saveCsi()
{ {
std::ofstream outfile; std::ofstream outfile;
outfile.open(arguments.outputFile, std::ios_base::app | std::ios::binary); outfile.open(Arguments::arguments.outputFile, std::ios_base::app | std::ios::binary);
if (outfile.fail()) if (outfile.fail())
{ {
throw std::ios_base::failure("Open file failed: " + std::string(std::strerror(errno))); throw std::ios_base::failure("Open file failed: " + std::string(std::strerror(errno)));
@ -74,7 +75,7 @@ void CsiProcessor::saveCsi()
outfile.write(reinterpret_cast<char *>(c->csi.data()), c->rawHeaderData.csiDataSize); outfile.write(reinterpret_cast<char *>(c->csi.data()), c->rawHeaderData.csiDataSize);
} }
outfile.close(); outfile.close();
std::filesystem::permissions(arguments.outputFile, std::filesystem::perms::all & ~(std::filesystem::perms::owner_exec | std::filesystem::perms::group_exec | std::filesystem::perms::others_exec), std::filesystem::perm_options::add); std::filesystem::permissions(Arguments::arguments.outputFile, std::filesystem::perms::all & ~(std::filesystem::perms::owner_exec | std::filesystem::perms::group_exec | std::filesystem::perms::others_exec), std::filesystem::perm_options::add);
} }
CsiProcessor::~CsiProcessor() CsiProcessor::~CsiProcessor()
@ -132,20 +133,20 @@ void CsiProcessor::process(Csi &csi)
csi.backup(); csi.backup();
csi.restore(); csi.restore();
if (arguments.processors[processor::interpolateLinear]) if (Arguments::arguments.processors[processor::interpolateLinear])
{ {
this->interpolate(csi, processor::interpolateLinear); this->interpolate(csi, processor::interpolateLinear);
} }
else if (arguments.processors[processor::interpolateCubic]) else if (Arguments::arguments.processors[processor::interpolateCubic])
{ {
this->interpolate(csi, processor::interpolateCubic); this->interpolate(csi, processor::interpolateCubic);
} }
else if (arguments.processors[processor::interpolateCosine]) else if (Arguments::arguments.processors[processor::interpolateCosine])
{ {
this->interpolate(csi, processor::interpolateCosine); this->interpolate(csi, processor::interpolateCosine);
} }
if (arguments.processors[processor::phaseCalibrationLinearTransform]) if (Arguments::arguments.processors[processor::phaseCalibrationLinearTransform])
{ {
this->phaseCalibLinearTransform(csi); this->phaseCalibLinearTransform(csi);
} }

View File

@ -1,6 +1,6 @@
/* /*
* FeitCSI is the tool for extracting CSI information from supported intel NICs. * FeitCSI is the tool for extracting CSI information from supported intel NICs.
* Copyright (C) 2023 Miroslav Hutar. * Copyright (C) 2023-2024 Miroslav Hutar.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -17,7 +17,7 @@
*/ */
#include "MainController.h" #include "MainController.h"
#include "main.h" #include "Arguments.h"
#include "Logger.h" #include "Logger.h"
#include "gui/MainWindow.h" #include "gui/MainWindow.h"
#include "layout.h" #include "layout.h"
@ -44,31 +44,42 @@ void MainController::deleteInstance()
delete MainController::INSTANCE; delete MainController::INSTANCE;
} }
void MainController::runNoGui() void MainController::runNoGui(bool detach)
{ {
this->initInterface(); this->initInterface();
if (arguments.measure) if (Arguments::arguments.measure)
{ {
pthread_create(&this->measureCsiThread, NULL, &MainController::measureCsi, NULL); pthread_create(&this->measureCsiThread, NULL, &MainController::measureCsi, NULL);
} }
if (arguments.inject) if (Arguments::arguments.inject)
{ {
pthread_create(&this->injectPacketThread, NULL, &MainController::injectPackets, NULL); pthread_create(&this->injectPacketThread, NULL, &MainController::injectPackets, NULL);
} }
if (arguments.measure) if (Arguments::arguments.measure)
{ {
if (detach) {
pthread_detach(this->measureCsiThread);
} else {
pthread_join(this->measureCsiThread, NULL); pthread_join(this->measureCsiThread, NULL);
} }
if (arguments.inject) }
if (Arguments::arguments.inject)
{ {
if (detach) {
pthread_detach(this->injectPacketThread);
} else {
pthread_join(this->injectPacketThread, NULL); pthread_join(this->injectPacketThread, NULL);
} }
}
if (!detach) {
this->deleteInstance(); this->deleteInstance();
} }
}
void MainController::measureCsi(bool stop) void MainController::measureCsi(bool stop)
{ {
this->wifiController.setFreq(arguments.frequency, arguments.bandwidth.c_str()); this->wifiController.setFreq(Arguments::arguments.frequency, Arguments::arguments.bandwidth.c_str());
if (stop) if (stop)
{ {
pthread_cancel(this->measureCsiThread); pthread_cancel(this->measureCsiThread);
@ -83,7 +94,7 @@ void MainController::measureCsi(bool stop)
void MainController::injectPackets(bool stop) void MainController::injectPackets(bool stop)
{ {
this->wifiController.setTxPower(); this->wifiController.setTxPower();
this->wifiController.setFreq(arguments.frequency, arguments.bandwidth.c_str()); this->wifiController.setFreq(Arguments::arguments.frequency, Arguments::arguments.bandwidth.c_str());
if (stop) if (stop)
{ {
pthread_cancel(this->injectPacketThread); pthread_cancel(this->injectPacketThread);
@ -97,10 +108,10 @@ void MainController::injectPackets(bool stop)
void MainController::runGui() void MainController::runGui()
{ {
arguments.plot = true; Arguments::arguments.plot = true;
arguments.verbose = true; Arguments::arguments.verbose = true;
arguments.measure = false; Arguments::arguments.measure = false;
arguments.inject = false; Arguments::arguments.inject = false;
gtk_init(NULL, NULL); gtk_init(NULL, NULL);
Glib::init(); Glib::init();
auto app = Gtk::Application::create("com.kuskosoft.feitcsi"); auto app = Gtk::Application::create("com.kuskosoft.feitcsi");
@ -110,6 +121,12 @@ void MainController::runGui()
app->run(*this->mainWindow); app->run(*this->mainWindow);
} }
void MainController::runUdpSocket()
{
this->udpSocket = new UdpSocket();
udpSocket->init();
}
void MainController::initInterface() void MainController::initInterface()
{ {
try try
@ -121,7 +138,7 @@ void MainController::initInterface()
// delete actual interfaces // delete actual interfaces
for (InterfaceInfo interface : this->wifiController.interfaces) for (InterfaceInfo interface : this->wifiController.interfaces)
{ {
if (arguments.verbose) if (Arguments::arguments.verbose)
{ {
Logger::log(info) << "Remove interface " << interface.ifName << "\n"; Logger::log(info) << "Remove interface " << interface.ifName << "\n";
} }
@ -130,7 +147,7 @@ void MainController::initInterface()
} }
this->wifiController.addMonitorDevice(MONITOR_INTERFACE_NAME, NL80211_IFTYPE_MONITOR); this->wifiController.addMonitorDevice(MONITOR_INTERFACE_NAME, NL80211_IFTYPE_MONITOR);
this->wifiController.setInterfaceUpDown(MONITOR_INTERFACE_NAME, true); this->wifiController.setInterfaceUpDown(MONITOR_INTERFACE_NAME, true);
this->wifiController.setFreq(arguments.frequency, arguments.bandwidth.c_str()); this->wifiController.setFreq(Arguments::arguments.frequency, Arguments::arguments.bandwidth.c_str());
if (!MainController::mainWindow) if (!MainController::mainWindow)
{ {
std::this_thread::sleep_for(std::chrono::milliseconds(500)); //wait on init then set power and go next std::this_thread::sleep_for(std::chrono::milliseconds(500)); //wait on init then set power and go next
@ -181,12 +198,12 @@ void *MainController::injectPackets(void *arg)
try try
{ {
PacketInjector pi; PacketInjector pi;
if (arguments.injectRepeat) if (Arguments::arguments.injectRepeat)
{ {
for (uint32_t i = 0; i < arguments.injectRepeat; i++) for (uint32_t i = 0; i < Arguments::arguments.injectRepeat; i++)
{ {
pi.inject(); pi.inject();
std::this_thread::sleep_for(std::chrono::microseconds(arguments.injectDelay)); std::this_thread::sleep_for(std::chrono::microseconds(Arguments::arguments.injectDelay));
} }
} }
else else
@ -194,7 +211,7 @@ void *MainController::injectPackets(void *arg)
while (true) while (true)
{ {
pi.inject(); pi.inject();
std::this_thread::sleep_for(std::chrono::microseconds(arguments.injectDelay)); std::this_thread::sleep_for(std::chrono::microseconds(Arguments::arguments.injectDelay));
} }
} }
} }
@ -229,14 +246,16 @@ void MainController::restoreState()
mainController->wifiController.removeInterface(MONITOR_INTERFACE_NAME); mainController->wifiController.removeInterface(MONITOR_INTERFACE_NAME);
for (InterfaceInfo interface : mainController->bkpInterfaces) for (InterfaceInfo interface : mainController->bkpInterfaces)
{ {
if (arguments.verbose) if (Arguments::arguments.verbose)
{ {
Logger::log(info) << "Recovering interface " << interface.ifName << "\n"; Logger::log(info) << "Recovering interface " << interface.ifName << "\n";
} }
mainController->wifiController.addMonitorDevice(interface.ifName.c_str(), (nl80211_iftype)interface.ifType); mainController->wifiController.addMonitorDevice(interface.ifName.c_str(), (nl80211_iftype)interface.ifType);
} }
mainController->bkpInterfaces.clear();
mainController->wifiController.interfaces.clear();
if (arguments.verbose) if (Arguments::arguments.verbose)
{ {
Logger::log(info) << "Exiting recovery state...\n"; Logger::log(info) << "Exiting recovery state...\n";
} }
@ -245,6 +264,9 @@ void MainController::restoreState()
MainController::~MainController() MainController::~MainController()
{ {
this->restoreState(); this->restoreState();
if (udpSocket) {
delete udpSocket;
}
} }
void MainController::intHandler(int dummy) void MainController::intHandler(int dummy)

View File

@ -1,6 +1,6 @@
/* /*
* FeitCSI is the tool for extracting CSI information from supported intel NICs. * FeitCSI is the tool for extracting CSI information from supported intel NICs.
* Copyright (C) 2023 Miroslav Hutar. * Copyright (C) 2023-2024 Miroslav Hutar.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -19,8 +19,8 @@
#include "PacketInjector.h" #include "PacketInjector.h"
#include "main.h" #include "main.h"
#include "Logger.h" #include "Logger.h"
#include "Arguments.h"
#include <string.h> #include <string.h>
#include <pcap.h>
#include <iostream> #include <iostream>
#define SPATIAL_STREAM 16 #define SPATIAL_STREAM 16
@ -32,25 +32,25 @@ uint8_t ieee80211Body[] = {};
void PacketInjector::inject() void PacketInjector::inject()
{ {
if (arguments.verbose) if (Arguments::arguments.verbose)
{ {
Logger::log(info) << "Injecting " << arguments.format << "\n"; Logger::log(info) << "Injecting " << Arguments::arguments.format << "\n";
} }
if (arguments.format == "NOHT") if (Arguments::arguments.format == "NOHT")
{ {
this->injectNoHT(); this->injectNoHT();
} }
else if (arguments.format == "HT") else if (Arguments::arguments.format == "HT")
{ {
this->injectHT(); this->injectHT();
} }
else if (arguments.format == "VHT") else if (Arguments::arguments.format == "VHT")
{ {
this->injectVHT(); this->injectVHT();
} }
else if (arguments.format == "HESU") else if (Arguments::arguments.format == "HESU")
{ {
this->injectHE(); this->injectHE();
} }
@ -59,11 +59,11 @@ void PacketInjector::inject()
void PacketInjector::injectNoHT() void PacketInjector::injectNoHT()
{ {
uint8_t mcs = 0; uint8_t mcs = 0;
if (RATE_LEGACY_RATE_MSK >= arguments.mcs) if (RATE_LEGACY_RATE_MSK >= Arguments::arguments.mcs)
{ {
mcs = RATE_LEGACY_RATE_MSK & arguments.mcs; mcs = RATE_LEGACY_RATE_MSK & Arguments::arguments.mcs;
} }
uint32_t rateNFlags = RATE_MCS_LEGACY_OFDM_MSK | mcs | arguments.antenna; uint32_t rateNFlags = RATE_MCS_LEGACY_OFDM_MSK | mcs | Arguments::arguments.antenna;
this->send(rateNFlags); this->send(rateNFlags);
} }
@ -71,65 +71,65 @@ void PacketInjector::injectNoHT()
void PacketInjector::injectHT() void PacketInjector::injectHT()
{ {
uint8_t mcs = 0; uint8_t mcs = 0;
if (RATE_HT_MCS_CODE_MSK >= arguments.mcs) if (RATE_HT_MCS_CODE_MSK >= Arguments::arguments.mcs)
{ {
mcs = RATE_HT_MCS_CODE_MSK & arguments.mcs; mcs = RATE_HT_MCS_CODE_MSK & Arguments::arguments.mcs;
} }
uint32_t rateNFlags = uint32_t rateNFlags =
RATE_MCS_HT_MSK | RATE_MCS_HT_MSK |
mcs | mcs |
arguments.antenna | Arguments::arguments.antenna |
(arguments.channelWidth == 40 ? RATE_MCS_CHAN_WIDTH_40 : 0) | (Arguments::arguments.channelWidth == 40 ? RATE_MCS_CHAN_WIDTH_40 : 0) |
(arguments.spatialStreams == 2 ? SPATIAL_STREAM : 0) | (Arguments::arguments.spatialStreams == 2 ? SPATIAL_STREAM : 0) |
(arguments.spatialStreams == 2 ? RATE_MCS_ANT_AB_MSK : 0) | (Arguments::arguments.spatialStreams == 2 ? RATE_MCS_ANT_AB_MSK : 0) |
(arguments.guardInterval == 400 ? RATE_MCS_SGI_MSK : 0) | (Arguments::arguments.guardInterval == 400 ? RATE_MCS_SGI_MSK : 0) |
(arguments.coding == "LDPC" ? RATE_MCS_LDPC_MSK : 0); (Arguments::arguments.coding == "LDPC" ? RATE_MCS_LDPC_MSK : 0);
this->send(rateNFlags); this->send(rateNFlags);
} }
void PacketInjector::injectVHT() void PacketInjector::injectVHT()
{ {
uint8_t mcs = 0; uint8_t mcs = 0;
if (RATE_MCS_CODE_MSK >= arguments.mcs) if (RATE_MCS_CODE_MSK >= Arguments::arguments.mcs)
{ {
mcs = RATE_MCS_CODE_MSK & arguments.mcs; mcs = RATE_MCS_CODE_MSK & Arguments::arguments.mcs;
} }
uint32_t rateNFlags = uint32_t rateNFlags =
RATE_MCS_VHT_MSK | RATE_MCS_VHT_MSK |
mcs | mcs |
arguments.antenna | Arguments::arguments.antenna |
(arguments.channelWidth == 40 ? RATE_MCS_CHAN_WIDTH_40 : 0) | (Arguments::arguments.channelWidth == 40 ? RATE_MCS_CHAN_WIDTH_40 : 0) |
(arguments.channelWidth == 80 ? RATE_MCS_CHAN_WIDTH_80 : 0) | (Arguments::arguments.channelWidth == 80 ? RATE_MCS_CHAN_WIDTH_80 : 0) |
(arguments.channelWidth == 160 ? RATE_MCS_CHAN_WIDTH_160 : 0) | (Arguments::arguments.channelWidth == 160 ? RATE_MCS_CHAN_WIDTH_160 : 0) |
(arguments.spatialStreams == 2 ? SPATIAL_STREAM : 0) | (Arguments::arguments.spatialStreams == 2 ? SPATIAL_STREAM : 0) |
(arguments.spatialStreams == 2 ? RATE_MCS_ANT_AB_MSK : 0) | (Arguments::arguments.spatialStreams == 2 ? RATE_MCS_ANT_AB_MSK : 0) |
(arguments.guardInterval == 400 ? RATE_MCS_SGI_MSK : 0) | (Arguments::arguments.guardInterval == 400 ? RATE_MCS_SGI_MSK : 0) |
(arguments.coding == "LDPC" ? RATE_MCS_LDPC_MSK : 0); (Arguments::arguments.coding == "LDPC" ? RATE_MCS_LDPC_MSK : 0);
this->send(rateNFlags); this->send(rateNFlags);
} }
void PacketInjector::injectHE() void PacketInjector::injectHE()
{ {
uint8_t mcs = 0; uint8_t mcs = 0;
if (RATE_MCS_CODE_MSK >= arguments.mcs) if (RATE_MCS_CODE_MSK >= Arguments::arguments.mcs)
{ {
mcs = RATE_MCS_CODE_MSK & arguments.mcs; mcs = RATE_MCS_CODE_MSK & Arguments::arguments.mcs;
} }
uint32_t ltf = 1; uint32_t ltf = 1;
if (arguments.ltf == "2xLTF+0.8") if (Arguments::arguments.ltf == "2xLTF+0.8")
{ {
ltf = 1; ltf = 1;
} }
else if (arguments.ltf == "2xLTF+1.6") else if (Arguments::arguments.ltf == "2xLTF+1.6")
{ {
ltf = 2; ltf = 2;
} }
else if (arguments.ltf == "4xLTF+3.2") else if (Arguments::arguments.ltf == "4xLTF+3.2")
{ {
ltf = 3; ltf = 3;
} }
else if (arguments.ltf == "4xLTF+0.8") else if (Arguments::arguments.ltf == "4xLTF+0.8")
{ {
ltf = 4; ltf = 4;
} }
@ -139,13 +139,13 @@ void PacketInjector::injectHE()
RATE_MCS_HE_MSK | RATE_MCS_HE_MSK |
RATE_MCS_LDPC_MSK | RATE_MCS_LDPC_MSK |
mcs | mcs |
arguments.antenna | Arguments::arguments.antenna |
ltf | ltf |
(arguments.channelWidth == 40 ? RATE_MCS_CHAN_WIDTH_40 : 0) | (Arguments::arguments.channelWidth == 40 ? RATE_MCS_CHAN_WIDTH_40 : 0) |
(arguments.channelWidth == 80 ? RATE_MCS_CHAN_WIDTH_80 : 0) | (Arguments::arguments.channelWidth == 80 ? RATE_MCS_CHAN_WIDTH_80 : 0) |
(arguments.channelWidth == 160 ? RATE_MCS_CHAN_WIDTH_160 : 0) | (Arguments::arguments.channelWidth == 160 ? RATE_MCS_CHAN_WIDTH_160 : 0) |
(arguments.spatialStreams == 2 ? SPATIAL_STREAM : 0) | (Arguments::arguments.spatialStreams == 2 ? SPATIAL_STREAM : 0) |
(arguments.spatialStreams == 2 ? RATE_MCS_ANT_AB_MSK : 0); (Arguments::arguments.spatialStreams == 2 ? RATE_MCS_ANT_AB_MSK : 0);
this->send(rateNFlags); this->send(rateNFlags);
} }
@ -170,15 +170,20 @@ void PacketInjector::send(uint32_t rateNFlags)
memcpy(&sendBuffer[rthdr.it_len], ieee80211Header, sizeof(ieee80211Header)); memcpy(&sendBuffer[rthdr.it_len], ieee80211Header, sizeof(ieee80211Header));
memcpy(&sendBuffer[rthdr.it_len + sizeof(ieee80211Header)], ieee80211Body, sizeof(ieee80211Body)); memcpy(&sendBuffer[rthdr.it_len + sizeof(ieee80211Header)], ieee80211Body, sizeof(ieee80211Body));
uint16_t totalSize = rthdr.it_len + sizeof(ieee80211Header) + sizeof(ieee80211Body); int totalSize = rthdr.it_len + sizeof(ieee80211Header) + sizeof(ieee80211Body);
char szErrbuf[500]; char szErrbuf[500];
pcap_t *ppcap = pcap_open_live("mon0", 800, 1, 20, szErrbuf);
if (ppcap == nullptr) {
ppcap = pcap_open_live("mon0", 800, 1, 20, szErrbuf);
}
int r = pcap_inject(ppcap, sendBuffer, totalSize); int r = pcap_inject(ppcap, sendBuffer, totalSize);
if (r > 0) if (r != totalSize)
{ {
//pcap_perror(ppcap, "Failed to inject packet"); //pcap_perror(ppcap, "Failed to inject packet");
pcap_close(ppcap); pcap_close(ppcap);
ppcap = nullptr;
//throw std::ios_base::failure("Failed to inject packet\n"); //throw std::ios_base::failure("Failed to inject packet\n");
} }

152
src/UdpSocket.cpp Normal file
View File

@ -0,0 +1,152 @@
/*
* FeitCSI is the tool for extracting CSI information from supported intel NICs.
* Copyright (C) 2024 Miroslav Hutar.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "UdpSocket.h"
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <netdb.h>
#include "Logger.h"
#include "Arguments.h"
#include "MainController.h"
#define PORT "8008"
#define BUF_SIZE 1024
void UdpSocket::init()
{
MainController *mainController = MainController::getInstance();
struct addrinfo hints;
struct addrinfo *result, *rp;
ssize_t nread;
int s;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */
hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */
hints.ai_protocol = 0; /* Any protocol */
hints.ai_canonname = NULL;
hints.ai_addr = NULL;
hints.ai_next = NULL;
s = getaddrinfo(NULL, PORT, &hints, &result);
if (s != 0)
{
Logger::log(error) << "getaddrinfo: " << gai_strerror(s) << "\n";
exit(1);
}
/* getaddrinfo() returns a list of address structures.
Try each address until we successfully bind(2).
If socket(2) (or bind(2)) fails, we (close the socket
and) try the next address. */
for (rp = result; rp != NULL; rp = rp->ai_next)
{
sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (sfd == -1)
continue;
if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0)
break; /* Success */
close(sfd);
}
if (rp == NULL)
{ /* No address succeeded */
Logger::log(error) << "Error bind socket \n";
exit(1);
}
freeaddrinfo(result); /* No longer needed */
/* Read datagrams and echo them back to sender */
while (1)
{
char buf[BUF_SIZE] = {0};
peer_addr_len = sizeof(struct sockaddr_storage);
nread = recvfrom(sfd, buf, BUF_SIZE, 0, (struct sockaddr *)&peer_addr, &peer_addr_len);
if (nread == -1)
continue; /* Ignore failed request */
char host[NI_MAXHOST], service[NI_MAXSERV];
s = getnameinfo(
(struct sockaddr *)&peer_addr,
peer_addr_len,
host,
NI_MAXHOST,
service,
NI_MAXSERV,
NI_NUMERICSERV);
if (s == 0) {
if (strncmp(buf, "stop", 4) == 0) {
if (this->running) {
mainController->restoreState();
this->running = false;
}
} else {
char *args[128];
std::istringstream iss(buf);
std::string token;
int index = 0;
while (iss >> token)
{
char *arg = new char[token.size() + 1];
copy(token.begin(), token.end(), arg);
arg[token.size()] = '\0';
args[index] = arg;
index++;
}
Arguments::parse(index, &args[0]);
for (int i = 0; i < index - 1; i++)
delete[] args[i];
mainController->runNoGui(true);
this->running = true;
}
}
else {
Logger::log(error) << "Error getnameinfo " << gai_strerror(s) << "\n";
}
}
}
void UdpSocket::send(char *buf, int size)
{
if (
sendto(
sfd,
buf,
size,
0,
(struct sockaddr *)&peer_addr,
peer_addr_len) != size)
{
Logger::log(error) << "Error sending response \n";
}
}

View File

@ -1,6 +1,6 @@
/* /*
* FeitCSI is the tool for extracting CSI information from supported intel NICs. * FeitCSI is the tool for extracting CSI information from supported intel NICs.
* Copyright (C) 2023 Miroslav Hutar. * Copyright (C) 2023-2024 Miroslav Hutar.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -33,6 +33,7 @@
#include <thread> #include <thread>
#include "main.h" #include "main.h"
#include "Logger.h" #include "Logger.h"
#include "Arguments.h"
const char *IF_MODES[NL80211_IFTYPE_MAX + 1] = { const char *IF_MODES[NL80211_IFTYPE_MAX + 1] = {
"unspecified", "unspecified",
@ -180,7 +181,7 @@ int WiFIController::setInterfaceUpDown(const char *ifName, bool up)
// Close the socket // Close the socket
close(sockfd); close(sockfd);
if (arguments.verbose) if (Arguments::arguments.verbose)
{ {
Logger::log(info) << "Interface " << ifName << " has been brought " << (up ? "up" : "down") << "\n"; Logger::log(info) << "Interface " << ifName << " has been brought " << (up ? "up" : "down") << "\n";
} }
@ -347,7 +348,7 @@ int WiFIController::processSetFreq(struct nl80211_state *state, struct nl_msg *m
uint16_t settingsFreq = *(uint16_t *)(settings[0]); uint16_t settingsFreq = *(uint16_t *)(settings[0]);
char *settingsWidth = (char *)(settings[1]); char *settingsWidth = (char *)(settings[1]);
if (arguments.verbose) if (Arguments::arguments.verbose)
{ {
Logger::log(info) << "Setting frequency " << settingsFreq << " channel width " << settingsWidth << "\n"; Logger::log(info) << "Setting frequency " << settingsFreq << " channel width " << settingsWidth << "\n";
} }
@ -416,7 +417,7 @@ nla_put_failure:
int WiFIController::setTxPowerHandler(nl80211_state * state, nl_msg * msg, void * arg) int WiFIController::setTxPowerHandler(nl80211_state * state, nl_msg * msg, void * arg)
{ {
enum nl80211_tx_power_setting type = NL80211_TX_POWER_FIXED; enum nl80211_tx_power_setting type = NL80211_TX_POWER_FIXED;
int mbm = arguments.txPower * 100; //dBm to mbm *100 int mbm = Arguments::arguments.txPower * 100; //dBm to mbm *100
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_TX_POWER_SETTING, type); NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_TX_POWER_SETTING, type);
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_TX_POWER_LEVEL, mbm); NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_TX_POWER_LEVEL, mbm);

View File

@ -1,6 +1,6 @@
/* /*
* FeitCSI is the tool for extracting CSI information from supported intel NICs. * FeitCSI is the tool for extracting CSI information from supported intel NICs.
* Copyright (C) 2023 Miroslav Hutar. * Copyright (C) 2023-2024 Miroslav Hutar.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -19,6 +19,8 @@
#include "WiFiCsiController.h" #include "WiFiCsiController.h"
#include "Csi.h" #include "Csi.h"
#include "GnuPlot.h" #include "GnuPlot.h"
#include "MainController.h"
#include "Arguments.h"
#include <errno.h> #include <errno.h>
#include <netlink/genl/genl.h> #include <netlink/genl/genl.h>
@ -93,37 +95,93 @@ int WiFiCsiController::processListenToCsiHandler(struct nl_msg *msg, void *arg)
Csi c; Csi c;
c.loadFromMemory(header, dataCsi); c.loadFromMemory(header, dataCsi);
if (
(c.channelWidth == RATE_MCS_CHAN_WIDTH_20 && Arguments::arguments.channelWidth == 20) ||
(c.channelWidth == RATE_MCS_CHAN_WIDTH_40 && Arguments::arguments.channelWidth == 40) ||
(c.channelWidth == RATE_MCS_CHAN_WIDTH_80 && Arguments::arguments.channelWidth == 80) ||
(c.channelWidth == RATE_MCS_CHAN_WIDTH_160 && Arguments::arguments.channelWidth == 160)
)
{
if (
(c.format == RATE_MCS_LEGACY_OFDM_MSK && Arguments::arguments.format == "NOHT") ||
(c.format == RATE_MCS_HT_MSK && Arguments::arguments.format == "HT") ||
(c.format == RATE_MCS_VHT_MSK && Arguments::arguments.format == "VHT") ||
(c.format == RATE_MCS_HE_MSK && Arguments::arguments.format == "HESU") ||
(c.format == RATE_MCS_EHT_MSK && Arguments::arguments.format == "EHT")
)
{
if (Arguments::arguments.verbose) {
printDetail(c);
}
instance->gnuPlot.updateChart(c); instance->gnuPlot.updateChart(c);
if ( MainController::getInstance()->udpSocket ) {
if ( c.sendUDP(MainController::getInstance()->udpSocket);
(c.channelWidth == RATE_MCS_CHAN_WIDTH_20 && arguments.channelWidth == 20) || } else {
(c.channelWidth == RATE_MCS_CHAN_WIDTH_40 && arguments.channelWidth == 40) ||
(c.channelWidth == RATE_MCS_CHAN_WIDTH_80 && arguments.channelWidth == 80) ||
(c.channelWidth == RATE_MCS_CHAN_WIDTH_160 && arguments.channelWidth == 160)
)
{
if (
(c.format == RATE_MCS_LEGACY_OFDM_MSK && arguments.format == "NOHT") ||
(c.format == RATE_MCS_HT_MSK && arguments.format == "HT") ||
(c.format == RATE_MCS_VHT_MSK && arguments.format == "VHT") ||
(c.format == RATE_MCS_HE_MSK && arguments.format == "HESU") ||
(c.format == RATE_MCS_EHT_MSK && arguments.format == "EHT")
)
{
c.save(); c.save();
} }
} }
} }
} }
}
return NL_SKIP; return NL_SKIP;
} }
void WiFiCsiController::printDetail(Csi &c)
{
Logger::log(info) << "Subcarrier count: " << c.rawHeaderData.numSubCarriers << ", ";
Logger::log(info, true) << "RX: " << +c.rawHeaderData.numRx << ", ";
Logger::log(info, true) << "TX: " << +c.rawHeaderData.numTx << ", ";
switch (c.channelWidth)
{
case RATE_MCS_CHAN_WIDTH_20:
Logger::log(info, true) << "Channel width: 20, ";
break;
case RATE_MCS_CHAN_WIDTH_40:
Logger::log(info, true) << "Channel width: 40, ";
break;
case RATE_MCS_CHAN_WIDTH_80:
Logger::log(info, true) << "Channel width: 80, ";
break;
case RATE_MCS_CHAN_WIDTH_160:
Logger::log(info, true) << "Channel width: 160, ";
break;
}
switch (c.format)
{
case RATE_MCS_CCK_MSK: // VERY OLD FORMAT
Logger::log(info, true) << "Format: CCK\n";
break;
case RATE_MCS_LEGACY_OFDM_MSK:
Logger::log(info, true) << "Format: LEGACY_OFDM\n";
break;
break;
case RATE_MCS_HT_MSK:
Logger::log(info, true) << "Format: HT\n";
break;
break;
case RATE_MCS_VHT_MSK:
Logger::log(info, true) << "Format: VHT\n";
break;
break;
case RATE_MCS_HE_MSK:
Logger::log(info, true) << "Format: HE\n";
break;
break;
case RATE_MCS_EHT_MSK:
Logger::log(info, true) << "Format: EHT\n";
break;
break;
}
}
void WiFiCsiController::enableCsi(bool enable) void WiFiCsiController::enableCsi(bool enable)
{ {
if (arguments.verbose) if (Arguments::arguments.verbose)
{ {
if (enable) if (enable)
{ {

View File

@ -1,6 +1,6 @@
/* /*
* FeitCSI is the tool for extracting CSI information from supported intel NICs. * FeitCSI is the tool for extracting CSI information from supported intel NICs.
* Copyright (C) 2023 Miroslav Hutar. * Copyright (C) 2023-2024 Miroslav Hutar.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -20,6 +20,7 @@
#include "GnuPlot.h" #include "GnuPlot.h"
#include "main.h" #include "main.h"
#include "Logger.h" #include "Logger.h"
#include "Arguments.h"
#include "CsiProcessingWindow.h" #include "CsiProcessingWindow.h"
void CsiProcessingWindow::init(Glib::RefPtr<Gtk::Builder> &builder) void CsiProcessingWindow::init(Glib::RefPtr<Gtk::Builder> &builder)
@ -53,7 +54,7 @@ void CsiProcessingWindow::init(Glib::RefPtr<Gtk::Builder> &builder)
void CsiProcessingWindow::inputFileChange() void CsiProcessingWindow::inputFileChange()
{ {
arguments.inputFile = this->inputFile->get_filename(); Arguments::arguments.inputFile = this->inputFile->get_filename();
csiProcessor.loadCsi(); csiProcessor.loadCsi();
this->refresh(); this->refresh();
} }
@ -95,7 +96,7 @@ void CsiProcessingWindow::interpolationLinearRadioButtonClicked()
{ {
if (!this->csiProcessor.csiData.empty()) if (!this->csiProcessor.csiData.empty())
{ {
arguments.processors[processor::interpolateLinear] = this->interpolationLinearRadioButton->get_active(); Arguments::arguments.processors[processor::interpolateLinear] = this->interpolationLinearRadioButton->get_active();
this->csiProcessor.process(*this->csiProcessor.csiData[this->currentIndex]); this->csiProcessor.process(*this->csiProcessor.csiData[this->currentIndex]);
this->refresh(); this->refresh();
} }
@ -105,7 +106,7 @@ void CsiProcessingWindow::interpolationCubicRadioButtonClicked()
{ {
if (!this->csiProcessor.csiData.empty()) if (!this->csiProcessor.csiData.empty())
{ {
arguments.processors[processor::interpolateCubic] = this->interpolationCubicRadioButton->get_active(); Arguments::arguments.processors[processor::interpolateCubic] = this->interpolationCubicRadioButton->get_active();
this->csiProcessor.process(*this->csiProcessor.csiData[this->currentIndex]); this->csiProcessor.process(*this->csiProcessor.csiData[this->currentIndex]);
this->refresh(); this->refresh();
} }
@ -115,7 +116,7 @@ void CsiProcessingWindow::interpolationCosineButtonClicked()
{ {
if (!this->csiProcessor.csiData.empty()) if (!this->csiProcessor.csiData.empty())
{ {
arguments.processors[processor::interpolateCosine] = this->interpolationCosineButton->get_active(); Arguments::arguments.processors[processor::interpolateCosine] = this->interpolationCosineButton->get_active();
this->csiProcessor.process(*this->csiProcessor.csiData[this->currentIndex]); this->csiProcessor.process(*this->csiProcessor.csiData[this->currentIndex]);
this->refresh(); this->refresh();
} }
@ -125,7 +126,7 @@ void CsiProcessingWindow::phaseLinearTransformCheckButtonClicked()
{ {
if (!this->csiProcessor.csiData.empty()) if (!this->csiProcessor.csiData.empty())
{ {
arguments.processors[processor::phaseCalibrationLinearTransform] = this->phaseLinearTransformCheckButton->get_active(); Arguments::arguments.processors[processor::phaseCalibrationLinearTransform] = this->phaseLinearTransformCheckButton->get_active();
this->csiProcessor.process(*this->csiProcessor.csiData[this->currentIndex]); this->csiProcessor.process(*this->csiProcessor.csiData[this->currentIndex]);
this->refresh(); this->refresh();
} }
@ -135,7 +136,7 @@ void CsiProcessingWindow::processingSaveGtkButtonClicked()
{ {
if (!this->csiProcessor.csiData.empty()) if (!this->csiProcessor.csiData.empty())
{ {
arguments.outputFile = "processedCsi.bin"; Arguments::arguments.outputFile = "processedCsi.bin";
this->csiProcessor.saveCsi(); this->csiProcessor.saveCsi();
} }
} }

View File

@ -1,6 +1,6 @@
/* /*
* FeitCSI is the tool for extracting CSI information from supported intel NICs. * FeitCSI is the tool for extracting CSI information from supported intel NICs.
* Copyright (C) 2023 Miroslav Hutar. * Copyright (C) 2023-2024 Miroslav Hutar.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -17,12 +17,12 @@
*/ */
#include "gui/GnuPlot.h" #include "gui/GnuPlot.h"
#include "main.h" #include "Arguments.h"
#include "GnuPlot.h" #include "GnuPlot.h"
void GnuPlot::init() void GnuPlot::init()
{ {
if (!arguments.plot || gnuPlotPipe) if (!Arguments::arguments.plot || gnuPlotPipe)
{ {
return; return;
} }
@ -66,7 +66,7 @@ void GnuPlot::setBlank()
void GnuPlot::updateChart(Csi &csi) void GnuPlot::updateChart(Csi &csi)
{ {
if (!arguments.plot) if (!Arguments::arguments.plot)
{ {
return; return;
} }

View File

@ -1,6 +1,6 @@
/* /*
* FeitCSI is the tool for extracting CSI information from supported intel NICs. * FeitCSI is the tool for extracting CSI information from supported intel NICs.
* Copyright (C) 2023 Miroslav Hutar. * Copyright (C) 2023-2024 Miroslav Hutar.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -17,12 +17,12 @@
*/ */
#include "gui/MainWindow.h" #include "gui/MainWindow.h"
#include "main.h"
#include <iostream> #include <iostream>
#include "MainWindow.h" #include "MainWindow.h"
#include "MainController.h" #include "MainController.h"
#include "WiFIController.h" #include "WiFIController.h"
#include "Logger.h" #include "Logger.h"
#include "Arguments.h"
MainWindow::MainWindow(BaseObjectType *obj, Glib::RefPtr<Gtk::Builder> const &builder) : Gtk::ApplicationWindow(obj), builder{builder} MainWindow::MainWindow(BaseObjectType *obj, Glib::RefPtr<Gtk::Builder> const &builder) : Gtk::ApplicationWindow(obj), builder{builder}
{ {
@ -157,71 +157,71 @@ void MainWindow::onResize()
void MainWindow::frequencyChange() void MainWindow::frequencyChange()
{ {
int v = std::atoi(this->frequency->get_text().raw().c_str()); int v = std::atoi(this->frequency->get_text().raw().c_str());
arguments.frequency = (uint16_t)v; Arguments::arguments.frequency = (uint16_t)v;
} }
void MainWindow::channelWidthChange() void MainWindow::channelWidthChange()
{ {
arguments.bandwidth = this->channelWidth->get_active_text().raw(); Arguments::arguments.bandwidth = this->channelWidth->get_active_text().raw();
struct ChanMode chMode = WiFIController::getChanMode(arguments.bandwidth.c_str()); struct ChanMode chMode = WiFIController::getChanMode(Arguments::arguments.bandwidth.c_str());
arguments.channelWidth = WiFIController::chanModeToWidth(chMode); Arguments::arguments.channelWidth = WiFIController::chanModeToWidth(chMode);
} }
void MainWindow::outputFileChange() void MainWindow::outputFileChange()
{ {
arguments.outputFile = this->outputFile->get_filename(); Arguments::arguments.outputFile = this->outputFile->get_filename();
this->filePath->set_text(arguments.outputFile); this->filePath->set_text(Arguments::arguments.outputFile);
} }
void MainWindow::formatChange() void MainWindow::formatChange()
{ {
arguments.format = this->format->get_active_text().raw(); Arguments::arguments.format = this->format->get_active_text().raw();
} }
void MainWindow::mcsChange() void MainWindow::mcsChange()
{ {
int v = std::atoi(this->mcs->get_active_text().raw().c_str()); int v = std::atoi(this->mcs->get_active_text().raw().c_str());
arguments.mcs = (uint8_t)v; Arguments::arguments.mcs = (uint8_t)v;
} }
void MainWindow::spatialStreamsChange() void MainWindow::spatialStreamsChange()
{ {
int v = std::atoi(this->spatialStreams->get_active_text().raw().c_str()); int v = std::atoi(this->spatialStreams->get_active_text().raw().c_str());
arguments.spatialStreams = (uint8_t)v; Arguments::arguments.spatialStreams = (uint8_t)v;
} }
void MainWindow::ltfChange() void MainWindow::ltfChange()
{ {
arguments.ltf = this->ltf->get_active_text().raw(); Arguments::arguments.ltf = this->ltf->get_active_text().raw();
} }
void MainWindow::guardIntervalChange() void MainWindow::guardIntervalChange()
{ {
int v = std::atoi(this->guardInterval->get_active_text().raw().c_str()); int v = std::atoi(this->guardInterval->get_active_text().raw().c_str());
arguments.guardInterval = (uint16_t)v; Arguments::arguments.guardInterval = (uint16_t)v;
} }
void MainWindow::txPowerChange() void MainWindow::txPowerChange()
{ {
int v = std::atoi(this->txPower->get_active_text().raw().c_str()); int v = std::atoi(this->txPower->get_active_text().raw().c_str());
arguments.txPower = (uint8_t)v; Arguments::arguments.txPower = (uint8_t)v;
} }
void MainWindow::codingChange() void MainWindow::codingChange()
{ {
arguments.coding = this->coding->get_active_text().raw(); Arguments::arguments.coding = this->coding->get_active_text().raw();
} }
void MainWindow::injectDelayChange() void MainWindow::injectDelayChange()
{ {
int v = std::atoi(this->injectDelay->get_text().raw().c_str()); int v = std::atoi(this->injectDelay->get_text().raw().c_str());
arguments.injectDelay = (uint32_t)v; Arguments::arguments.injectDelay = (uint32_t)v;
} }
void MainWindow::injectRepeatChange() void MainWindow::injectRepeatChange()
{ {
int v = std::atoi(this->injectRepeat->get_text().raw().c_str()); int v = std::atoi(this->injectRepeat->get_text().raw().c_str());
arguments.injectRepeat = (uint32_t)v; Arguments::arguments.injectRepeat = (uint32_t)v;
} }
void MainWindow::updateErrorMessages() void MainWindow::updateErrorMessages()

View File

@ -1,6 +1,6 @@
/* /*
* FeitCSI is the tool for extracting CSI information from supported intel NICs. * FeitCSI is the tool for extracting CSI information from supported intel NICs.
* Copyright (C) 2023 Miroslav Hutar. * Copyright (C) 2023-2024 Miroslav Hutar.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -18,7 +18,6 @@
#include <iostream> #include <iostream>
#include <thread> #include <thread>
#include <argp.h>
#include <chrono> #include <chrono>
#include "Csi.h" #include "Csi.h"
#include "WiFIController.h" #include "WiFIController.h"
@ -28,308 +27,38 @@
#include "PacketInjector.h" #include "PacketInjector.h"
#include "MainController.h" #include "MainController.h"
#include "Logger.h" #include "Logger.h"
#include "Arguments.h"
struct Arguments arguments;
const char *argp_program_version =
"argp-ex3 1.0";
const char *argp_program_bug_address =
"<bug-gnu-utils@gnu.org>";
/* Program documentation. */
static char doc[] =
"Argp example #3 -- a program with options and arguments using argp";
/* A description of the arguments we accept. */
static char args_doc[] = "ARG1 ARG2";
/* The options we understand. */
static struct argp_option options[] = {
{"frequency", 'f', "FREQUENCY", 0, "Frequency to measure/inject CSI"},
{"channel-width", 'w', "CHANNELWIDTH", 0, "Channel width to measure/inject CSI. Possible values [20|40|HT40-|80|160]"},
{"output-file", 'o', "FILE", 0, "Output file where measurements should be stored."},
{"mcs", 'm', "MCS", 0, "Mcs index [0-11]"},
{"format", 'r', "FORMAT", 0, "Data frame format [NOHT|HT|VHT|HESU]"},
{"spatial-streams", 's', "SPATIALSTREAMS", 0, "Number of spatial streams [1|2]"},
{"guard-interval", 'g', "GUARDINTERVAL", 0, "Guard interval in ns [400|800]"},
{"ltf", 'l', "LTF", 0, "HE LTF [2xLTF+0.8|2xLTF+1.6|4xLTF+3.2|4xLTF+0.8]"},
{"coding", 'c', "CODING", 0, "Coding scheme [LDPC|BCC]"},
{"tx-power", 't', "TXPOWER", 0, "TX power of antenna in dBm [1-22]"},
{"antenna", 'a', "ANTENNA", 0, "Transmitting antenna 1, 2 or 12 for both"},
{"mode", 'i', "MODE", 0, "Mode of program[measure|inject|measureinject]"},
{"inject-delay", 'd', "INJECTDELAY", 0, "Delay between frame injections is us"},
{"inject-repeat", 'j', "INJECTREPEAT", 0, "How many times inject frame"},
{"verbose", 'v', 0, OPTION_ARG_OPTIONAL, "Produce verbose output"},
{"plot", 'p', 0, OPTION_ARG_OPTIONAL, "Plot CSI data"},
{"gui", 'x', 0, OPTION_ARG_OPTIONAL, "Run application in GUI"},
{0}};
/* Used by main to communicate with parse_opt. */
/* Parse a single option. */
static error_t
parse_opt(int key, char *arg, struct argp_state *state)
{
/* Get the input argument from argp_parse, which we
know is a pointer to our arguments structure. */
struct Arguments *args = (struct Arguments *)state->input;
switch (key)
{
case 'v':
args->verbose = true;
break;
case 'x':
args->gui = true;
break;
case 'p':
args->plot = true;
break;
case 'i':
{
args->mode.assign(arg);
if (args->mode == "measure")
{
args->measure = true;
}
else if (args->mode == "inject")
{
args->inject = true;
args->measure = false;
}
else if (args->mode == "measureinject")
{
args->measure = true;
args->inject = true;
}
else
{
argp_failure(state, 1, 0, "Bad mode. Possible values [measure|inject|measureinject]");
exit(ARGP_ERR_UNKNOWN);
}
break;
}
case 'm':
{
int mcs = std::atoi(arg);
if (mcs < 0 || mcs > 11)
{
argp_failure(state, 1, 0, "Bad MCS index. Possible values [0-11]");
exit(ARGP_ERR_UNKNOWN);
}
args->mcs = (uint8_t)mcs;
break;
}
case 'r':
{
args->format.assign(arg);
if (args->format == "NOHT" || args->format == "HT" || args->format == "VHT" || args->format == "HESU")
{
} else
{
argp_failure(state, 1, 0, "Bad format. Possible values [NOHT|HT|VHT|HESU]");
exit(ARGP_ERR_UNKNOWN);
}
break;
}
case 'c':
{
args->coding.assign(arg);
if (args->coding == "LDPC" || args->coding == "BCC")
{
}
else
{
argp_failure(state, 1, 0, "Bad coding. Possible values [LDPC|BCC]");
exit(ARGP_ERR_UNKNOWN);
}
break;
}
case 'l':
{
args->ltf.assign(arg);
if (args->ltf == "1xLTF+0.8" || args->ltf == "2xLTF+0.8" || args->ltf == "2xLTF+1.6" || args->ltf == "4xLTF+3.2" || args->ltf == "4xLTF+0.8")
{
} else
{
argp_failure(state, 1, 0, "Bad LTF. Possible values [2xLTF+0.8|2xLTF+1.6|4xLTF+3.2|4xLTF+0.8]");
exit(ARGP_ERR_UNKNOWN);
}
break;
}
case 'g':
{
int gi = std::atoi(arg);
if (gi == 400 || gi == 800)
{
args->guardInterval = (uint16_t)gi;
}
else
{
argp_failure(state, 1, 0, "Bad guard interval. Possible values [400|800]");
exit(ARGP_ERR_UNKNOWN);
}
break;
}
case 'd':
{
int injd = std::atoi(arg);
if (injd <= 0)
{
argp_failure(state, 1, 0, "Inject delay is not correct number");
exit(ARGP_ERR_UNKNOWN);
}
args->injectDelay = (uint32_t)injd;
break;
}
case 'j':
{
int injr = std::atoi(arg);
if (injr <= 0)
{
argp_failure(state, 1, 0, "Inject repeat is not correct number");
exit(ARGP_ERR_UNKNOWN);
}
args->injectRepeat = (uint32_t)injr;
break;
}
case 's':
{
int ss = std::atoi(arg);
if (ss < 1 || ss > 2)
{
argp_failure(state, 1, 0, "Bad spatial stream. Possible values [1|2]");
exit(ARGP_ERR_UNKNOWN);
}
args->spatialStreams = (uint8_t)ss;
break;
}
case 't':
{
int tx = std::atoi(arg);
if (tx < 1 || tx > 22)
{
argp_failure(state, 1, 0, "Bad tx power. Possible values [1-22]");
exit(ARGP_ERR_UNKNOWN);
}
args->txPower = (uint8_t)tx;
break;
}
case 'a':
{
int a = std::atoi(arg);
if (a == 1)
{
args->antenna = RATE_MCS_ANT_A_MSK;
}
else if (a == 2)
{
args->antenna = RATE_MCS_ANT_B_MSK;
}
else if (a == 12)
{
args->antenna = RATE_MCS_ANT_AB_MSK;
}
else {
argp_failure(state, 1, 0, "Bad transmitting antenna value. Possible values 1, 2 or 12 for both");
exit(ARGP_ERR_UNKNOWN);
}
break;
}
case 'f':
{
int f = std::atoi(arg);
if (f <= 0)
{
argp_failure(state, 1, 0, "Frequency is not correct");
exit(ARGP_ERR_UNKNOWN);
}
args->frequency = (uint16_t)f;
break;
}
case 'w':
{
struct ChanMode chMode = WiFIController::getChanMode(arg);
if (chMode.width == 0)
{
argp_failure(state, 1, 0, "Bad bandwidth. Possible values of bandwidth are [20|40|HT40-|80|160]");
exit(ARGP_ERR_UNKNOWN);
}
args->bandwidth = arg;
args->channelWidth = WiFIController::chanModeToWidth(chMode);
break;
}
case 'o':
args->outputFile = arg;
break;
case ARGP_KEY_ARG:
case ARGP_KEY_END:
if (args->frequency == 0 ||
args->bandwidth.empty())
{
argp_failure(state, 1, 0, "Fill required arguments -f -b . See --help for more information");
exit(ARGP_ERR_UNKNOWN);
}
return 0;
default:
return ARGP_ERR_UNKNOWN;
}
return 0;
}
/* Our argp parser. */
static struct argp argp = {options, parse_opt, args_doc, doc};
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
struct Arguments defValues = { Arguments args;
.verbose = false, args.init();
.frequency = 2412, args.parse(argc, argv);
.gui = false,
.plot = false,
.bandwidth = "20",
.mcs = 0,
.channelWidth = 20,
.spatialStreams = 1,
.txPower = 10,
.antenna = RATE_MCS_ANT_A_MSK,
.guardInterval = 400,
.injectDelay = 100000,
.injectRepeat = 0,
.coding = "LDPC",
.format = "HT",
.inject = false,
.measure = true,
.mode = "measure",
.ltf = "1xLTF+0.8",
};
arguments = defValues; if (Arguments::arguments.outputFile.empty())
if (arguments.outputFile.empty())
{ {
const auto t = std::chrono::system_clock::now(); const auto t = std::chrono::system_clock::now();
int64_t tInt = std::chrono::duration_cast<std::chrono::seconds>(t.time_since_epoch()).count(); int64_t tInt = std::chrono::duration_cast<std::chrono::seconds>(t.time_since_epoch()).count();
arguments.outputFile = "FeitCSI_" + std::to_string(tInt) + ".dat"; Arguments::arguments.outputFile = "FeitCSI_" + std::to_string(tInt) + ".dat";
} }
/* Default values. */
argp_parse(&argp, argc, argv, 0, 0, &arguments);
// all arguments ok and sanitized go next // all arguments ok and sanitized go next
MainController *mainController = MainController::getInstance(); MainController *mainController = MainController::getInstance();
if (!arguments.gui) if (Arguments::arguments.gui)
{ {
mainController->runNoGui();
} else
{
arguments = defValues;
mainController->runGui(); mainController->runGui();
} }
else if (Arguments::arguments.udpSocket)
{
mainController->runUdpSocket();
}
else
{
mainController->runNoGui();
}
if (arguments.verbose) if (Arguments::arguments.verbose)
{ {
Logger::log(info) << "Exiting...\n"; Logger::log(info) << "Exiting...\n";
} }