Pages

Monday, March 7, 2011

Scanning for Wireless Access Points with Erlang

The Linux wireless LAN network interface (802.11) uses a socket/ioctl
interface to communicate with the kernel. I am going to go over building
an Erlang interface for initiating scanning and retrieving the scan
results.

The Scanning Process

The scan process works as follows:

Open a datagram socket

Allocate a iwreq structure. The structure contains the device name
used for scanning and a pointer to an optional user allocated buffer
containing an ESSID. According to the man page, specifying an ESSID with
some drivers allows hidden networks to be found.

Call an ioctl on the socket with the request set to SIOCSIWSCAN (0x8B18).

Allocate another iwreq structure containing a pointer to a user
allocated buffer with enough space to hold the response.

Call a second ioctl on the socket with the request set to SIOCGIWSCAN (0x8B19)

When the ioctl returns successfully, both the iwreq structure and the
user allocated buffer are updated. The iwreq structure contains the actual
size of the data held in the buffer and the buffer holds the set of events.

Some of the data may be larger than can be held in the union. The iw_point structure, for example, contains a pointer to user allocated memory that can be used to hold either arguments to be read by the kernel or data returned by the kernel.

The SIOCSIWSCAN ioctl

To initiate the scan, we call an ioctl on a socket file descriptor. Any socket type can be used. The structure we pass to ioctl contains the interface name. For example, to scan using the default ESSID:

the iwreq structure will be updated to hold the actual size of the data in our buffer

our buffer will hold the scan list

An Erlang Approach to Pointers and ioctl()'s: Resources

To make system calls that aren't supported by the Erlang VM, we will need to integrate a small amount of C code using Erlang's NIF interface. The procket library on GitHub was made to perform some low level operations on sockets. I've added some additional functions to deal with versions of ioctl() using input/output fields containing pointers to memory: