Skip to content

Instantly share code, notes, and snippets.

@msantos
Created March 7, 2011 22:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save msantos/859390 to your computer and use it in GitHub Desktop.
Save msantos/859390 to your computer and use it in GitHub Desktop.
Erlang wireless AP scanner
-module(wierl).
-export([start/1]).
-define(UINT16, 2/native-unsigned-integer-unit:8).
-define(UINT32, 4/native-unsigned-integer-unit:8).
-define(UINT64, 8/native-unsigned-integer-unit:8).
-define(IFNAMSIZ, 16).
-define(SIOCSIWSCAN, 16#8B18). % Trigger a scan
-define(SIOCGIWSCAN, 16#8B19). % Retrieve the scan results
% Event types
-define(SIOCGIWAP, 16#8B15).
-define(SIOCGIWAPLIST, 16#8B17).
-define(SIOCGIWAUTH, 16#8B33).
-define(SIOCGIWENCODE, 16#8B2B).
-define(SIOCGIWENCODEEXT, 16#8B35).
-define(SIOCGIWESSID, 16#8B1B).
-define(SIOCGIWFRAG, 16#8B25).
-define(SIOCGIWFREQ, 16#8B05).
-define(SIOCGIWGENIE, 16#8B31).
-define(SIOCGIWMODE, 16#8B07).
-define(SIOCGIWMODUL, 16#8B2F).
-define(SIOCGIWNAME, 16#8B01).
-define(SIOCGIWNICKN, 16#8B1D).
-define(SIOCGIWNWID, 16#8B03).
-define(SIOCGIWPOWER, 16#8B2D).
-define(SIOCGIWPRIV, 16#8B0D).
-define(SIOCGIWRANGE, 16#8B0B).
-define(SIOCGIWRATE, 16#8B21).
-define(SIOCGIWRETRY, 16#8B29).
-define(SIOCGIWRTS, 16#8B23).
-define(SIOCGIWSENS, 16#8B09).
-define(SIOCGIWSPY, 16#8B11).
-define(SIOCGIWSTATS, 16#8B0F).
-define(SIOCGIWTHRSPY, 16#8B13).
-define(SIOCGIWTXPOW, 16#8B27).
-define(IWEVGENIE, 16#8C05).
-define(IWEVQUAL, 16#8C01).
-define(IWEVCUSTOM, 16#8C02).
%%
%% Open an unprivileged, datagram socket using
%% procket
%%
start(Dev) when is_binary(Dev) ->
{ok, Socket} = procket:socket(inet, dgram, 0),
scan(Dev, Socket),
procket:close(Socket).
%%
%% Initiate the scan
%%
scan(Dev, Socket) when byte_size(Dev) < ?IFNAMSIZ ->
Req = <<Dev/binary, 0:((?IFNAMSIZ - byte_size(Dev))*8), 0:(16*8)>>,
{ok, _Req} = procket:ioctl(Socket, ?SIOCSIWSCAN, Req),
result(Dev, Socket).
%%
%% Retrieve the scan results by specifying a buffer for the
%% kernel to return the results
%%
result(Dev, Socket) ->
{ok, Req, [Res]} = procket:alloc([
<<Dev/bytes, 0:( (?IFNAMSIZ - byte_size(Dev))*8)>>,
{ptr, 4096},
<<4096:?UINT16, 0:?UINT16>>
]),
case procket:ioctl(Socket, ?SIOCGIWSCAN, Req) of
{ok, <<_Ifname:16/bytes, _Ptr:?UINT32, Len:?UINT16, _Flag:?UINT16>>} ->
{ok, <<Stream:Len/bytes, _/binary>>} = procket:buf(Res),
event(Stream);
% Poll the socket for the results
{error, eagain} ->
timer:sleep(1000),
result(Dev, Socket);
Error ->
Error
end.
% The events are returned in the form: length, command, data
% (length bytes)
%
% We believe the length returned in the packet and print out
% the binary data. If the length is wrong, we'll just crash.
event(<<>>) ->
ok;
event(<<Len:?UINT16, Cmd:?UINT16, Bin/binary>>) ->
EventLen = Len - 4,
<<Event:EventLen/bytes, Rest/binary>> = Bin,
io:format("~p:~p~n", [cmd(Cmd), Event]),
event(Rest).
% Convert the integer command values to almost human readable atoms
cmd(?SIOCGIWNAME) -> name;
cmd(?SIOCGIWNWID) -> nwid;
cmd(?SIOCGIWFREQ) -> freq;
cmd(?SIOCGIWMODE) -> mode;
cmd(?SIOCGIWSENS) -> sens;
cmd(?SIOCGIWRANGE) -> range;
cmd(?SIOCGIWPRIV) -> priv;
cmd(?SIOCGIWSTATS) -> stats;
cmd(?SIOCGIWSPY) -> spy;
cmd(?SIOCGIWTHRSPY) -> thrspy;
cmd(?SIOCGIWAP) -> bssid;
cmd(?SIOCGIWAPLIST) -> aplist;
cmd(?SIOCGIWESSID) -> essid;
cmd(?SIOCGIWNICKN) -> nickn;
cmd(?SIOCGIWRATE) -> rate;
cmd(?SIOCGIWRTS) -> rts;
cmd(?SIOCGIWFRAG) -> frag;
cmd(?SIOCGIWTXPOW) -> txpow;
cmd(?SIOCGIWRETRY) -> retry;
cmd(?SIOCGIWENCODE) -> encode;
cmd(?SIOCGIWPOWER) -> power;
cmd(?SIOCGIWMODUL) -> modul;
cmd(?SIOCGIWGENIE) -> genie;
cmd(?SIOCGIWAUTH) -> auth;
cmd(?SIOCGIWENCODEEXT) -> encodeext;
cmd(?IWEVGENIE) -> genie;
cmd(?IWEVQUAL) -> qual;
cmd(?IWEVCUSTOM) -> custom;
cmd(Unknown) -> {unknown, Unknown}.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment