241 lines
6.7 KiB
Matlab
241 lines
6.7 KiB
Matlab
addpath("from_matlab_example");
|
|
|
|
rxFrame1 = trace1.iq(:);
|
|
rxFrame2 = trace2.iq(:);
|
|
rxFrame3 = trace3.iq(:);
|
|
rxFrame4 = trace4.iq(:);
|
|
|
|
beaconFrames1 = extractBeaconFrames(rxFrame1);
|
|
beaconFrames2 = extractBeaconFrames(rxFrame2);
|
|
beaconFrames3 = extractBeaconFrames(rxFrame3);
|
|
beaconFrames4 = extractBeaconFrames(rxFrame4);
|
|
|
|
% 1.
|
|
disp("Beacon Frame 1")
|
|
printBeaconTable(beaconFrames1);
|
|
disp("Beacon Frame 2")
|
|
printBeaconTable(beaconFrames2);
|
|
disp("Beacon Frame 3")
|
|
printBeaconTable(beaconFrames3);
|
|
disp("Beacon Frame 4")
|
|
printBeaconTable(beaconFrames4);
|
|
|
|
% 2.
|
|
%{
|
|
Address 1: used to announce the destination station, in a beacon frame its
|
|
FF:FF:FF:FF:FF:FF (meaning broadcast to all stations)
|
|
Address 2: used to remark the source device address of the frame,
|
|
the ap mac who sent the beacon is inserted
|
|
Address 3: used for the bssid of the device sending the beacon, means
|
|
usually address 2 equals address 3, when no virtual ap is used
|
|
Address 4: this field does not exists, after the seq ctrl the frame body
|
|
follows containing beacon data instead of an address, like
|
|
timestamp, beacon interval, capability info, ssid, potentially
|
|
the channel number, see the extracts from 2.1
|
|
%}
|
|
|
|
% 3.
|
|
%{
|
|
Downlink: AP -> Station
|
|
Address 1: MAC of the destination station
|
|
Address 2: MAC of the AP which transmits the frame
|
|
Address 3: MAC of the initial sender which has started the frame
|
|
Address 4: not used
|
|
|
|
Uplink: Station -> AP
|
|
Address 1: MAC of the AP that receives and potentially forwards the frame
|
|
Address 2: MAC of the sending station
|
|
Address 3: MAC of the final destination station
|
|
Address 4: not used
|
|
|
|
4 Address case: wireless bridge:
|
|
Address 1: MAC of the AP that should receive / transmit through the frame,
|
|
for example AP, bridge node, repeater or mesh node
|
|
Address 2: MAC of the transmitter (into the other network)
|
|
Address 3: MAC of the final destination
|
|
Address 4: MAC of the initial sender
|
|
%}
|
|
|
|
function beaconFrames = extractBeaconFrames(rxFrame)
|
|
beaconFrames = struct( ...
|
|
"SSID", {}, ...
|
|
"BSSID", {}, ...
|
|
"Offset", {}, ...
|
|
"MAC_Config", {}, ...
|
|
"Bits", {}, ...
|
|
"SNR_dB", {} ...
|
|
);
|
|
|
|
searchOffset = 0;
|
|
index = 1;
|
|
|
|
while searchOffset < length(rxFrame)
|
|
oldOffset = searchOffset;
|
|
[bitsData, decParams, searchOffset, res] = recoverOFDMBits(rxFrame, searchOffset);
|
|
|
|
if searchOffset <= oldOffset
|
|
searchOffset = oldOffset + 1;
|
|
end
|
|
|
|
if isempty(bitsData)
|
|
continue;
|
|
end
|
|
|
|
[cfgMAC, ~, decodeStatus] = wlanMPDUDecode(bitsData, SuppressWarnings=true);
|
|
|
|
if ~decodeStatus && matches(cfgMAC.FrameType, "Beacon")
|
|
if isempty(cfgMAC.ManagementConfig.SSID)
|
|
ssid = "Hidden";
|
|
else
|
|
ssid = string(cfgMAC.ManagementConfig.SSID);
|
|
end
|
|
|
|
if isfield(res, "PacketOffset")
|
|
beaconFrames(index).Offset = res.PacketOffset;
|
|
else
|
|
beaconFrames(index).Offset = oldOffset;
|
|
end
|
|
|
|
if isfield(res, "LLTFSNR")
|
|
beaconFrames(index).SNR_dB = res.LLTFSNR;
|
|
else
|
|
beaconFrames(index).SNR_dB = NaN;
|
|
end
|
|
|
|
beaconFrames(index).SSID = ssid;
|
|
beaconFrames(index).BSSID = string(cfgMAC.Address3);
|
|
beaconFrames(index).MAC_Config = cfgMAC;
|
|
beaconFrames(index).Bits = bitsData;
|
|
|
|
index = index + 1;
|
|
end
|
|
end
|
|
end
|
|
|
|
function printBeaconTable(beaconFrames)
|
|
beaconCount = numel(beaconFrames);
|
|
|
|
tableFormat = "%-20s %-18s %-10s %-8s %-8s %-8s %-12s %-8s %-80s\n";
|
|
|
|
if(beaconCount < 1)
|
|
disp("No valid beacons could be extracted")
|
|
return;
|
|
end
|
|
|
|
fprintf("\n");
|
|
fprintf(tableFormat, ...
|
|
"SSID", "BSSID", "Interval", "B. ch.", "Op. ch.", "SNR", "Vendor", "Std.", "Rates");
|
|
|
|
for i = 1 : beaconCount
|
|
mgmt = beaconFrames(i).MAC_Config.ManagementConfig;
|
|
|
|
ssid = string(beaconFrames(i).SSID);
|
|
bssid = toMACAddress(beaconFrames(i).BSSID);
|
|
interval = string(mgmt.BeaconInterval);
|
|
snr = sprintf("%.1f", beaconFrames(i).SNR_dB);
|
|
|
|
[bch, opch] = extractChannels(mgmt);
|
|
vendor = lookupVendor(beaconFrames(i).BSSID);
|
|
rates = getRates(mgmt);
|
|
std = getWifiStandard(mgmt);
|
|
|
|
fprintf(tableFormat, ...
|
|
ssid, bssid, interval, bch, opch, snr, vendor, std, rates);
|
|
end
|
|
|
|
fprintf("\n");
|
|
end
|
|
|
|
function mac = toMACAddress(mac)
|
|
mac = upper(string(mac));
|
|
|
|
if strlength(mac) ~= 12
|
|
return;
|
|
end
|
|
|
|
macChars = char(mac);
|
|
|
|
mac = string(sprintf("%s:%s:%s:%s:%s:%s", ...
|
|
macChars(1:2), ...
|
|
macChars(3:4), ...
|
|
macChars(5:6), ...
|
|
macChars(7:8), ...
|
|
macChars(9:10), ...
|
|
macChars(11:12)));
|
|
end
|
|
|
|
function rates = getRates(mgmt)
|
|
basicRates = string(mgmt.BasicRates);
|
|
additionalRates = string(mgmt.AdditionalRates);
|
|
|
|
if isempty(basicRates) && isempty(additionalRates)
|
|
rates = "-";
|
|
return;
|
|
end
|
|
|
|
basicRates = "[" + strjoin(basicRates, ", ") + "]";
|
|
rates = strjoin([basicRates, additionalRates], ", ");
|
|
end
|
|
|
|
function vendor = lookupVendor(bssid)
|
|
bssid = upper(string(bssid));
|
|
|
|
if strlength(bssid) < 6
|
|
vendor = "-";
|
|
return;
|
|
end
|
|
|
|
oui = extractBefore(bssid, 7);
|
|
|
|
switch oui
|
|
case { "C884A1", "5CE176" }
|
|
vendor = "Cisco";
|
|
case { "6466B3", "647002" }
|
|
vendor = "TP-Link";
|
|
otherwise
|
|
vendor = "Unknown";
|
|
end
|
|
end
|
|
|
|
function std = getWifiStandard(mgmt)
|
|
rates = [string(mgmt.BasicRates), string(mgmt.AdditionalRates)];
|
|
|
|
if any(contains(rates, ["6 Mbps", "9 Mbps", "12 Mbps", "18 Mbps", "24 Mbps", "36 Mbps", "48 Mbps", "54 Mbps"]))
|
|
std = "802.11g";
|
|
elseif any(contains(rates, ["1 Mbps", "2 Mbps", "5.5 Mbps", "11 Mbps"]))
|
|
std = "802.11b";
|
|
else
|
|
std = "Unknown";
|
|
end
|
|
end
|
|
|
|
function [b_ch, op_ch] = extractChannels(mgmt)
|
|
b_ch = "-";
|
|
op_ch = "-";
|
|
|
|
ies = mgmt.InformationElements;
|
|
|
|
if(isempty(ies))
|
|
return;
|
|
end
|
|
|
|
for i = 1 : size(ies, 1)
|
|
id = ies{i, 1};
|
|
value = ies{i, 2};
|
|
|
|
if isempty(id) || isempty(value)
|
|
continue;
|
|
end
|
|
|
|
switch id(1)
|
|
case 3
|
|
b_ch = string(double(value(1)));
|
|
case 61
|
|
op_ch = string(double(value(1)));
|
|
end
|
|
|
|
if ~strcmp(b_ch, "-") && ~strcmp(op_ch, "-")
|
|
return;
|
|
end
|
|
end
|
|
end |