Skip to content

Commit

Permalink
Fix incorrect usage of TX_INFO signalling acked frames
Browse files Browse the repository at this point in the history
Before this change every CMD_FRAME coming from the kernel would be
ack'ed locally through the TX_INFO command. This tells the client
that the frame was acked in all cases, regardless if the server
dropped it.

The kernel does expect a TX_INFO for each CMD_FRAME but the ACK
flag should only be set if the peer received the frame. If the
server drops it the ACK flag should be unset.

To fix this TX_INFO messages can be sent over the "air" just as
frames are. Then clients can choose to include the ACK flag or
not. This did require the server still sends all frames regardless
if they were dropped, but a new boolean was added to signal to
clients if the frame should be dropped. If so the client won't
forward the frame but will still send a TX_INFO (with the ACK
flag set appropriately).
  • Loading branch information
jprestwo committed Sep 25, 2023
1 parent b56260b commit 6c2f91a
Show file tree
Hide file tree
Showing 8 changed files with 108 additions and 62 deletions.
110 changes: 68 additions & 42 deletions src/ckernelwifi.cc
Original file line number Diff line number Diff line change
Expand Up @@ -44,24 +44,19 @@ void CKernelWifi::cout_mac_address(struct ether_addr *src)
std::cout << addr;
}

int CKernelWifi::send_tx_info_frame_nl(struct ether_addr *src, unsigned int flags, int signal, struct hwsim_tx_rate *tx_attempts, unsigned long cookie)
struct nl_msg *CKernelWifi::build_tx_info(struct ether_addr *src, unsigned int flags, int signal, struct hwsim_tx_rate *tx_attempts, unsigned long cookie)
{
struct nl_msg *msg = nullptr;

msg = nlmsg_alloc();

if (!msg) {

std::cerr << "Error allocating new message MSG !" << std::endl ;
nlmsg_free(msg);
return 0;
}
if (!msg)
return nullptr;

if (m_family_id < 0){

std::cerr << __func__ << "m_family_id < 0" << std::endl ;
nlmsg_free(msg);
return 0;
return nullptr;
}

genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, m_family_id, 0, NLM_F_REQUEST, HWSIM_CMD_TX_INFO_FRAME, VERSION_NR);
Expand All @@ -77,10 +72,21 @@ int CKernelWifi::send_tx_info_frame_nl(struct ether_addr *src, unsigned int flag
{
std::cerr << "Error filling payload" << std::endl;
nlmsg_free(msg);
return 0;
return NULL;
}

//nl_send_auto_complete(_netlink_socket, msg); //deprecated
return msg;
}

int CKernelWifi::send_tx_info_frame_nl(struct ether_addr *src, unsigned int flags, int signal, struct hwsim_tx_rate *tx_attempts, unsigned long cookie)
{
struct nl_msg *msg = build_tx_info(src, flags, signal, tx_attempts, cookie);

if (!msg) {
std::cerr << "Error allocating new message MSG !" << std::endl ;
nlmsg_free(msg);
return 0;
}

if (nl_send_auto(_netlink_socket, msg) < 0)
{
Expand Down Expand Up @@ -137,31 +143,6 @@ int CKernelWifi::process_messages(struct nl_msg *msg)
struct ether_addr macsrchwsim;
memcpy(&macsrchwsim,src,sizeof(macsrchwsim)); // backup the original mac src

/* Let's flag this frame as ACK'ed */
/* whatever that means... */
unsigned int flags = nla_get_u32(attrs[HWSIM_ATTR_FLAGS]);
flags |= HWSIM_TX_STAT_ACK;

/* this is the signal sent to the sender, not the receiver */
int signal = -10;

/* We get the tx_rates struct */
struct hwsim_tx_rate* tx_rates = (struct hwsim_tx_rate *)nla_data(attrs[HWSIM_ATTR_TX_INFO]);

u64 cookie = nla_get_u64(attrs[HWSIM_ATTR_COOKIE]);

/* this has to be an ack the driver expects */
/* what does the driver do with these values? can i remove them? */
send_tx_info_frame_nl(src, flags, signal, tx_rates, cookie);

/*
* no need to send a tx info frame indicating failure with a
* signal of 0 - that was done in the tx code i took this from
* if i check for ack messages than i could add a failure message
*/

/* we are now done with our code addition which sends the ack */

/* we get the attributes*/
char* data = (char *)nla_data(attrs[HWSIM_ATTR_FRAME]);
unsigned int data_len = nla_len(attrs[HWSIM_ATTR_FRAME]);
Expand Down Expand Up @@ -454,6 +435,7 @@ int CKernelWifi::send_cloned_frame_msg(struct ether_addr *dst, char *data, int d
}

void CKernelWifi::recv_from_server(){
uint8_t dropped;

if ( ! is_connected_to_server())
return ;
Expand All @@ -467,7 +449,7 @@ void CKernelWifi::recv_from_server(){
return ;

TPower power;
if( _RecvSignal(&power, &Buffer) == SOCKET_ERROR )
if( _RecvSignal(&power, &dropped, &Buffer) == SOCKET_ERROR )
manage_server_crash();

int signal = power ;
Expand All @@ -478,16 +460,41 @@ void CKernelWifi::recv_from_server(){
/* generic netlink header */
struct genlmsghdr* gnlh = (struct genlmsghdr*)nlmsg_data(nlh);

/* we get the attributes*/
struct nlattr *attrs[HWSIM_ATTR_MAX + 1];
genlmsg_parse(nlh, 0, attrs, HWSIM_ATTR_MAX, NULL);

struct hwsim_tx_rate* tx_rates = (struct hwsim_tx_rate *)nla_data(attrs[HWSIM_ATTR_TX_INFO]);
u64 cookie = nla_get_u64(attrs[HWSIM_ATTR_COOKIE]);
unsigned int flags = nla_get_u32(attrs[HWSIM_ATTR_FLAGS]);
if (gnlh->cmd == HWSIM_CMD_TX_INFO_FRAME) {
// TX_INFO receved from server, send to kernel
std::vector<WirelessDevice> &inets = _list_winterfaces.list_devices();

for (auto & inet : inets)
{
struct ether_addr macdsthwsim = inet.getMachwsim();

send_tx_info_frame_nl(&macdsthwsim,
flags,
(int)signal,
tx_rates,
cookie);
}

delete &inets;

return;
}

/* exit if the message does not contain frame data */
if (gnlh->cmd != HWSIM_CMD_FRAME) {

std::cerr << "Error - received no frame data in message" << std::endl;
return ;
}

/* we get the attributes*/
struct nlattr *attrs[HWSIM_ATTR_MAX + 1];
genlmsg_parse(nlh, 0, attrs, HWSIM_ATTR_MAX, NULL);


/* we get frequence */
TFrequency freq;
Expand Down Expand Up @@ -526,8 +533,27 @@ void CKernelWifi::recv_from_server(){
#endif

/* copy mac dst address from frame */
struct ether_addr framedst;
memcpy(&framedst, data + 4, ETH_ALEN);
struct ether_addr framesrc;
memcpy(&framesrc, data + 10, ETH_ALEN);

if (!dropped)
flags |= HWSIM_TX_STAT_ACK;

struct nl_msg *tx_info = build_tx_info(&framesrc, flags,
(int)signal,
tx_rates,
cookie);
struct nlmsghdr *hdr = nlmsg_hdr(tx_info);

// Send TX_Info back to server
int value=_SendSignal(&power, (char*)hdr, hdr->nlmsg_len);

nlmsg_free(tx_info);
if( value == SOCKET_ERROR )
manage_server_crash();

if (dropped)
return;

#ifdef _DEBUG
std::cout << "frame dst: "; cout_mac_address(&framedst);std::cout<<std::endl ;
Expand Down
5 changes: 4 additions & 1 deletion src/ckernelwifi.h
Original file line number Diff line number Diff line change
Expand Up @@ -228,12 +228,15 @@ class CKernelWifi : public intthread::AsyncTask {
*/
void manage_server_crash();

struct nl_msg *build_tx_info(struct ether_addr *src, unsigned int flags, int signal, struct hwsim_tx_rate *tx_attempts, unsigned long cookie);


// virtual :

virtual bool _Connect(int* id) = 0;

virtual ssize_t _SendSignal(TPower* power, const char* buffer, int sizeOfBuffer) = 0;
virtual ssize_t _RecvSignal(TPower* power, CDynBuffer* buffer) = 0;
virtual ssize_t _RecvSignal(TPower* power, uint8_t *dropped, CDynBuffer* buffer) = 0;

virtual void _Close() = 0;

Expand Down
13 changes: 11 additions & 2 deletions src/cwifi.cc
Original file line number Diff line number Diff line change
Expand Up @@ -62,18 +62,22 @@ bool CWifi::PacketIsLost(TPower signalLevel)
return true;
}

ssize_t CWifi::SendSignalWithSocket(CSocket* socket, TDescriptor descriptor, TPower* power, const char* buffer, int sizeOfBuffer)
ssize_t CWifi::SendSignalWithSocket(CSocket* socket, TDescriptor descriptor, TPower* power, uint8_t *dropped, const char* buffer, int sizeOfBuffer)
{
// cout<<"send power : "<<power<<endl;
int val=socket->Send(descriptor, (char*)power, sizeof(TPower));
if( val <= 0 )
return val;

val=socket->Send(descriptor, (char*)dropped, sizeof(uint8_t));
if( val <= 0 )
return val;

// std::cout<<"send big data of size : "<<sizeOfBuffer<<std::endl;
return socket->Send(descriptor, buffer, sizeOfBuffer);
}

ssize_t CWifi::RecvSignalWithSocket(CSocket* socket, TDescriptor descriptor, TPower* power, CDynBuffer* buffer)
ssize_t CWifi::RecvSignalWithSocket(CSocket* socket, TDescriptor descriptor, TPower* power, uint8_t *dropped, CDynBuffer* buffer)
{
int valread;

Expand All @@ -82,6 +86,11 @@ ssize_t CWifi::RecvSignalWithSocket(CSocket* socket, TDescriptor descriptor, TPo
if ( valread <= 0 )
return valread;

// read dropped
valread = socket->Read(descriptor, (char*)dropped, sizeof(uint8_t));
if ( valread <= 0 )
return valread;

// read the signal
// "nlmsg_len" (type "uint32_t") is the first attribut of the "struct nlmsghdr" in "libnl3/netlink/netlink-kernel.h"
ssize_t sizeRead = socket->ReadEqualSize(descriptor, buffer, 0, sizeof(struct nlmsghdr));
Expand Down
4 changes: 2 additions & 2 deletions src/cwifi.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ class CWifi

bool PacketIsLost(TPower signalLevel);

ssize_t SendSignalWithSocket(CSocket* socket, TDescriptor descriptor, TPower* power, const char* buffer, int sizeOfBuffer);
ssize_t RecvSignalWithSocket(CSocket* socket, TDescriptor descriptor, TPower* power, CDynBuffer* buffer);
ssize_t SendSignalWithSocket(CSocket* socket, TDescriptor descriptor, TPower* power, uint8_t *dropped, const char* buffer, int sizeOfBuffer);
ssize_t RecvSignalWithSocket(CSocket* socket, TDescriptor descriptor, TPower* power, uint8_t *dropped, CDynBuffer* buffer);
};

#endif
9 changes: 6 additions & 3 deletions src/cwificlient.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,13 @@ class CWifiClient : public CKernelWifi, public CWifi, public TypeCSocketClient
}

ssize_t _SendSignal(TPower* power, const char* buffer, int sizeOfBuffer) override
{ return SendSignalWithSocket(this, this->GetDescriptor(), power, buffer, sizeOfBuffer); }
{
uint8_t dropped = 0;
return SendSignalWithSocket(this, this->GetDescriptor(), power, &dropped, buffer, sizeOfBuffer);
}

ssize_t _RecvSignal(TPower* power, CDynBuffer* buffer) override
{ return RecvSignalWithSocket(this, this->GetDescriptor(), power, buffer); }
ssize_t _RecvSignal(TPower* power, uint8_t *dropped, CDynBuffer* buffer) override
{ return RecvSignalWithSocket(this, this->GetDescriptor(), power, dropped, buffer); }

void _Close() override { TypeCSocketClient::Close(); };
};
Expand Down
22 changes: 13 additions & 9 deletions src/cwifiserver.cc
Original file line number Diff line number Diff line change
Expand Up @@ -180,14 +180,14 @@ void CWifiServer::CloseAllClient()
CloseClient(0); // we can Close the 0 because we use the shift
}

ssize_t CWifiServer::SendSignal(TDescriptor descriptor, TPower* power, const char* buffer, int sizeOfBuffer)
ssize_t CWifiServer::SendSignal(TDescriptor descriptor, TPower* power, uint8_t *dropped, const char* buffer, int sizeOfBuffer)
{
return SendSignalWithSocket(this, descriptor, power, buffer, sizeOfBuffer);
return SendSignalWithSocket(this, descriptor, power, dropped, buffer, sizeOfBuffer);
}

ssize_t CWifiServer::RecvSignal(TDescriptor descriptor, TPower* power, CDynBuffer* buffer)
ssize_t CWifiServer::RecvSignal(TDescriptor descriptor, TPower* power, uint8_t *dropped, CDynBuffer* buffer)
{
return RecvSignalWithSocket(this, descriptor, power, buffer);
return RecvSignalWithSocket(this, descriptor, power, dropped, buffer);
}

void CWifiServer::SendAllOtherClients(TIndex index,TPower power, const char* data, ssize_t sizeOfData)
Expand All @@ -202,30 +202,34 @@ void CWifiServer::SendAllOtherClients(TIndex index,TPower power, const char* dat
{
TFrequency frequency=GetFrequency((struct nlmsghdr*)data);
TPower signalLevel=BoundedPower(power-Attenuation(coo.DistanceWith((*InfoWifis)[i]),frequency));
uint8_t dropped = CanLostPackets && PacketIsLost(signalLevel);

if( ! CanLostPackets || ! PacketIsLost(signalLevel) )
if( SendSignal((*InfoSockets)[i].GetDescriptor(), &signalLevel, data, sizeOfData) < 0 )
(*InfoSockets)[i].DisableIt();
if( SendSignal((*InfoSockets)[i].GetDescriptor(), &signalLevel, &dropped, data, sizeOfData) < 0 )
(*InfoSockets)[i].DisableIt();
}
}
}

void CWifiServer::SendAllOtherClientsWithoutLoss(TIndex index, TPower power, const char* data, ssize_t sizeOfData)
{
uint8_t dropped = 0;

for (TIndex i = 0; i < GetNumberClient(); i++)
{
if( i != index )
if( IsEnable(i) )
if( SendSignal((*InfoSockets)[i].GetDescriptor(), &power, data, sizeOfData) < 0 )
if( SendSignal((*InfoSockets)[i].GetDescriptor(), &power, &dropped, data, sizeOfData) < 0 )
(*InfoSockets)[i].DisableIt();
}
}

void CWifiServer::SendAllClientsWithoutLoss(TPower power, const char* data, ssize_t sizeOfData)
{
uint8_t dropped = 0;

for (TIndex i = 0; i < GetNumberClient(); i++)
if( IsEnable(i) )
if( SendSignal((*InfoSockets)[i].GetDescriptor(), &power, data, sizeOfData) < 0 )
if( SendSignal((*InfoSockets)[i].GetDescriptor(), &power, &dropped, data, sizeOfData) < 0 )
(*InfoSockets)[i].DisableIt();
}

Expand Down
4 changes: 2 additions & 2 deletions src/cwifiserver.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ class CWifiServer : public CSocketServer, public CWifi

void CloseAllClient();

ssize_t SendSignal(TDescriptor descriptor, TPower* power, const char* buffer, int sizeOfBuffer);
ssize_t SendSignal(TDescriptor descriptor, TPower* power, uint8_t *dropped, const char* buffer, int sizeOfBuffer);

ssize_t RecvSignal(TDescriptor descriptor, TPower* power, CDynBuffer* buffer);
ssize_t RecvSignal(TDescriptor descriptor, TPower* power, uint8_t *dropped, CDynBuffer* buffer);

void SendAllOtherClients(TIndex index,TPower power, const char* data, ssize_t sizeOfData);

Expand Down
3 changes: 2 additions & 1 deletion src/vwifi-server.cc
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ void ForwardData(bool srcIsSpy, CWifiServer* src, CWifiServer* otherDst)
{
int valread;
TPower power;
uint8_t dropped;

for ( TIndex i = 0 ; i < src->GetNumberClient() ; )
{
Expand All @@ -57,7 +58,7 @@ void ForwardData(bool srcIsSpy, CWifiServer* src, CWifiServer* otherDst)
//Check if it was for closing , and also read the
//incoming message

valread=src->RecvSignal(socket,&power,&Buffer);
valread=src->RecvSignal(socket,&power,&dropped,&Buffer);
if( valread <=0 )
{
RemoveClient(src, srcIsSpy , i, socket);
Expand Down

0 comments on commit 6c2f91a

Please sign in to comment.