Poor performance when sending/receiving in monitor mode

38 views Asked by At

I am trying to make a WiFi boardcast application in Python. The idea is to place two network interface cards (NICs) in monitor mode, and inject packets such that two devices can communicate. This has been done before, especially in the context of drone RC/telemetry/video links, some examples include OpenHD, ez-Wifibroadcast and WFB-NG. I specifically tested my hardware on OpenHD and was able to achieve a bitrate of ~4 MBits/s (2 x Raspberry Pi 3B+, 2 x TL-WN722N V2, 1 USB camera).

I put the two NICs into monitor mode, confirmed with iwconfig. They are also at the same frequency.

In making my Python application, I noticed a very poor bitrate and packet loss. I created a test script to demonstrate:

import socket
from time import perf_counter, sleep
import binascii
import sys
import threading

class PacketLoss:

def __init__(self, transmitter_receiver, size, iface1, iface2):
    self.transmitter_receiver = transmitter_receiver
    self.iface1, self.iface2 = iface1, iface2
    
    self.send = True
    self.counting = False
    
    self.packet_recv_counter = 0
    self.packet_send_counter = 0
    
    self.t_target = 1
    self.t_true = None
    
    payload = (0).to_bytes(size, byteorder='little', signed=False)
    self.payload_length = len(payload)
    
    h = bytes((self.payload_length).to_bytes(2, byteorder='little', signed=False))
    
    radiotap_header = b'\x00\x00\x0c\x00\x04\x80\x00\x00' + bytes([6 * 2]) + b'\x00\x18\x00'
    frame_type = b'\xb4\x00\x00\x00'
    self.msg = radiotap_header + frame_type + transmitter_receiver + h + payload

def inject_packets(self):
    rawSocket = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(0x0004))
    rawSocket.bind((self.iface1, 0))
    
    t0 = perf_counter()
    while (self.send):
        rawSocket.send(self.msg)
        
        if self.counting:
            self.packet_send_counter += 1
    self.t_send_true = perf_counter() - t0
        
    rawSocket.close()
    
def sniff_packets(self):
    s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(0x0003))
    s.bind((self.iface2, 0))
    
    t0 = perf_counter()
    self.counting = True
    while perf_counter() - t0 < self.t_target:
        packet = s.recv(200)
        match = packet[22:34]
        
        if match == self.transmitter_receiver:
            self.packet_recv_counter += 1
    
    self.t_true = perf_counter() - t0
    self.send = False
    self.counting = False
    
    s.close()

def get_stats(self):
    dr_send = self.packet_send_counter * self.payload_length / self.t_send_true
    dr_recv = self.packet_recv_counter * self.payload_length / self.t_true
    packet_loss = 1 - self.packet_recv_counter/self.packet_send_counter
    return dr_send, dr_recv, packet_loss
    
def print_statistics(self):
    print(f'In {self.t_true:.3f}s, sent {self.packet_send_counter} captured {self.packet_recv_counter} packets.')
    
    dr_send, dr_recv, packet_loss = self.get_stats()
    
    print(f'{dr_send=:.1f}B/s; {dr_recv=:.1f}B/s; Packet loss: {packet_loss*100:.1f}%')

I tested PacketLoss with the following:

if __name__ == '__main__':
    # Get test parameters
    iface1, iface2 = sys.argv[1], sys.argv[2] # eg 'wlan0', 'wlan1'
    size = int(sys.argv[3]) # eg 60
    
    # Recv/transmit mac addresses
    MAC_r = '35:eb:9e:3b:75:33'
    MAC_t = 'e5:26:be:89:65:27'
    receiver_transmitter = binascii.unhexlify(MAC_r.replace(':', '')) + binascii.unhexlify(MAC_t.replace(':', ''))
    
    # create testing object
    pl = PacketLoss(receiver_transmitter, size, iface1, iface2)
    
    # start injecting packets
    t = threading.Thread(target=pl.inject_packets)
    t.start()
    
    # wait a bit
    sleep(0.1)
    
    # start sniffing
    pl.sniff_packets()
    
    # print statistics
    pl.print_statistics()

I tested with packet sizes of 30, 60 and 120, getting the following results:

Packet size (B) Received data rate (kB/s) Packet loss (%)
30 32.3 47.3
60 51.3 57.2
120 63.9 73.0

Eventually I want to use my program to stream video (and RC/telemetry), and I would need at least 125 kB/s received data rate, and a much better packet loss. Am I overlooking something that would increase the data rate and reduce the packet loss?

Thank you

0

There are 0 answers