Include peer certificate always in EAP events
[mech_eap.git] / wpa_supplicant / wpas_glue.c
index 0dca0e6..8029ae5 100644 (file)
@@ -26,6 +26,7 @@
 #include "bss.h"
 #include "scan.h"
 #include "notify.h"
+#include "wpas_kay.h"
 
 
 #ifndef CONFIG_NO_CONFIG_BLOBS
@@ -95,11 +96,26 @@ static u8 * wpa_alloc_eapol(const struct wpa_supplicant *wpa_s, u8 type,
 static int wpa_ether_send(struct wpa_supplicant *wpa_s, const u8 *dest,
                          u16 proto, const u8 *buf, size_t len)
 {
+#ifdef CONFIG_TESTING_OPTIONS
+       if (wpa_s->ext_eapol_frame_io && proto == ETH_P_EAPOL) {
+               size_t hex_len = 2 * len + 1;
+               char *hex = os_malloc(hex_len);
+
+               if (hex == NULL)
+                       return -1;
+               wpa_snprintf_hex(hex, hex_len, buf, len);
+               wpa_msg(wpa_s, MSG_INFO, "EAPOL-TX " MACSTR " %s",
+                       MAC2STR(dest), hex);
+               os_free(hex);
+               return 0;
+       }
+#endif /* CONFIG_TESTING_OPTIONS */
+
        if (wpa_s->l2) {
                return l2_packet_send(wpa_s->l2, dest, proto, buf, len);
        }
 
-       return wpa_drv_send_eapol(wpa_s, dest, proto, buf, len);
+       return -1;
 }
 #endif /* IEEE8021X_EAPOL || !CONFIG_NO_WPA */
 
@@ -141,11 +157,29 @@ static int wpa_supplicant_eapol_send(void *ctx, int type, const u8 *buf,
 
        if (pmksa_cache_get_current(wpa_s->wpa) &&
            type == IEEE802_1X_TYPE_EAPOL_START) {
-               /* Trying to use PMKSA caching - do not send EAPOL-Start frames
-                * since they will trigger full EAPOL authentication. */
-               wpa_printf(MSG_DEBUG, "RSN: PMKSA caching - do not send "
-                          "EAPOL-Start");
-               return -1;
+               /*
+                * We were trying to use PMKSA caching and sending EAPOL-Start
+                * would abort that and trigger full EAPOL authentication.
+                * However, we've already waited for the AP/Authenticator to
+                * start 4-way handshake or EAP authentication, and apparently
+                * it has not done so since the startWhen timer has reached zero
+                * to get the state machine sending EAPOL-Start. This is not
+                * really supposed to happen, but an interoperability issue with
+                * a deployed AP has been identified where the connection fails
+                * due to that AP failing to operate correctly if PMKID is
+                * included in the Association Request frame. To work around
+                * this, assume PMKSA caching failed and try to initiate full
+                * EAP authentication.
+                */
+               if (!wpa_s->current_ssid ||
+                   wpa_s->current_ssid->eap_workaround) {
+                       wpa_printf(MSG_DEBUG,
+                                  "RSN: Timeout on waiting for the AP to initiate 4-way handshake for PMKSA caching or EAP authentication - try to force it to start EAP authentication");
+               } else {
+                       wpa_printf(MSG_DEBUG,
+                                  "RSN: PMKSA caching - do not send EAPOL-Start");
+                       return -1;
+               }
        }
 
        if (is_zero_ether_addr(wpa_s->bssid)) {
@@ -254,6 +288,8 @@ static void wpa_supplicant_eapol_cb(struct eapol_sm *eapol,
                 * authentication failure.
                 */
                wpa_supplicant_req_auth_timeout(wpa_s, 2, 0);
+       } else {
+               ieee802_1x_notify_create_actor(wpa_s, wpa_s->last_eapol_src);
        }
 
        if (result != EAPOL_SUPP_RESULT_SUCCESS ||
@@ -507,7 +543,44 @@ static int wpa_supplicant_send_ft_action(void *ctx, u8 action,
                                         const u8 *ies, size_t ies_len)
 {
        struct wpa_supplicant *wpa_s = ctx;
-       return wpa_drv_send_ft_action(wpa_s, action, target_ap, ies, ies_len);
+       int ret;
+       u8 *data, *pos;
+       size_t data_len;
+
+       if (action != 1) {
+               wpa_printf(MSG_ERROR, "Unsupported send_ft_action action %d",
+                          action);
+               return -1;
+       }
+
+       /*
+        * Action frame payload:
+        * Category[1] = 6 (Fast BSS Transition)
+        * Action[1] = 1 (Fast BSS Transition Request)
+        * STA Address
+        * Target AP Address
+        * FT IEs
+        */
+
+       data_len = 2 + 2 * ETH_ALEN + ies_len;
+       data = os_malloc(data_len);
+       if (data == NULL)
+               return -1;
+       pos = data;
+       *pos++ = 0x06; /* FT Action category */
+       *pos++ = action;
+       os_memcpy(pos, wpa_s->own_addr, ETH_ALEN);
+       pos += ETH_ALEN;
+       os_memcpy(pos, target_ap, ETH_ALEN);
+       pos += ETH_ALEN;
+       os_memcpy(pos, ies, ies_len);
+
+       ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0,
+                                 wpa_s->bssid, wpa_s->own_addr, wpa_s->bssid,
+                                 data, data_len, 0);
+       os_free(data);
+
+       return ret;
 }
 
 
@@ -536,12 +609,14 @@ static int wpa_supplicant_mark_authenticated(void *ctx, const u8 *target_ap)
 #ifdef CONFIG_TDLS
 
 static int wpa_supplicant_tdls_get_capa(void *ctx, int *tdls_supported,
-                                       int *tdls_ext_setup)
+                                       int *tdls_ext_setup,
+                                       int *tdls_chan_switch)
 {
        struct wpa_supplicant *wpa_s = ctx;
 
        *tdls_supported = 0;
        *tdls_ext_setup = 0;
+       *tdls_chan_switch = 0;
 
        if (!wpa_s->drv_capa_known)
                return -1;
@@ -552,18 +627,23 @@ static int wpa_supplicant_tdls_get_capa(void *ctx, int *tdls_supported,
        if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP)
                *tdls_ext_setup = 1;
 
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH)
+               *tdls_chan_switch = 1;
+
        return 0;
 }
 
 
 static int wpa_supplicant_send_tdls_mgmt(void *ctx, const u8 *dst,
                                         u8 action_code, u8 dialog_token,
-                                        u16 status_code, const u8 *buf,
+                                        u16 status_code, u32 peer_capab,
+                                        int initiator, const u8 *buf,
                                         size_t len)
 {
        struct wpa_supplicant *wpa_s = ctx;
        return wpa_drv_send_tdls_mgmt(wpa_s, dst, action_code, dialog_token,
-                                     status_code, buf, len);
+                                     status_code, peer_capab, initiator, buf,
+                                     len);
 }
 
 
@@ -579,7 +659,7 @@ static int wpa_supplicant_tdls_peer_addset(
        const u8 *supp_rates, size_t supp_rates_len,
        const struct ieee80211_ht_capabilities *ht_capab,
        const struct ieee80211_vht_capabilities *vht_capab,
-       u8 qosinfo, const u8 *ext_capab, size_t ext_capab_len,
+       u8 qosinfo, int wmm, const u8 *ext_capab, size_t ext_capab_len,
        const u8 *supp_channels, size_t supp_channels_len,
        const u8 *supp_oper_classes, size_t supp_oper_classes_len)
 {
@@ -594,10 +674,10 @@ static int wpa_supplicant_tdls_peer_addset(
        params.flags = WPA_STA_TDLS_PEER | WPA_STA_AUTHORIZED;
 
        /*
-        * TDLS Setup frames do not contain WMM IEs, hence need to depend on
-        * qosinfo to check if the peer is WMM capable.
+        * Don't rely only on qosinfo for WMM capability. It may be 0 even when
+        * present. Allow the WMM IE to also indicate QoS support.
         */
-       if (qosinfo)
+       if (wmm || qosinfo)
                params.flags |= WPA_STA_WMM;
 
        params.ht_capabilities = ht_capab;
@@ -617,6 +697,25 @@ static int wpa_supplicant_tdls_peer_addset(
        return wpa_drv_sta_add(wpa_s, &params);
 }
 
+
+static int wpa_supplicant_tdls_enable_channel_switch(
+       void *ctx, const u8 *addr, u8 oper_class,
+       const struct hostapd_freq_params *params)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+
+       return wpa_drv_tdls_enable_channel_switch(wpa_s, addr, oper_class,
+                                                 params);
+}
+
+
+static int wpa_supplicant_tdls_disable_channel_switch(void *ctx, const u8 *addr)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+
+       return wpa_drv_tdls_disable_channel_switch(wpa_s, addr);
+}
+
 #endif /* CONFIG_TDLS */
 
 #endif /* CONFIG_NO_WPA */
@@ -725,7 +824,7 @@ static void wpa_supplicant_eap_param_needed(void *ctx,
        len = os_snprintf(buf, buflen,
                          WPA_CTRL_REQ "%s-%d:%s needed for SSID ",
                          field_name, ssid->id, txt);
-       if (len < 0 || (size_t) len >= buflen) {
+       if (os_snprintf_error(buflen, len)) {
                os_free(buf);
                return;
        }
@@ -843,11 +942,13 @@ int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s)
        ctx->opensc_engine_path = wpa_s->conf->opensc_engine_path;
        ctx->pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
        ctx->pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
+       ctx->openssl_ciphers = wpa_s->conf->openssl_ciphers;
        ctx->wps = wpa_s->wps;
        ctx->eap_param_needed = wpa_supplicant_eap_param_needed;
        ctx->port_cb = wpa_supplicant_port_cb;
        ctx->cb = wpa_supplicant_eapol_cb;
        ctx->cert_cb = wpa_supplicant_cert_cb;
+       ctx->cert_in_cb = wpa_s->conf->cert_in_cb;
        ctx->status_cb = wpa_supplicant_status_cb;
        ctx->set_anon_id = wpa_supplicant_set_anon_id;
        ctx->cb_ctx = wpa_s;
@@ -876,6 +977,19 @@ static void wpa_supplicant_set_rekey_offload(void *ctx, const u8 *kek,
 #endif /* CONFIG_NO_WPA */
 
 
+static int wpa_supplicant_key_mgmt_set_pmk(void *ctx, const u8 *pmk,
+                                          size_t pmk_len)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+
+       if (wpa_s->conf->key_mgmt_offload)
+               return wpa_drv_set_key(wpa_s, WPA_ALG_PMK, NULL, 0, 0,
+                                      NULL, 0, pmk, pmk_len);
+       else
+               return 0;
+}
+
+
 int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
 {
 #ifndef CONFIG_NO_WPA
@@ -915,13 +1029,19 @@ int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
        ctx->send_tdls_mgmt = wpa_supplicant_send_tdls_mgmt;
        ctx->tdls_oper = wpa_supplicant_tdls_oper;
        ctx->tdls_peer_addset = wpa_supplicant_tdls_peer_addset;
+       ctx->tdls_enable_channel_switch =
+               wpa_supplicant_tdls_enable_channel_switch;
+       ctx->tdls_disable_channel_switch =
+               wpa_supplicant_tdls_disable_channel_switch;
 #endif /* CONFIG_TDLS */
        ctx->set_rekey_offload = wpa_supplicant_set_rekey_offload;
+       ctx->key_mgmt_set_pmk = wpa_supplicant_key_mgmt_set_pmk;
 
        wpa_s->wpa = wpa_sm_init(ctx);
        if (wpa_s->wpa == NULL) {
                wpa_printf(MSG_ERROR, "Failed to initialize WPA state "
                           "machine");
+               os_free(ctx);
                return -1;
        }
 #endif /* CONFIG_NO_WPA */
@@ -949,7 +1069,8 @@ void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s,
                conf.ssid_len = ssid->ssid_len;
                conf.wpa_ptk_rekey = ssid->wpa_ptk_rekey;
 #ifdef CONFIG_P2P
-               if (ssid->p2p_group && wpa_s->current_bss) {
+               if (ssid->p2p_group && wpa_s->current_bss &&
+                   !wpa_s->p2p_disable_ip_addr_req) {
                        struct wpabuf *p2p;
                        p2p = wpa_bss_get_vendor_ie_multi(wpa_s->current_bss,
                                                          P2P_IE_VENDOR_TYPE);