Task 2 should be finished
This commit is contained in:
+146
@@ -0,0 +1,146 @@
|
||||
trace1 = load("traces/2412mhz.mat", "iq");
|
||||
trace2 = load("traces/2432mhz.mat", "iq");
|
||||
trace3 = load("traces/2452mhz.mat", "iq");
|
||||
trace4 = load("traces/2472mhz.mat", "iq");
|
||||
|
||||
window = 512;
|
||||
overlap = 64;
|
||||
fft_precision = 2048;
|
||||
|
||||
sample_rate = 20e6; % 20 MS/s -> 20e6 S/s
|
||||
|
||||
% 1.
|
||||
duration1 = length(trace1.iq) / sample_rate;
|
||||
duration2 = length(trace2.iq) / sample_rate;
|
||||
duration3 = length(trace3.iq) / sample_rate;
|
||||
duration4 = length(trace4.iq) / sample_rate;
|
||||
|
||||
% 2.
|
||||
% get all four plot values
|
||||
[S1,F1,T1] = spectrogram(trace1.iq, window, overlap, fft_precision, sample_rate, "centered");
|
||||
[S2,F2,T2] = spectrogram(trace2.iq, window, overlap, fft_precision, sample_rate, "centered");
|
||||
[S3,F3,T3] = spectrogram(trace3.iq, window, overlap, fft_precision, sample_rate, "centered");
|
||||
[S4,F4,T4] = spectrogram(trace4.iq, window, overlap, fft_precision, sample_rate, "centered");
|
||||
|
||||
mag1 = abs(S1).^2;
|
||||
mag2 = abs(S2).^2;
|
||||
mag3 = abs(S3).^2;
|
||||
mag4 = abs(S4).^2;
|
||||
|
||||
% begin calibrated color scale
|
||||
P1_dB = 10 * log10(mag1);
|
||||
P2_dB = 10 * log10(mag2);
|
||||
P3_dB = 10 * log10(mag3);
|
||||
P4_dB = 10 * log10(mag4);
|
||||
|
||||
all_P_dB = [P1_dB(:); P2_dB(:); P3_dB(:); P4_dB(:)];
|
||||
|
||||
p_dB_min = min(all_P_dB);
|
||||
p_dB_max = max(all_P_dB);
|
||||
% end power calibrated color scale
|
||||
|
||||
if ~calculations_only
|
||||
% plot all figures like example shows
|
||||
figure(1);
|
||||
imagesc(T1, F1, P1_dB);
|
||||
axis ij;
|
||||
xlabel("Time [s]");
|
||||
ylabel("Freq. [Hz]");
|
||||
title("Spectrogram Trace 1");
|
||||
cb = colorbar;
|
||||
ylabel(cb, "Power [dB]");
|
||||
clim([p_dB_min p_dB_max]);
|
||||
xlim([0 0.05]);
|
||||
|
||||
figure(2);
|
||||
imagesc(T2, F2, P2_dB);
|
||||
axis ij;
|
||||
xlabel("Time [s]");
|
||||
ylabel("Freq. [Hz]");
|
||||
title("Spectrogram Trace 2");
|
||||
cb = colorbar;
|
||||
ylabel(cb, "Power [dB]");
|
||||
clim([p_dB_min p_dB_max]);
|
||||
xlim([0 0.05]);
|
||||
|
||||
figure(3);
|
||||
imagesc(T3, F3, P3_dB);
|
||||
axis ij;
|
||||
xlabel("Time [s]");
|
||||
ylabel("Freq. [Hz]");
|
||||
title("Spectrogram Trace 3");
|
||||
cb = colorbar;
|
||||
ylabel(cb, "Power [dB]");
|
||||
clim([p_dB_min p_dB_max]);
|
||||
xlim([0 0.05]);
|
||||
|
||||
figure(4);
|
||||
imagesc(T4, F4, P4_dB);
|
||||
axis ij; % flip so its like the example fig
|
||||
xlabel("Time [s]");
|
||||
ylabel("Freq. [Hz]");
|
||||
title("Spectrogram Trace 4");
|
||||
cb = colorbar;
|
||||
ylabel(cb, "Power [dB]");
|
||||
clim([p_dB_min p_dB_max]);
|
||||
xlim([0 0.05]); % reduce view so its like the example fig
|
||||
end
|
||||
|
||||
% 3.
|
||||
% taking the 10th percentile on the linear values or the logarithmic ones
|
||||
% should not make any difference
|
||||
|
||||
noise_floor1_linear = prctile(mag1(:), 10);
|
||||
noise_floor2_linear = prctile(mag2(:), 10);
|
||||
noise_floor3_linear = prctile(mag3(:), 10);
|
||||
noise_floor4_linear = prctile(mag4(:), 10);
|
||||
|
||||
noise_floor1 = 10 * log10(noise_floor1_linear);
|
||||
noise_floor2 = prctile(P2_dB(:), 10);
|
||||
noise_floor3 = prctile(P3_dB(:), 10);
|
||||
noise_floor4 = prctile(P4_dB(:), 10);
|
||||
|
||||
% this is false -> linear avg on logarithmic values
|
||||
% noise_floor_avg = sum([noise_floor1 noise_floor2, noise_floor3, noise_floor4]) / 4;
|
||||
|
||||
noise_floor_avg = 10 * log10(abs(sum([prctile(mag1(:), 10) prctile(mag2(:), 10) prctile(mag3(:), 10) prctile(mag4(:), 10)]) / 4));
|
||||
|
||||
% 4.
|
||||
occupancy1 = sum(P1_dB(:) > noise_floor1 + 10) / numel(P1_dB) * 100;
|
||||
occupancy2 = sum(P2_dB(:) > noise_floor2 + 10) / numel(P2_dB) * 100;
|
||||
occupancy3 = sum(P3_dB(:) > noise_floor3 + 10) / numel(P3_dB) * 100;
|
||||
occupancy4 = sum(P4_dB(:) > noise_floor4 + 10) / numel(P4_dB) * 100;
|
||||
|
||||
occupancies = [occupancy1 occupancy2 occupancy3 occupancy4];
|
||||
channels = [1 5 9 13];
|
||||
|
||||
[occupancy_max, max_idx] = max(occupancies);
|
||||
busiest_channel = channels(max_idx);
|
||||
|
||||
if ~calculations_only
|
||||
disp("Results Task 1:" + newline)
|
||||
|
||||
disp("-- Trace duration ---")
|
||||
disp("Channel 1 duration: " + duration1 + "s")
|
||||
disp("Channel 5 duration: " + duration2 + "s")
|
||||
disp("Channel 9 duration: " + duration3 + "s")
|
||||
disp("Channel 13 duration: " + duration4 + "s" + newline)
|
||||
|
||||
disp("--- Noise floor ---")
|
||||
disp("Distinct:")
|
||||
disp("Channel 1 noise floor: " + noise_floor1 + "dB")
|
||||
disp("Channel 5 noise floor: " + noise_floor2 + "dB")
|
||||
disp("Channel 9 noise floor: " + noise_floor3 + "dB")
|
||||
disp("Channel 13 noise floor: " + noise_floor4 + "dB" + newline)
|
||||
|
||||
disp("Combined:")
|
||||
disp("Channel all noise floor: " + noise_floor_avg + "dB" + newline)
|
||||
|
||||
disp("-- Occupancy ---")
|
||||
disp("Channel 1 occupancy: " + occupancy1 + "%")
|
||||
disp("Channel 5 occupancy: " + occupancy2 + "%")
|
||||
disp("Channel 9 occupancy: " + occupancy3 + "%")
|
||||
disp("Channel 13 occupancy: " + occupancy4 + "%" + newline)
|
||||
|
||||
disp("Busiest channel: " + busiest_channel)
|
||||
end
|
||||
+70
-14
@@ -22,15 +22,19 @@ duration4 = length(trace4.iq) / sample_rate;
|
||||
[S3,F3,T3] = spectrogram(trace3.iq, window, overlap, fft_precision, sample_rate, "centered");
|
||||
[S4,F4,T4] = spectrogram(trace4.iq, window, overlap, fft_precision, sample_rate, "centered");
|
||||
|
||||
mag1 = abs(S1).^2;
|
||||
mag2 = abs(S2).^2;
|
||||
mag3 = abs(S3).^2;
|
||||
mag4 = abs(S4).^2;
|
||||
|
||||
% begin calibrated color scale
|
||||
P1_dB = 20 * log10(abs(S1).^2);
|
||||
P2_dB = 20 * log10(abs(S2).^2);
|
||||
P3_dB = 20 * log10(abs(S3).^2);
|
||||
P4_dB = 20 * log10(abs(S4).^2);
|
||||
P1_dB = 10 * log10(mag1);
|
||||
P2_dB = 10 * log10(mag2);
|
||||
P3_dB = 10 * log10(mag3);
|
||||
P4_dB = 10 * log10(mag4);
|
||||
|
||||
all_P_dB = [P1_dB(:); P2_dB(:); P3_dB(:); P4_dB(:)];
|
||||
|
||||
% -50 to +50 so its like the example fig
|
||||
p_dB_min = min(all_P_dB);
|
||||
p_dB_max = max(all_P_dB);
|
||||
% end power calibrated color scale
|
||||
@@ -46,7 +50,7 @@ if ~calculations_only
|
||||
cb = colorbar;
|
||||
ylabel(cb, "Power [dB]");
|
||||
clim([p_dB_min p_dB_max]);
|
||||
xlim([0 0.05]);
|
||||
% xlim([0 0.05]);
|
||||
|
||||
figure(2);
|
||||
imagesc(T2, F2, P2_dB);
|
||||
@@ -57,7 +61,7 @@ if ~calculations_only
|
||||
cb = colorbar;
|
||||
ylabel(cb, "Power [dB]");
|
||||
clim([p_dB_min p_dB_max]);
|
||||
xlim([0 0.05]);
|
||||
% xlim([0 0.05]);
|
||||
|
||||
figure(3);
|
||||
imagesc(T3, F3, P3_dB);
|
||||
@@ -68,7 +72,7 @@ if ~calculations_only
|
||||
cb = colorbar;
|
||||
ylabel(cb, "Power [dB]");
|
||||
clim([p_dB_min p_dB_max]);
|
||||
xlim([0 0.05]);
|
||||
% xlim([0 0.05]);
|
||||
|
||||
figure(4);
|
||||
imagesc(T4, F4, P4_dB);
|
||||
@@ -79,22 +83,70 @@ if ~calculations_only
|
||||
cb = colorbar;
|
||||
ylabel(cb, "Power [dB]");
|
||||
clim([p_dB_min p_dB_max]);
|
||||
xlim([0 0.05]); % reduce view so its like the example fig
|
||||
% xlim([0 0.05]); % reduce view so its like the example fig
|
||||
end
|
||||
|
||||
%{
|
||||
% 3.
|
||||
noise_floor1 = prctile(P1_dB(:), 10);
|
||||
noise_floor2 = prctile(P2_dB(:), 10);
|
||||
noise_floor3 = prctile(P3_dB(:), 10);
|
||||
noise_floor4 = prctile(P4_dB(:), 10);
|
||||
% taking the 10th percentile on the linear values or the logarithmic ones
|
||||
% should not make any difference
|
||||
|
||||
noise_floor_avg = sum([noise_floor1 noise_floor2, noise_floor3, noise_floor4]) / 4;
|
||||
noise_floor1_linear = prctile(mag1(:), 10);
|
||||
noise_floor2_linear = prctile(mag2(:), 10);
|
||||
noise_floor3_linear = prctile(mag3(:), 10);
|
||||
noise_floor4_linear = prctile(mag4(:), 10);
|
||||
|
||||
noise_floor1 = linearTodB(noise_floor1_linear);
|
||||
noise_floor2 = linearTodB(noise_floor2_linear);
|
||||
noise_floor3 = linearTodB(noise_floor3_linear);
|
||||
noise_floor4 = linearTodB(noise_floor4_linear);
|
||||
|
||||
% this is false -> linear avg on logarithmic values
|
||||
% noise_floor_avg = sum([noise_floor1 noise_floor2, noise_floor3, noise_floor4]) / 4;
|
||||
|
||||
noise_floor_avg = linearTodB(mean([noise_floor1_linear noise_floor2_linear noise_floor3_linear noise_floor4_linear]));
|
||||
|
||||
% 4.
|
||||
occupancy1 = sum(P1_dB(:) > noise_floor1 + 10) / numel(P1_dB) * 100;
|
||||
occupancy2 = sum(P2_dB(:) > noise_floor2 + 10) / numel(P2_dB) * 100;
|
||||
occupancy3 = sum(P3_dB(:) > noise_floor3 + 10) / numel(P3_dB) * 100;
|
||||
occupancy4 = sum(P4_dB(:) > noise_floor4 + 10) / numel(P4_dB) * 100;
|
||||
%}
|
||||
|
||||
% 3.
|
||||
% Sum all frequency bins per time slot to obtain total channel power.
|
||||
channel_power1_linear = sum(mag1, 1);
|
||||
channel_power2_linear = sum(mag2, 1);
|
||||
channel_power3_linear = sum(mag3, 1);
|
||||
channel_power4_linear = sum(mag4, 1);
|
||||
|
||||
channel_power1_dB = linearTodB(channel_power1_linear);
|
||||
channel_power2_dB = linearTodB(channel_power2_linear);
|
||||
channel_power3_dB = linearTodB(channel_power3_linear);
|
||||
channel_power4_dB = linearTodB(channel_power4_linear);
|
||||
|
||||
noise_floor1_linear = prctile(channel_power1_linear, 10);
|
||||
noise_floor2_linear = prctile(channel_power2_linear, 10);
|
||||
noise_floor3_linear = prctile(channel_power3_linear, 10);
|
||||
noise_floor4_linear = prctile(channel_power4_linear, 10);
|
||||
|
||||
noise_floor1 = linearTodB(noise_floor1_linear);
|
||||
noise_floor2 = linearTodB(noise_floor2_linear);
|
||||
noise_floor3 = linearTodB(noise_floor3_linear);
|
||||
noise_floor4 = linearTodB(noise_floor4_linear);
|
||||
|
||||
noise_floor_avg = linearTodB(mean([
|
||||
noise_floor1_linear
|
||||
noise_floor2_linear
|
||||
noise_floor3_linear
|
||||
noise_floor4_linear
|
||||
]));
|
||||
|
||||
% 4.
|
||||
occupancy1 = sum(channel_power1_dB > noise_floor1 + 10) / numel(channel_power1_dB) * 100;
|
||||
occupancy2 = sum(channel_power2_dB > noise_floor2 + 10) / numel(channel_power2_dB) * 100;
|
||||
occupancy3 = sum(channel_power3_dB > noise_floor3 + 10) / numel(channel_power3_dB) * 100;
|
||||
occupancy4 = sum(channel_power4_dB > noise_floor4 + 10) / numel(channel_power4_dB) * 100;
|
||||
|
||||
occupancies = [occupancy1 occupancy2 occupancy3 occupancy4];
|
||||
channels = [1 5 9 13];
|
||||
@@ -129,3 +181,7 @@ if ~calculations_only
|
||||
|
||||
disp("Busiest channel: " + busiest_channel)
|
||||
end
|
||||
|
||||
function val = linearTodB(toConvert)
|
||||
val = 10 * log10(toConvert);
|
||||
end
|
||||
+218
-7
@@ -1,18 +1,81 @@
|
||||
channel_bandwidth = "CBW20"; % 20MHz
|
||||
addpath("from_matlab_example");
|
||||
|
||||
rxFrame1 = trace1.iq(:);
|
||||
rxFrame2 = trace2.iq(:);
|
||||
rxFrame3 = trace3.iq(:);
|
||||
rxFrame4 = trace4.iq(:);
|
||||
|
||||
function beaconFrames = extractBeaconFrames(rxFrame)
|
||||
beaconFrames = [];
|
||||
searchOffset = 0;
|
||||
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:
|
||||
Address 1: MAC of the destination station
|
||||
Address 2: MAC of the AP which further routes the frame
|
||||
Address 3: MAC of the initial sender which has started the process of
|
||||
the frame to AP's
|
||||
Address 4: not used
|
||||
Uplink:
|
||||
Address 1: MAC of the AP the WiFi frame should route through
|
||||
(the connected AP)
|
||||
Address 2: MAC of the sending station
|
||||
Address 3: used to store the final destination MAC address
|
||||
|
||||
Address 4: not used
|
||||
|
||||
4 Address case:
|
||||
Address 4: is only used in wireless bridge solutions, environments where
|
||||
multiple AP's connect different LAN's to one big one
|
||||
%}
|
||||
|
||||
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
|
||||
@@ -20,10 +83,158 @@ function beaconFrames = extractBeaconFrames(rxFrame)
|
||||
[cfgMAC, ~, decodeStatus] = wlanMPDUDecode(bitsData, SuppressWarnings=true);
|
||||
|
||||
if ~decodeStatus && matches(cfgMAC.FrameType, "Beacon")
|
||||
disp("Beacon at " + searchOffset);
|
||||
beaconFrames(end + 1) = cfgMAC;
|
||||
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
|
||||
|
||||
beaconFrames1 = extractBeaconFrames(rxFrame1);
|
||||
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
|
||||
+155
-18
@@ -10,17 +10,52 @@ beaconFrames2 = extractBeaconFrames(rxFrame2);
|
||||
beaconFrames3 = extractBeaconFrames(rxFrame3);
|
||||
beaconFrames4 = extractBeaconFrames(rxFrame4);
|
||||
|
||||
cfgMAC = beaconFrames1(1).MAC_Config;
|
||||
mgmt = cfgMAC.ManagementConfig;
|
||||
|
||||
disp(mgmt)
|
||||
properties(mgmt)
|
||||
|
||||
% 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", {}, ...
|
||||
@@ -31,8 +66,6 @@ function beaconFrames = extractBeaconFrames(rxFrame)
|
||||
"SNR_dB", {} ...
|
||||
);
|
||||
|
||||
channel_bandwidth = "CBW20"; % 20MHz
|
||||
|
||||
searchOffset = 0;
|
||||
index = 1;
|
||||
|
||||
@@ -80,25 +113,129 @@ function beaconFrames = extractBeaconFrames(rxFrame)
|
||||
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("%-20s %-18s %-10s %-8s %-8s %-8s %-12s %-8s %-20s\n", ...
|
||||
fprintf(tableFormat, ...
|
||||
"SSID", "BSSID", "Interval", "B. ch.", "Op. ch.", "SNR", "Vendor", "Std.", "Rates");
|
||||
|
||||
for i = 1:numel(beaconFrames)
|
||||
for i = 1 : beaconCount
|
||||
mgmt = beaconFrames(i).MAC_Config.ManagementConfig;
|
||||
|
||||
ssid = string(beaconFrames(i).SSID);
|
||||
bssid = string(beaconFrames(i).BSSID);
|
||||
interval = string(beaconFrames(i).MAC_Config.ManagementConfig.BeaconInterval);
|
||||
bssid = toMACAddress(beaconFrames(i).BSSID);
|
||||
interval = string(mgmt.BeaconInterval);
|
||||
snr = sprintf("%.1f", beaconFrames(i).SNR_dB);
|
||||
|
||||
bch = "-";
|
||||
opch = "-";
|
||||
vendor = "-";
|
||||
std = "-";
|
||||
rates = "-";
|
||||
[bch, opch] = extractChannels(mgmt);
|
||||
vendor = lookupVendor(beaconFrames(i).BSSID);
|
||||
rates = getRates(mgmt);
|
||||
std = getWifiStandard(mgmt);
|
||||
|
||||
fprintf("%-20s %-18s %-10s %-8s %-8s %-8s %-12s %-8s %-20s\n", ...
|
||||
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
|
||||
Reference in New Issue
Block a user