diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index f757c72..b5ca1a7 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -2300,6 +2300,22 @@ 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;
+
+	/* check if the ssid is correctly configured as IBSS/RSN */
+	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 */
 
 
@@ -2694,6 +2710,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;
@@ -2703,7 +2721,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) {
@@ -2719,9 +2739,17 @@ 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 >= 30) {
+				wpa_supplicant_event_ibss_auth(wpa_s, data);
+				break;
+			}
+#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 &&
@@ -2737,9 +2765,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 687c042..05ad5f2 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"
 
 
@@ -437,48 +438,123 @@ 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)
+	if (wpa_s->driver->send_frame == NULL)
+		return -1;
+
+	memset(&auth, 0, sizeof(auth));
+
+	auth.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					  WLAN_FC_STYPE_AUTH);
+	memcpy(auth.da, da, ETH_ALEN);
+	memcpy(auth.sa, wpa_s->own_addr, ETH_ALEN);
+	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)
 {
-	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 -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));
+		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 -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;
 
+	return peer;
+}
+
+
+int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr)
+{
+	struct ibss_rsn_peer *peer;
+
+	/* 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 AUTH frame */
+	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)
+{
+	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;
+	}
+
+	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)
 {
@@ -605,27 +681,43 @@ static int ibss_rsn_process_rx_eapol(struct ibss_rsn *ibss_rsn,
 				     struct ibss_rsn_peer *peer,
 				     const u8 *buf, size_t len)
 {
-	int supp;
-	u8 *tmp;
+	int supp, ret = -1;
+	u8 *tmp = NULL;
 
 	supp = ibss_rsn_eapol_dst_supp(buf, len);
 	if (supp < 0)
-		return -1;
+		goto out;
 
 	tmp = os_malloc(len);
 	if (tmp == NULL)
-		return -1;
+		goto out;
+
 	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));
+
+			goto out;
+		}
+
+		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);
+	ret = 1;
+out:
+	if (tmp)
+		os_free(tmp);
 
-	return 1;
+	return ret;
 }
 
 
@@ -646,8 +738,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 +755,84 @@ 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 AUTH message even if 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 AUTH 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);
+	}
+}
diff --git a/wpa_supplicant/ibss_rsn.h b/wpa_supplicant/ibss_rsn.h
index 1da94ab..5a8eda4 100644
--- a/wpa_supplicant/ibss_rsn.h
+++ b/wpa_supplicant/ibss_rsn.h
@@ -11,6 +11,15 @@
 
 struct ibss_rsn;
 
+/* not authenticated */
+#define IBSS_RSN_AUTH_NOT_AUTHENTICATED	0x00
+/* remote peer sent an EAPOL message */
+#define IBSS_RSN_AUTH_EAPOL_BY_PEER	0x01
+/* we sent an AUTH message with seq 1 */
+#define IBSS_RSN_AUTH_BY_US		0x02
+/* we sent an EAPOL message */
+#define IBSS_RSN_AUTH_EAPOL_BY_US	0x04
+
 struct ibss_rsn_peer {
 	struct ibss_rsn_peer *next;
 	struct ibss_rsn *ibss_rsn;
@@ -23,6 +32,7 @@ struct ibss_rsn_peer {
 	size_t supp_ie_len;
 
 	struct wpa_state_machine *auth;
+	int authentication_status;
 };
 
 struct ibss_rsn {
@@ -40,5 +50,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 */
