@@ -309,6 +309,9 @@ static int nl80211_send_frame_cmd(struct i802_bss *bss,
unsigned int freq, unsigned int wait,
const u8 *buf, size_t buf_len, u64 *cookie,
int no_cck, int no_ack, int offchanok);
+static int nl80211_register_frame(struct i802_bss *bss,
+ struct nl_handle *hl_handle,
+ u16 type, const u8 *match, size_t match_len);
static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss,
int report);
#ifdef ANDROID
@@ -1579,6 +1582,12 @@ static void mlme_event_join_ibss(struct wpa_driver_nl80211_data *drv,
return;
}
os_memcpy(drv->bssid, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+
+ nl80211_register_frame(&drv->first_bss, drv->first_bss.nl_mgmt,
+ ((WLAN_FC_TYPE_MGMT << 2) |
+ (WLAN_FC_STYPE_AUTH << 4)),
+ (u8*)"\0\0", 2);
+
drv->associated = 1;
wpa_printf(MSG_DEBUG, "nl80211: IBSS " MACSTR " joined",
MAC2STR(drv->bssid));
@@ -2271,6 +2271,18 @@ static void wpa_supplicant_event_ibss_rsn_start(struct wpa_supplicant *wpa_s,
ibss_rsn_start(wpa_s->ibss_rsn, data->ibss_rsn_start.peer);
}
+
+static void wpa_supplicant_event_ibss_auth(struct wpa_supplicant *wpa_s,
+ union wpa_event_data *data)
+{
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ if (ssid == NULL)
+ return;
+ if (ssid->mode != WPAS_MODE_IBSS || !wpa_key_mgmt_wpa(ssid->key_mgmt))
+ return;
+ ibss_rsn_handle_auth(wpa_s->ibss_rsn, data->rx_mgmt.frame,
+ data->rx_mgmt.frame_len);
+}
#endif /* CONFIG_IBSS_RSN */
@@ -2664,6 +2676,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
data->ch_switch.ch_offset);
#endif /* CONFIG_AP */
break;
+#endif /* CONFIG_AP */
+#if defined(CONFIG_AP) || defined(CONFIG_IBSS_RSN)
case EVENT_RX_MGMT: {
u16 fc, stype;
const struct ieee80211_mgmt *mgmt;
@@ -2673,7 +2687,9 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
fc = le_to_host16(mgmt->frame_control);
stype = WLAN_FC_GET_STYPE(fc);
+#ifdef CONFIG_AP
if (wpa_s->ap_iface == NULL) {
+#endif /* CONFIG_AP */
#ifdef CONFIG_P2P
if (stype == WLAN_FC_STYPE_PROBE_REQ &&
data->rx_mgmt.frame_len > 24) {
@@ -2689,9 +2705,16 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
break;
}
#endif /* CONFIG_P2P */
+#ifdef CONFIG_IBSS_RSN
+ if (stype == WLAN_FC_STYPE_AUTH &&
+ data->rx_mgmt.frame_len > 24)
+ wpa_supplicant_event_ibss_auth(wpa_s, data);
+ else
+#endif /* CONFIG_IBSS_RSN */
wpa_dbg(wpa_s, MSG_DEBUG, "AP: ignore received "
"management frame in non-AP mode");
break;
+#ifdef CONFIG_AP
}
if (stype == WLAN_FC_STYPE_PROBE_REQ &&
@@ -2707,9 +2730,10 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
}
ap_mgmt_rx(wpa_s, &data->rx_mgmt);
+#endif /* CONFIG_AP */
break;
}
-#endif /* CONFIG_AP */
+#endif /* CONFIG_AP || CONFIG_IBSS_RSN */
case EVENT_RX_ACTION:
wpa_dbg(wpa_s, MSG_DEBUG, "Received Action frame: SA=" MACSTR
" Category=%u DataLen=%d freq=%d MHz",
@@ -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"
@@ -429,48 +430,118 @@ static int ibss_rsn_auth_init(struct ibss_rsn *ibss_rsn,
return 0;
}
+static int ibss_rsn_send_auth(struct ibss_rsn *ibss_rsn, const u8* da, int seq)
+{
+ struct ieee80211_mgmt auth;
+ const size_t auth_length = IEEE80211_HDRLEN + sizeof auth.u.auth;
+ struct wpa_supplicant *wpa_s = ibss_rsn->wpa_s;
-int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr)
+ auth.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_AUTH);
+ auth.duration = 0; // filled by kernel.
+ memcpy(auth.da, da, 6);
+ memcpy(auth.sa, wpa_s->own_addr, 6);
+ memcpy(auth.bssid, wpa_s->bssid, 6);
+ auth.seq_ctrl = 0; // filled by kernel.
+ 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);
+
+ if (wpa_s->driver->send_frame == NULL)
+ return -1;
+ 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)
{
- 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, int *was_created)
+{
+ struct ibss_rsn_peer *peer;
if (ibss_rsn == NULL)
- return -1;
+ return NULL;
- 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;
+ peer = ibss_rsn_get_peer(ibss_rsn, addr);
+ if (peer) {
+ wpa_printf(MSG_DEBUG, "RSN: IBSS Supplicant for peer "MACSTR
+ " already running", MAC2STR(addr));
+ if (was_created)
+ *was_created = 0;
+ return peer;
}
- wpa_printf(MSG_DEBUG, "RSN: Starting IBSS Authenticator and "
- "Supplicant for peer " MACSTR, MAC2STR(addr));
+ // Start the supplicant now so we are ready to accept any EAPOL from
+ // peers that don't use Open System Authentication.
+ 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) {
ibss_rsn_free(peer);
- return -1;
- }
-
- if (ibss_rsn_auth_init(ibss_rsn, peer) < 0) {
- ibss_rsn_free(peer);
- return -1;
+ return NULL;
}
peer->next = ibss_rsn->peers;
ibss_rsn->peers = peer;
+ if (was_created)
+ *was_created = 1;
+
+ return peer;
+}
+
+int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr)
+{
+ int was_created = 0;
+ struct ibss_rsn_peer *p;
+ p = ibss_rsn_peer_init(ibss_rsn, addr, &was_created);
+ if (p == NULL)
+ return -1;
+ // We use open system authentication, do not start authenticator until
+ // it completes or the other side acknowledge us.
+ if (was_created)
+ ibss_rsn_send_auth(ibss_rsn, addr, 1);
return 0;
}
+static int ibss_rsn_peer_authenticated(struct ibss_rsn *ibss_rsn,
+ struct ibss_rsn_peer * peer,
+ int reason)
+{
+ if (ibss_rsn == NULL || peer == NULL)
+ return -1;
+ int 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;
+ }
+
+ wpa_printf(MSG_DEBUG, "RSN: Starting IBSS Authenticator "
+ "for now-authenticated peer " MACSTR, MAC2STR(peer->addr));
+
+ return ibss_rsn_auth_init(ibss_rsn, peer);
+}
+
void ibss_rsn_stop(struct ibss_rsn *ibss_rsn, const u8 *peermac)
{
@@ -600,6 +671,7 @@ static int ibss_rsn_process_rx_eapol(struct ibss_rsn *ibss_rsn,
int supp;
u8 *tmp;
+
supp = ibss_rsn_eapol_dst_supp(buf, len);
if (supp < 0)
return -1;
@@ -609,10 +681,19 @@ 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));
+ 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);
@@ -638,8 +719,15 @@ 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, NULL);
+ if (peer == NULL)
return -1;
+ // Don't use open system authentication,
+ // just do it implicitly
+ wpa_printf(MSG_DEBUG, "RSN: 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);
}
@@ -654,3 +742,70 @@ void ibss_rsn_set_psk(struct ibss_rsn *ibss_rsn, const u8 *psk)
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 Auth frame (SEQ 1) from "MACSTR,
+ MAC2STR(addr));
+ if (peer != NULL && peer->authentication_status &
+ IBSS_RSN_AUTH_EAPOL_BY_PEER) {
+ // We should reinit state machines here, but it's much
+ // more complicated than just deleting and recreating
+ // all the state machines.
+ wpa_printf(MSG_DEBUG, "RSN: IBSS: Reinitializing station.");
+ ibss_rsn_stop(ibss_rsn, addr);
+ peer = NULL;
+ }
+ if (peer == NULL) {
+ peer = ibss_rsn_peer_init(ibss_rsn, addr, NULL);
+ if (peer == NULL)
+ return;
+ wpa_printf(MSG_DEBUG, "RSN: IBSS Auth started by peer.");
+
+ // send it now, before sending an EAPOL.
+ ibss_rsn_send_auth(ibss_rsn, addr, 2);
+
+ // No need to do open system if the other does.
+ ibss_rsn_peer_authenticated(ibss_rsn, peer,
+ IBSS_RSN_AUTH_EAPOL_BY_US);
+ } else
+ ibss_rsn_send_auth(ibss_rsn, addr, 2);
+}
+
+
+void ibss_rsn_handle_auth(struct ibss_rsn *ibss_rsn, const u8 *auth_frame,
+ size_t len) {
+ const struct ieee80211_mgmt* header
+ = (const struct ieee80211_mgmt*)auth_frame;
+ const size_t auth_length = IEEE80211_HDRLEN + sizeof header->u.auth;
+ struct ibss_rsn_peer *peer;
+ 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);
+ // peer can be NULL here
+
+ 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 Auth frame (SEQ 2) from "
+ MACSTR, MAC2STR(header->sa));
+ if (peer == NULL) {
+ wpa_printf(MSG_DEBUG, "RSN: Received Auth seq 2 from "
+ "unknown sta "MACSTR, MAC2STR(header->sa));
+ break;
+ }
+ // authentication completed, start negotiating.
+ 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);
+ }
+}
@@ -11,6 +11,17 @@
struct ibss_rsn;
+// no authentication
+#define IBSS_RSN_AUTH_NOT_AUTHENTICATED 0
+// remote sent an eapol
+#define IBSS_RSN_AUTH_EAPOL_BY_PEER 1
+
+// We did open system authentication.
+#define IBSS_RSN_AUTH_BY_US 2
+// We sent an EAPOL
+#define IBSS_RSN_AUTH_EAPOL_BY_US 4
+
+
struct ibss_rsn_peer {
struct ibss_rsn_peer *next;
struct ibss_rsn *ibss_rsn;
@@ -23,6 +34,7 @@ struct ibss_rsn_peer {
size_t supp_ie_len;
struct wpa_state_machine *auth;
+ int authentication_status;
};
struct ibss_rsn {
@@ -40,5 +52,7 @@ void ibss_rsn_stop(struct ibss_rsn *ibss_rsn, const u8 *peermac);
int ibss_rsn_rx_eapol(struct ibss_rsn *ibss_rsn, const u8 *src_addr,
const u8 *buf, size_t len);
void ibss_rsn_set_psk(struct ibss_rsn *ibss_rsn, const u8 *psk);
+void ibss_rsn_handle_auth(struct ibss_rsn *ibss_rsn, const u8 *auth_frame,
+ size_t len);
#endif /* IBSS_RSN_H */