Update to new version 0.8.16 from BRCM

Sync with main tree commit b8349523e460493fa0b4de36c689595109e45e91
Author: Neeraj Kumar Garg <neerajkg@broadcom.com>
Date:   Tue Dec 27 23:21:45 2011 +0200
    P2P: Reject p2p_group_add if forced frequency is not acceptable

Change-Id: Icb4541a371b05c270e80440d7a7fdea7f33ff61e
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index e0a3a36..a1a7270 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -1,6 +1,6 @@
 /*
  * hostapd / IEEE 802.11 Management
- * Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -163,59 +163,6 @@
 }
 
 
-u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
-{
-	u8 *pos = eid;
-
-	if ((hapd->conf->tdls & (TDLS_PROHIBIT | TDLS_PROHIBIT_CHAN_SWITCH)) ==
-	    0)
-		return eid;
-
-	*pos++ = WLAN_EID_EXT_CAPAB;
-	*pos++ = 5;
-	*pos++ = 0x00;
-	*pos++ = 0x00;
-	*pos++ = 0x00;
-	*pos++ = 0x00;
-	*pos = 0x00;
-	if (hapd->conf->tdls & TDLS_PROHIBIT)
-		*pos |= 0x40; /* Bit 38 - TDLS Prohibited */
-	if (hapd->conf->tdls & TDLS_PROHIBIT_CHAN_SWITCH)
-		*pos |= 0x80; /* Bit 39 - TDLS Channel Switching Prohibited */
-	pos++;
-
-	return pos;
-}
-
-
-#ifdef CONFIG_IEEE80211W
-static u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
-					    struct sta_info *sta, u8 *eid)
-{
-	u8 *pos = eid;
-	u32 timeout, tu;
-	struct os_time now, passed;
-
-	*pos++ = WLAN_EID_TIMEOUT_INTERVAL;
-	*pos++ = 5;
-	*pos++ = WLAN_TIMEOUT_ASSOC_COMEBACK;
-	os_get_time(&now);
-	os_time_sub(&now, &sta->sa_query_start, &passed);
-	tu = (passed.sec * 1000000 + passed.usec) / 1024;
-	if (hapd->conf->assoc_sa_query_max_timeout > tu)
-		timeout = hapd->conf->assoc_sa_query_max_timeout - tu;
-	else
-		timeout = 0;
-	if (timeout < hapd->conf->assoc_sa_query_max_timeout)
-		timeout++; /* add some extra time for local timers */
-	WPA_PUT_LE32(pos, timeout);
-	pos += 4;
-
-	return pos;
-}
-#endif /* CONFIG_IEEE80211W */
-
-
 void ieee802_11_print_ssid(char *buf, const u8 *ssid, u8 len)
 {
 	int i;
@@ -322,7 +269,7 @@
 		   " auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu)",
 		   MAC2STR(dst), auth_alg, auth_transaction,
 		   resp, (unsigned long) ies_len);
-	if (hostapd_drv_send_mlme(hapd, reply, rlen) < 0)
+	if (hostapd_drv_send_mlme(hapd, reply, rlen, 0) < 0)
 		perror("send_auth_reply: send");
 
 	os_free(buf);
@@ -366,6 +313,8 @@
 	const u8 *challenge = NULL;
 	u32 session_timeout, acct_interim_interval;
 	int vlan_id = 0;
+	u8 psk[PMK_LEN];
+	int has_psk = 0;
 	u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
 	size_t resp_ies_len = 0;
 
@@ -400,9 +349,7 @@
 	if (!(((hapd->conf->auth_algs & WPA_AUTH_ALG_OPEN) &&
 	       auth_alg == WLAN_AUTH_OPEN) ||
 #ifdef CONFIG_IEEE80211R
-	      (hapd->conf->wpa &&
-	       (hapd->conf->wpa_key_mgmt &
-		(WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_FT_PSK)) &&
+	      (hapd->conf->wpa && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) &&
 	       auth_alg == WLAN_AUTH_FT) ||
 #endif /* CONFIG_IEEE80211R */
 	      ((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) &&
@@ -430,7 +377,9 @@
 
 	res = hostapd_allowed_address(hapd, mgmt->sa, (u8 *) mgmt, len,
 				      &session_timeout,
-				      &acct_interim_interval, &vlan_id);
+				      &acct_interim_interval, &vlan_id,
+				      psk, &has_psk);
+
 	if (res == HOSTAPD_ACL_REJECT) {
 		printf("Station " MACSTR " not allowed to authenticate.\n",
 		       MAC2STR(mgmt->sa));
@@ -468,6 +417,16 @@
 			       HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
 	}
 
+	if (has_psk && hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) {
+		os_free(sta->psk);
+		sta->psk = os_malloc(PMK_LEN);
+		if (sta->psk)
+			os_memcpy(sta->psk, psk, PMK_LEN);
+	} else {
+		os_free(sta->psk);
+		sta->psk = NULL;
+	}
+
 	sta->flags &= ~WLAN_STA_PREAUTH;
 	ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
 
@@ -592,15 +551,22 @@
 		     const u8 *wmm_ie, size_t wmm_ie_len)
 {
 	sta->flags &= ~WLAN_STA_WMM;
+	sta->qosinfo = 0;
 	if (wmm_ie && hapd->conf->wmm_enabled) {
-		if (hostapd_eid_wmm_valid(hapd, wmm_ie, wmm_ie_len))
+		struct wmm_information_element *wmm;
+
+		if (!hostapd_eid_wmm_valid(hapd, wmm_ie, wmm_ie_len)) {
 			hostapd_logger(hapd, sta->addr,
 				       HOSTAPD_MODULE_WPA,
 				       HOSTAPD_LEVEL_DEBUG,
 				       "invalid WMM element in association "
 				       "request");
-		else
-			sta->flags |= WLAN_STA_WMM;
+			return WLAN_STATUS_UNSPECIFIED_FAILURE;
+		}
+
+		sta->flags |= WLAN_STA_WMM;
+		wmm = (struct wmm_information_element *) wmm_ie;
+		sta->qosinfo = wmm->qos_info;
 	}
 	return WLAN_STATUS_SUCCESS;
 }
@@ -701,7 +667,7 @@
 	}
 
 #ifdef CONFIG_WPS
-	sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS);
+	sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
 	if (hapd->conf->wps_state && elems.wps_ie) {
 		wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)Association "
 			   "Request - assume WPS is used");
@@ -709,6 +675,10 @@
 		wpabuf_free(sta->wps_ie);
 		sta->wps_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
 							  WPS_IE_VENDOR_TYPE);
+		if (sta->wps_ie && wps_is_20(sta->wps_ie)) {
+			wpa_printf(MSG_DEBUG, "WPS: STA supports WPS 2.0");
+			sta->flags |= WLAN_STA_WPS2;
+		}
 		wpa_ie = NULL;
 		wpa_ie_len = 0;
 		if (sta->wps_ie && wps_validate_assoc_req(sta->wps_ie) < 0) {
@@ -854,7 +824,7 @@
 	send_len = IEEE80211_HDRLEN + sizeof(reply.u.deauth);
 	reply.u.deauth.reason_code = host_to_le16(reason_code);
 
-	if (hostapd_drv_send_mlme(hapd, &reply, send_len) < 0)
+	if (hostapd_drv_send_mlme(hapd, &reply, send_len, 0) < 0)
 		wpa_printf(MSG_INFO, "Failed to send deauth: %s",
 			   strerror(errno));
 }
@@ -917,7 +887,8 @@
 		p = hostapd_eid_wmm(hapd, p);
 
 #ifdef CONFIG_WPS
-	if (sta->flags & WLAN_STA_WPS) {
+	if ((sta->flags & WLAN_STA_WPS) ||
+	    ((sta->flags & WLAN_STA_MAYBE_WPS) && hapd->conf->wpa)) {
 		struct wpabuf *wps = wps_build_assoc_resp_ie();
 		if (wps) {
 			os_memcpy(p, wpabuf_head(wps), wpabuf_len(wps));
@@ -959,7 +930,7 @@
 
 	send_len += p - reply->u.assoc_resp.variable;
 
-	if (hostapd_drv_send_mlme(hapd, reply, send_len) < 0)
+	if (hostapd_drv_send_mlme(hapd, reply, send_len, 0) < 0)
 		wpa_printf(MSG_INFO, "Failed to send assoc resp: %s",
 			   strerror(errno));
 }
@@ -1160,15 +1131,8 @@
 		return;
 	}
 
+	ap_sta_set_authorized(hapd, sta, 0);
 	sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
-	wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED MACSTR,
-		MAC2STR(sta->addr));
-#ifdef ANDROID_BRCM_P2P_PATCH
-	if(hapd->msg_ctx_parent)
-		wpa_msg(hapd->msg_ctx_parent, MSG_INFO, AP_STA_DISCONNECTED MACSTR,
-			MAC2STR(sta->addr));
-#endif /* ANDROID_BRCM_P2P_PATCH */
-
 	wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
 	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
 		       HOSTAPD_LEVEL_INFO, "disassociated");
@@ -1199,32 +1163,26 @@
 	struct sta_info *sta;
 
 	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.deauth)) {
-		wpa_msg(hapd, MSG_DEBUG, "handle_deauth - too short payload "
-			"(len=%lu)", (unsigned long) len);
+		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "handle_deauth - too short "
+			"payload (len=%lu)", (unsigned long) len);
 		return;
 	}
 
-	wpa_msg(hapd, MSG_DEBUG, "deauthentication: STA=" MACSTR
+	wpa_msg(hapd->msg_ctx, MSG_DEBUG, "deauthentication: STA=" MACSTR
 		" reason_code=%d",
 		MAC2STR(mgmt->sa), le_to_host16(mgmt->u.deauth.reason_code));
 
 	sta = ap_get_sta(hapd, mgmt->sa);
 	if (sta == NULL) {
-		wpa_msg(hapd, MSG_DEBUG, "Station " MACSTR " trying to "
-			"deauthenticate, but it is not authenticated",
+		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR " trying "
+			"to deauthenticate, but it is not authenticated",
 			MAC2STR(mgmt->sa));
 		return;
 	}
 
+	ap_sta_set_authorized(hapd, sta, 0);
 	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC |
 			WLAN_STA_ASSOC_REQ_OK);
-	wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED MACSTR,
-		MAC2STR(sta->addr));
-#ifdef ANDROID_BRCM_P2P_PATCH
-	if(hapd->msg_ctx_parent)
-		wpa_msg(hapd->msg_ctx_parent, MSG_INFO, AP_STA_DISCONNECTED MACSTR,
-			MAC2STR(sta->addr));
-#endif /* ANDROID_BRCM_P2P_PATCH */
 	wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
 	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
 		       HOSTAPD_LEVEL_DEBUG, "deauthenticated");
@@ -1259,81 +1217,11 @@
 
 #ifdef CONFIG_IEEE80211W
 
-/* MLME-SAQuery.request */
-void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
-				  const u8 *addr, const u8 *trans_id)
-{
-	struct ieee80211_mgmt mgmt;
-	u8 *end;
-
-	wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Request to "
-		   MACSTR, MAC2STR(addr));
-	wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
-		    trans_id, WLAN_SA_QUERY_TR_ID_LEN);
-
-	os_memset(&mgmt, 0, sizeof(mgmt));
-	mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-					  WLAN_FC_STYPE_ACTION);
-	os_memcpy(mgmt.da, addr, ETH_ALEN);
-	os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
-	os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
-	mgmt.u.action.category = WLAN_ACTION_SA_QUERY;
-	mgmt.u.action.u.sa_query_req.action = WLAN_SA_QUERY_REQUEST;
-	os_memcpy(mgmt.u.action.u.sa_query_req.trans_id, trans_id,
-		  WLAN_SA_QUERY_TR_ID_LEN);
-	end = mgmt.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
-	if (hostapd_drv_send_mlme(hapd, &mgmt, end - (u8 *) &mgmt) < 0)
-		perror("ieee802_11_send_sa_query_req: send");
-}
-
-
-static void hostapd_sa_query_request(struct hostapd_data *hapd,
-				     const struct ieee80211_mgmt *mgmt)
-{
-	struct sta_info *sta;
-	struct ieee80211_mgmt resp;
-	u8 *end;
-
-	wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Request from "
-		   MACSTR, MAC2STR(mgmt->sa));
-	wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
-		    mgmt->u.action.u.sa_query_resp.trans_id,
-		    WLAN_SA_QUERY_TR_ID_LEN);
-
-	sta = ap_get_sta(hapd, mgmt->sa);
-	if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) {
-		wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignore SA Query Request "
-			   "from unassociated STA " MACSTR, MAC2STR(mgmt->sa));
-		return;
-	}
-
-	wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Response to "
-		   MACSTR, MAC2STR(mgmt->sa));
-
-	os_memset(&resp, 0, sizeof(resp));
-	resp.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-					  WLAN_FC_STYPE_ACTION);
-	os_memcpy(resp.da, mgmt->sa, ETH_ALEN);
-	os_memcpy(resp.sa, hapd->own_addr, ETH_ALEN);
-	os_memcpy(resp.bssid, hapd->own_addr, ETH_ALEN);
-	resp.u.action.category = WLAN_ACTION_SA_QUERY;
-	resp.u.action.u.sa_query_req.action = WLAN_SA_QUERY_RESPONSE;
-	os_memcpy(resp.u.action.u.sa_query_req.trans_id,
-		  mgmt->u.action.u.sa_query_req.trans_id,
-		  WLAN_SA_QUERY_TR_ID_LEN);
-	end = resp.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
-	if (hostapd_drv_send_mlme(hapd, &resp, end - (u8 *) &resp) < 0)
-		perror("hostapd_sa_query_request: send");
-}
-
-
 static void hostapd_sa_query_action(struct hostapd_data *hapd,
 				    const struct ieee80211_mgmt *mgmt,
 				    size_t len)
 {
-	struct sta_info *sta;
 	const u8 *end;
-	int i;
 
 	end = mgmt->u.action.u.sa_query_resp.trans_id +
 		WLAN_SA_QUERY_TR_ID_LEN;
@@ -1343,50 +1231,9 @@
 		return;
 	}
 
-	if (mgmt->u.action.u.sa_query_resp.action == WLAN_SA_QUERY_REQUEST) {
-		hostapd_sa_query_request(hapd, mgmt);
-		return;
-	}
-
-	if (mgmt->u.action.u.sa_query_resp.action != WLAN_SA_QUERY_RESPONSE) {
-		wpa_printf(MSG_DEBUG, "IEEE 802.11: Unexpected SA Query "
-			   "Action %d", mgmt->u.action.u.sa_query_resp.action);
-		return;
-	}
-
-	wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Response from "
-		   MACSTR, MAC2STR(mgmt->sa));
-	wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
-		    mgmt->u.action.u.sa_query_resp.trans_id,
-		    WLAN_SA_QUERY_TR_ID_LEN);
-
-	/* MLME-SAQuery.confirm */
-
-	sta = ap_get_sta(hapd, mgmt->sa);
-	if (sta == NULL || sta->sa_query_trans_id == NULL) {
-		wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching STA with "
-			   "pending SA Query request found");
-		return;
-	}
-
-	for (i = 0; i < sta->sa_query_count; i++) {
-		if (os_memcmp(sta->sa_query_trans_id +
-			      i * WLAN_SA_QUERY_TR_ID_LEN,
-			      mgmt->u.action.u.sa_query_resp.trans_id,
-			      WLAN_SA_QUERY_TR_ID_LEN) == 0)
-			break;
-	}
-
-	if (i >= sta->sa_query_count) {
-		wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching SA Query "
-			   "transaction identifier found");
-		return;
-	}
-
-	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
-		       HOSTAPD_LEVEL_DEBUG,
-		       "Reply to pending SA Query received");
-	ap_sta_stop_sa_query(hapd, sta);
+	ieee802_11_sa_query_action(hapd, mgmt->sa,
+				   mgmt->u.action.u.sa_query_resp.action,
+				   mgmt->u.action.u.sa_query_resp.trans_id);
 }
 
 
@@ -1401,7 +1248,10 @@
 static void handle_action(struct hostapd_data *hapd,
 			  const struct ieee80211_mgmt *mgmt, size_t len)
 {
+#if defined(CONFIG_IEEE80211W) || defined(CONFIG_IEEE80211R)
 	struct sta_info *sta;
+	sta = ap_get_sta(hapd, mgmt->sa);
+#endif /* CONFIG_IEEE80211W || CONFIG_IEEE80211R */
 
 	if (len < IEEE80211_HDRLEN + 1) {
 		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
@@ -1411,7 +1261,6 @@
 		return;
 	}
 
-	sta = ap_get_sta(hapd, mgmt->sa);
 #ifdef CONFIG_IEEE80211W
 	if (sta && (sta->flags & WLAN_STA_MFP) &&
 	    !(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP) &&
@@ -1493,7 +1342,7 @@
 		os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
 		resp->u.action.category |= 0x80;
 
-		hostapd_drv_send_mlme(hapd, resp, len);
+		hostapd_drv_send_mlme(hapd, resp, len, 0);
 		os_free(resp);
 	}
 }
@@ -1536,6 +1385,11 @@
 		mgmt->bssid[4] == 0xff && mgmt->bssid[5] == 0xff;
 
 	if (!broadcast &&
+#ifdef CONFIG_P2P
+	    /* Invitation responses can be sent with the peer MAC as BSSID */
+	    !((hapd->conf->p2p & P2P_GROUP_OWNER) &&
+	      stype == WLAN_FC_STYPE_ACTION) &&
+#endif /* CONFIG_P2P */
 	    os_memcmp(mgmt->bssid, hapd->own_addr, ETH_ALEN) != 0) {
 		printf("MGMT: BSSID=" MACSTR " not our address\n",
 		       MAC2STR(mgmt->bssid));
@@ -1574,7 +1428,7 @@
 		handle_disassoc(hapd, mgmt, len);
 		break;
 	case WLAN_FC_STYPE_DEAUTH:
-		wpa_msg(hapd, MSG_DEBUG, "mgmt::deauth");
+		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "mgmt::deauth");
 		handle_deauth(hapd, mgmt, len);
 		break;
 	case WLAN_FC_STYPE_ACTION:
@@ -1688,14 +1542,6 @@
 		 * step.
 		 */
 		ap_sta_set_authorized(hapd, sta, 1);
-		wpa_msg(hapd->msg_ctx, MSG_INFO,
-			AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr));
-#ifdef ANDROID_BRCM_P2P_PATCH
-		/* Sending the event to parent is required as SSL listens on parent ctrl iface */
-		if(hapd->msg_ctx_parent)
-			wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
-				AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr));
-#endif /* ANDROID_BRCM_P2P_PATCH */
 	}
 
 	if (reassoc)
@@ -1722,10 +1568,16 @@
 	if (hostapd_sta_add(hapd, sta->addr, sta->aid, sta->capability,
 			    sta->supported_rates, sta->supported_rates_len,
 			    sta->listen_interval,
-			    sta->flags & WLAN_STA_HT ? &ht_cap : NULL)) {
+			    sta->flags & WLAN_STA_HT ? &ht_cap : NULL,
+			    sta->flags, sta->qosinfo)) {
 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
 			       HOSTAPD_LEVEL_NOTICE,
 			       "Could not add STA to kernel driver");
+
+		ap_sta_disconnect(hapd, sta, sta->addr,
+				  WLAN_REASON_DISASSOC_AP_BUSY);
+
+		goto fail;
 	}
 
 	if (sta->flags & WLAN_STA_WDS)
@@ -1764,6 +1616,54 @@
 }
 
 
+static void handle_deauth_cb(struct hostapd_data *hapd,
+			     const struct ieee80211_mgmt *mgmt,
+			     size_t len, int ok)
+{
+	struct sta_info *sta;
+	if (mgmt->da[0] & 0x01)
+		return;
+	sta = ap_get_sta(hapd, mgmt->da);
+	if (!sta) {
+		wpa_printf(MSG_DEBUG, "handle_deauth_cb: STA " MACSTR
+			   " not found", MAC2STR(mgmt->da));
+		return;
+	}
+	if (ok)
+		wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged deauth",
+			   MAC2STR(sta->addr));
+	else
+		wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge "
+			   "deauth", MAC2STR(sta->addr));
+
+	ap_sta_deauth_cb(hapd, sta);
+}
+
+
+static void handle_disassoc_cb(struct hostapd_data *hapd,
+			       const struct ieee80211_mgmt *mgmt,
+			       size_t len, int ok)
+{
+	struct sta_info *sta;
+	if (mgmt->da[0] & 0x01)
+		return;
+	sta = ap_get_sta(hapd, mgmt->da);
+	if (!sta) {
+		wpa_printf(MSG_DEBUG, "handle_disassoc_cb: STA " MACSTR
+			   " not found", MAC2STR(mgmt->da));
+		return;
+	}
+	if (ok)
+		wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged disassoc",
+			   MAC2STR(sta->addr));
+	else
+		wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge "
+			   "disassoc", MAC2STR(sta->addr));
+
+	ap_sta_disassoc_cb(hapd, sta);
+}
+
+
 /**
  * ieee802_11_mgmt_cb - Process management frame TX status callback
  * @hapd: hostapd BSS data structure (the BSS from which the management frame
@@ -1796,7 +1696,12 @@
 		wpa_printf(MSG_EXCESSIVE, "mgmt::proberesp cb");
 		break;
 	case WLAN_FC_STYPE_DEAUTH:
-		/* ignore */
+		wpa_printf(MSG_DEBUG, "mgmt::deauth cb");
+		handle_deauth_cb(hapd, mgmt, len, ok);
+		break;
+	case WLAN_FC_STYPE_DISASSOC:
+		wpa_printf(MSG_DEBUG, "mgmt::disassoc cb");
+		handle_disassoc_cb(hapd, mgmt, len, ok);
 		break;
 	case WLAN_FC_STYPE_ACTION:
 		wpa_printf(MSG_DEBUG, "mgmt::action cb");
@@ -1853,6 +1758,55 @@
 }
 
 
+void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
+			     const u8 *data, size_t len, int ack)
+{
+	struct sta_info *sta;
+	struct hostapd_iface *iface = hapd->iface;
+
+	sta = ap_get_sta(hapd, dst);
+	if (sta == NULL && iface->num_bss > 1) {
+		size_t j;
+		for (j = 0; j < iface->num_bss; j++) {
+			hapd = iface->bss[j];
+			sta = ap_get_sta(hapd, dst);
+			if (sta)
+				break;
+		}
+	}
+	if (sta == NULL)
+		return;
+
+	ieee802_1x_eapol_tx_status(hapd, sta, data, len, ack);
+}
+
+
+void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr)
+{
+	struct sta_info *sta;
+	struct hostapd_iface *iface = hapd->iface;
+
+	sta = ap_get_sta(hapd, addr);
+	if (sta == NULL && iface->num_bss > 1) {
+		size_t j;
+		for (j = 0; j < iface->num_bss; j++) {
+			hapd = iface->bss[j];
+			sta = ap_get_sta(hapd, addr);
+			if (sta)
+				break;
+		}
+	}
+	if (sta == NULL)
+		return;
+	if (!(sta->flags & WLAN_STA_PENDING_POLL))
+		return;
+
+	wpa_printf(MSG_DEBUG, "STA " MACSTR " ACKed pending "
+		   "activity poll", MAC2STR(sta->addr));
+	sta->flags &= ~WLAN_STA_PENDING_POLL;
+}
+
+
 void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
 				int wds)
 {