/wierl

Erlang interface for manipulating 802.11 wireless devices

Primary LanguageErlang

Erlang interface for manipulating 802.11 wireless network devices

wierl is a set of Erlang modules for interacting with 802.11 wireless devices on Linux.

NOTE ON PRIVILEGES

To run this code, Erlang will either have to run as root or have CAP_NET_ADMIN privileges:

setcap cap_net_admin=ep /path/to/beam

QUICK SETUP

cd wierl
make

sudo setcap cap_net_admin=ep /path/to/beam

./start.sh
% Scan using the "wlan0" interface
wierl_scan:list(<<"wlan0">>).

% Monitor mode: make sure the network manager is stopped. For example,
% on Ubuntu: service network-manager stop
{ok, Socket} = wierl_monitor:open(<<"wlan0">>),
{ok, Frame} = wierl_monitor:read(Socket),
wierl_monitor:frame(Socket, Frame).

# If you want to remove the privs
sudo setcap -r /path/to/beam

USAGE

wierl_scan

wierl_scan:list() ->  [{Interface, AccessPoints}]
wierl_scan:list(Interface) ->  AccessPoints
wierl_scan:list(Interface, Options) ->  AccessPoints

    Types   Interface = binary()
            AccessPoints = [AccessPoint]
            AccessPoint = {BSSID, ScanInfo}
            BSSID = binary()
            ScanInfo = [Info]
            Info = {Key, binary()}
            Key = custom
                | encode
                | essid
                | freq
                | genie
                | mode
                | qual
                | rate
            Options = [{essid, binary()}]

    Initiate a wireless scan and return the scan list.

wierl:format(AccessPoints) -> proplist()

    Decode some of the binary data values returned in the list of
    access points.

wierl_config

param(Ifname) -> Parameters
param(Ifname, Attr) -> binary() | {error, unsupported}
        | {error, posix()}
param(Socket, Ifname, Attr) -> binary() | {error, unsupported}
        | {error, posix()}

    Types   Ifname = binary()
            Socket = int()
            Attr = {Key,Value} | Key
            Key = name
                | nwid
                | freq
                | mode
                | essid
                | encode
                | range
                | ap
                | rate
                | power
            Value = binary() | integer()
            Parameters = [Parameter]
            Parameter = {name, binary()}
                | {nwid, binary()}
                | {freq, binary()}
                | {mode, binary()}
                | {essid, binary()}
                | {encode, binary()}
                | {range, binary()}
                | {ap, binary()}
                | {rate, binary()}
                | {power, binary()}

    Query or set a wireless parameter.

    param/1 lists all parameters for the interface.

    param/3 queries or sets a single parameter.

    param/2 is a wrapper around param/3 that will open and close the
    netlink socket for the caller.

    Use the wierl module to decode the values, e.g.,

        1> wierl_config:param(<<"wlan0">>, freq).
        <<108,9,0,0,6,0,0,0,0,0,0,0,0,0,0,0>>

        2> wierl:decode({freq,<<108,9,0,0,6,0,0,0,0,0,0,0,0,0,0,0>>}).
        {frequency,2.412e9}

    To set a parameter, use a key/value as the attribute, e.g.,

        1> wierl_config:param(<<"wlan0">>, {essid, <<"MY ESSID">>}).
        <<"MY ESSID">>

    Depending on the parameter, the value can be either an integer or a
    binary (which will be converted to a pointer to an iw_point struct
    and may require assigning a value to the flag field of the structure).

    To change some parameters, the interface must first be brought
    down. For example, to put the interface into monitor mode:

        wierl_config:down(<<"wlan0">>),
        wierl_config:param(<<"wlan0">>, {mode, wierl:mode(monitor)}),
        wierl_config:up(<<"wlan0">>).


up(Ifname) -> ok

    Types   Ifname = binary()

    Configure the interface as up and running.


down(Ifname) -> ok

    Types   Ifname = binary()

    Bring down the interface.


open() -> {ok, FD}

    Types   FD = integer()

    Obtain a netlink socket file descriptor.


close(FD) -> ok

    Types   FD = integer()

    Close the file descriptor.

wierl

wierl_monitor

wierl_monitor:open(Interface) ->  {ok, Socket} | {error, posix()}

    Types   Interface = binary()
            Socket = pid()
	
    Place a wireless network interface into monitor mode, returning a
    file descriptor (the pid of a gen_server holding the fd) that can
    be used for reading 802.11 frames.

wierl_monitor:close(Socket) ->  ok | {error, posix()}

    Types   Socket = pid()
            Interface = binary()

    Close the file descriptor associated with the wireless device. close/1
    leaves the device in monitor mode.

wierl_monitor:read(Socket) -> {ok, Frame} | {error, posix()}
wierl_monitor:read(Socket, Size) -> {ok, Frame} | {error, posix()}

    Types   Socket = pid()
            Size = integer()
            Frame = binary()

    Attempt to read a frame from the wireless device.

wierl_monitor:write(Socket, Frame) -> ok | {error, posix()}

    Types   Socket = pid()
            Frame = binary()

    Attempt to write a frame to the wireless device.

wierl_monitor:frame(Socket, Frame) -> {Radiotap, FrameControl,
    FrameBody, FrameCheckSequence} | {error, bad_frame}
wierl_monitor:frame(Socket, {FrameControl, FrameBody}) -> Frame

    Types   Socket = pid()
            Frame = binary()
            Radiotap = #ieee802_11_radiotap{}
            FrameControl = #ieee802_11_fc{}
            FrameBody = #ieee802_11_management{}
                | #ieee802_11_cf_rts{},
                | #ieee802_11_cf_cts{},
                | #ieee802_11_cf_ack{},
                | #ieee802_11_cf_ps{},
                | #ieee802_11_cf_cfend{},
                | #ieee802_11_cf_bar{},
                | #ieee802_11_cf_ba{},
                | #ieee802_11_data{}
            FrameCheckSequence = integer()

    Encode or decode an 802.11 wireless frame between binaries and
    records. Include the wierl_frame header to have access to the
    record structures:

        -include("include/wierl_frame.hrl")

rfkill

rfkill is a wireless soft kill switch.

-include("include/rfkill.hrl")


block() -> ok | {error, posix()}

    Disable wireless devices.

unblock() -> ok | {error, posix()}

    Enable wireless devices.

list() -> #rfkill_event{} | {error, posix()}

    Monitor rfkill device events.

TODO

  • get stats from /proc/net/wireless

  • wierl_monitor

    • sending frames
    • cleanup: redundant constants between wierl/procket
    • frame/1: allow the caller to specify the header type
  • support Mac OS X

  • wierl: support decoding

    • encode, genie, name, rate