|
@@ -15,6 +15,7 @@
|
|
|
#include "ap/wpa_auth.h"
|
|
|
#include "wpa_supplicant_i.h"
|
|
|
#include "driver_i.h"
|
|
|
+#include "common/ieee802_11_defs.h"
|
|
|
#include "ibss_rsn.h"
|
|
|
|
|
|
|
|
@@ -438,45 +439,132 @@ static int ibss_rsn_auth_init(struct ibss_rsn *ibss_rsn,
|
|
|
}
|
|
|
|
|
|
|
|
|
-int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr)
|
|
|
+static int ibss_rsn_send_auth(struct ibss_rsn *ibss_rsn, const u8 *da, int seq)
|
|
|
{
|
|
|
- struct ibss_rsn_peer *peer;
|
|
|
+ struct ieee80211_mgmt auth;
|
|
|
+ const size_t auth_length = IEEE80211_HDRLEN + sizeof(auth.u.auth);
|
|
|
+ struct wpa_supplicant *wpa_s = ibss_rsn->wpa_s;
|
|
|
|
|
|
- if (ibss_rsn == NULL)
|
|
|
+ if (wpa_s->driver->send_frame == NULL)
|
|
|
return -1;
|
|
|
|
|
|
- if (ibss_rsn_get_peer(ibss_rsn, addr)) {
|
|
|
- wpa_printf(MSG_DEBUG, "RSN: IBSS Authenticator and Supplicant "
|
|
|
- "for peer " MACSTR " already running",
|
|
|
- MAC2STR(addr));
|
|
|
- return 0;
|
|
|
+ os_memset(&auth, 0, sizeof(auth));
|
|
|
+
|
|
|
+ auth.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
|
|
|
+ WLAN_FC_STYPE_AUTH);
|
|
|
+ os_memcpy(auth.da, da, ETH_ALEN);
|
|
|
+ os_memcpy(auth.sa, wpa_s->own_addr, ETH_ALEN);
|
|
|
+ os_memcpy(auth.bssid, wpa_s->bssid, ETH_ALEN);
|
|
|
+
|
|
|
+ auth.u.auth.auth_alg = host_to_le16(WLAN_AUTH_OPEN);
|
|
|
+ auth.u.auth.auth_transaction = host_to_le16(seq);
|
|
|
+ auth.u.auth.status_code = host_to_le16(WLAN_STATUS_SUCCESS);
|
|
|
+
|
|
|
+ wpa_printf(MSG_DEBUG, "RSN: IBSS TX Auth frame (SEQ %d) to " MACSTR,
|
|
|
+ seq, MAC2STR(da));
|
|
|
+
|
|
|
+ return wpa_s->driver->send_frame(wpa_s->drv_priv, (u8 *) &auth,
|
|
|
+ auth_length, 0);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static int ibss_rsn_is_auth_started(struct ibss_rsn_peer * peer)
|
|
|
+{
|
|
|
+ return peer->authentication_status &
|
|
|
+ (IBSS_RSN_AUTH_BY_US | IBSS_RSN_AUTH_EAPOL_BY_US);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static struct ibss_rsn_peer *
|
|
|
+ibss_rsn_peer_init(struct ibss_rsn *ibss_rsn, const u8 *addr)
|
|
|
+{
|
|
|
+ struct ibss_rsn_peer *peer;
|
|
|
+ if (ibss_rsn == NULL)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ peer = ibss_rsn_get_peer(ibss_rsn, addr);
|
|
|
+ if (peer) {
|
|
|
+ wpa_printf(MSG_DEBUG, "RSN: IBSS Supplicant for peer "MACSTR
|
|
|
+ " already running", MAC2STR(addr));
|
|
|
+ return peer;
|
|
|
}
|
|
|
|
|
|
- wpa_printf(MSG_DEBUG, "RSN: Starting IBSS Authenticator and "
|
|
|
- "Supplicant for peer " MACSTR, MAC2STR(addr));
|
|
|
+ wpa_printf(MSG_DEBUG, "RSN: Starting IBSS Supplicant for peer "MACSTR,
|
|
|
+ MAC2STR(addr));
|
|
|
|
|
|
peer = os_zalloc(sizeof(*peer));
|
|
|
- if (peer == NULL)
|
|
|
- return -1;
|
|
|
+ if (peer == NULL) {
|
|
|
+ wpa_printf(MSG_DEBUG, "RSN: Could not allocate memory.");
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
|
|
|
peer->ibss_rsn = ibss_rsn;
|
|
|
os_memcpy(peer->addr, addr, ETH_ALEN);
|
|
|
+ peer->authentication_status = IBSS_RSN_AUTH_NOT_AUTHENTICATED;
|
|
|
|
|
|
- if (ibss_rsn_supp_init(peer, ibss_rsn->wpa_s->own_addr, ibss_rsn->psk)
|
|
|
- < 0) {
|
|
|
+ if (ibss_rsn_supp_init(peer, ibss_rsn->wpa_s->own_addr,
|
|
|
+ ibss_rsn->psk) < 0) {
|
|
|
ibss_rsn_free(peer);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ peer->next = ibss_rsn->peers;
|
|
|
+ ibss_rsn->peers = peer;
|
|
|
+
|
|
|
+ return peer;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr)
|
|
|
+{
|
|
|
+ struct ibss_rsn_peer *peer;
|
|
|
+ int res;
|
|
|
+
|
|
|
+ /* if the peer already exists, exit immediately */
|
|
|
+ peer = ibss_rsn_get_peer(ibss_rsn, addr);
|
|
|
+ if (peer)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ peer = ibss_rsn_peer_init(ibss_rsn, addr);
|
|
|
+ if (peer == NULL)
|
|
|
return -1;
|
|
|
+
|
|
|
+ /* Open Authentication: send first Authentication frame */
|
|
|
+ res = ibss_rsn_send_auth(ibss_rsn, addr, 1);
|
|
|
+ if (res) {
|
|
|
+ /*
|
|
|
+ * The driver may not support Authentication frame exchange in
|
|
|
+ * IBSS. Ignore authentication and go through EAPOL exchange.
|
|
|
+ */
|
|
|
+ peer->authentication_status |= IBSS_RSN_AUTH_BY_US;
|
|
|
+ return ibss_rsn_auth_init(ibss_rsn, peer);
|
|
|
}
|
|
|
|
|
|
- if (ibss_rsn_auth_init(ibss_rsn, peer) < 0) {
|
|
|
- ibss_rsn_free(peer);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static int ibss_rsn_peer_authenticated(struct ibss_rsn *ibss_rsn,
|
|
|
+ struct ibss_rsn_peer *peer, int reason)
|
|
|
+{
|
|
|
+ int already_started;
|
|
|
+
|
|
|
+ if (ibss_rsn == NULL || peer == NULL)
|
|
|
return -1;
|
|
|
+
|
|
|
+ already_started = ibss_rsn_is_auth_started(peer);
|
|
|
+ peer->authentication_status |= reason;
|
|
|
+
|
|
|
+ if (already_started) {
|
|
|
+ wpa_printf(MSG_DEBUG, "RSN: IBSS Authenticator already "
|
|
|
+ "started for peer " MACSTR, MAC2STR(peer->addr));
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
- peer->next = ibss_rsn->peers;
|
|
|
- ibss_rsn->peers = peer;
|
|
|
+ wpa_printf(MSG_DEBUG, "RSN: Starting IBSS Authenticator "
|
|
|
+ "for now-authenticated peer " MACSTR, MAC2STR(peer->addr));
|
|
|
|
|
|
- return 0;
|
|
|
+ return ibss_rsn_auth_init(ibss_rsn, peer);
|
|
|
}
|
|
|
|
|
|
|
|
@@ -617,10 +705,21 @@ static int ibss_rsn_process_rx_eapol(struct ibss_rsn *ibss_rsn,
|
|
|
return -1;
|
|
|
os_memcpy(tmp, buf, len);
|
|
|
if (supp) {
|
|
|
- wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Supplicant");
|
|
|
+ peer->authentication_status |= IBSS_RSN_AUTH_EAPOL_BY_PEER;
|
|
|
+ wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Supplicant from "
|
|
|
+ MACSTR, MAC2STR(peer->addr));
|
|
|
wpa_sm_rx_eapol(peer->supp, peer->addr, tmp, len);
|
|
|
} else {
|
|
|
- wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Authenticator");
|
|
|
+ if (ibss_rsn_is_auth_started(peer) == 0) {
|
|
|
+ wpa_printf(MSG_DEBUG, "RSN: IBSS EAPOL for "
|
|
|
+ "Authenticator dropped as " MACSTR " is not "
|
|
|
+ "authenticated", MAC2STR(peer->addr));
|
|
|
+ os_free(tmp);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Authenticator "
|
|
|
+ "from "MACSTR, MAC2STR(peer->addr));
|
|
|
wpa_receive(ibss_rsn->auth_group, peer->auth, tmp, len);
|
|
|
}
|
|
|
os_free(tmp);
|
|
@@ -646,8 +745,16 @@ int ibss_rsn_rx_eapol(struct ibss_rsn *ibss_rsn, const u8 *src_addr,
|
|
|
* Create new IBSS peer based on an EAPOL message from the peer
|
|
|
* Authenticator.
|
|
|
*/
|
|
|
- if (ibss_rsn_start(ibss_rsn, src_addr) < 0)
|
|
|
+ peer = ibss_rsn_peer_init(ibss_rsn, src_addr);
|
|
|
+ if (peer == NULL)
|
|
|
return -1;
|
|
|
+
|
|
|
+ /* assume the peer is authenticated already */
|
|
|
+ wpa_printf(MSG_DEBUG, "RSN: IBSS Not using IBSS Auth for peer "
|
|
|
+ MACSTR, MAC2STR(src_addr));
|
|
|
+ ibss_rsn_peer_authenticated(ibss_rsn, peer,
|
|
|
+ IBSS_RSN_AUTH_EAPOL_BY_US);
|
|
|
+
|
|
|
return ibss_rsn_process_rx_eapol(ibss_rsn, ibss_rsn->peers,
|
|
|
buf, len);
|
|
|
}
|
|
@@ -655,10 +762,89 @@ int ibss_rsn_rx_eapol(struct ibss_rsn *ibss_rsn, const u8 *src_addr,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
void ibss_rsn_set_psk(struct ibss_rsn *ibss_rsn, const u8 *psk)
|
|
|
{
|
|
|
if (ibss_rsn == NULL)
|
|
|
return;
|
|
|
os_memcpy(ibss_rsn->psk, psk, PMK_LEN);
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
+static void ibss_rsn_handle_auth_1_of_2(struct ibss_rsn *ibss_rsn,
|
|
|
+ struct ibss_rsn_peer *peer,
|
|
|
+ const u8* addr)
|
|
|
+{
|
|
|
+ wpa_printf(MSG_DEBUG, "RSN: IBSS RX Auth frame (SEQ 1) from " MACSTR,
|
|
|
+ MAC2STR(addr));
|
|
|
+
|
|
|
+ if (peer &&
|
|
|
+ peer->authentication_status & IBSS_RSN_AUTH_EAPOL_BY_PEER) {
|
|
|
+ /*
|
|
|
+ * A peer sent us an Authentication frame even though it already
|
|
|
+ * started an EAPOL session. We should reinit state machines
|
|
|
+ * here, but it's much more complicated than just deleting and
|
|
|
+ * recreating the state machine
|
|
|
+ */
|
|
|
+ wpa_printf(MSG_DEBUG, "RSN: IBSS Reinitializing station "
|
|
|
+ MACSTR, MAC2STR(addr));
|
|
|
+
|
|
|
+ ibss_rsn_stop(ibss_rsn, addr);
|
|
|
+ peer = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!peer) {
|
|
|
+ peer = ibss_rsn_peer_init(ibss_rsn, addr);
|
|
|
+ if (!peer)
|
|
|
+ return;
|
|
|
+
|
|
|
+ wpa_printf(MSG_DEBUG, "RSN: IBSS Auth started by peer " MACSTR,
|
|
|
+ MAC2STR(addr));
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 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.. */
|
|
|
+ ibss_rsn_peer_authenticated(ibss_rsn, peer, IBSS_RSN_AUTH_EAPOL_BY_US);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void ibss_rsn_handle_auth(struct ibss_rsn *ibss_rsn, const u8 *auth_frame,
|
|
|
+ size_t len)
|
|
|
+{
|
|
|
+ const struct ieee80211_mgmt *header;
|
|
|
+ struct ibss_rsn_peer *peer;
|
|
|
+ size_t auth_length;
|
|
|
+
|
|
|
+ header = (const struct ieee80211_mgmt *) auth_frame;
|
|
|
+ auth_length = IEEE80211_HDRLEN + sizeof(header->u.auth);
|
|
|
+
|
|
|
+ if (ibss_rsn == NULL || len < auth_length)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (le_to_host16(header->u.auth.auth_alg) != WLAN_AUTH_OPEN ||
|
|
|
+ le_to_host16(header->u.auth.status_code) != WLAN_STATUS_SUCCESS)
|
|
|
+ return;
|
|
|
+
|
|
|
+ peer = ibss_rsn_get_peer(ibss_rsn, header->sa);
|
|
|
+
|
|
|
+ switch (le_to_host16(header->u.auth.auth_transaction)) {
|
|
|
+ case 1:
|
|
|
+ ibss_rsn_handle_auth_1_of_2(ibss_rsn, peer, header->sa);
|
|
|
+ break;
|
|
|
+ case 2:
|
|
|
+ wpa_printf(MSG_DEBUG, "RSN: IBSS RX Auth frame (SEQ 2) from "
|
|
|
+ MACSTR, MAC2STR(header->sa));
|
|
|
+ if (!peer) {
|
|
|
+ wpa_printf(MSG_DEBUG, "RSN: Received Auth seq 2 from "
|
|
|
+ "unknown STA " MACSTR, MAC2STR(header->sa));
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* authentication has been completed */
|
|
|
+ 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);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+}
|