Skip to content

Instantly share code, notes, and snippets.

@msantos
Created August 1, 2011 16:26
Show Gist options
  • Select an option

  • Save msantos/1118456 to your computer and use it in GitHub Desktop.

Select an option

Save msantos/1118456 to your computer and use it in GitHub Desktop.
Passive scan for wireless access points in Erlang
-module(apscan).
-include("include/wierl_frame.hrl").
-export([start/0, start/3]).
start() ->
start(<<"wlan0">>, 1, 11).
start(Ifname, Min, Max) when is_binary(Ifname), Min =< Max, Min > 0, Max < 12 ->
{ok, Socket} = wierl_monitor:open(Ifname),
spawn_link(fun() -> channel_hop(Ifname, lists:seq(Min,Max)) end),
read(Socket, dict:new()).
read(Socket, AP) ->
AP1 = case wierl_monitor:read(Socket) of
{ok, Frame} ->
frame(Socket, Frame, AP);
{error, Error} when Error == eagain; Error == enetdown ->
timer:sleep(10),
AP
end,
read(Socket, AP1).
frame(Socket, Frame, AP) ->
try wierl_monitor:frame(Socket, Frame) of
F -> event(F, AP)
catch
error:_ ->
AP
end.
%% Management frame
event({#ieee802_11_radiotap{present = Present},
#ieee802_11_fc{type = 0, subtype = 8},
#ieee802_11_management{bssid = BSSID, body = Body},
_FCS}, AP) ->
% Radiotap header
Rate = get_value(rate, Present),
Channel = get_value(channel, Present),
Signal = get_value(dbm_antsignal, Present),
% Management frame
SSID = get_value(ssid, Body),
WAP = {ap, Rate, Channel, Signal, SSID},
event_1(BSSID, WAP, AP);
event({#ieee802_11_prism{
rate = #prism_value{data = Rate},
channel = #prism_value{data = Channel},
rssi = #prism_value{data = Signal}
},
#ieee802_11_fc{type = 0, subtype = 8},
#ieee802_11_management{bssid = BSSID, body = Body},
_FCS}, AP) ->
% Management frame
SSID = get_value(ssid, Body),
WAP = {ap, Rate, Channel, Signal, SSID},
event_1(BSSID, WAP, AP);
%% Ignore other frame types
event(_Frame, AP) ->
AP.
event_1(BSSID, WAP, AP) ->
case dict:find(BSSID, AP) of
{ok, PID} ->
PID ! WAP,
AP;
error ->
Pid = spawn(fun() -> wap(WAP, 60000) end),
dict:store(BSSID, Pid, AP)
end.
wap(WAP, Timeout) ->
error_logger:info_report([WAP]),
cache(WAP, Timeout).
cache({ap, Rate, Channel, Signal, SSID}, Timeout) ->
receive
{ap, Rate, Channel, Signal1, SSID} = WAP
when Signal1 =< Signal + Signal div 20, Signal1 >= Signal - Signal div 20 ->
cache(WAP, Timeout);
{ap, _Rate1, _Channel1, _Signal, _SSID1} = WAP ->
error_logger:info_report([WAP]),
cache(WAP, Timeout)
after
Timeout ->
ok
end.
get_value(Key, List) when is_list(List) ->
case lists:keyfind(Key, 1, List) of
false -> undefined;
Value -> element(2, Value)
end;
get_value(_Key, _Bin) ->
undefined.
channel_hop(Ifname, [C|Cs]) ->
error_logger:info_report([{channel_hop, C}]),
{ok, _} = wierl_config:param(Ifname, {channel, C}),
timer:sleep(10000),
channel_hop(Ifname, Cs ++ [C]).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment