Make deauthentication and disassociation consistent
[wpasupplicant] / wpa_supplicant / wpa_supplicant.c
index ffe6729..f730bcf 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant
- * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
 #include "eap_peer/eap.h"
 #include "wpa.h"
 #include "eloop.h"
-#include "drivers/driver.h"
 #include "config.h"
 #include "l2_packet/l2_packet.h"
 #include "wpa_supplicant_i.h"
+#include "driver_i.h"
 #include "ctrl_iface.h"
 #include "ctrl_iface_dbus.h"
 #include "pcsc_funcs.h"
 #include "ieee802_11_defs.h"
 #include "blacklist.h"
 #include "wpas_glue.h"
-#include "wps/wps.h"
 #include "wps_supplicant.h"
+#include "ibss_rsn.h"
+#include "sme.h"
+#include "ap.h"
 
 const char *wpa_supplicant_version =
 "wpa_supplicant v" VERSION_STR "\n"
-"Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi> and contributors";
 
 const char *wpa_supplicant_license =
 "This program is free software. You can distribute it and/or modify it\n"
@@ -109,11 +111,10 @@ const char *wpa_supplicant_full_license5 =
 "\n";
 #endif /* CONFIG_NO_STDOUT_DEBUG */
 
-extern struct wpa_driver_ops *wpa_supplicant_drivers[];
-
 extern int wpa_debug_level;
 extern int wpa_debug_show_keys;
 extern int wpa_debug_timestamp;
+extern struct wpa_driver_ops *wpa_drivers[];
 
 /* Configure default/group WEP keys for static WEP */
 static int wpa_set_wep_keys(struct wpa_supplicant *wpa_s,
@@ -214,7 +215,7 @@ void wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s,
                                     int sec, int usec)
 {
        if (wpa_s->conf && wpa_s->conf->ap_scan == 0 &&
-           wpa_s->driver && IS_WIRED(wpa_s->driver))
+           (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED))
                return;
 
        wpa_msg(wpa_s, MSG_DEBUG, "Setting authentication timeout: %d sec "
@@ -253,10 +254,24 @@ void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s)
        struct eapol_config eapol_conf;
        struct wpa_ssid *ssid = wpa_s->current_ssid;
 
-       if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
-               eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
+#ifdef CONFIG_IBSS_RSN
+       if (ssid->mode == IEEE80211_MODE_IBSS &&
+           wpa_s->key_mgmt != WPA_KEY_MGMT_NONE &&
+           wpa_s->key_mgmt != WPA_KEY_MGMT_WPA_NONE) {
+               /*
+                * RSN IBSS authentication is per-STA and we can disable the
+                * per-BSSID EAPOL authentication.
+                */
+               eapol_sm_notify_portControl(wpa_s->eapol, ForceAuthorized);
+               eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
                eapol_sm_notify_eap_fail(wpa_s->eapol, FALSE);
+               return;
        }
+#endif /* CONFIG_IBSS_RSN */
+
+       eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
+       eapol_sm_notify_eap_fail(wpa_s->eapol, FALSE);
+
        if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
            wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE)
                eapol_sm_notify_portControl(wpa_s->eapol, ForceAuthorized);
@@ -275,9 +290,8 @@ void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s)
                                EAPOL_REQUIRE_KEY_BROADCAST;
                }
 
-               if (wpa_s->conf && wpa_s->driver && IS_WIRED(wpa_s->driver)) {
+               if (wpa_s->conf && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED))
                        eapol_conf.required_keys = 0;
-               }
        }
        if (wpa_s->conf)
                eapol_conf.fast_reauth = wpa_s->conf->fast_reauth;
@@ -389,6 +403,21 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
        ieee80211_sta_deinit(wpa_s);
 
        wpas_wps_deinit(wpa_s);
+
+#ifdef CONFIG_IBSS_RSN
+       ibss_rsn_deinit(wpa_s->ibss_rsn);
+       wpa_s->ibss_rsn = NULL;
+#endif /* CONFIG_IBSS_RSN */
+
+#ifdef CONFIG_SME
+       os_free(wpa_s->sme.ft_ies);
+       wpa_s->sme.ft_ies = NULL;
+       wpa_s->sme.ft_ies_len = 0;
+#endif /* CONFIG_SME */
+
+#ifdef CONFIG_AP
+       wpa_supplicant_ap_deinit(wpa_s);
+#endif /* CONFIG_AP */
 }
 
 
@@ -449,6 +478,8 @@ const char * wpa_supplicant_state_txt(int state)
                return "INACTIVE";
        case WPA_SCANNING:
                return "SCANNING";
+       case WPA_AUTHENTICATING:
+               return "AUTHENTICATING";
        case WPA_ASSOCIATING:
                return "ASSOCIATING";
        case WPA_ASSOCIATED:
@@ -915,6 +946,26 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
        struct wpa_driver_capa capa;
        int assoc_failed = 0;
 
+       if (ssid->mode == 2) {
+#ifdef CONFIG_AP
+               if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_AP)) {
+                       wpa_printf(MSG_INFO, "Driver does not support AP "
+                                  "mode");
+                       return;
+               }
+               wpa_supplicant_create_ap(wpa_s, ssid);
+#else /* CONFIG_AP */
+               wpa_printf(MSG_ERROR, "AP mode support not included in the "
+                          "build");
+#endif /* CONFIG_AP */
+               return;
+       }
+
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) {
+               sme_authenticate(wpa_s, bss, ssid);
+               return;
+       }
+
        wpa_s->reassociate = 0;
        if (bss) {
 #ifdef CONFIG_IEEE80211R
@@ -936,6 +987,17 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                        wpa_ft_prepare_auth_request(wpa_s->wpa);
                }
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_WPS
+       } else if ((ssid->ssid == NULL || ssid->ssid_len == 0) &&
+                  wpa_s->conf->ap_scan == 2 &&
+                  (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
+               /* Use ap_scan==1 style network selection to find the network
+                */
+               wpa_s->scan_req = 2;
+               wpa_s->reassociate = 1;
+               wpa_supplicant_req_scan(wpa_s, 0, 0);
+               return;
+#endif /* CONFIG_WPS */
        } else {
                wpa_msg(wpa_s, MSG_INFO, "Trying to associate with SSID '%s'",
                        wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
@@ -1012,11 +1074,13 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                }
 #ifdef CONFIG_WPS
        } else if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
-               struct wpabuf *wps_ie = wps_build_assoc_req_ie();
+               struct wpabuf *wps_ie;
+               wps_ie = wps_build_assoc_req_ie(wpas_wps_get_req_type(ssid));
                if (wps_ie && wpabuf_len(wps_ie) <= sizeof(wpa_ie)) {
                        wpa_ie_len = wpabuf_len(wps_ie);
                        os_memcpy(wpa_ie, wpabuf_head(wps_ie), wpa_ie_len);
-               }
+               } else
+                       wpa_ie_len = 0;
                wpabuf_free(wps_ie);
                wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
 #endif /* CONFIG_WPS */
@@ -1091,7 +1155,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
        }
        params.wep_tx_keyidx = ssid->wep_tx_keyidx;
 
-       if (wpa_s->driver_4way_handshake &&
+       if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) &&
            (params.key_mgmt_suite == KEY_MGMT_PSK ||
             params.key_mgmt_suite == KEY_MGMT_FT_PSK)) {
                params.passphrase = ssid->passphrase;
@@ -1099,6 +1163,8 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                        params.psk = ssid->psk;
        }
 
+       params.drop_unencrypted = use_crypt;
+
 #ifdef CONFIG_IEEE80211W
        switch (ssid->ieee80211w) {
        case NO_IEEE80211W:
@@ -1111,9 +1177,21 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                params.mgmt_frame_protection = MGMT_FRAME_PROTECTION_REQUIRED;
                break;
        }
+       if (ssid->ieee80211w != NO_IEEE80211W && bss) {
+               const u8 *rsn = wpa_scan_get_ie(bss, WLAN_EID_RSN);
+               struct wpa_ie_data ie;
+               if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie) == 0 &&
+                   ie.capabilities &
+                   (WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR)) {
+                       wpa_printf(MSG_DEBUG, "WPA: Selected AP supports MFP: "
+                                  "require MFP");
+                       params.mgmt_frame_protection =
+                               MGMT_FRAME_PROTECTION_REQUIRED;
+               }
+       }
 #endif /* CONFIG_IEEE80211W */
 
-       if (wpa_s->use_client_mlme)
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
                ret = ieee80211_sta_associate(wpa_s, &params);
        else
                ret = wpa_drv_associate(wpa_s, &params);
@@ -1133,6 +1211,18 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                 * management. */
                wpa_supplicant_cancel_auth_timeout(wpa_s);
                wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+#ifdef CONFIG_IBSS_RSN
+       } else if (ssid->mode == IEEE80211_MODE_IBSS &&
+                  wpa_s->key_mgmt != WPA_KEY_MGMT_NONE &&
+                  wpa_s->key_mgmt != WPA_KEY_MGMT_WPA_NONE) {
+               ibss_rsn_set_psk(wpa_s->ibss_rsn, ssid->psk);
+               /*
+                * RSN IBSS authentication is per-STA and we can disable the
+                * per-BSSID authentication.
+                */
+               wpa_supplicant_cancel_auth_timeout(wpa_s);
+               wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+#endif /* CONFIG_IBSS_RSN */
        } else {
                /* Timeout for IEEE 802.11 authentication and association */
                int timeout = 60;
@@ -1179,7 +1269,7 @@ void wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s,
 {
        u8 *addr = NULL;
        if (!is_zero_ether_addr(wpa_s->bssid)) {
-               if (wpa_s->use_client_mlme)
+               if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
                        ieee80211_sta_disassociate(wpa_s, reason_code);
                else
                        wpa_drv_disassociate(wpa_s, wpa_s->bssid, reason_code);
@@ -1198,16 +1288,15 @@ void wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s,
  * @wpa_s: Pointer to wpa_supplicant data
  * @reason_code: IEEE 802.11 reason code for the deauthenticate frame
  *
- * This function is used to request %wpa_supplicant to disassociate with the
+ * This function is used to request %wpa_supplicant to deauthenticate from the
  * current AP.
  */
 void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
                                   int reason_code)
 {
        u8 *addr = NULL;
-       wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
        if (!is_zero_ether_addr(wpa_s->bssid)) {
-               if (wpa_s->use_client_mlme)
+               if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
                        ieee80211_sta_deauthenticate(wpa_s, reason_code);
                else
                        wpa_drv_deauthenticate(wpa_s, wpa_s->bssid,
@@ -1215,11 +1304,10 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
                addr = wpa_s->bssid;
        }
        wpa_clear_keys(wpa_s, addr);
+       wpa_supplicant_mark_disassoc(wpa_s);
        wpa_s->current_ssid = NULL;
        wpa_sm_set_config(wpa_s->wpa, NULL);
        eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
-       eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
-       eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
 }
 
 
@@ -1343,7 +1431,7 @@ int wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s)
 {
        int ret;
 
-       if (wpa_s->use_client_mlme) {
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) {
                wpa_scan_results_free(wpa_s->scan_res);
                wpa_s->scan_res = ieee80211_sta_get_scan_results(wpa_s);
                if (wpa_s->scan_res == NULL) {
@@ -1384,7 +1472,7 @@ struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s)
        u8 bssid[ETH_ALEN];
        int wired;
 
-       if (wpa_s->use_client_mlme) {
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) {
                if (ieee80211_sta_get_ssid(wpa_s, ssid, &ssid_len)) {
                        wpa_printf(MSG_WARNING, "Could not read SSID from "
                                   "MLME.");
@@ -1400,15 +1488,15 @@ struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s)
                ssid_len = res;
        }
 
-       if (wpa_s->use_client_mlme)
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
                os_memcpy(bssid, wpa_s->bssid, ETH_ALEN);
        else if (wpa_drv_get_bssid(wpa_s, bssid) < 0) {
                wpa_printf(MSG_WARNING, "Could not read BSSID from driver.");
                return NULL;
        }
 
-       wired = wpa_s->conf->ap_scan == 0 && wpa_s->driver &&
-               IS_WIRED(wpa_s->driver);
+       wired = wpa_s->conf->ap_scan == 0 &&
+               (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED);
 
        entry = wpa_s->conf->ssid;
        while (entry) {
@@ -1418,6 +1506,14 @@ struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s)
                    (!entry->bssid_set ||
                     os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0))
                        return entry;
+#ifdef CONFIG_WPS
+               if (!entry->disabled &&
+                   (entry->key_mgmt & WPA_KEY_MGMT_WPS) &&
+                   (entry->ssid == NULL || entry->ssid_len == 0) &&
+                   (!entry->bssid_set ||
+                    os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0))
+                       return entry;
+#endif /* CONFIG_WPS */
                entry = entry->next;
        }
 
@@ -1429,11 +1525,13 @@ static int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s,
                                     const char *name)
 {
        int i;
+       size_t len;
+       const char *pos;
 
        if (wpa_s == NULL)
                return -1;
 
-       if (wpa_supplicant_drivers[0] == NULL) {
+       if (wpa_drivers[0] == NULL) {
                wpa_printf(MSG_ERROR, "No driver interfaces build into "
                           "wpa_supplicant.");
                return -1;
@@ -1441,18 +1539,25 @@ static int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s,
 
        if (name == NULL) {
                /* default to first driver in the list */
-               wpa_s->driver = wpa_supplicant_drivers[0];
+               wpa_s->driver = wpa_drivers[0];
                return 0;
        }
 
-       for (i = 0; wpa_supplicant_drivers[i]; i++) {
-               if (os_strcmp(name, wpa_supplicant_drivers[i]->name) == 0) {
-                       wpa_s->driver = wpa_supplicant_drivers[i];
+       pos = os_strchr(name, ',');
+       if (pos)
+               len = pos - name;
+       else
+               len = os_strlen(name);
+       for (i = 0; wpa_drivers[i]; i++) {
+               if (os_strlen(wpa_drivers[i]->name) == len &&
+                   os_strncmp(name, wpa_drivers[i]->name, len) ==
+                   0) {
+                       wpa_s->driver = wpa_drivers[i];
                        return 0;
                }
        }
 
-       wpa_printf(MSG_ERROR, "Unsupported driver '%s'.\n", name);
+       wpa_printf(MSG_ERROR, "Unsupported driver '%s'.", name);
        return -1;
 }
 
@@ -1472,14 +1577,15 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
        }
 
        if (wpa_s->eapol_received == 0 &&
-           (!wpa_s->driver_4way_handshake ||
+           (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) ||
             !wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
             wpa_s->wpa_state != WPA_COMPLETED)) {
                /* Timeout for completing IEEE 802.1X and WPA authentication */
                wpa_supplicant_req_auth_timeout(
                        wpa_s,
                        (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
-                        wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) ?
+                        wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA ||
+                        wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) ?
                        70 : 10, 0);
        }
        wpa_s->eapol_received++;
@@ -1490,6 +1596,14 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
                return;
        }
 
+#ifdef CONFIG_IBSS_RSN
+       if (wpa_s->current_ssid &&
+           wpa_s->current_ssid->mode == IEEE80211_MODE_IBSS) {
+               ibss_rsn_rx_eapol(wpa_s->ibss_rsn, src_addr, buf, len);
+               return;
+       }
+#endif /* CONFIG_IBSS_RSN */
+
        /* Source address of the incoming EAPOL frame could be compared to the
         * current BSSID. However, it is possible that a centralized
         * Authenticator could be using another MAC address than the BSSID of
@@ -1501,7 +1615,7 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
            eapol_sm_rx_eapol(wpa_s->eapol, src_addr, buf, len) > 0)
                return;
        wpa_drv_poll(wpa_s);
-       if (!wpa_s->driver_4way_handshake)
+       if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
                wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len);
        else if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
                /*
@@ -1515,13 +1629,6 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
 }
 
 
-void wpa_supplicant_sta_free_hw_features(struct wpa_hw_modes *hw_features,
-                                        size_t num_hw_features)
-{
-       ieee80211_sta_free_hw_features(hw_features, num_hw_features);
-}
-
-
 void wpa_supplicant_sta_rx(void *ctx, const u8 *buf, size_t len,
                           struct ieee80211_rx_status *rx_status)
 {
@@ -1608,7 +1715,7 @@ int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s)
        wpa_printf(MSG_DEBUG, "RSN: flushing PMKID list in the driver");
        wpa_drv_flush_pmkid(wpa_s);
 
-       wpa_s->prev_scan_ssid = BROADCAST_SSID_SCAN;
+       wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
        wpa_supplicant_req_scan(wpa_s, interface_count, 100000);
        interface_count++;
 
@@ -1639,6 +1746,9 @@ static struct wpa_supplicant * wpa_supplicant_alloc(void)
 static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
                                     struct wpa_interface *iface)
 {
+       const char *ifname, *driver;
+       struct wpa_driver_capa capa;
+
        wpa_printf(MSG_DEBUG, "Initializing interface '%s' conf '%s' driver "
                   "'%s' ctrl_interface '%s' bridge '%s'", iface->ifname,
                   iface->confname ? iface->confname : "N/A",
@@ -1646,10 +1756,6 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
                   iface->ctrl_interface ? iface->ctrl_interface : "N/A",
                   iface->bridge_ifname ? iface->bridge_ifname : "N/A");
 
-       if (wpa_supplicant_set_driver(wpa_s, iface->driver) < 0) {
-               return -1;
-       }
-
        if (iface->confname) {
 #ifdef CONFIG_BACKEND_FILE
                wpa_s->confname = os_rel2abs_path(iface->confname);
@@ -1717,18 +1823,6 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
                           sizeof(wpa_s->bridge_ifname));
        }
 
-       return 0;
-}
-
-
-static int wpa_supplicant_init_iface2(struct wpa_supplicant *wpa_s)
-{
-       const char *ifname;
-       struct wpa_driver_capa capa;
-
-       wpa_printf(MSG_DEBUG, "Initializing interface (2) '%s'",
-                  wpa_s->ifname);
-
        /* RSNA Supplicant Key Management - INITIALIZE */
        eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
        eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
@@ -1737,8 +1831,21 @@ static int wpa_supplicant_init_iface2(struct wpa_supplicant *wpa_s)
         * L2 receive handler so that association events are processed before
         * EAPOL-Key packets if both become available for the same select()
         * call. */
+       driver = iface->driver;
+next_driver:
+       if (wpa_supplicant_set_driver(wpa_s, driver) < 0)
+               return -1;
+
        wpa_s->drv_priv = wpa_drv_init(wpa_s, wpa_s->ifname);
        if (wpa_s->drv_priv == NULL) {
+               const char *pos;
+               pos = os_strchr(driver, ',');
+               if (pos) {
+                       wpa_printf(MSG_DEBUG, "Failed to initialize driver "
+                                  "interface - try next driver wrapper");
+                       driver = pos + 1;
+                       goto next_driver;
+               }
                wpa_printf(MSG_ERROR, "Failed to initialize driver interface");
                return -1;
        }
@@ -1790,6 +1897,12 @@ static int wpa_supplicant_init_iface2(struct wpa_supplicant *wpa_s)
        if (wpa_supplicant_driver_init(wpa_s) < 0)
                return -1;
 
+       if (wpa_s->conf->country[0] && wpa_s->conf->country[1] &&
+           wpa_drv_set_country(wpa_s, wpa_s->conf->country)) {
+               wpa_printf(MSG_DEBUG, "Failed to set country");
+               return -1;
+       }
+
        wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
 
        if (wpas_wps_init(wpa_s))
@@ -1814,14 +1927,21 @@ static int wpa_supplicant_init_iface2(struct wpa_supplicant *wpa_s)
        }
 
        if (wpa_drv_get_capa(wpa_s, &capa) == 0) {
+               wpa_s->drv_flags = capa.flags;
                if (capa.flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) {
-                       wpa_s->use_client_mlme = 1;
                        if (ieee80211_sta_init(wpa_s))
                                return -1;
                }
-               if (capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE)
-                       wpa_s->driver_4way_handshake = 1;
+               wpa_s->max_scan_ssids = capa.max_scan_ssids;
+       }
+
+#ifdef CONFIG_IBSS_RSN
+       wpa_s->ibss_rsn = ibss_rsn_init(wpa_s);
+       if (!wpa_s->ibss_rsn) {
+               wpa_printf(MSG_DEBUG, "Failed to init IBSS RSN");
+               return -1;
        }
+#endif /* CONFIG_IBSS_RSN */
 
        return 0;
 }
@@ -1879,8 +1999,7 @@ struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
        if (wpa_s == NULL)
                return NULL;
 
-       if (wpa_supplicant_init_iface(wpa_s, iface) ||
-           wpa_supplicant_init_iface2(wpa_s)) {
+       if (wpa_supplicant_init_iface(wpa_s, iface)) {
                wpa_printf(MSG_DEBUG, "Failed to add interface %s",
                           iface->ifname);
                wpa_supplicant_deinit_iface(wpa_s);
@@ -1974,12 +2093,14 @@ struct wpa_supplicant * wpa_supplicant_get_iface(struct wpa_global *global,
 struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
 {
        struct wpa_global *global;
-       int ret;
+       int ret, i;
 
        if (params == NULL)
                return NULL;
 
        wpa_debug_open_file(params->wpa_debug_file_path);
+       if (params->wpa_debug_syslog)
+               wpa_debug_open_syslog();
 
        ret = eap_peer_register_methods();
        if (ret) {
@@ -2029,6 +2150,30 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
                }
        }
 
+       for (i = 0; wpa_drivers[i]; i++)
+               global->drv_count++;
+       if (global->drv_count == 0) {
+               wpa_printf(MSG_ERROR, "No drivers enabled");
+               wpa_supplicant_deinit(global);
+               return NULL;
+       }
+       global->drv_priv = os_zalloc(global->drv_count * sizeof(void *));
+       if (global->drv_priv == NULL) {
+               wpa_supplicant_deinit(global);
+               return NULL;
+       }
+       for (i = 0; wpa_drivers[i]; i++) {
+               if (!wpa_drivers[i]->global_init)
+                       continue;
+               global->drv_priv[i] = wpa_drivers[i]->global_init();
+               if (global->drv_priv[i] == NULL) {
+                       wpa_printf(MSG_ERROR, "Failed to initialize driver "
+                                  "'%s'", wpa_drivers[i]->name);
+                       wpa_supplicant_deinit(global);
+                       return NULL;
+               }
+       }
+
        return global;
 }
 
@@ -2075,6 +2220,8 @@ int wpa_supplicant_run(struct wpa_global *global)
  */
 void wpa_supplicant_deinit(struct wpa_global *global)
 {
+       int i;
+
        if (global == NULL)
                return;
 
@@ -2088,6 +2235,13 @@ void wpa_supplicant_deinit(struct wpa_global *global)
 
        eap_peer_unregister_methods();
 
+       for (i = 0; wpa_drivers[i] && global->drv_priv; i++) {
+               if (!global->drv_priv[i])
+                       continue;
+               wpa_drivers[i]->global_deinit(global->drv_priv[i]);
+       }
+       os_free(global->drv_priv);
+
        eloop_destroy();
 
        if (global->params.pid_file) {
@@ -2097,5 +2251,6 @@ void wpa_supplicant_deinit(struct wpa_global *global)
        os_free(global->params.ctrl_interface);
 
        os_free(global);
+       wpa_debug_close_syslog();
        wpa_debug_close_file();
 }