Develop wpa_supplicant and hostapd

The source code and read-only access to the combined wpa_supplicant and hostapd Git repository is available from the project home page at http://w1.fi/wpa_supplicant/.
This developers' documentation is also available as a PDF file from http://w1.fi/wpa_supplicant/wpa_supplicant-devel.pdf .

Here is a list of all related documentation pages.

Developers' documentation for wpa_supplicant and hostapd

1 wpa_supplicant

Supplicant is the IEEE 802.1X/WPA component that is used in the client stations.
It implements key negotiation with a WPA Authenticator and it can optionally control roaming and IEEE 802.11 authentication/association of the wlan driver.

The design goal for wpa_supplicant was to use hardware, driver, and OS independent, portable C code for all WPA functionality.

  • The source code is divided into separate C files as shown on the "1.1 code structure" page.
  • All hardware/driver specific functionality is in separate files that implement a well-defined driver API.
  • Information about porting to different target boards and operating systems is available on the porting page.
  • EAPOL (IEEE 802.1X) state machines are implemented as a separate module that interacts with EAP peer implementation.
  • wpa_supplicant source tree includes number of testing and development tools that make it easier to test the programs without having to setup a full test setup with wireless cards.
  • These tools can also be used to implement automatic test suites.
wpa_supplicant implements a control interface that can be used by external programs to control the operations of the wpa_supplicant daemon and to get status information and event notifications.
There is a small C library that provides helper functions to facilitate the use of the control interface.
This library can also be used with C++.

2 hostapd

hostapd includes:
  • IEEE 802.11 Access Point management (authentication / association)
  • IEEE 802.1X/WPA/WPA2 Authenticator,
  • EAP server
  • RADIUS authentication server functionality.
It can be build with various configuration option, e.g., a standalone AP management solution or a RADIUS authentication server with support for number of EAP methods.

3 Structure of the source code

wpa_supplicant implementation is divided into number of independent modules.
Core code includes functionality for controlling the network selection, association, and configuration.
Independent modules include:
  • WPA code (key handshake, PMKSA caching, pre-authentication)
  • EAPOL state machine
  • EAP state machine and methods
In addition, there are number of separate files for generic helper functions.

Both WPA and EAPOL/EAP state machines can be used separately in other programs than wpa_supplicant.
As an example, the included test programs eapol_test and preauth_test are using these modules.

3.1 wpa_supplicant core functionality

  • wpa_supplicant.c
  • Program initialization, main control loop
  • wpa_supplicant/main.c
  • main() for UNIX-like operating systems and MinGW (Windows); this uses command line arguments to configure wpa_supplicant
  • events.c
  • Driver event processing; wpa_supplicant_event() and related functions
  • wpa_supplicant_i.h
  • Internal definitions for wpa_supplicant core; should not be included into independent modules

3.2 Generic helper functions

wpa_supplicant uses generic helper functions, some of which are shared with with hostapd.
The following C files are currently used:
  • eloop.c and eloop.h
  • Event loop (select() loop with registerable timeouts, socket read callbacks, and signal callbacks)
  • common.c and common.h
  • Common helper functions
  • defs.h
  • Definitions shared by multiple files
  • l2_packet.h, l2_packet_linux.c, and l2_packet_pcap.c
  • Layer 2 (link) access wrapper (includes native Linux implementation and wrappers for libdnet/libpcap).
    A new l2_packet implementation may need to be added when porting to new operating systems that are not supported by libdnet/libpcap.
    Makefile can be used to select which l2_packet implementation is included.
    l2_packet_linux.c uses Linux packet sockets and l2_packet_pcap.c has a more portable version using libpcap and libdnet.
  • pcsc_funcs.c and pcsc_funcs.h
  • Wrapper for PC/SC lite SIM and smart card readers
  • priv_netlink.h
  • Private version of netlink definitions from Linux kernel header files; this could be replaced with C library header file once suitable version becomes commonly available
  • version.h
  • Version number definitions

3.3 Cryptographic functions

3.4 TLS library

3.5 Configuration

3.6 Control interface

3.7 WPA supplicant

3.8 EAP peer

3.9 EAPOL supplicant

3.10 Windows port

3.11 Test programs

4 wpa_supplicant control interface

wpa_supplicant implements a control interface that can be used by external programs to control the operations of the wpa_supplicant daemon and to get status information and event notifications.

There is a small C library, in a form of a single C file, wpa_ctrl.c, that provides helper functions to facilitate the use of the control interface.
External programs can link this file into them and then use the library functions documented in wpa_ctrl.h to interact with wpa_supplicant.
This library can also be used with C++.
wpa_cli.c and wpa_gui are example programs using this library.

There are multiple mechanisms for inter-process communication. For example, Linux version of wpa_supplicant is using UNIX domain sockets for the control interface.

Using the control interface

Control interface commands

Control interface events

wpa_supplicant generates number messages based on events like connection or a completion of a task.
These messages are available to external programs that attach to receive unsolicited messages over the control interface with wpa_ctrl_attach().

The event messages will be delivered over the attach control interface as text strings that start with the priority level of the message and a fixed prefix text as defined in wpa_ctrl.h.
After this, optional additional information may be included depending on the event message.

For example, following event message is delivered when new scan results are available:


<2>CTRL-EVENT-SCAN-RESULTS

5 wpa_supplicant D-Bus API

Every D-Bus interface implemented by wpa_supplicant is described here including their methods, signals, and properties with arguments, returned values, and possible errors.

fi.w1.wpa_supplicant1

fi.w1.wpa_supplicant1.Interface

fi.w1.wpa_supplicant1.Interface.WPS

fi.w1.wpa_supplicant1.Interface.P2PDevice

fi.w1.wpa_supplicant1.BSS

fi.w1.wpa_supplicant1.Network

fi.w1.wpa_supplicant1.Peer

fi.w1.wpa_supplicant1.Group

fi.w1.wpa_supplicant1.PersistentGroup

6 Driver wrapper implementation (driver.h, drivers.c)

All hardware and driver dependent functionality is in separate C files that implement defined wrapper functions.
Driver wrappers need to implement whatever calls are used in the target operating system/driver for controlling wireless LAN devices.

As an example, in case of Linux, these are mostly some glue code and ioctl() calls and netlink message parsing for Linux Wireless Extensions (WE). If the target driver includes full support for WE-18, in theory, it could use the same driver wrapper code.

A driver wrapper needs to implement some or all of the functions defined in driver.h.
These functions are registered by filling struct wpa_driver_ops with function pointers.

  • src/drivers/drivers.c
  • 
    const struct wpa_driver_ops *const wpa_drivers[] =
    {
    #ifdef CONFIG_DRIVER_NL80211
    	&wpa_driver_nl80211_ops,
    #endif /* CONFIG_DRIVER_NL80211 */
    #ifdef CONFIG_DRIVER_WEXT
    	&wpa_driver_wext_ops,
    #endif /* CONFIG_DRIVER_WEXT */
    ...
    	NULL
    };
    		
  • src/drivers/driver_nl80211.c
  • 
    const struct wpa_driver_ops wpa_driver_nl80211_ops = {
    	.name = "nl80211",
    	.desc = "Linux nl80211/cfg80211",
    	.get_bssid = wpa_driver_nl80211_get_bssid,
    ... 
    	.set_ap = wpa_driver_nl80211_set_ap,
    ...
    #ifdef ANDROID
    #ifndef ANDROID_LIB_STUB
    	.driver_cmd = wpa_driver_nl80211_driver_cmd,
    #endif /* !ANDROID_LIB_STUB */
    #endif /* ANDROID */
    ...
    } 
    		
Hardware independent parts of wpa_supplicant will call these functions to control the driver/wlan card.

In addition, support for driver events is required. The event callback function, wpa_supplicant_event(), and its parameters are documented in driver.h.
In addition, a pointer to the 'struct wpa_driver_ops' needs to be registered in drivers.c file.

Generic Linux Wireless Extensions functions are implemented in driver_wext.c. All Linux driver wrappers can use these when the kernel driver supports the generic ioctl()s and wireless events.
Driver specific functions are implemented in separate C files, e.g., driver_hostap.c.
These files need to define struct wpa_driver_ops entry that will be used in wpa_supplicant.c when calling driver functions.
struct wpa_driver_ops entries are registered in drivers.c.

Driver requirements for WPA

TKIP/CCMP

WPA requires that the pairwise cipher suite (encryption algorithm for unicast data packets) is TKIP or CCMP. Specification for both TKIP and CCMP is available from IEEE (IEEE 802.11i amendment).

The driver will also need to provide configuration mechanism to allow user space programs to configure TKIP and CCMP.
Linux Wireless Extensions v18 added support for configuring these algorithms and individual/non-default keys.

Roaming control and scanning support

wpa_supplicant can optionally control AP selection based on the information received from Beacon and/or Probe Response frames (ap_scan=1 mode in configuration).
wpa_supplicant needs to also be able to request the driver to associate with a specific BSS.

7 EAP peer implementation

8 EAP server implementation

9 hostapd control interface

10 Wi-Fi Direct - P2P module

11 Porting to different target boards and operating systems

12 Testing and development tools

Debug

  • src/utils/wpa_debug.h
  • 
    extern int wpa_debug_level;
    
    enum {
            MSG_EXCESSIVE, MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR
    };
    
    /**
     * wpa_printf - conditional printf
     * @level: priority level (MSG_*) of the message
     * @fmt: printf format string, followed by optional arguments
     *
     * This function is used to print conditional debugging and error messages. The
     * output may be directed to stdout, stderr, and/or syslog based on
     * configuration.
     *
     * Note: New line '\n' is added to the end of the text when printing to stdout.
     */
    void wpa_printf(int level, const char *fmt, ...)
    PRINTF_FORMAT(2, 3);
    
    void wpa_msg(void *ctx, int level, const char *fmt, ...) PRINTF_FORMAT(3, 4);
    
    
  • src/utils/wpa_debug.c
  • 
    
    int wpa_debug_level = MSG_INFO;
    
    
    
  • src/drivers/driver_nl80211.c
  • 
    const struct wpa_driver_ops wpa_driver_nl80211_ops = {
    	.name = "nl80211",
    	.desc = "Linux nl80211/cfg80211",
    	.get_bssid = wpa_driver_nl80211_get_bssid,
    ... 
    	.set_ap = wpa_driver_nl80211_set_ap,
    ...
    #ifdef ANDROID
    #ifndef ANDROID_LIB_STUB
    	.driver_cmd = wpa_driver_nl80211_driver_cmd,
    #endif /* !ANDROID_LIB_STUB */
    #endif /* ANDROID */
    ...
    }    
    
    static int wpa_driver_nl80211_set_ap(void *priv,
    				     struct wpa_driver_ap_params *params)
    {
    ...
    	wpa_printf(MSG_DEBUG, "nl80211: key_mgmt_suites=0x%x",
    		   params->key_mgmt_suites);
    	num_suites = wpa_key_mgmt_to_suites(params->key_mgmt_suites,
    					    suites, ARRAY_SIZE(suites));
    	if (num_suites > NL80211_MAX_NR_AKM_SUITES)
    		wpa_printf(MSG_DEBUG,
    			   "nl80211: Not enough room for all AKM suites (num_suites=%d > NL80211_MAX_NR_AKM_SUITES)",
    			   num_suites);
    	else if (num_suites &&
    		 nla_put(msg, NL80211_ATTR_AKM_SUITES, num_suites * sizeof(u32),
    			 suites))
    		goto fail;
    ...        
    }
    
    static void * nl80211_global_init(void *ctx)
    {
    ...
    	cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink;
    	cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink;
    	global->netlink = netlink_init(cfg); // register event handler
    ...
    	if (wpa_driver_nl80211_init_nl_global(global) < 0)
    		goto err;
    
    	global->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); // ioctl(fd,...)
    	if (global->ioctl_sock < 0) {
    		wpa_printf(MSG_ERROR, "nl80211: socket(PF_INET,SOCK_DGRAM) failed: %s",
    			   strerror(errno));
    		goto err;
    	}
    
    	return global;
    
    err:
    	nl80211_global_deinit(global);
    	return NULL;
    }
    
    
    
  • wpa_supplicant/dbus/dbus_dict_helpers.c
  • 
    /**
     * Return whether or not there are additional dictionary entries.
     *
     * @param iter_dict A valid DBusMessageIter returned from
     *    wpa_dbus_dict_open_read()
     * @return TRUE if more dict entries exists, FALSE if no more dict entries
     * exist
     */
    dbus_bool_t wpa_dbus_dict_has_dict_entry(DBusMessageIter *iter_dict)
    {
            if (!iter_dict)
                    return FALSE;
            return dbus_message_iter_get_arg_type(iter_dict) ==
                    DBUS_TYPE_DICT_ENTRY;
    }
    
    static dbus_bool_t _wpa_dbus_dict_fill_value_from_variant(
            struct wpa_dbus_dict_entry *entry, DBusMessageIter *iter)
    {
    ...
            case DBUS_TYPE_STRING:
                    dbus_message_iter_get_basic(iter, &v);
                    wpa_printf(MSG_MSGDUMP, "%s: string value: %s",
                               __func__, wpa_debug_show_keys ? v : "[omitted]");
                    entry->str_value = os_strdup(v);
                    if (entry->str_value == NULL)
                            return FALSE;
                    break;
    ...
    }
    
    
    dbus_bool_t wpa_dbus_dict_get_entry(DBusMessageIter *iter_dict,
                                        struct wpa_dbus_dict_entry * entry)
    {
    ...
            if (!_wpa_dbus_dict_fill_value_from_variant(entry, &iter_dict_val)) {
                    wpa_printf(MSG_DEBUG,
                               "%s: failed to fetch dict values from variant",
                               __func__);
                    goto error;
            }
    ...
    }
    
  • wpa_supplicant/dbus/dbus_new_handlers.c
  • 
    dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s,
                                       struct wpa_ssid *ssid,
                                       DBusMessageIter *iter,
                                       DBusError *error)
    {
     ...
            while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
     ...
     ...
                    if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
                            goto error; 
     ...
                    ret = wpa_config_set(ssid, entry.key, value, 0);
                    if (ret < 0)
                            goto error;
                    if (ret == 1)
                            goto skip_update;
     ...
    } 
    
  • src/common/defs.h
  • 
    
    .#define WPA_CIPHER_NONE BIT(0)
    #define WPA_CIPHER_WEP40 BIT(1)
    #define WPA_CIPHER_WEP104 BIT(2)
    #define WPA_CIPHER_TKIP BIT(3)
    #define WPA_CIPHER_CCMP BIT(4)
    #define WPA_CIPHER_AES_128_CMAC BIT(5)
    #define WPA_CIPHER_GCMP BIT(6)
    #define WPA_CIPHER_SMS4 BIT(7)
    #define WPA_CIPHER_GCMP_256 BIT(8)
    #define WPA_CIPHER_CCMP_256 BIT(9)
    #define WPA_CIPHER_BIP_GMAC_128 BIT(11)
    #define WPA_CIPHER_BIP_GMAC_256 BIT(12)
    #define WPA_CIPHER_BIP_CMAC_256 BIT(13)
    #define WPA_CIPHER_GTK_NOT_USED BIT(14)
    ...
    #define WPA_PROTO_WPA BIT(0)
    #define WPA_PROTO_RSN BIT(1)
    ...
    #define WPA_KEY_MGMT_IEEE8021X BIT(0)
    #define WPA_KEY_MGMT_PSK BIT(1)
    ...
    
    wpa_supplicant/config_ssid.h:
    
    ...
    #define DEFAULT_PROTO (WPA_PROTO_WPA | WPA_PROTO_RSN)
    #define DEFAULT_PAIRWISE (WPA_CIPHER_CCMP)
    #define DEFAULT_GROUP (WPA_CIPHER_CCMP | WPA_CIPHER_TKIP)
    #define DEFAULT_KEY_MGMT (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X)
    ...
    
  • wpa_supplicant/config.c
  • 
    /**
     * wpa_config_set_network_defaults - Set network default values
     * @ssid: Pointer to network configuration data
     */
    void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
    {
            ssid->proto = DEFAULT_PROTO;
            ssid->pairwise_cipher = DEFAULT_PAIRWISE;
            ssid->group_cipher = DEFAULT_GROUP;
            ssid->key_mgmt = DEFAULT_KEY_MGMT;
    ...
    
    }
    
    /**
     * wpa_config_set - Set a variable in network configuration
     * @ssid: Pointer to network configuration data
     * @var: Variable name, e.g., "ssid"
     * @value: Variable value
     * @line: Line number in configuration file or 0 if not used
     * Returns: 0 on success with possible change in the value, 1 on success with
     * no change to previously configured value, or -1 on failure
     *
     * This function can be used to set network configuration variables based on
     * both the configuration file and management interface input. The value
     * parameter must be in the same format as the text-based configuration file is
     * using. For example, strings are using double quotation marks.
     */
    int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value,
                       int line)
    {
    ...
            for (i = 0; i < NUM_SSID_FIELDS; i++) {
                    const struct parse_data *field = &ssid_fields[i];
                    if (os_strcmp(var, field->name) != 0)
                            continue;
    
                    ret = field->parser(field, ssid, line, value);
                    if (ret < 0) {
                            if (line) {
                                    wpa_printf(MSG_ERROR, "Line %d: failed to "
                                               "parse %s '%s'.", line, var, value);
                            }
                            ret = -1;
                    }
    #ifdef CONFIG_SAE
                    if (os_strcmp(var, "ssid") == 0 ||
                        os_strcmp(var, "psk") == 0 ||
                        os_strcmp(var, "sae_password") == 0 ||
                        os_strcmp(var, "sae_password_id") == 0) {
                            sae_deinit_pt(ssid->pt);
                            ssid->pt = NULL;
                    }
    #endif /* CONFIG_SAE */
                    break;
            }
    ...
    }
    
    /*
     * Table of network configuration variables. This table is used to parse each
     * network configuration variable, e.g., each line in wpa_supplicant.conf file
     * that is inside a network block.
     *
     * This table is generated using the helper macros defined above and with
     * generous help from the C pre-processor. The field name is stored as a string
     * into .name and for STR and INT types, the offset of the target buffer within
     * struct wpa_ssid is stored in .param1. .param2 (if not NULL) is similar
     * offset to the field containing the length of the configuration variable.
     * .param3 and .param4 can be used to mark the allowed range (length for STR
     * and value for INT).
     *
     * For each configuration line in wpa_supplicant.conf, the parser goes through
     * this table and select the entry that matches with the field name. The parser
     * function (.parser) is then called to parse the actual value of the field.
     *
     * This kind of mechanism makes it easy to add new configuration parameters,
     * since only one line needs to be added into this table and into the
     * struct wpa_ssid definition if the new variable is either a string or
     * integer. More complex types will need to use their own parser and writer
     * functions.
     */
    static const struct parse_data ssid_fields[] = {
            { STR_RANGE(ssid, 0, SSID_MAX_LEN) },
            { INT_RANGE(scan_ssid, 0, 1) },
            { FUNC(bssid) },
    ...
    };
    
    static int wpa_config_parse_key_mgmt(const struct parse_data *data,
                                         struct wpa_ssid *ssid, int line,
                                         const char *value)
    {
    ...
            wpa_printf(MSG_MSGDUMP, "key_mgmt: 0x%x", val);
            ssid->key_mgmt = val;
            return errors ? -1 : 0;
    }
    
    
  • wpa_supplicant/config_file.c
  • 
    static struct wpa_ssid * wpa_config_read_network(FILE *f, int *line, int id)
    {
    ...
            wpa_config_set_network_defaults(ssid);
    ...
    }
    
    struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp)
    {
    ...
            wpa_printf(MSG_DEBUG, "Reading configuration file '%s'", name);
            f = fopen(name, "r");
    
    ...
           while (wpa_config_get_line(buf, sizeof(buf), f, &line, &pos)) {
                           if (os_strcmp(pos, "network={") == 0) {
                            ssid = wpa_config_read_network(f, &line, id++);
                            if (ssid == NULL) {
                                    wpa_printf(MSG_ERROR, "Line %d: failed to "
                                               "parse network block.", line);
                                    errors++;
                                    continue;
                            }
                            if (head == NULL) {
                                    head = tail = ssid;
                            } else {
                                    tail->next = ssid;
                                    tail = ssid;
                            }
                            if (wpa_config_add_prio_network(config, ssid)) {
                                    wpa_printf(MSG_ERROR, "Line %d: failed to add "
                                               "network block to priority list.",
                                               line);
                                    errors++;
                                    continue;
                            }
                    } 
    ...
    }
    
  • wpa_supplicant/driver_i.h
  •   
    /* driver_ops */
    static inline void * wpa_drv_init(struct wpa_supplicant *wpa_s,
    				  const char *ifname)
    {
    	if (wpa_s->driver->init2)
    		return wpa_s->driver->init2(wpa_s, ifname,
    					    wpa_s->global_drv_priv);
    	if (wpa_s->driver->init) {
    		return wpa_s->driver->init(wpa_s, ifname);
    	}
    	return NULL;
    }
    ...
    static inline int wpa_drv_set_ap(struct wpa_supplicant *wpa_s,
    				 struct wpa_driver_ap_params *params)
    {
    	if (wpa_s->driver->set_ap)
    		return wpa_s->driver->set_ap(wpa_s->drv_priv, params);
    	return -1;
    }
    ...
    #ifdef ANDROID
    static inline int wpa_drv_driver_cmd(struct wpa_supplicant *wpa_s,
    				     char *cmd, char *buf, size_t buf_len)
    {
    	if (!wpa_s->driver->driver_cmd)
    		return -1;
    	return wpa_s->driver->driver_cmd(wpa_s->drv_priv, cmd, buf, buf_len);
    }
    #endif /* ANDROID */
    ...
    	
  • wpa_supplicant/ctrl_iface.c
  •  
    #ifdef ANDROID
    static int wpa_supplicant_driver_cmd(struct wpa_supplicant *wpa_s, char *cmd,
                                         char *buf, size_t buflen)
    {
            int ret;
    
            ret = wpa_drv_driver_cmd(wpa_s, cmd, buf, buflen);
            if (ret == 0) {
                    if (os_strncasecmp(cmd, "COUNTRY", 7) == 0) {
                            struct p2p_data *p2p = wpa_s->global->p2p;
                            if (p2p) {
                                    char country[3];
                                    country[0] = cmd[8];
                                    country[1] = cmd[9];
                                    country[2] = 0x04;
                                    p2p_set_country(p2p, country);
                            }
                    }
                    ret = os_snprintf(buf, buflen, "%s\n", "OK");
                    if (os_snprintf_error(buflen, ret))
                            ret = -1;
            }
            return ret;
    }
    #endif /* ANDROID */
    
    
    
    char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                                             char *buf, size_t *resp_len)
    {
    ...
            os_memcpy(reply, "OK\n", 3);
            reply_len = 3;
    
            if (os_strcmp(buf, "PING") == 0) {
                    os_memcpy(reply, "PONG\n", 5);
                    reply_len = 5;
    ...
    #ifdef ANDROID
            } else if (os_strncmp(buf, "DRIVER ", 7) == 0) {
                    reply_len = wpa_supplicant_driver_cmd(wpa_s, buf + 7, reply,
                                                          reply_size);
    #endif /* ANDROID */
            }
    ...
            *resp_len = reply_len;
            return reply;
    }    
        
  • wpa_supplicant/wpa_supplicant.c
  • 
    static int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s,
    				     const char *name)
    {
    ...
    				/* First driver that succeeds wins */
    				if (select_driver(wpa_s, i) == 0)
    ...
    }
    static int wpas_init_driver(struct wpa_supplicant *wpa_s,
    			    const struct wpa_interface *iface)
    {
    ...
    	if (wpa_supplicant_set_driver(wpa_s, driver) < 0)
    		return -1;
    
    	wpa_s->drv_priv = wpa_drv_init(wpa_s, wpa_s->ifname);
    ...
    }
    
    int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
    {
    ...
            conf = wpa_config_read(wpa_s->confname, NULL);
    ...
    
    }
    static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
                                         const struct wpa_interface *iface)
    {
    ...
            if (iface->confname) {
    ...
                    wpa_s->conf = wpa_config_read(wpa_s->confname, NULL);
    ...
    }
    
    struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
                                                     struct wpa_interface *iface,
                                                     struct wpa_supplicant *parent)
    {
    ...
    
    ...                
            if (global->params.override_driver) {
                    wpa_printf(MSG_DEBUG, "Override interface parameter: driver "
                               "('%s' -> '%s')",
                               iface->driver, global->params.override_driver);
                    t_iface.driver = global->params.override_driver;
            }
            if (global->params.override_ctrl_interface) {
                    wpa_printf(MSG_DEBUG, "Override interface parameter: "
                               "ctrl_interface ('%s' -> '%s')",
                               iface->ctrl_interface,
                               global->params.override_ctrl_interface);
                    t_iface.ctrl_interface =
                            global->params.override_ctrl_interface;
            }
            if (wpa_supplicant_init_iface(wpa_s, &t_iface)) {
                    wpa_printf(MSG_DEBUG, "Failed to add interface %s",
                               iface->ifname);
                    wpa_supplicant_deinit_iface(wpa_s, 0, 0);
                    return NULL;
            }
    ...
            wpa_dbg(wpa_s, MSG_DEBUG, "Added interface %s", wpa_s->ifname);
            wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
    ...
    }
    
    /**
     * wpa_supplicant_init - Initialize %wpa_supplicant
     * @params: Parameters for %wpa_supplicant
     * Returns: Pointer to global %wpa_supplicant data, or %NULL on failure
     *
     * This function is used to initialize %wpa_supplicant. After successful
     * initialization, the returned data pointer can be used to add and remove
     * network interfaces, and eventually, to deinitialize %wpa_supplicant.
     */
    struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
    {
    ...
            if (params == NULL)
                    return NULL;
    ...
    	for (i = 0; wpa_drivers[i]; i++)
    		global->drv_count++;
    ...
    }
    
    int wpa_supplicant_run(struct wpa_global *global)
    {
    ...
    	eloop_run();
    
    	return 0;
    }
    
  • wpa_supplicant/main.c
  • 
    int main(int argc, char *argv[])
    {
    ...
            global = wpa_supplicant_init(&params);
            if (global == NULL) {
                    wpa_printf(MSG_ERROR, "Failed to initialize wpa_supplicant");
                    exitcode = -1;
                    goto out;
            } else {
                    wpa_printf(MSG_INFO, "Successfully initialized "
                               "wpa_supplicant");
            }
    ...
    		wpa_s = wpa_supplicant_add_iface(global, &ifaces[i], NULL);
    ...
    		exitcode = wpa_supplicant_run(global);
    ...
    	return exitcode;
    }
    

Build

Building and installing

-----------------------

In order to be able to build wpa_supplicant, you will first need to
select which parts of it will be included. This is done by creating a
build time configuration file, .config, in the wpa_supplicant root
directory.

After you have created a configuration file, you can build
wpa_supplicant and wpa_cli with 'make' command. You may then install
the binaries to a suitable system directory, e.g., /usr/local/bin.

Example commands:

# build wpa_supplicant and wpa_cli
make
# install binaries (this may need root privileges)
cp wpa_cli wpa_supplicant /usr/local/bin

Build via Ubuntu package

Getting the Target Source then Build the Package

  1. Use one of the following to download the source:
    • downloads the version of the source that is available on your current system
    • 
      $ apt-get source wpa
      			
    • specify a version or Ubuntu release to be downloaded
    • 
      $ pull-lp-source wpa focal  
      			
  2. Install the build-essential package and all the needed dependencies:
  3. 
    $ cd wpa/wpa-2.9
    $ sudo apt-get build-dep wpa
    
  4. Rebuild without changes:
  5. 
    $ debuild -b -uc -us    
        

留言

熱門文章