nl80211: Fix WFD and WPS certification problem for GO (BRCM)

Change-Id: I5bbac818aad7c0a14fddb3beb88a6a2d87c07ea0
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 8481469..dfca9ef 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -171,6 +171,7 @@
 	u64 send_action_cookie;
 
 	unsigned int last_mgmt_freq;
+	unsigned int ap_oper_freq;
 
 	struct wpa_driver_scan_filter *filter_ssids;
 	size_t num_filter_ssids;
@@ -204,6 +205,16 @@
 				  unsigned int freq, unsigned int wait,
 				  const u8 *buf, size_t buf_len, u64 *cookie);
 static int wpa_driver_nl80211_probe_req_report(void *priv, int report);
+#ifdef ANDROID_BRCM_P2P_PATCH
+static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
+				  enum wpa_event_type type,
+				  const u8 *frame, size_t len);
+int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration);
+int wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow);
+int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon,
+				  const struct wpabuf *proberesp,
+				  const struct wpabuf *assocresp);
+#endif
 
 #ifdef HOSTAPD
 static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
@@ -810,6 +821,14 @@
 		event.rx_action.data = &mgmt->u.action.category + 1;
 		event.rx_action.len = frame + len - event.rx_action.data;
 		wpa_supplicant_event(drv->ctx, EVENT_RX_ACTION, &event);
+#ifdef ANDROID_BRCM_P2P_PATCH
+	} else if (stype == WLAN_FC_STYPE_ASSOC_REQ) {
+		mlme_event_assoc(drv, frame, len);
+	} else if (stype == WLAN_FC_STYPE_DISASSOC) {
+		mlme_event_deauth_disassoc(drv, EVENT_DISASSOC, frame, len);
+	} else if (stype == WLAN_FC_STYPE_DEAUTH) {
+		mlme_event_deauth_disassoc(drv, EVENT_DEAUTH, frame, len);
+#endif
 	} else {
 		event.rx_mgmt.frame = frame;
 		event.rx_mgmt.frame_len = len;
@@ -3730,11 +3749,7 @@
 
 	mgmt = (struct ieee80211_mgmt *) data;
 	fc = le_to_host16(mgmt->frame_control);
-#ifndef ANDROID_BRCM_P2P_PATCH
 	if (drv->nlmode == NL80211_IFTYPE_STATION &&
-#else
-	if (
-#endif
 	    WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
 	    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_RESP) {
 		/*
@@ -3745,7 +3760,18 @@
 		return nl80211_send_frame_cmd(drv, drv->last_mgmt_freq, 0,
 					      data, data_len, NULL);
 	}
-
+#ifdef ANDROID_BRCM_P2P_PATCH
+	if (drv->nlmode == NL80211_IFTYPE_AP) {
+		wpa_printf(MSG_DEBUG, "%s: Sending frame on ap_oper_freq %d using nl80211_send_frame_cmd", __func__, drv->ap_oper_freq);
+		return nl80211_send_frame_cmd(drv, drv->ap_oper_freq, 0,
+					  data, data_len, &drv->send_action_cookie);
+	}
+#else
+	if (drv->no_monitor_iface_capab && drv->nlmode == NL80211_IFTYPE_AP ) {
+		return nl80211_send_frame_cmd(drv, drv->ap_oper_freq, 0,
+					      data, data_len, NULL);
+	}
+#endif
 	if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
 	    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) {
 		/*
@@ -3759,7 +3785,7 @@
 		if (auth_alg != WLAN_AUTH_SHARED_KEY || auth_trans != 3)
 			encrypt = 0;
 	}
-
+	wpa_printf(MSG_DEBUG, "%s: Sending frame using monitor interface/l2 socket", __func__);
 	return wpa_driver_nl80211_send_frame(drv, data, data_len, encrypt);
 }
 
@@ -3776,11 +3802,7 @@
 	int ret;
 	int beacon_set;
 	int ifindex = if_nametoindex(bss->ifname);
-#ifdef ANDROID_BRCM_P2P_PATCH
-		beacon_set = 1;
-#else
-		beacon_set = bss->beacon_set;
-#endif
+	beacon_set = bss->beacon_set;
 
 	msg = nlmsg_alloc();
 	if (!msg)
@@ -4572,6 +4594,8 @@
 
 	/* TODO: setup monitor interface (and add code somewhere to remove this
 	 * when AP mode is stopped; associate with mode != 2 or drv_deinit) */
+	wpa_printf(MSG_DEBUG, "nl80211: Update ap_oper_freq with params->freq %d", params->freq);
+	drv->ap_oper_freq = params->freq;
 
 	return 0;
 }
@@ -6019,17 +6043,8 @@
 				nl80211_remove_iface(drv, ifidx);
 				return -1;
 			}
-			os_memcpy(if_addr, new_addr, ETH_ALEN);
 		}
-#ifdef ANDROID_BRCM_P2P_PATCH
-		 else {
-			/* P2P_ADDR: Driver uses a different mac address than the primary mac */
-			wpa_printf(MSG_DEBUG, "nl80211: Driver uses a "
-				   "different mac address for the Virtual I/F. Get that and store it locally");
-			os_memcpy(if_addr, new_addr, ETH_ALEN);
-
-		}
-#endif
+		os_memcpy(if_addr, new_addr, ETH_ALEN);
 	}
 #endif /* CONFIG_P2P */
 
@@ -6151,8 +6166,9 @@
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
 #ifndef ANDROID_BRCM_P2P_PATCH
-	NLA_PUT_U32(msg, NL80211_ATTR_DURATION, wait);
-#endif	
+	if (wait)
+		NLA_PUT_U32(msg, NL80211_ATTR_DURATION, wait);
+#endif
 	NLA_PUT_FLAG(msg, NL80211_ATTR_OFFCHANNEL_TX_OK);
 	NLA_PUT(msg, NL80211_ATTR_FRAME, buf_len, buf);
 
@@ -6161,7 +6177,8 @@
 	msg = NULL;
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: Frame command failed: ret=%d "
-			   "(%s)", ret, strerror(-ret));
+			   "(%s) (freq=%u wait=%u)", ret, strerror(-ret),
+			   freq, wait);
 		goto nla_put_failure;
 	}
 	wpa_printf(MSG_DEBUG, "nl80211: Frame TX command accepted; "
@@ -6320,14 +6337,7 @@
 {
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
-#ifndef ANDROID_BRCM_P2P_PATCH
-	if (drv->nlmode != NL80211_IFTYPE_STATION) {
-		wpa_printf(MSG_DEBUG, "nl80211: probe_req_report control only "
-			   "allowed in station mode (iftype=%d)",
-			   drv->nlmode);
-		return -1;
-	}
-#endif
+
 	if (!report) {
 		if (drv->nl_handle_preq) {
 			eloop_unregister_read_sock(
@@ -6826,6 +6836,11 @@
 	.add_pmkid = nl80211_add_pmkid,
 	.remove_pmkid = nl80211_remove_pmkid,
 	.flush_pmkid = nl80211_flush_pmkid,
+#ifdef ANDROID_BRCM_P2P_PATCH
+	.set_noa = wpa_driver_set_p2p_noa,
+	.set_p2p_powersave = wpa_driver_set_p2p_ps,
+	.set_ap_wps_ie = wpa_driver_set_ap_wps_p2p_ie,
+#endif
 #ifdef ANDROID
 	.driver_cmd = wpa_driver_nl80211_driver_cmd,
 #endif