iwlwifi: Eliminate association from beacon

This patch removes association from beacon
using bss_info_change handler for association

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Gregory Greenman <gregory.greenman@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
index 90ecf26..32eb414 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
@@ -275,7 +275,7 @@
 	if (flags & CMD_ASYNC)
 		cmd.meta.u.callback = iwl4965_lq_sync_callback;
 
-	if (iwl4965_is_associated(priv) && priv->assoc_station_added &&
+	if (iwl_is_associated(priv) && priv->assoc_station_added &&
 	    priv->lq_mngr.lq_ready)
 		return  iwl_send_cmd(priv, &cmd);
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index 89d600c..0171bb8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -1306,7 +1306,7 @@
 	struct iwl4965_chain_noise_data *data = NULL;
 
 	data = &(priv->chain_noise_data);
-	if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl4965_is_associated(priv)) {
+	if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) {
 		struct iwl4965_calibration_cmd cmd;
 
 		memset(&cmd, 0, sizeof(cmd));
@@ -1581,7 +1581,7 @@
 
 	data = &(priv->sensitivity_data);
 
-	if (!iwl4965_is_associated(priv)) {
+	if (!iwl_is_associated(priv)) {
 		IWL_DEBUG_CALIB("<< - not associated\n");
 		return;
 	}
@@ -3575,77 +3575,6 @@
 
 #ifdef CONFIG_IWL4965_HT
 
-/* Parsed Information Elements */
-struct ieee802_11_elems {
-	u8 *ds_params;
-	u8 ds_params_len;
-	u8 *tim;
-	u8 tim_len;
-	u8 *ibss_params;
-	u8 ibss_params_len;
-	u8 *erp_info;
-	u8 erp_info_len;
-	u8 *ht_cap_param;
-	u8 ht_cap_param_len;
-	u8 *ht_extra_param;
-	u8 ht_extra_param_len;
-};
-
-static int parse_elems(u8 *start, size_t len, struct ieee802_11_elems *elems)
-{
-	size_t left = len;
-	u8 *pos = start;
-	int unknown = 0;
-
-	memset(elems, 0, sizeof(*elems));
-
-	while (left >= 2) {
-		u8 id, elen;
-
-		id = *pos++;
-		elen = *pos++;
-		left -= 2;
-
-		if (elen > left)
-			return -1;
-
-		switch (id) {
-		case WLAN_EID_DS_PARAMS:
-			elems->ds_params = pos;
-			elems->ds_params_len = elen;
-			break;
-		case WLAN_EID_TIM:
-			elems->tim = pos;
-			elems->tim_len = elen;
-			break;
-		case WLAN_EID_IBSS_PARAMS:
-			elems->ibss_params = pos;
-			elems->ibss_params_len = elen;
-			break;
-		case WLAN_EID_ERP_INFO:
-			elems->erp_info = pos;
-			elems->erp_info_len = elen;
-			break;
-		case WLAN_EID_HT_CAPABILITY:
-			elems->ht_cap_param = pos;
-			elems->ht_cap_param_len = elen;
-			break;
-		case WLAN_EID_HT_EXTRA_INFO:
-			elems->ht_extra_param = pos;
-			elems->ht_extra_param_len = elen;
-			break;
-		default:
-			unknown++;
-			break;
-		}
-
-		left -= elen;
-		pos += elen;
-	}
-
-	return 0;
-}
-
 void iwl4965_init_ht_hw_capab(struct iwl_priv *priv,
 			      struct ieee80211_ht_info *ht_info,
 			      enum ieee80211_band band)
@@ -3862,7 +3791,6 @@
 #endif
 
 
-#define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6)
 
 /* Called for REPLY_RX (legacy ABG frames), or
  * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */
@@ -3951,7 +3879,7 @@
 	 *   which are gathered only when associated, and indicate noise
 	 *   only for the associated network channel ...
 	 * Ignore these noise values while scanning (other channels) */
-	if (iwl4965_is_associated(priv) &&
+	if (iwl_is_associated(priv) &&
 	    !test_bit(STATUS_SCANNING, &priv->status)) {
 		rx_status.noise = priv->last_rx_noise;
 		rx_status.signal = iwl4965_calc_sig_qual(rx_status.ssi,
@@ -3962,7 +3890,7 @@
 	}
 
 	/* Reset beacon noise level if not associated. */
-	if (!iwl4965_is_associated(priv))
+	if (!iwl_is_associated(priv))
 		priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
 
 	/* Set "1" to report good data frames in groups of 100 */
@@ -3983,101 +3911,9 @@
 	fc = le16_to_cpu(header->frame_control);
 	switch (fc & IEEE80211_FCTL_FTYPE) {
 	case IEEE80211_FTYPE_MGMT:
-
 		if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
 			iwl4965_update_ps_mode(priv, fc  & IEEE80211_FCTL_PM,
 						header->addr2);
-		switch (fc & IEEE80211_FCTL_STYPE) {
-		case IEEE80211_STYPE_PROBE_RESP:
-		case IEEE80211_STYPE_BEACON:
-			if ((priv->iw_mode == IEEE80211_IF_TYPE_STA &&
-			     !compare_ether_addr(header->addr2, priv->bssid)) ||
-			    (priv->iw_mode == IEEE80211_IF_TYPE_IBSS &&
-			     !compare_ether_addr(header->addr3, priv->bssid))) {
-				struct ieee80211_mgmt *mgmt =
-					(struct ieee80211_mgmt *)header;
-				u64 timestamp =
-					le64_to_cpu(mgmt->u.beacon.timestamp);
-
-				priv->timestamp0 = timestamp & 0xFFFFFFFF;
-				priv->timestamp1 =
-					(timestamp >> 32) & 0xFFFFFFFF;
-				priv->beacon_int = le16_to_cpu(
-				    mgmt->u.beacon.beacon_int);
-				if (priv->call_post_assoc_from_beacon &&
-				    (priv->iw_mode == IEEE80211_IF_TYPE_STA)) {
-					priv->call_post_assoc_from_beacon = 0;
-					queue_work(priv->workqueue,
-					    &priv->post_associate.work);
-				}
-			}
-			break;
-
-		case IEEE80211_STYPE_ACTION:
-			break;
-
-			/*
-			 * TODO: Use the new callback function from
-			 * mac80211 instead of sniffing these packets.
-			 */
-		case IEEE80211_STYPE_ASSOC_RESP:
-		case IEEE80211_STYPE_REASSOC_RESP:
-			if (network_packet) {
-#ifdef CONFIG_IWL4965_HT
-				u8 *pos = NULL;
-				struct ieee802_11_elems elems;
-#endif				/*CONFIG_IWL4965_HT */
-				struct ieee80211_mgmt *mgnt =
-					(struct ieee80211_mgmt *)header;
-
-				/* We have just associated, give some
-				 * time for the 4-way handshake if
-				 * any. Don't start scan too early. */
-				priv->next_scan_jiffies = jiffies +
-					IWL_DELAY_NEXT_SCAN_AFTER_ASSOC;
-
-				priv->assoc_id = (~((1 << 15) | (1 << 14))
-					& le16_to_cpu(mgnt->u.assoc_resp.aid));
-				priv->assoc_capability =
-					le16_to_cpu(
-						mgnt->u.assoc_resp.capab_info);
-#ifdef CONFIG_IWL4965_HT
-				pos = mgnt->u.assoc_resp.variable;
-				if (!parse_elems(pos,
-						 len - (pos - (u8 *) mgnt),
-						 &elems)) {
-					if (elems.ht_extra_param &&
-					    elems.ht_cap_param)
-						break;
-				}
-#endif				/*CONFIG_IWL4965_HT */
-				/* assoc_id is 0 no association */
-				if (!priv->assoc_id)
-					break;
-				if (priv->beacon_int)
-					queue_work(priv->workqueue,
-					    &priv->post_associate.work);
-				else
-					priv->call_post_assoc_from_beacon = 1;
-			}
-
-			break;
-
-		case IEEE80211_STYPE_PROBE_REQ:
-			if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
-			    !iwl4965_is_associated(priv)) {
-				DECLARE_MAC_BUF(mac1);
-				DECLARE_MAC_BUF(mac2);
-				DECLARE_MAC_BUF(mac3);
-
-				IWL_DEBUG_DROP("Dropping (non network): "
-					       "%s, %s, %s\n",
-					       print_mac(mac1, header->addr1),
-					       print_mac(mac2, header->addr2),
-					       print_mac(mac3, header->addr3));
-				return;
-			}
-		}
 		iwl4965_handle_data_packet(priv, 0, include_phy, rxb, &rx_status);
 		break;
 
@@ -4136,7 +3972,6 @@
 	memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]),
 	       sizeof(struct iwl4965_rx_phy_res));
 }
-
 static void iwl4965_rx_missed_beacon_notif(struct iwl_priv *priv,
 					   struct iwl4965_rx_mem_buffer *rxb)
 
@@ -4158,7 +3993,6 @@
 	}
 #endif /*CONFIG_IWL4965_SENSITIVITY*/
 }
-
 #ifdef CONFIG_IWL4965_HT
 
 /**
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h
index 8c14e9a..c8e7028 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.h
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.h
@@ -1068,7 +1068,6 @@
 	u16 active_rate;
 	u16 active_rate_basic;
 
-	u8 call_post_assoc_from_beacon;
 	u8 assoc_station_added;
 	u8 use_ant_b_for_management_frame;	/* Tx antenna selection */
 	u8 valid_antenna;	/* Bit mask of antennas actually connected */
@@ -1161,8 +1160,7 @@
 	struct sk_buff *ibss_beacon;
 
 	/* Last Rx'd beacon timestamp */
-	u32 timestamp0;
-	u32 timestamp1;
+	u64 timestamp;
 	u16 beacon_int;
 	struct iwl4965_driver_hw_info hw_setting;
 	struct ieee80211_vif *vif;
@@ -1226,7 +1224,7 @@
 	struct timer_list statistics_periodic;
 }; /*iwl_priv */
 
-static inline int iwl4965_is_associated(struct iwl_priv *priv)
+static inline int iwl_is_associated(struct iwl_priv *priv)
 {
 	return (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0;
 }
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
index 826c912..f995af6 100644
--- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -901,7 +901,7 @@
 	 * an RXON_ASSOC and the new config wants the associated mask enabled,
 	 * we must clear the associated from the active configuration
 	 * before we apply the new config */
-	if (iwl4965_is_associated(priv) &&
+	if (iwl_is_associated(priv) &&
 	    (priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK)) {
 		IWL_DEBUG_INFO("Toggling associated bit on current RXON\n");
 		active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
@@ -967,7 +967,7 @@
 
 	/* If we have set the ASSOC_MSK and we are in BSS mode then
 	 * add the IWL_AP_ID to the station rate table */
-	if (iwl4965_is_associated(priv) &&
+	if (iwl_is_associated(priv) &&
 	    (priv->iw_mode == IEEE80211_IF_TYPE_STA)) {
 		if (iwl4965_rxon_add_station(priv, priv->active_rxon.bssid_addr, 1)
 		    == IWL_INVALID_STATION) {
@@ -1319,7 +1319,7 @@
 				const u8 *dest, int left)
 {
 
-	if (!iwl4965_is_associated(priv) || !priv->ibss_beacon ||
+	if (!iwl_is_associated(priv) || !priv->ibss_beacon ||
 	    ((priv->iw_mode != IEEE80211_IF_TYPE_IBSS) &&
 	     (priv->iw_mode != IEEE80211_IF_TYPE_AP)))
 		return 0;
@@ -1582,7 +1582,7 @@
 
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	if (force || iwl4965_is_associated(priv)) {
+	if (force || iwl_is_associated(priv)) {
 		IWL_DEBUG_QOS("send QoS cmd with Qos active=%d FLAGS=0x%X\n",
 				priv->qos_data.qos_active,
 				priv->qos_data.def_qos_parm.qos_flags);
@@ -1921,13 +1921,13 @@
 	conf = ieee80211_get_hw_conf(priv->hw);
 
 	spin_lock_irqsave(&priv->lock, flags);
-	priv->rxon_timing.timestamp.dw[1] = cpu_to_le32(priv->timestamp1);
-	priv->rxon_timing.timestamp.dw[0] = cpu_to_le32(priv->timestamp0);
+	priv->rxon_timing.timestamp.dw[1] = cpu_to_le32(priv->timestamp >> 32);
+	priv->rxon_timing.timestamp.dw[0] =
+				cpu_to_le32(priv->timestamp & 0xFFFFFFFF);
 
 	priv->rxon_timing.listen_interval = INTEL_CONN_LISTEN_INTERVAL;
 
-	tsf = priv->timestamp1;
-	tsf = ((tsf << 32) | priv->timestamp0);
+	tsf = priv->timestamp;
 
 	beacon_int = priv->beacon_int;
 	spin_unlock_irqrestore(&priv->lock, flags);
@@ -2374,10 +2374,10 @@
 
 	/* drop all data frame if we are not associated */
 	if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) &&
-	   (!iwl4965_is_associated(priv) ||
+	   (!iwl_is_associated(priv) ||
 	    ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && !priv->assoc_id) ||
 	    !priv->assoc_station_added)) {
-		IWL_DEBUG_DROP("Dropping - !iwl4965_is_associated\n");
+		IWL_DEBUG_DROP("Dropping - !iwl_is_associated\n");
 		goto drop_unlock;
 	}
 
@@ -2838,7 +2838,7 @@
 	int spectrum_resp_status;
 	int duration = le16_to_cpu(params->duration);
 
-	if (iwl4965_is_associated(priv))
+	if (iwl_is_associated(priv))
 		add_time =
 		    iwl4965_usecs_to_beacons(
 			le64_to_cpu(params->start_time) - priv->last_tsf,
@@ -2853,7 +2853,7 @@
 	cmd.len = sizeof(spectrum);
 	spectrum.len = cpu_to_le16(cmd.len - sizeof(spectrum.len));
 
-	if (iwl4965_is_associated(priv))
+	if (iwl_is_associated(priv))
 		spectrum.start_time =
 		    iwl4965_add_beacon_time(priv->last_beacon_time,
 				add_time,
@@ -4504,7 +4504,7 @@
 		IWL_DEBUG(IWL_DL_INFO | IWL_DL_FW_ERRORS,
 			  "Restarting adapter due to uCode error.\n");
 
-		if (iwl4965_is_associated(priv)) {
+		if (iwl_is_associated(priv)) {
 			memcpy(&priv->recovery_rxon, &priv->active_rxon,
 			       sizeof(priv->recovery_rxon));
 			priv->error_recovering = 1;
@@ -4790,7 +4790,7 @@
 	    IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 :
 	    IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52;
 
-	if (iwl4965_is_associated(priv)) {
+	if (iwl_is_associated(priv)) {
 		/* If we're associated, we clamp the maximum passive
 		 * dwell time to be 98% of the beacon interval (minus
 		 * 2 * channel tune time) */
@@ -4830,7 +4830,7 @@
 	for (i = 0, added = 0; i < sband->n_channels; i++) {
 		if (ieee80211_frequency_to_channel(channels[i].center_freq) ==
 		    le16_to_cpu(priv->active_rxon.channel)) {
-			if (iwl4965_is_associated(priv)) {
+			if (iwl_is_associated(priv)) {
 				IWL_DEBUG_SCAN
 				    ("Skipping current channel %d\n",
 				     le16_to_cpu(priv->active_rxon.channel));
@@ -5711,7 +5711,7 @@
 
 	iwl4965_send_power_mode(priv, IWL_POWER_LEVEL(priv->power_mode));
 
-	if (iwl4965_is_associated(priv)) {
+	if (iwl_is_associated(priv)) {
 		struct iwl4965_rxon_cmd *active_rxon =
 				(struct iwl4965_rxon_cmd *)(&priv->active_rxon);
 
@@ -6129,7 +6129,7 @@
 	scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH;
 	scan->quiet_time = IWL_ACTIVE_QUIET_TIME;
 
-	if (iwl4965_is_associated(priv)) {
+	if (iwl_is_associated(priv)) {
 		u16 interval = 0;
 		u32 extra;
 		u32 suspend_time = 100;
@@ -6166,7 +6166,7 @@
 		memcpy(scan->direct_scan[0].ssid,
 		       priv->direct_ssid, priv->direct_ssid_len);
 		direct_mask = 1;
-	} else if (!iwl4965_is_associated(priv) && priv->essid_len) {
+	} else if (!iwl_is_associated(priv) && priv->essid_len) {
 		scan->direct_scan[0].id = WLAN_EID_SSID;
 		scan->direct_scan[0].len = priv->essid_len;
 		memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len);
@@ -6999,6 +6999,7 @@
 }
 #endif
 
+#define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6)
 static void iwl4965_bss_info_changed(struct ieee80211_hw *hw,
 				     struct ieee80211_vif *vif,
 				     struct ieee80211_bss_conf *bss_conf,
@@ -7006,7 +7007,11 @@
 {
 	struct iwl_priv *priv = hw->priv;
 
+	IWL_DEBUG_MAC80211("changes = 0x%X\n", changes);
+
 	if (changes & BSS_CHANGED_ERP_PREAMBLE) {
+		IWL_DEBUG_MAC80211("ERP_PREAMBLE %d\n",
+				   bss_conf->use_short_preamble);
 		if (bss_conf->use_short_preamble)
 			priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
 		else
@@ -7014,6 +7019,7 @@
 	}
 
 	if (changes & BSS_CHANGED_ERP_CTS_PROT) {
+		IWL_DEBUG_MAC80211("ERP_CTS %d\n", bss_conf->use_cts_prot);
 		if (bss_conf->use_cts_prot && (priv->band != IEEE80211_BAND_5GHZ))
 			priv->staging_rxon.flags |= RXON_FLG_TGG_PROTECT_MSK;
 		else
@@ -7021,19 +7027,30 @@
 	}
 
 	if (changes & BSS_CHANGED_HT) {
+		IWL_DEBUG_MAC80211("HT %d\n", bss_conf->assoc_ht);
 		iwl4965_ht_conf(priv, bss_conf);
 		iwl4965_set_rxon_chain(priv);
 	}
 
 	if (changes & BSS_CHANGED_ASSOC) {
-		/*
-		 * TODO:
-		 * do stuff instead of sniffing assoc resp
-		 */
+		IWL_DEBUG_MAC80211("ASSOC %d\n", bss_conf->assoc);
+		if (bss_conf->assoc) {
+			priv->assoc_id = bss_conf->aid;
+			priv->beacon_int = bss_conf->beacon_int;
+			priv->timestamp = bss_conf->timestamp;
+			priv->assoc_capability = bss_conf->assoc_capability;
+			priv->next_scan_jiffies = jiffies +
+					IWL_DELAY_NEXT_SCAN_AFTER_ASSOC;
+			queue_work(priv->workqueue, &priv->post_associate.work);
+		} else {
+			priv->assoc_id = 0;
+			IWL_DEBUG_MAC80211("DISASSOC %d\n", bss_conf->assoc);
+		}
+	} else if (changes && iwl_is_associated(priv) && priv->assoc_id) {
+			IWL_DEBUG_MAC80211("Associated Changes %d\n", changes);
+			iwl4965_send_rxon_assoc(priv);
 	}
 
-	if (iwl4965_is_associated(priv))
-		iwl4965_send_rxon_assoc(priv);
 }
 
 static int iwl4965_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
@@ -7166,7 +7183,7 @@
 
 	/* FIXME: need to differenciate between static and dynamic key
 	 * in the level of mac80211 */
-	static_key = !iwl4965_is_associated(priv);
+	static_key = !iwl_is_associated(priv);
 
 	if (!static_key) {
 		sta_id = iwl4965_hw_find_station(priv, addr);
@@ -7247,7 +7264,7 @@
 	mutex_lock(&priv->mutex);
 	if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
 		iwl4965_activate_qos(priv, 1);
-	else if (priv->assoc_id && iwl4965_is_associated(priv))
+	else if (priv->assoc_id && iwl_is_associated(priv))
 		iwl4965_activate_qos(priv, 0);
 
 	mutex_unlock(&priv->mutex);
@@ -7330,7 +7347,6 @@
 	spin_lock_irqsave(&priv->lock, flags);
 	priv->assoc_id = 0;
 	priv->assoc_capability = 0;
-	priv->call_post_assoc_from_beacon = 0;
 	priv->assoc_station_added = 0;
 
 	/* new association get rid of ibss beacon skb */
@@ -7340,8 +7356,7 @@
 	priv->ibss_beacon = NULL;
 
 	priv->beacon_int = priv->hw->conf.beacon_int;
-	priv->timestamp1 = 0;
-	priv->timestamp0 = 0;
+	priv->timestamp = 0;
 	if ((priv->iw_mode == IEEE80211_IF_TYPE_STA))
 		priv->beacon_int = 0;