diff options
Diffstat (limited to 'drivers/net/wireless/mwifiex/cfg80211.c')
| -rw-r--r-- | drivers/net/wireless/mwifiex/cfg80211.c | 484 | 
1 files changed, 364 insertions, 120 deletions
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index fbad00a5abc..b511613bba2 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -50,24 +50,24 @@ static const struct ieee80211_regdomain mwifiex_world_regdom_custom = {  		REG_RULE(2412-10, 2462+10, 40, 3, 20, 0),  		/* Channel 12 - 13 */  		REG_RULE(2467-10, 2472+10, 20, 3, 20, -			 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS), +			 NL80211_RRF_NO_IR),  		/* Channel 14 */  		REG_RULE(2484-10, 2484+10, 20, 3, 20, -			 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS | +			 NL80211_RRF_NO_IR |  			 NL80211_RRF_NO_OFDM),  		/* Channel 36 - 48 */  		REG_RULE(5180-10, 5240+10, 40, 3, 20, -			 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS), +			 NL80211_RRF_NO_IR),  		/* Channel 149 - 165 */  		REG_RULE(5745-10, 5825+10, 40, 3, 20, -			 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS), +			 NL80211_RRF_NO_IR),  		/* Channel 52 - 64 */  		REG_RULE(5260-10, 5320+10, 40, 3, 30, -			 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS | +			 NL80211_RRF_NO_IR |  			 NL80211_RRF_DFS),  		/* Channel 100 - 140 */  		REG_RULE(5500-10, 5700+10, 40, 3, 30, -			 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS | +			 NL80211_RRF_NO_IR |  			 NL80211_RRF_DFS),  	}  }; @@ -184,10 +184,10 @@ mwifiex_form_mgmt_frame(struct sk_buff *skb, const u8 *buf, size_t len)   */  static int  mwifiex_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, -			 struct ieee80211_channel *chan, bool offchan, -			 unsigned int wait, const u8 *buf, size_t len, -			 bool no_cck, bool dont_wait_for_ack, u64 *cookie) +			 struct cfg80211_mgmt_tx_params *params, u64 *cookie)  { +	const u8 *buf = params->buf; +	size_t len = params->len;  	struct sk_buff *skb;  	u16 pkt_len;  	const struct ieee80211_mgmt *mgmt; @@ -220,8 +220,10 @@ mwifiex_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,  	}  	tx_info = MWIFIEX_SKB_TXCB(skb); +	memset(tx_info, 0, sizeof(*tx_info));  	tx_info->bss_num = priv->bss_num;  	tx_info->bss_type = priv->bss_type; +	tx_info->pkt_len = pkt_len;  	mwifiex_form_mgmt_frame(skb, buf, len);  	mwifiex_queue_tx_pkt(priv, skb); @@ -251,9 +253,9 @@ mwifiex_cfg80211_mgmt_frame_register(struct wiphy *wiphy,  	if (mask != priv->mgmt_frame_mask) {  		priv->mgmt_frame_mask = mask; -		mwifiex_send_cmd_async(priv, HostCmd_CMD_MGMT_FRAME_REG, -				       HostCmd_ACT_GEN_SET, 0, -				       &priv->mgmt_frame_mask); +		mwifiex_send_cmd(priv, HostCmd_CMD_MGMT_FRAME_REG, +				 HostCmd_ACT_GEN_SET, 0, +				 &priv->mgmt_frame_mask, false);  		wiphy_dbg(wiphy, "info: mgmt frame registered\n");  	}  } @@ -514,8 +516,8 @@ static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy)  	priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); -	if (mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11D_DOMAIN_INFO, -				   HostCmd_ACT_GEN_SET, 0, NULL)) { +	if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11D_DOMAIN_INFO, +			     HostCmd_ACT_GEN_SET, 0, NULL, false)) {  		wiphy_err(wiphy, "11D: setting domain info in FW\n");  		return -1;  	} @@ -537,23 +539,33 @@ static void mwifiex_reg_notifier(struct wiphy *wiphy,  				 struct regulatory_request *request)  {  	struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); +	struct mwifiex_private *priv = mwifiex_get_priv(adapter, +							MWIFIEX_BSS_ROLE_ANY);  	wiphy_dbg(wiphy, "info: cfg80211 regulatory domain callback for %c%c\n",  		  request->alpha2[0], request->alpha2[1]); -	memcpy(adapter->country_code, request->alpha2, sizeof(request->alpha2)); -  	switch (request->initiator) {  	case NL80211_REGDOM_SET_BY_DRIVER:  	case NL80211_REGDOM_SET_BY_CORE:  	case NL80211_REGDOM_SET_BY_USER: -		break; -		/* Todo: apply driver specific changes in channel flags based -		   on the request initiator if necessary. */  	case NL80211_REGDOM_SET_BY_COUNTRY_IE:  		break; +	default: +		wiphy_err(wiphy, "unknown regdom initiator: %d\n", +			  request->initiator); +		return; +	} + +	/* Don't send world or same regdom info to firmware */ +	if (strncmp(request->alpha2, "00", 2) && +	    strncmp(request->alpha2, adapter->country_code, +		    sizeof(request->alpha2))) { +		memcpy(adapter->country_code, request->alpha2, +		       sizeof(request->alpha2)); +		mwifiex_send_domain_info_cmd_fw(wiphy); +		mwifiex_dnld_txpwr_table(priv);  	} -	mwifiex_send_domain_info_cmd_fw(wiphy);  }  /* @@ -569,9 +581,9 @@ mwifiex_set_frag(struct mwifiex_private *priv, u32 frag_thr)  	    frag_thr > MWIFIEX_FRAG_MAX_VALUE)  		frag_thr = MWIFIEX_FRAG_MAX_VALUE; -	return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB, -				     HostCmd_ACT_GEN_SET, FRAG_THRESH_I, -				     &frag_thr); +	return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB, +				HostCmd_ACT_GEN_SET, FRAG_THRESH_I, +				&frag_thr, true);  }  /* @@ -586,9 +598,9 @@ mwifiex_set_rts(struct mwifiex_private *priv, u32 rts_thr)  	if (rts_thr < MWIFIEX_RTS_MIN_VALUE || rts_thr > MWIFIEX_RTS_MAX_VALUE)  		rts_thr = MWIFIEX_RTS_MAX_VALUE; -	return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB, -				    HostCmd_ACT_GEN_SET, RTS_THRESH_I, -				    &rts_thr); +	return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB, +				HostCmd_ACT_GEN_SET, RTS_THRESH_I, +				&rts_thr, true);  }  /* @@ -626,20 +638,19 @@ mwifiex_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)  			bss_started = priv->bss_started; -			ret = mwifiex_send_cmd_sync(priv, -						    HostCmd_CMD_UAP_BSS_STOP, -						    HostCmd_ACT_GEN_SET, 0, -						    NULL); +			ret = mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP, +					       HostCmd_ACT_GEN_SET, 0, +					       NULL, true);  			if (ret) {  				wiphy_err(wiphy, "Failed to stop the BSS\n");  				kfree(bss_cfg);  				return ret;  			} -			ret = mwifiex_send_cmd_async(priv, -						     HostCmd_CMD_UAP_SYS_CONFIG, -						     HostCmd_ACT_GEN_SET, -						     UAP_BSS_PARAMS_I, bss_cfg); +			ret = mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG, +					       HostCmd_ACT_GEN_SET, +					       UAP_BSS_PARAMS_I, bss_cfg, +					       false);  			kfree(bss_cfg); @@ -651,10 +662,9 @@ mwifiex_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)  			if (!bss_started)  				break; -			ret = mwifiex_send_cmd_async(priv, -						     HostCmd_CMD_UAP_BSS_START, -						     HostCmd_ACT_GEN_SET, 0, -						     NULL); +			ret = mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_START, +					       HostCmd_ACT_GEN_SET, 0, +					       NULL, false);  			if (ret) {  				wiphy_err(wiphy, "Failed to start BSS\n");  				return ret; @@ -689,8 +699,8 @@ mwifiex_cfg80211_deinit_p2p(struct mwifiex_private *priv)  	if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA)  		mwifiex_set_bss_role(priv, MWIFIEX_BSS_ROLE_STA); -	if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_P2P_MODE_CFG, -				  HostCmd_ACT_GEN_SET, 0, &mode)) +	if (mwifiex_send_cmd(priv, HostCmd_CMD_P2P_MODE_CFG, +			     HostCmd_ACT_GEN_SET, 0, &mode, true))  		return -1;  	return 0; @@ -710,13 +720,13 @@ mwifiex_cfg80211_init_p2p_client(struct mwifiex_private *priv)  		return -1;  	mode = P2P_MODE_DEVICE; -	if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_P2P_MODE_CFG, -				  HostCmd_ACT_GEN_SET, 0, &mode)) +	if (mwifiex_send_cmd(priv, HostCmd_CMD_P2P_MODE_CFG, +			     HostCmd_ACT_GEN_SET, 0, &mode, true))  		return -1;  	mode = P2P_MODE_CLIENT; -	if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_P2P_MODE_CFG, -				  HostCmd_ACT_GEN_SET, 0, &mode)) +	if (mwifiex_send_cmd(priv, HostCmd_CMD_P2P_MODE_CFG, +			     HostCmd_ACT_GEN_SET, 0, &mode, true))  		return -1;  	return 0; @@ -736,13 +746,13 @@ mwifiex_cfg80211_init_p2p_go(struct mwifiex_private *priv)  		return -1;  	mode = P2P_MODE_DEVICE; -	if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_P2P_MODE_CFG, -				  HostCmd_ACT_GEN_SET, 0, &mode)) +	if (mwifiex_send_cmd(priv, HostCmd_CMD_P2P_MODE_CFG, +			     HostCmd_ACT_GEN_SET, 0, &mode, true))  		return -1;  	mode = P2P_MODE_GO; -	if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_P2P_MODE_CFG, -				  HostCmd_ACT_GEN_SET, 0, &mode)) +	if (mwifiex_send_cmd(priv, HostCmd_CMD_P2P_MODE_CFG, +			     HostCmd_ACT_GEN_SET, 0, &mode, true))  		return -1;  	if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_UAP) @@ -842,8 +852,8 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy,  	priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM; -	ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_SET_BSS_MODE, -				    HostCmd_ACT_GEN_SET, 0, NULL); +	ret = mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE, +			       HostCmd_ACT_GEN_SET, 0, NULL, true);  	return ret;  } @@ -931,8 +941,8 @@ mwifiex_dump_station_info(struct mwifiex_private *priv,  			STATION_INFO_SIGNAL | STATION_INFO_SIGNAL_AVG;  	/* Get signal information from the firmware */ -	if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_RSSI_INFO, -				  HostCmd_ACT_GEN_GET, 0, NULL)) { +	if (mwifiex_send_cmd(priv, HostCmd_CMD_RSSI_INFO, +			     HostCmd_ACT_GEN_GET, 0, NULL, true)) {  		dev_err(priv->adapter->dev, "failed to get signal information\n");  		return -EFAULT;  	} @@ -943,9 +953,9 @@ mwifiex_dump_station_info(struct mwifiex_private *priv,  	}  	/* Get DTIM period information from firmware */ -	mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB, -			      HostCmd_ACT_GEN_GET, DTIM_PERIOD_I, -			      &priv->dtim_period); +	mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB, +			 HostCmd_ACT_GEN_GET, DTIM_PERIOD_I, +			 &priv->dtim_period, true);  	mwifiex_parse_htinfo(priv, priv->tx_htinfo, &sinfo->txrate); @@ -985,7 +995,7 @@ mwifiex_dump_station_info(struct mwifiex_private *priv,   */  static int  mwifiex_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, -			     u8 *mac, struct station_info *sinfo) +			     const u8 *mac, struct station_info *sinfo)  {  	struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); @@ -1149,9 +1159,10 @@ static int mwifiex_cfg80211_set_bitrate_mask(struct wiphy *wiphy,  	struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);  	u16 bitmap_rates[MAX_BITMAP_RATES_SIZE];  	enum ieee80211_band band; +	struct mwifiex_adapter *adapter = priv->adapter;  	if (!priv->media_connected) { -		dev_err(priv->adapter->dev, +		dev_err(adapter->dev,  			"Can not set Tx data rate in disconnected state\n");  		return -EINVAL;  	} @@ -1170,13 +1181,20 @@ static int mwifiex_cfg80211_set_bitrate_mask(struct wiphy *wiphy,  	else  		bitmap_rates[1] = mask->control[band].legacy; -	/* Fill MCS rates */ -	bitmap_rates[2] = mask->control[band].mcs[0]; -	if (priv->adapter->hw_dev_mcs_support == HT_STREAM_2X2) -		bitmap_rates[2] |= mask->control[band].mcs[1] << 8; +	/* Fill HT MCS rates */ +	bitmap_rates[2] = mask->control[band].ht_mcs[0]; +	if (adapter->hw_dev_mcs_support == HT_STREAM_2X2) +		bitmap_rates[2] |= mask->control[band].ht_mcs[1] << 8; + +       /* Fill VHT MCS rates */ +	if (adapter->fw_api_ver == MWIFIEX_FW_V15) { +		bitmap_rates[10] = mask->control[band].vht_mcs[0]; +		if (adapter->hw_dev_mcs_support == HT_STREAM_2X2) +			bitmap_rates[11] = mask->control[band].vht_mcs[1]; +	} -	return mwifiex_send_cmd_sync(priv, HostCmd_CMD_TX_RATE_CFG, -				     HostCmd_ACT_GEN_SET, 0, bitmap_rates); +	return mwifiex_send_cmd(priv, HostCmd_CMD_TX_RATE_CFG, +				HostCmd_ACT_GEN_SET, 0, bitmap_rates, true);  }  /* @@ -1205,14 +1223,14 @@ static int mwifiex_cfg80211_set_cqm_rssi_config(struct wiphy *wiphy,  		subsc_evt.bcn_h_rssi_cfg.abs_value = abs(rssi_thold);  		subsc_evt.bcn_l_rssi_cfg.evt_freq = 1;  		subsc_evt.bcn_h_rssi_cfg.evt_freq = 1; -		return mwifiex_send_cmd_sync(priv, -					     HostCmd_CMD_802_11_SUBSCRIBE_EVENT, -					     0, 0, &subsc_evt); +		return mwifiex_send_cmd(priv, +					HostCmd_CMD_802_11_SUBSCRIBE_EVENT, +					0, 0, &subsc_evt, true);  	} else {  		subsc_evt.action = HostCmd_ACT_BITWISE_CLR; -		return mwifiex_send_cmd_sync(priv, -					     HostCmd_CMD_802_11_SUBSCRIBE_EVENT, -					     0, 0, &subsc_evt); +		return mwifiex_send_cmd(priv, +					HostCmd_CMD_802_11_SUBSCRIBE_EVENT, +					0, 0, &subsc_evt, true);  	}  	return 0; @@ -1253,7 +1271,7 @@ static int mwifiex_cfg80211_change_beacon(struct wiphy *wiphy,   */  static int  mwifiex_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev, -			     u8 *mac) +			     const u8 *mac)  {  	struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);  	struct mwifiex_sta_node *sta_node; @@ -1265,10 +1283,9 @@ mwifiex_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev,  	if (!mac || is_broadcast_ether_addr(mac)) {  		wiphy_dbg(wiphy, "%s: NULL/broadcast mac address\n", __func__);  		list_for_each_entry(sta_node, &priv->sta_list, list) { -			if (mwifiex_send_cmd_sync(priv, -						  HostCmd_CMD_UAP_STA_DEAUTH, -						  HostCmd_ACT_GEN_SET, 0, -						  sta_node->mac_addr)) +			if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_STA_DEAUTH, +					     HostCmd_ACT_GEN_SET, 0, +					     sta_node->mac_addr, true))  				return -1;  			mwifiex_uap_del_sta_data(priv, sta_node);  		} @@ -1278,10 +1295,9 @@ mwifiex_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev,  		sta_node = mwifiex_get_sta_entry(priv, mac);  		spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);  		if (sta_node) { -			if (mwifiex_send_cmd_sync(priv, -						  HostCmd_CMD_UAP_STA_DEAUTH, -						  HostCmd_ACT_GEN_SET, 0, -						  sta_node->mac_addr)) +			if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_STA_DEAUTH, +					     HostCmd_ACT_GEN_SET, 0, +					     sta_node->mac_addr, true))  				return -1;  			mwifiex_uap_del_sta_data(priv, sta_node);  		} @@ -1317,13 +1333,40 @@ mwifiex_cfg80211_set_antenna(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant)  			tx_ant = RF_ANTENNA_AUTO;  			rx_ant = RF_ANTENNA_AUTO;  		} +	} else { +		struct ieee80211_sta_ht_cap *ht_info; +		int rx_mcs_supp; +		enum ieee80211_band band; + +		if ((tx_ant == 0x1 && rx_ant == 0x1)) { +			adapter->user_dev_mcs_support = HT_STREAM_1X1; +			if (adapter->is_hw_11ac_capable) +				adapter->usr_dot_11ac_mcs_support = +						MWIFIEX_11AC_MCS_MAP_1X1; +		} else { +			adapter->user_dev_mcs_support = HT_STREAM_2X2; +			if (adapter->is_hw_11ac_capable) +				adapter->usr_dot_11ac_mcs_support = +						MWIFIEX_11AC_MCS_MAP_2X2; +		} + +		for (band = 0; band < IEEE80211_NUM_BANDS; band++) { +			if (!adapter->wiphy->bands[band]) +				continue; + +			ht_info = &adapter->wiphy->bands[band]->ht_cap; +			rx_mcs_supp = +				GET_RXMCSSUPP(adapter->user_dev_mcs_support); +			memset(&ht_info->mcs, 0, adapter->number_of_antenna); +			memset(&ht_info->mcs, 0xff, rx_mcs_supp); +		}  	}  	ant_cfg.tx_ant = tx_ant;  	ant_cfg.rx_ant = rx_ant; -	return mwifiex_send_cmd_sync(priv, HostCmd_CMD_RF_ANTENNA, -				     HostCmd_ACT_GEN_SET, 0, &ant_cfg); +	return mwifiex_send_cmd(priv, HostCmd_CMD_RF_ANTENNA, +				HostCmd_ACT_GEN_SET, 0, &ant_cfg, true);  }  /* cfg80211 operation handler for stop ap. @@ -1338,8 +1381,8 @@ static int mwifiex_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)  	priv->ap_11n_enabled = 0; -	if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_UAP_BSS_STOP, -				  HostCmd_ACT_GEN_SET, 0, NULL)) { +	if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP, +			     HostCmd_ACT_GEN_SET, 0, NULL, true)) {  		wiphy_err(wiphy, "Failed to stop the BSS\n");  		return -1;  	} @@ -1405,9 +1448,6 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,  		if (params->chandef.width > NL80211_CHAN_WIDTH_20_NOHT)  			config_bands |= BAND_GN; - -		if (params->chandef.width > NL80211_CHAN_WIDTH_40) -			config_bands |= BAND_GAC;  	} else {  		bss_cfg->band_cfg = BAND_CONFIG_A;  		config_bands = BAND_A; @@ -1453,16 +1493,16 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,  		bss_cfg->ps_sta_ao_timer = 10 * params->inactivity_timeout;  	} -	if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_UAP_BSS_STOP, -				  HostCmd_ACT_GEN_SET, 0, NULL)) { +	if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP, +			     HostCmd_ACT_GEN_SET, 0, NULL, true)) {  		wiphy_err(wiphy, "Failed to stop the BSS\n");  		kfree(bss_cfg);  		return -1;  	} -	if (mwifiex_send_cmd_async(priv, HostCmd_CMD_UAP_SYS_CONFIG, -				   HostCmd_ACT_GEN_SET, -				   UAP_BSS_PARAMS_I, bss_cfg)) { +	if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG, +			     HostCmd_ACT_GEN_SET, +			     UAP_BSS_PARAMS_I, bss_cfg, false)) {  		wiphy_err(wiphy, "Failed to set the SSID\n");  		kfree(bss_cfg);  		return -1; @@ -1470,8 +1510,8 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,  	kfree(bss_cfg); -	if (mwifiex_send_cmd_async(priv, HostCmd_CMD_UAP_BSS_START, -				   HostCmd_ACT_GEN_SET, 0, NULL)) { +	if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_START, +			     HostCmd_ACT_GEN_SET, 0, NULL, false)) {  		wiphy_err(wiphy, "Failed to start the BSS\n");  		return -1;  	} @@ -1481,9 +1521,9 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,  	else  		priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE; -	if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_MAC_CONTROL, -				  HostCmd_ACT_GEN_SET, 0, -				  &priv->curr_pkt_filter)) +	if (mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL, +			     HostCmd_ACT_GEN_SET, 0, +			     &priv->curr_pkt_filter, true))  		return -1;  	return 0; @@ -1572,8 +1612,9 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv)   * the function notifies the CFG802.11 subsystem of the new BSS connection.   */  static int -mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, -		       u8 *bssid, int mode, struct ieee80211_channel *channel, +mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, +		       const u8 *ssid, const u8 *bssid, int mode, +		       struct ieee80211_channel *channel,  		       struct cfg80211_connect_params *sme, bool privacy)  {  	struct cfg80211_ssid req_ssid; @@ -1870,7 +1911,8 @@ mwifiex_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,  				     params->privacy);  done:  	if (!ret) { -		cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid, GFP_KERNEL); +		cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid, +				     params->chandef.chan, GFP_KERNEL);  		dev_dbg(priv->adapter->dev,  			"info: joined/created adhoc network with bssid"  			" %pM successfully\n", priv->cfg_bssid); @@ -1968,7 +2010,7 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,  		user_scan_cfg->chan_list[i].chan_number = chan->hw_value;  		user_scan_cfg->chan_list[i].radio_type = chan->band; -		if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) +		if (chan->flags & IEEE80211_CHAN_NO_IR)  			user_scan_cfg->chan_list[i].scan_type =  						MWIFIEX_SCAN_TYPE_PASSIVE;  		else @@ -2059,10 +2101,10 @@ mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info,  	else  		ht_info->cap &= ~IEEE80211_HT_CAP_SGI_40; -	if (ISSUPP_RXSTBC(adapter->hw_dot_11n_dev_cap)) -		ht_info->cap |= 1 << IEEE80211_HT_CAP_RX_STBC_SHIFT; +	if (adapter->user_dev_mcs_support == HT_STREAM_2X2) +		ht_info->cap |= 3 << IEEE80211_HT_CAP_RX_STBC_SHIFT;  	else -		ht_info->cap &= ~(3 << IEEE80211_HT_CAP_RX_STBC_SHIFT); +		ht_info->cap |= 1 << IEEE80211_HT_CAP_RX_STBC_SHIFT;  	if (ISSUPP_TXSTBC(adapter->hw_dot_11n_dev_cap))  		ht_info->cap |= IEEE80211_HT_CAP_TX_STBC; @@ -2087,8 +2129,8 @@ mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info,  	ht_info->cap &= ~IEEE80211_HT_CAP_MAX_AMSDU;  	ht_info->cap |= IEEE80211_HT_CAP_SM_PS; -	rx_mcs_supp = GET_RXMCSSUPP(adapter->hw_dev_mcs_support); -	/* Set MCS for 1x1 */ +	rx_mcs_supp = GET_RXMCSSUPP(adapter->user_dev_mcs_support); +	/* Set MCS for 1x1/2x2 */  	memset(mcs, 0xff, rx_mcs_supp);  	/* Clear all the other values */  	memset(&mcs[rx_mcs_supp], 0, @@ -2210,8 +2252,10 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,  		priv->bss_started = 0;  		priv->bss_num = 0; -		if (mwifiex_cfg80211_init_p2p_client(priv)) -			return ERR_PTR(-EFAULT); +		if (mwifiex_cfg80211_init_p2p_client(priv)) { +			wdev = ERR_PTR(-EFAULT); +			goto done; +		}  		break;  	default: @@ -2224,7 +2268,8 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,  	if (!dev) {  		wiphy_err(wiphy, "no memory available for netdevice\n");  		priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; -		return ERR_PTR(-ENOMEM); +		wdev = ERR_PTR(-ENOMEM); +		goto done;  	}  	mwifiex_init_priv_params(priv, dev); @@ -2264,7 +2309,9 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,  		wiphy_err(wiphy, "cannot register virtual network device\n");  		free_netdev(dev);  		priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; -		return ERR_PTR(-EFAULT); +		priv->netdev = NULL; +		wdev = ERR_PTR(-EFAULT); +		goto done;  	}  	sema_init(&priv->async_sem, 1); @@ -2274,6 +2321,13 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,  #ifdef CONFIG_DEBUG_FS  	mwifiex_dev_debugfs_init(priv);  #endif + +done: +	if (IS_ERR(wdev)) { +		kfree(priv->wdev); +		priv->wdev = NULL; +	} +  	return wdev;  }  EXPORT_SYMBOL_GPL(mwifiex_add_virtual_intf); @@ -2298,7 +2352,10 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)  		unregister_netdevice(wdev->netdev);  	/* Clear the priv in adapter */ +	priv->netdev->ieee80211_ptr = NULL;  	priv->netdev = NULL; +	kfree(wdev); +	priv->wdev = NULL;  	priv->media_connected = false; @@ -2423,7 +2480,7 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy,  		       ETH_ALEN);  		mef_entry->filter[filt_num].byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] =  								ETH_ALEN; -		mef_entry->filter[filt_num].offset = 14; +		mef_entry->filter[filt_num].offset = 28;  		mef_entry->filter[filt_num].filt_type = TYPE_EQ;  		if (filt_num)  			mef_entry->filter[filt_num].filt_action = TYPE_OR; @@ -2434,9 +2491,8 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy,  				   MWIFIEX_CRITERIA_UNICAST |  				   MWIFIEX_CRITERIA_MULTICAST; -	ret =  mwifiex_send_cmd_sync(priv, HostCmd_CMD_MEF_CFG, -				     HostCmd_ACT_GEN_SET, 0, -				     &mef_cfg); +	ret = mwifiex_send_cmd(priv, HostCmd_CMD_MEF_CFG, +			       HostCmd_ACT_GEN_SET, 0, &mef_cfg, true);  	kfree(mef_entry);  	return ret; @@ -2548,9 +2604,9 @@ static int mwifiex_cfg80211_set_coalesce(struct wiphy *wiphy,  	if (!coalesce) {  		dev_dbg(adapter->dev,  			"Disable coalesce and reset all previous rules\n"); -		return mwifiex_send_cmd_sync(priv, HostCmd_CMD_COALESCE_CFG, -					     HostCmd_ACT_GEN_SET, 0, -					     &coalesce_cfg); +		return mwifiex_send_cmd(priv, HostCmd_CMD_COALESCE_CFG, +					HostCmd_ACT_GEN_SET, 0, +					&coalesce_cfg, true);  	}  	coalesce_cfg.num_of_rules = coalesce->n_rules; @@ -2565,8 +2621,171 @@ static int mwifiex_cfg80211_set_coalesce(struct wiphy *wiphy,  		}  	} -	return mwifiex_send_cmd_sync(priv, HostCmd_CMD_COALESCE_CFG, -				     HostCmd_ACT_GEN_SET, 0, &coalesce_cfg); +	return mwifiex_send_cmd(priv, HostCmd_CMD_COALESCE_CFG, +				HostCmd_ACT_GEN_SET, 0, &coalesce_cfg, true); +} + +/* cfg80211 ops handler for tdls_mgmt. + * Function prepares TDLS action frame packets and forwards them to FW + */ +static int +mwifiex_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, +			   const u8 *peer, u8 action_code, u8 dialog_token, +			   u16 status_code, u32 peer_capability, +			   const u8 *extra_ies, size_t extra_ies_len) +{ +	struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); +	int ret; + +	if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)) +		return -ENOTSUPP; + +	/* make sure we are in station mode and connected */ +	if (!(priv->bss_type == MWIFIEX_BSS_TYPE_STA && priv->media_connected)) +		return -ENOTSUPP; + +	switch (action_code) { +	case WLAN_TDLS_SETUP_REQUEST: +		dev_dbg(priv->adapter->dev, +			"Send TDLS Setup Request to %pM status_code=%d\n", peer, +			 status_code); +		ret = mwifiex_send_tdls_data_frame(priv, peer, action_code, +						   dialog_token, status_code, +						   extra_ies, extra_ies_len); +		break; +	case WLAN_TDLS_SETUP_RESPONSE: +		dev_dbg(priv->adapter->dev, +			"Send TDLS Setup Response to %pM status_code=%d\n", +			peer, status_code); +		ret = mwifiex_send_tdls_data_frame(priv, peer, action_code, +						   dialog_token, status_code, +						   extra_ies, extra_ies_len); +		break; +	case WLAN_TDLS_SETUP_CONFIRM: +		dev_dbg(priv->adapter->dev, +			"Send TDLS Confirm to %pM status_code=%d\n", peer, +			status_code); +		ret = mwifiex_send_tdls_data_frame(priv, peer, action_code, +						   dialog_token, status_code, +						   extra_ies, extra_ies_len); +		break; +	case WLAN_TDLS_TEARDOWN: +		dev_dbg(priv->adapter->dev, "Send TDLS Tear down to %pM\n", +			peer); +		ret = mwifiex_send_tdls_data_frame(priv, peer, action_code, +						   dialog_token, status_code, +						   extra_ies, extra_ies_len); +		break; +	case WLAN_TDLS_DISCOVERY_REQUEST: +		dev_dbg(priv->adapter->dev, +			"Send TDLS Discovery Request to %pM\n", peer); +		ret = mwifiex_send_tdls_data_frame(priv, peer, action_code, +						   dialog_token, status_code, +						   extra_ies, extra_ies_len); +		break; +	case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: +		dev_dbg(priv->adapter->dev, +			"Send TDLS Discovery Response to %pM\n", peer); +		ret = mwifiex_send_tdls_action_frame(priv, peer, action_code, +						   dialog_token, status_code, +						   extra_ies, extra_ies_len); +		break; +	default: +		dev_warn(priv->adapter->dev, +			 "Unknown TDLS mgmt/action frame %pM\n", peer); +		ret = -EINVAL; +		break; +	} + +	return ret; +} + +static int +mwifiex_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, +			   const u8 *peer, enum nl80211_tdls_operation action) +{ +	struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + +	if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) || +	    !(wiphy->flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP)) +		return -ENOTSUPP; + +	/* make sure we are in station mode and connected */ +	if (!(priv->bss_type == MWIFIEX_BSS_TYPE_STA && priv->media_connected)) +		return -ENOTSUPP; + +	dev_dbg(priv->adapter->dev, +		"TDLS peer=%pM, oper=%d\n", peer, action); + +	switch (action) { +	case NL80211_TDLS_ENABLE_LINK: +		action = MWIFIEX_TDLS_ENABLE_LINK; +		break; +	case NL80211_TDLS_DISABLE_LINK: +		action = MWIFIEX_TDLS_DISABLE_LINK; +		break; +	case NL80211_TDLS_TEARDOWN: +		/* shouldn't happen!*/ +		dev_warn(priv->adapter->dev, +			 "tdls_oper: teardown from driver not supported\n"); +		return -EINVAL; +	case NL80211_TDLS_SETUP: +		/* shouldn't happen!*/ +		dev_warn(priv->adapter->dev, +			 "tdls_oper: setup from driver not supported\n"); +		return -EINVAL; +	case NL80211_TDLS_DISCOVERY_REQ: +		/* shouldn't happen!*/ +		dev_warn(priv->adapter->dev, +			 "tdls_oper: discovery from driver not supported\n"); +		return -EINVAL; +	default: +		dev_err(priv->adapter->dev, +			"tdls_oper: operation not supported\n"); +		return -ENOTSUPP; +	} + +	return mwifiex_tdls_oper(priv, peer, action); +} + +static int +mwifiex_cfg80211_add_station(struct wiphy *wiphy, struct net_device *dev, +			     const u8 *mac, struct station_parameters *params) +{ +	struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + +	if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) +		return -ENOTSUPP; + +	/* make sure we are in station mode and connected */ +	if ((priv->bss_type != MWIFIEX_BSS_TYPE_STA) || !priv->media_connected) +		return -ENOTSUPP; + +	return mwifiex_tdls_oper(priv, mac, MWIFIEX_TDLS_CREATE_LINK); +} + +static int +mwifiex_cfg80211_change_station(struct wiphy *wiphy, struct net_device *dev, +				const u8 *mac, +				struct station_parameters *params) +{ +	int ret; +	struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + +	/* we support change_station handler only for TDLS peers*/ +	if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) +		return -ENOTSUPP; + +	/* make sure we are in station mode and connected */ +	if ((priv->bss_type != MWIFIEX_BSS_TYPE_STA) || !priv->media_connected) +		return -ENOTSUPP; + +	priv->sta_params = params; + +	ret = mwifiex_tdls_oper(priv, mac, MWIFIEX_TDLS_CONFIG_LINK); +	priv->sta_params = NULL; + +	return ret;  }  /* station cfg80211 operations */ @@ -2604,6 +2823,10 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {  	.set_wakeup = mwifiex_cfg80211_set_wakeup,  #endif  	.set_coalesce = mwifiex_cfg80211_set_coalesce, +	.tdls_mgmt = mwifiex_cfg80211_tdls_mgmt, +	.tdls_oper = mwifiex_cfg80211_tdls_oper, +	.add_station = mwifiex_cfg80211_add_station, +	.change_station = mwifiex_cfg80211_change_station,  };  #ifdef CONFIG_PM @@ -2651,6 +2874,7 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)  	struct wiphy *wiphy;  	struct mwifiex_private *priv = adapter->priv[MWIFIEX_BSS_TYPE_STA];  	u8 *country_code; +	u32 thr, retry;  	/* create a new wiphy for use with cfg80211 */  	wiphy = wiphy_new(&mwifiex_cfg80211_ops, @@ -2687,10 +2911,16 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)  	wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME |  			WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD |  			WIPHY_FLAG_AP_UAPSD | -			WIPHY_FLAG_CUSTOM_REGULATORY | -			WIPHY_FLAG_STRICT_REGULATORY |  			WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; +	if (ISSUPP_TDLS_ENABLED(adapter->fw_cap_info)) +		wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS | +				WIPHY_FLAG_TDLS_EXTERNAL_SETUP; + +	wiphy->regulatory_flags |= +			REGULATORY_CUSTOM_REG | +			REGULATORY_STRICT_REG; +  	wiphy_apply_custom_regulatory(wiphy, &mwifiex_world_regdom_custom);  #ifdef CONFIG_PM @@ -2708,7 +2938,8 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)  	wiphy->features |= NL80211_FEATURE_HT_IBSS |  			   NL80211_FEATURE_INACTIVITY_TIMER | -			   NL80211_FEATURE_LOW_PRIORITY_SCAN; +			   NL80211_FEATURE_LOW_PRIORITY_SCAN | +			   NL80211_FEATURE_NEED_OBSS_SCAN;  	/* Reserve space for mwifiex specific private data for BSS */  	wiphy->bss_priv_size = sizeof(struct mwifiex_bss_priv); @@ -2739,6 +2970,19 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)  				   country_code);  	} +	mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB, +			 HostCmd_ACT_GEN_GET, FRAG_THRESH_I, &thr, true); +	wiphy->frag_threshold = thr; +	mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB, +			 HostCmd_ACT_GEN_GET, RTS_THRESH_I, &thr, true); +	wiphy->rts_threshold = thr; +	mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB, +			 HostCmd_ACT_GEN_GET, SHORT_RETRY_LIM_I, &retry, true); +	wiphy->retry_short = (u8) retry; +	mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB, +			 HostCmd_ACT_GEN_GET, LONG_RETRY_LIM_I, &retry, true); +	wiphy->retry_long = (u8) retry; +  	adapter->wiphy = wiphy;  	return ret;  }  | 
