#include "ap/wpa_auth.h"
#include "wpa_supplicant_i.h"
#include "driver_i.h"
+#include "common/ieee802_11_defs.h"
#include "ibss_rsn.h"
}
-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);
}
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);
* 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);
}
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;
+ }
+}