diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index a932b8d..fbc8d32 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -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));
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 8d276c5..cee1bf6 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -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",
diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c
index 046f181..4b5ccd9 100644
--- a/wpa_supplicant/ibss_rsn.c
+++ b/wpa_supplicant/ibss_rsn.c
@@ -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);
+	}
+}
diff --git a/wpa_supplicant/ibss_rsn.h b/wpa_supplicant/ibss_rsn.h
index 1da94ab..923b9df 100644
--- a/wpa_supplicant/ibss_rsn.h
+++ b/wpa_supplicant/ibss_rsn.h
@@ -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 */
