Porting to different target boards and operating systems

wpa_supplicant was designed to be easily portable to different hardware (board, CPU) and software (OS, drivers) targets. It is already used with number of operating systems and numerous wireless card models and drivers. The main wpa_supplicant repository includes support for Linux, FreeBSD, and Windows. In addition, at least VxWorks and PalmOS are supported in separate repositories. On the hardware side, wpa_supplicant is used on various systems: desktops, laptops, PDAs, and embedded devices with CPUs including x86, PowerPC, arm/xscale, and MIPS. Both big and little endian configurations are supported.

Extra functions on top of ANSI C

wpa_supplicant is mostly using ANSI C functions that are available on most targets. However, couple of additional functions that are common on modern UNIX systems are used. Number of these are listed with prototypes in common.h (the #ifdef CONFIG_ANSI_C_EXTRA block). These functions may need to be implemented or at least defined as macros to native functions in the target OS or C library.

Driver interface

Unless the target OS and driver is already supported, most porting projects have to implement a driver wrapper. This may be done by adding a new driver interface module or modifying an existing module (driver_*.c) if the new target is similar to one of them. Driver wrapper implementation describes the details of the driver interface and discusses the tasks involved in porting this part of wpa_supplicant.

l2_packet (link layer access)

wpa_supplicant needs to have access to sending and receiving layer 2 (link layer) packets with two Ethertypes: EAP-over-LAN (EAPOL) 0x888e and RSN pre-authentication 0x88c7. l2_packet.h defines the interfaces used for this in the core wpa_supplicant implementation.

If the target operating system supports a generic mechanism for link layer access, that is likely the best mechanism for providing the needed functionality for wpa_supplicant. Linux packet socket is an example of such a generic mechanism. If this is not available, a separate interface may need to be implemented to the network stack or driver. This is usually an intermediate or protocol driver that is operating between the device driver and the OS network stack. If such a mechanism is not feasible, the interface can also be implemented directly in the device driver.

The main wpa_supplicant repository includes l2_packet implementations for Linux using packet sockets (l2_packet_linux.c), more portable version using libpcap/libdnet libraries (l2_packet_pcap.c; this supports WinPcap, too), and FreeBSD specific version of libpcap interface (l2_packet_freebsd.c).

If the target operating system is supported by libpcap (receiving) and libdnet (sending), l2_packet_pcap.c can likely be used with minimal or no changes. If this is not a case or a proprietary interface for link layer is required, a new l2_packet module may need to be added. Alternatively, struct wpa_driver_ops::send_eapol() handler can be used to override the l2_packet library if the link layer access is integrated with the driver interface implementation.

Event loop

wpa_supplicant uses a single process/thread model and an event loop to provide callbacks on events (registered timeout, received packet, signal). eloop.h defines the event loop interface. eloop.c is an implementation of such an event loop using select() and sockets. This is suitable for most UNIX/POSIX systems. When porting to other operating systems, it may be necessary to replace that implementation with OS specific mechanisms that provide similar functionality.

Control interface

wpa_supplicant uses a control interface to allow external processed to get status information and to control the operations. Currently, this is implemented with socket based communication; both UNIX domain sockets and UDP sockets are supported. If the target OS does not support sockets, this interface will likely need to be modified to use another mechanism like message queues. The control interface is optional component, so it is also possible to run wpa_supplicant without porting this part.

The wpa_supplicant side of the control interface is implemented in ctrl_iface.c. Matching client side is implemented as a control interface library in wpa_ctrl.c.

Program entry point

wpa_supplicant defines a set of functions that can be used to initialize main supplicant processing. Each operating system has a mechanism for starting new processing or threads. This is usually a function with a specific set of arguments and calling convention. This function is responsible on initializing wpa_supplicant.

main.c includes an entry point for UNIX-like operating system, i.e., main() function that uses command line arguments for setting parameters for wpa_supplicant. When porting to other operating systems, similar OS-specific entry point implementation is needed. It can be implemented in a new file that is then linked with wpa_supplicant instead of main.o. main.c is also a good example on how the initialization process should be done.

The supplicant initialization functions are defined in wpa_supplicant_i.h. In most cases, the entry point function should start by fetching configuration parameters. After this, a global wpa_supplicant context is initialized with a call to wpa_supplicant_init(). After this, existing network interfaces can be added with wpa_supplicant_add_iface(). wpa_supplicant_run() is then used to start the main event loop. Once this returns at program termination time, wpa_supplicant_deinit() is used to release global context data.

wpa_supplicant_add_iface() and wpa_supplicant_remove_iface() can be used dynamically to add and remove interfaces based on when wpa_supplicant processing is needed for them. This can be done, e.g., when hotplug network adapters are being inserted and ejected. It is also possible to do this when a network interface is being enabled/disabled if it is desirable that wpa_supplicant processing for the interface is fully enabled/disabled at the same time.

Simple build example

One way to start a porting project is to begin with a very simple build of wpa_supplicant with WPA-PSK support and once that is building correctly, start adding features.

Following command can be used to build very simple version of wpa_supplicant:

cc -o wpa_supplicant config.c eloop.c common.c md5.c rc4.c sha1.c \
	config_none.c l2_packet_none.c tls_none.c wpa.c preauth.c \
	aes_wrap.c wpa_supplicant.c events.c main_none.c drivers.c

The end result is not really very useful since it uses empty functions for configuration parsing and layer 2 packet access and does not include a driver interface. However, this is a good starting point since the build is complete in the sense that all functions are present and this is easy to configure to a build system by just including the listed C files.

Once this version can be build successfully, the end result can be made functional by adding a proper program entry point (main*.c), driver interface (driver_*.c and matching CONFIG_DRIVER_* define for registration in drivers.c), configuration parser/writer (config_*.c), and layer 2 packet access implementation (l2_packet_*.c). After these components have been added, the end result should be a working WPA/WPA2-PSK enabled supplicant.

After the basic functionality has been verified to work, more features can be added by linking in more files and defining C pre-processor defines. Currently, the best source of information for what options are available and which files needs to be included is in the Makefile used for building the supplicant with make. Similar configuration will be needed for build systems that either use different type of make tool or a GUI-based project configuration.

Generated on Sun Dec 31 13:56:00 2006 for wpa_supplicant by  doxygen 1.4.2