TDLS: Declare tdls_testing as extern in a header file
[mech_eap.git] / wpa_supplicant / ibss_rsn.c
index 62d68b8..c00db31 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * wpa_supplicant - IBSS RSN
- * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2013, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -9,6 +9,8 @@
 #include "includes.h"
 
 #include "common.h"
+#include "common/wpa_ctrl.h"
+#include "utils/eloop.h"
 #include "l2_packet/l2_packet.h"
 #include "rsn_supp/wpa.h"
 #include "rsn_supp/wpa_ie.h"
@@ -19,6 +21,9 @@
 #include "ibss_rsn.h"
 
 
+static void ibss_rsn_auth_timeout(void *eloop_ctx, void *timeout_ctx);
+
+
 static struct ibss_rsn_peer * ibss_rsn_get_peer(struct ibss_rsn *ibss_rsn,
                                                const u8 *addr)
 {
@@ -33,6 +38,7 @@ static struct ibss_rsn_peer * ibss_rsn_get_peer(struct ibss_rsn *ibss_rsn,
 
 static void ibss_rsn_free(struct ibss_rsn_peer *peer)
 {
+       eloop_cancel_timeout(ibss_rsn_auth_timeout, peer, NULL);
        wpa_auth_sta_deinit(peer->auth);
        wpa_sm_deinit(peer->supp);
        os_free(peer);
@@ -66,7 +72,7 @@ static int supp_ether_send(void *ctx, const u8 *dest, u16 proto, const u8 *buf,
        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;
 }
 
 
@@ -114,6 +120,22 @@ static int supp_get_beacon_ie(void *ctx)
 }
 
 
+static void ibss_check_rsn_completed(struct ibss_rsn_peer *peer)
+{
+       struct wpa_supplicant *wpa_s = peer->ibss_rsn->wpa_s;
+
+       if ((peer->authentication_status &
+            (IBSS_RSN_SET_PTK_SUPP | IBSS_RSN_SET_PTK_AUTH)) !=
+           (IBSS_RSN_SET_PTK_SUPP | IBSS_RSN_SET_PTK_AUTH))
+               return;
+       if (peer->authentication_status & IBSS_RSN_REPORTED_PTK)
+               return;
+       peer->authentication_status |= IBSS_RSN_REPORTED_PTK;
+       wpa_msg(wpa_s, MSG_INFO, IBSS_RSN_COMPLETED MACSTR,
+               MAC2STR(peer->addr));
+}
+
+
 static int supp_set_key(void *ctx, enum wpa_alg alg,
                        const u8 *addr, int key_idx, int set_tx,
                        const u8 *seq, size_t seq_len,
@@ -128,6 +150,8 @@ static int supp_set_key(void *ctx, enum wpa_alg alg,
        wpa_hexdump_key(MSG_DEBUG, "SUPP: set_key - key", key, key_len);
 
        if (key_idx == 0) {
+               peer->authentication_status |= IBSS_RSN_SET_PTK_SUPP;
+               ibss_check_rsn_completed(peer);
                /*
                 * In IBSS RSN, the pairwise key from the 4-way handshake
                 * initiated by the peer with highest MAC address is used.
@@ -206,7 +230,7 @@ static int ibss_rsn_supp_init(struct ibss_rsn_peer *peer, const u8 *own_addr,
        wpa_sm_set_param(peer->supp, WPA_PARAM_PAIRWISE, WPA_CIPHER_CCMP);
        wpa_sm_set_param(peer->supp, WPA_PARAM_GROUP, WPA_CIPHER_CCMP);
        wpa_sm_set_param(peer->supp, WPA_PARAM_KEY_MGMT, WPA_KEY_MGMT_PSK);
-       wpa_sm_set_pmk(peer->supp, psk, PMK_LEN);
+       wpa_sm_set_pmk(peer->supp, psk, PMK_LEN, NULL, NULL);
 
        peer->supp_ie_len = sizeof(peer->supp_ie);
        if (wpa_sm_set_assoc_wpa_ie_default(peer->supp, peer->supp_ie,
@@ -233,7 +257,8 @@ static void auth_logger(void *ctx, const u8 *addr, logger_level level,
 }
 
 
-static const u8 * auth_get_psk(void *ctx, const u8 *addr, const u8 *prev_psk)
+static const u8 * auth_get_psk(void *ctx, const u8 *addr,
+                              const u8 *p2p_dev_addr, const u8 *prev_psk)
 {
        struct ibss_rsn *ibss_rsn = ctx;
        wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)",
@@ -258,7 +283,7 @@ static int auth_send_eapol(void *ctx, const u8 *addr, const u8 *data,
                return l2_packet_send(wpa_s->l2, addr, ETH_P_EAPOL, data,
                                      data_len);
 
-       return wpa_drv_send_eapol(wpa_s, addr, ETH_P_EAPOL, data, data_len);
+       return -1;
 }
 
 
@@ -281,6 +306,15 @@ static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
        wpa_hexdump_key(MSG_DEBUG, "AUTH: set_key - key", key, key_len);
 
        if (idx == 0) {
+               if (addr) {
+                       struct ibss_rsn_peer *peer;
+                       peer = ibss_rsn_get_peer(ibss_rsn, addr);
+                       if (peer) {
+                               peer->authentication_status |=
+                                       IBSS_RSN_SET_PTK_AUTH;
+                               ibss_check_rsn_completed(peer);
+                       }
+               }
                /*
                 * In IBSS RSN, the pairwise key from the 4-way handshake
                 * initiated by the peer with highest MAC address is used.
@@ -411,7 +445,7 @@ static int ibss_rsn_auth_init_group(struct ibss_rsn *ibss_rsn,
 static int ibss_rsn_auth_init(struct ibss_rsn *ibss_rsn,
                              struct ibss_rsn_peer *peer)
 {
-       peer->auth = wpa_auth_sta_init(ibss_rsn->auth_group, peer->addr);
+       peer->auth = wpa_auth_sta_init(ibss_rsn->auth_group, peer->addr, NULL);
        if (peer->auth == NULL) {
                wpa_printf(MSG_DEBUG, "AUTH: wpa_auth_sta_init() failed");
                return -1;
@@ -515,11 +549,31 @@ ibss_rsn_peer_init(struct ibss_rsn *ibss_rsn, const u8 *addr)
 }
 
 
+static void ibss_rsn_auth_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+       struct ibss_rsn_peer *peer = eloop_ctx;
+
+       /*
+        * Assume peer does not support Authentication exchange or the frame was
+        * lost somewhere - start EAPOL Authenticator.
+        */
+       wpa_printf(MSG_DEBUG,
+                  "RSN: Timeout on waiting Authentication frame response from "
+                  MACSTR " - start authenticator", MAC2STR(peer->addr));
+
+       peer->authentication_status |= IBSS_RSN_AUTH_BY_US;
+       ibss_rsn_auth_init(peer->ibss_rsn, peer);
+}
+
+
 int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr)
 {
        struct ibss_rsn_peer *peer;
        int res;
 
+       if (!ibss_rsn)
+               return -1;
+
        /* if the peer already exists, exit immediately */
        peer = ibss_rsn_get_peer(ibss_rsn, addr);
        if (peer)
@@ -538,6 +592,9 @@ int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr)
                 */
                peer->authentication_status |= IBSS_RSN_AUTH_BY_US;
                return ibss_rsn_auth_init(ibss_rsn, peer);
+       } else {
+               os_get_reltime(&peer->own_auth_tx);
+               eloop_register_timeout(1, 0, ibss_rsn_auth_timeout, peer, NULL);
        }
 
        return 0;
@@ -640,7 +697,8 @@ void ibss_rsn_deinit(struct ibss_rsn *ibss_rsn)
                ibss_rsn_free(prev);
        }
 
-       wpa_deinit(ibss_rsn->auth_group);
+       if (ibss_rsn->auth_group)
+               wpa_deinit(ibss_rsn->auth_group);
        os_free(ibss_rsn);
 
 }
@@ -779,6 +837,16 @@ static void ibss_rsn_handle_auth_1_of_2(struct ibss_rsn *ibss_rsn,
 
        if (peer &&
            peer->authentication_status & IBSS_RSN_AUTH_EAPOL_BY_PEER) {
+               if (peer->own_auth_tx.sec) {
+                       struct os_reltime now, diff;
+                       os_get_reltime(&now);
+                       os_reltime_sub(&now, &peer->own_auth_tx, &diff);
+                       if (diff.sec == 0 && diff.usec < 500000) {
+                               wpa_printf(MSG_DEBUG, "RSN: Skip IBSS reinit since only %u usec from own Auth frame TX",
+                                          (int) diff.usec);
+                               goto skip_reinit;
+                       }
+               }
                /*
                 * A peer sent us an Authentication frame even though it already
                 * started an EAPOL session. We should reinit state machines
@@ -801,6 +869,7 @@ static void ibss_rsn_handle_auth_1_of_2(struct ibss_rsn *ibss_rsn,
                           MAC2STR(addr));
        }
 
+skip_reinit:
        /* reply with an Authentication frame now, before sending an EAPOL */
        ibss_rsn_send_auth(ibss_rsn, addr, 2);
        /* no need to start another AUTH challenge in the other way.. */
@@ -841,7 +910,8 @@ void ibss_rsn_handle_auth(struct ibss_rsn *ibss_rsn, const u8 *auth_frame,
                }
 
                /* authentication has been completed */
-               wpa_printf(MSG_DEBUG, "RSN: IBSS Auth completed with "MACSTR,
+               eloop_cancel_timeout(ibss_rsn_auth_timeout, peer, NULL);
+               wpa_printf(MSG_DEBUG, "RSN: IBSS Auth completed with " MACSTR,
                           MAC2STR(header->sa));
                ibss_rsn_peer_authenticated(ibss_rsn, peer,
                                            IBSS_RSN_AUTH_BY_US);