Main Content

OFDM Beacon Receiver Using Software-Defined Radio

This example shows how to retrieve information about WiFi networks on the 5 GHz band using a software-defined radio (SDR). The example scans over the 5 GHz beacon channels and captures waveforms for analysis within MATLAB®. The example then decodes the OFDM packets to determine which packets are access point (AP) beacons. The AP beacon information includes the service set identifier (SSID), media access control (MAC) address (also known as the basic SSID, or BSSID), AP channel bandwidth, and 802.11 standard used by the AP.

Introduction

This example scans through a set of WiFi channels in the 5 GHz band to detect AP beacons that are transmitted on 20 MHz subchannels.

The scanning procedure comprises these steps.

  • Set the frequency band and channels for the SDR to capture.

  • Capture a waveform for a set duration for each specified channel.

  • Process the waveform in MATLAB by searching for beacon frames in the captured waveform and extracting relevant information from each successfully decoded beacon frame.

  • Display key information about the detected APs.

This example supports these SDRs for capturing waveforms in the 5 GHz band.

  • ADALM-Pluto from the Communications Toolbox Support Package for Analog Devices® ADALM-Pluto Radio

  • USRP™ E310/E312 from the Communications Toolbox Support Package for USRP™ Embedded Series Radio

  • 从Commun AD936x / FMCOMMS5ications Toolbox Support Package for Xilinx® Zynq®-Based Radio

  • USRP™ N200/N210/USRP2/N320/N321/B200/B210/X300/X310 from the Communications Toolbox Support Package for USRP™ Radio

Alternatively, if an SDR is not available for waveform capture, the example supports importing a file with a precaptured waveform.

Example Setup

Before running the example, ensure that you have installed the appropriate support package for the SDR that you intend to use and that you have set up the hardware.

TheReceiveOnSDRfield of therxsimstructure determines whether the example receives a waveform off the air or imports a waveform from a MAT file.

rxsim.ReceiveOnSDR =false;

Specify the file name of a precaptured waveform in thefileNamevariable. Confirm that the MAT file contains these variables:capturedWaveforms,channels,radioSampleRate, andband.

fileName ="capturedBeacons.mat";

By default, the example processes waveforms that are stored in a MAT file. If using an SDR to perform a live scan of the 5 GHz band, specify the SDR name, radio identifier, radio sample rate, channel numbers, and other parameters. The valid channel numbers for the 5 GHz band are between 1 and 200. However, the valid 20 MHz control channels for an AP are 32, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 149, 153, 157, 161, 165, 169, 173, and 177.

ifrxsim.ReceiveOnSDR rxsim.SDRDeviceName ="AD936x";% SDR that is used for waveform receptionrxsim.RadioIdentifier ='192.168.3.2';% Value used to identify radio, for example, IP address, USB port, or serial number 30AD2D5rxsim.RadioSampleRate =20000000;% Configured for 20e6 Hz as this is beacon transmission BWrxsim.RadioGain =50; rxsim.FrequencyBand = 5; rxsim.ChannelNumbers =[32, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 149, 153, 157, 161, 165, 169, 173, 177];% Default scans all 5 GHz beacon channelsrxsim.ReceiveAntenna =1;% Configure to work with only a single antennarxsim.CaptureTime =milliseconds(100);% Value expected to be of type duration% Derived Parametersrxsim.CenterFrequencies = wlanChannelFrequency(rxsim.ChannelNumbers,rxsim.FrequencyBand); rxsim.NumSamplesToCapture = seconds(rxsim.CaptureTime)*rxsim.RadioSampleRate;elserx = load(fileName); rxsim.ChannelNumbers = rx.channels; rxsim.RadioSampleRate = rx.radioSampleRate; rxsim.FrequencyBand = rx.band;% Derived Parametersrxsim.NumSamplesToCapture = size(rx.capturedWaveforms,1);endosf = rxsim.RadioSampleRate/20e6;

Set Optional Information to Display

To determine the hardware manufacturer of the AP, select theretrieveVendorInfobox. Selecting theretrieveVendorInfobox downloads the organizationally unique identifier (OUI) CSV file from the IEEE® Registration Authority website for vendor AP identification.

retrieveVendorInfo =true;

To display additional packet information such as payload size, code rate, and modulation for all successfully decoded non-HT packets, select thedisplayAdditionalInfobox.

displayAdditionalInfo =false;

To display a spectrum and spectrogram for the captured waveform, select thedisplayScopebox.

displayScope =false;

Scan 5 GHz Channels

Initialize SDR object

This example communicates with the radio hardware using the object pertaining to the selected radio.

Create an SDR object by either callingsdrrxorcomm.SDRuReceiver. Then, apply the parameters set in therxsimstructure above to the properties of that object.

ifrxsim.ReceiveOnSDRifmatches(rxsim.SDRDeviceName, ["AD936x","FMCOMMS5","Pluto","E3xx"])sdrReceiver = sdrrx(...rxsim.SDRDeviceName,...BasebandSampleRate=rxsim.RadioSampleRate,...GainSource="Manual");ifmatches(rxsim.SDRDeviceName, ["AD936x","FMCOMMS5","E3xx"])% When capturing a waveform, skip the FPGA and have the data% sent straight to the hostsdrReceiver.ShowAdvancedProperties = true; sdrReceiver.BypassUserLogic = true; sdrReceiver.IPAddress = rxsim.RadioIdentifier;elsesdrReceiver.RadioID = rxsim.RadioIdentifier;endelse% For the USRP SDRssdrReceiver = comm.SDRuReceiver(...Platform=rxsim.SDRDeviceName,...EnableBurstMode=true);% Determine burst capture values% Each frame will have 100 symbolssdrReceiver.SamplesPerFrame = 4e-6*rxsim.RadioSampleRate*100; sdrReceiver.NumFramesInBurst = rxsim.NumSamplesToCapture/sdrReceiver.SamplesPerFrame; [sdrReceiver.MasterClockRate, sdrReceiver.DecimationFactor] =...hGetUSRPRateInformation(rxsim.SDRDeviceName,rxsim.RadioSampleRate);ifmatches(rxsim.SDRDeviceName, ["B200","B210"])% Change the serial number as needed for USRP B200/B210sdrReceiver.SerialNum = rxsim.RadioIdentifier;elsesdrReceiver.IPAddress = rxsim.RadioIdentifier;endendsdrReceiver.Gain = rxsim.RadioGain; sdrReceiver.OutputDataType ="double"; sdrReceiver.ChannelMapping = rxsim.ReceiveAntenna;end

Receiver Design

This diagram shows an overview of the receiver for scanning the selected channels and frequency band and recovering beacon information.

These steps provide further information on the diagram.

  1. Set the center frequency of the SDR, then initialize the capture of a waveform for a set duration.

  2. Determine and apply frequency and timing corrections on the waveform, then attempt to recover the legacy signal (L-SIG) field bits.

  3. Check that the packet format is non-HT.

  4. 从恢复L-SIG提取调制nd coding scheme (MCS) and the length of the PLCP service data unit (PSDU). Then recover the non-HT data and subsequently decode the MAC protocol data unit (MPDU).

  5. Using the recovered MAC frame configuration, check if the non-HT packet is a beacon.

  6. Recover the SSID, BSSID, vendor of the AP, SNR, primary 20 MHz channel, current channel center frequency index, supported channel width, frequency band, and wireless standard used by the AP.

  7. Check if the waveform contains another packet that you can decode.

Begin Packet Capture and Processing

Create a structure (APs) for storing this information for each successfully decoded beacon.

  • SSID

  • BSSID

  • Vendor of AP

  • Signal-to-noise ratio (SNR)

  • Primary 20 MHz channel

  • Current channel center frequency index

  • Channel width

  • Frequency band

  • Operating mode supported by the AP

  • MAC frame configuration

  • Waveform in which the beacon exists

  • Index value at which the non-HT beacon packet begins in the captured waveform

APs = struct(..."SSID",[],"BSSID",[],"Vendor",[],"SNR_dB",[],"Beacon_Channel",[],..."Operating_Channel",[],"Channel_Width_MHz",[],"Band",[],"Mode",[],..."MAC_Config",wlanMACFrameConfig,"Waveform",[],"Offset",[]);

Initialize a non-HT config object to use for processing incoming waveforms.

cbw ="CBW20"; cfg = wlanNonHTConfig(ChannelBandwidth=cbw); ind = wlanFieldIndices(cfg); indexAP = 1;

Begin scanning and decoding for specified channels.

fori = 1:length(rxsim.ChannelNumbers) fprintf("Scanning channel %d on band %.1f.\n",rxsim.ChannelNumbers(i),rxsim.FrequencyBand);ifrxsim.ReceiveOnSDR sdrReceiver.CenterFrequency = rxsim.CenterFrequencies(i); capturedData = captureWaveform(sdrReceiver,rxsim.NumSamplesToCapture);elsecapturedData = rx.capturedWaveforms(:,i);end% Display spectrum and spectrogramifdisplayScope%#ok<*UNRCH>scope = spectrumAnalyzer(ViewType="spectrum-and-spectrogram",SampleRate=rxsim.RadioSampleRate,...TimeSpanSource="property",TimeSpan=rxsim.NumSamplesToCapture/rxsim.RadioSampleRate); scope(capturedData);end% Resample the captured data to 20 MHz for beacon processing.ifosf ~= 1 capturedData = resample(capturedData,20e6,rxsim.RadioSampleRate);endsearchOffset = 0;whilesearchOffset% recoverPreamble detects a packet and performs analysis of the non-HT preamble.[preambleStatus,res] = recoverPreamble(capturedData,cbw,searchOffset);ifmatches(preambleStatus,"No packet detected")break;end% Retrieve synchronized data and scale it with LSTF power as done% in the recoverPreamble function.syncData = capturedData(res.PacketOffset+1:end)./sqrt(res.LSTFPower); syncData = frequencyOffset(syncData,rxsim.RadioSampleRate/osf,-res.CFOEstimate);% Need only 4 OFDM symbols (LSIG + 3 more symbols) following LLTF% for format detectionfmtDetect = syncData(ind.LSIG(1):(ind.LSIG(2)+4e-6*rxsim.RadioSampleRate/osf*3)); [LSIGBits, failcheck] = wlanLSIGRecover(fmtDetect(1:4e-6*rxsim.RadioSampleRate/osf*1),...res.ChanEstNonHT,res.NoiseEstNonHT,cbw);if~failcheck format = wlanFormatDetect(fmtDetect,res.ChanEstNonHT,res.NoiseEstNonHT,cbw);ifmatches(format,"Non-HT")%提取MCS L-SIG的前3位。rate = double(bit2int(LSIGBits(1:3),3));ifrate <= 1 cfg.MCS = rate + 6;elsecfg.MCS = mod(rate,6);end% Determine PSDU length from L-SIG.cfg.PSDULength = double(bit2int(LSIGBits(6:17),12,0)); ind.NonHTData = wlanFieldIndices(cfg,"NonHT-Data");if双(ind.NonHTData (2) -ind.NonHTData (1)) >...length(syncData(ind.NonHTData(1):end))% Exit while loop as full packet not captured.break;endnonHTData = syncData(ind.NonHTData(1):ind.NonHTData(2)); bitsData = wlanNonHTDataRecover(nonHTData,res.ChanEstNonHT,...res.NoiseEstNonHT,cfg); [cfgMAC, ~, decodeStatus] = wlanMPDUDecode(bitsData,cfg,...SuppressWarnings=true);% Print additional information on all successfully packetsif~decodeStatus && displayAdditionalInfo payloadSize = floor(length(bitsData)/8); [modulation,coderate] = getRateInfo(cfg.MCS); fprintf("Payload Size: %d | Modulation: %s | Code Rate: %s \n",payloadSize,modulation,coderate); fprintf("Type: %s | Sub-Type: %s",cfgMAC.getType,cfgMAC.getSubtype);end% Extract information about channel from the beacon.if~decodeStatus && matches(cfgMAC.FrameType,"Beacon")% Populate the table with information about the beacon.ifisempty(cfgMAC.ManagementConfig.SSID) APs(indexAP).SSID ="Hidden";elseAPs(indexAP).SSID = string(cfgMAC.ManagementConfig.SSID);endfprintf("%s beacon detected on channel %d in band %.1f.\n",APs(indexAP).SSID,rxsim.ChannelNumbers(i),rxsim.FrequencyBand); APs(indexAP).BSSID = string(cfgMAC.Address3);ifretrieveVendorInfo APs(indexAP).Vendor = determineVendor(cfgMAC.Address3);elseAPs(indexAP).Vendor ="Skipped";end[APs(indexAP).Mode, APs(indexAP).Channel_Width_MHz, operatingChannel] =...determineMode(cfgMAC.ManagementConfig.InformationElements);ifisempty(operatingChannel)% Default to scanning channel if operating channel% cannot be determined.operatingChannel = rxsim.ChannelNumbers(i);endAPs(indexAP).Beacon_Channel = rxsim.ChannelNumbers(i); APs(indexAP).Operating_Channel = operatingChannel; APs(indexAP).SNR_dB = res.LLTFSNR; APs(indexAP).MAC_Config = cfgMAC; APs(indexAP).Offset = res.PacketOffset; APs(indexAP).Waveform = capturedData; indexAP = indexAP + 1;end% Shift packet search offset for next iteration of while loop.searchOffset = res.PacketOffset + double(ind.NonHTData(2));else% Packet is NOT non-HT; shift packet search offset by 10 OFDM symbols (minimum% packet length of non-HT) for next iteration of while loop.searchOffset = res.PacketOffset + 4e-6*rxsim.RadioSampleRate/osf*10;endelse% L-SIG recovery failed; shift packet search offset by 10 OFDM symbols (minimum% packet length of non-HT) for next iteration of while loop.searchOffset = res.PacketOffset + 4e-6*rxsim.RadioSampleRate/osf*10;endendend
Scanning channel 52 on band 5.0.
WLAN_5G beacon detected on channel 52 in band 5.0.
Downloading oui.csv from IEEE Registration Authority...
Scanning channel 56 on band 5.0.
w-inside beacon detected on channel 56 in band 5.0. w-mobile beacon detected on channel 56 in band 5.0. w-guest beacon detected on channel 56 in band 5.0.
Scanning channel 157 on band 5.0.
w-inside beacon detected on channel 157 in band 5.0. w-mobile beacon detected on channel 157 in band 5.0. w-guest beacon detected on channel 157 in band 5.0.

Convert theAPsstructure to a table and display the information specified instep 6by using the local functiongenerateBeaconTable.

detectedBeaconsInfo = generateBeaconTable(APs,rxsim.FrequencyBand,retrieveVendorInfo)
detectedBeaconsInfo=7×9 tableSSID BSSID Vendor SNR (dB) Primary 20 MHz Channel Current Channel Center Frequency Index Channel Width (MHz) Band Mode __________ ______________ ____________________________ ________ ______________________ ______________________________________ ___________________ ____ __________ "WLAN_5G" "04D4C451C584" "ASUSTek COMPUTER INC." 34.57 52 50 "160" 5 "802.11ax" "w-inside" "B0B867F6B2D0" "Hewlett Packard Enterprise" 26.24 56 58 "80" 5 "802.11ac" "w-mobile" "B0B867F6B2D1" "Hewlett Packard Enterprise" 26.251 56 58 "80" 5 "802.11ac" "w-guest" "B0B867F6B2D2" "Hewlett Packard Enterprise" 25.843 56 58 "80" 5 "802.11ac" "w-inside" "B0B867F3D9B0" "Hewlett Packard Enterprise" 31.592 157 155 "80" 5 "802.11ac" "w-mobile" "B0B867F3D9B1" "Hewlett Packard Enterprise" 31.971 157 155 "80" 5 "802.11ac" "w-guest" "B0B867F3D9B2" "Hewlett Packard Enterprise" 33.3 157 155 "80" 5 "802.11ac"
ifrxsim.ReceiveOnSDR release(sdrReceiver);end

Further Exploration

  • ThedetectedBeaconsInfotable shows only key information about the APs. To get further information about the beacons, such as data rates supported by the AP, explore the MAC frame configuration in theAPsstructure.

  • If you have access to a configurable AP, change the channel width of your AP and rerun the example to confirm the channel width.

Local Functions

These functions assist in processing the incoming beacons.

functionwaveform = captureWaveform(sdrReceiver,numSamplesToCapture)% CAPTUREWAVEFORM returns a column vector of complex values given an% SDRRECEIVER object and a scalar NUMSAMPLESTOCAPTURE value.% For a comm.SDRuReceiver object, use the burst capture technique to% acquire the waveformifisa(sdrReceiver,'comm.SDRuReceiver') waveform = complex(zeros(numSamplesToCapture,1)); samplesPerFrame = sdrReceiver.SamplesPerFrame;fori = 1:sdrReceiver.NumFramesInBurst waveform(samplesPerFrame*(i-1)+(1:samplesPerFrame)) = sdrReceiver();endelsewaveform = capture(sdrReceiver,numSamplesToCapture);endendfunction[modulation,coderate] = getRateInfo(mcs)% GETRATEINFO returns the modulation scheme as a character array and the% code rate of a packet given a scalar integer representing the modulation% coding schemeswitchmcscase0% BPSKmodulation ='BPSK'; coderate ='1/2';case1% BPSKmodulation ='BPSK'; coderate ='3/4';case2% QPSKmodulation ='QPSK'; coderate ='1/2';case3% QPSKmodulation ='QPSK'; coderate ='3/4';case4% 16QAMmodulation ='16QAM'; coderate ='1/2';case5% 16QAMmodulation ='16QAM'; coderate ='3/4';case6% 64QAMmodulation ='64QAM'; coderate ='2/3';otherwise% 64QAMmodulation ='64QAM'; coderate ='3/4';endendfunctionvendor = determineVendor(mac)% DETERMINEVENDOR收益;ns the vendor name of the AP by extracting the% organizationally unique identifier (OUI) from the specified MAC address.persistentouis vendor = strings(0);tryifisempty(ouis)if~exist("oui.csv","file") disp("Downloading oui.csv from IEEE Registration Authority...") options = weboptions(“超时”,10); websave("oui.csv","http://standards-oui.ieee.org/oui/oui.csv",options);endouis = readtable("oui.csv",VariableNamingRule="preserve");end% Extract OUI from MAC Address.oui = mac(1:6);% Extract vendors name based on OUI.vendor = string(cell2mat(ouis.("Organization Name")(matches(ouis.Assignment,oui))));catchME% Rethrow caught error as warning.warning(ME.message+"\nTo skip the determineVendor function call, set retrieveVendorInfo to false.",[]);endifisempty(vendor) vendor ="Unknown";endendfunction[mode,bw,operatingChannel] = determineMode(informationElements)% DETERMINEMODE determines the 802.11 standard that the AP uses.% The function checks for the presence of HT, VHT, and HE capability% elements and determines the 802.11 standard that the AP uses. The element% IDs are defined in IEEE Std 802.11-2020 and IEEE Std 802.11ax-2021.elementIDs = cell2mat(informationElements(:,1)); IDs = elementIDs(:,1);ifany(IDs==255)ifany(elementIDs(IDs==255,2)==35)% HE Packet Formatmode ="802.11ax";elsemode ="Unknown";endvhtElement = informationElements{IDs==192,2}; htElement = informationElements{IDs==61,2}; [bw,operatingChannel] = determineChannelWidth(htElement,vhtElement);elseifany(IDs==191)% VHT Packet Formatmode ="802.11ac"; vhtElement = informationElements{IDs==192,2}; htElement = informationElements{IDs==61,2}; [bw,operatingChannel] = determineChannelWidth(htElement,vhtElement);elseifany(IDs==45)% HT Packet Formatmode ="802.11n"; htElement = informationElements{IDs==61,2}; [bw,operatingChannel] = determineChannelWidth(htElement);else% Non-HT Packet Format% Exclude b as only DSSS is supportedmode ="802.11a/g/j/p"; bw ="Unknown"; operatingChannel = [];endendfunction[bw,operatingChannel] = determineChannelWidth(htElement,varargin)% DETERMINECHANNELWIDTH returns the bandwidth of the channel from the% beacons operation information elements as defined in IEEE Std 802.11-2020% Table 11-23.msbFirst = false;% Convert to bits to get STA channel width value in 3rd bit.htOperationInfoBits = int2bit(htElement(2),5*8,msbFirst); operatingChannel = 0;ifnargin == 2 vhtElement = varargin{1};% VHT Operation Channel Width FieldCW = vhtElement(1);% Channel Center Frequency Segment 0CCFS0 = vhtElement(2);% Channel Center Frequency Segment 1CCFS1 = vhtElement(3);ifhtOperationInfoBits(3) == 0 bw ="20"; operatingChannel = CCFS0;elseifCW == 0% HT Operation Channel Width Field is 1bw ="40"; operatingChannel = CCFS0;elseifCCFS1 == 0% HT Operation Channel Width Field is 1 and% VHT Operation Channel Width Field is 1bw ="80"; operatingChannel = CCFS0;elseifabs(CCFS1 - CCFS0) == 8% HT Operation Channel Width Field is 1 and% VHT Operation Channel Width Field is 1 and% CCFS1 is greater than 0bw ="160"; operatingChannel = CCFS1;else% HT Operation Channel Width Field is 1 and% VHT Operation Channel Width Field is 1 and% CCFS1 is greater than 0 and% |CCFS1 - CCFS0| is greater than 16bw ="80+80";endendifoperatingChannel == 0ifhtOperationInfoBits(3) == 1 bw ="40"; secondaryChannelOffset = bit2int(htOperationInfoBits(1:2),2,false);ifsecondaryChannelOffset == 1% Secondary Channel is above the primary channel.operatingChannel = htElement(1) + 2;elseifsecondaryChannelOffset == 3% Secondary Channel is below the primary channel.operatingChannel = htElement(1) - 2;elsewarning("Could not determine operating channel.")endelsebw ="20"; operatingChannel = htElement(1);endendendfunctiontbl = generateBeaconTable(APs,band,retrieveVendorInfo)% GENERATEBEACONTABLE converts the access point structure to a table and% cleans up the variable names.tbl = struct2table(APs,"AsArray",true); tbl.Band = repmat(band,length(tbl.SSID),1); tbl = renamevars(tbl,["SNR_dB","Beacon_Channel","Operating_Channel","Channel_Width_MHz"],...["SNR (dB)","Primary 20 MHz Channel","Current Channel Center Frequency Index",..."Channel Width (MHz)"]);ifretrieveVendorInfo tbl = tbl(:,1:9);elsetbl = tbl(:,[1:2,4:9]);endend