Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
This commit is contained in:
		
				commit
				
					
						f20b6213f1
					
				
			
		
					 106 changed files with 1761 additions and 717 deletions
				
			
		|  | @ -48,12 +48,12 @@ config BCMA_DRIVER_MIPS | ||||||
| 
 | 
 | ||||||
| config BCMA_SFLASH | config BCMA_SFLASH | ||||||
| 	bool | 	bool | ||||||
| 	depends on BCMA_DRIVER_MIPS && BROKEN | 	depends on BCMA_DRIVER_MIPS | ||||||
| 	default y | 	default y | ||||||
| 
 | 
 | ||||||
| config BCMA_NFLASH | config BCMA_NFLASH | ||||||
| 	bool | 	bool | ||||||
| 	depends on BCMA_DRIVER_MIPS && BROKEN | 	depends on BCMA_DRIVER_MIPS | ||||||
| 	default y | 	default y | ||||||
| 
 | 
 | ||||||
| config BCMA_DRIVER_GMAC_CMN | config BCMA_DRIVER_GMAC_CMN | ||||||
|  |  | ||||||
|  | @ -54,6 +54,7 @@ u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc); | ||||||
| #ifdef CONFIG_BCMA_SFLASH | #ifdef CONFIG_BCMA_SFLASH | ||||||
| /* driver_chipcommon_sflash.c */ | /* driver_chipcommon_sflash.c */ | ||||||
| int bcma_sflash_init(struct bcma_drv_cc *cc); | int bcma_sflash_init(struct bcma_drv_cc *cc); | ||||||
|  | extern struct platform_device bcma_sflash_dev; | ||||||
| #else | #else | ||||||
| static inline int bcma_sflash_init(struct bcma_drv_cc *cc) | static inline int bcma_sflash_init(struct bcma_drv_cc *cc) | ||||||
| { | { | ||||||
|  | @ -65,6 +66,7 @@ static inline int bcma_sflash_init(struct bcma_drv_cc *cc) | ||||||
| #ifdef CONFIG_BCMA_NFLASH | #ifdef CONFIG_BCMA_NFLASH | ||||||
| /* driver_chipcommon_nflash.c */ | /* driver_chipcommon_nflash.c */ | ||||||
| int bcma_nflash_init(struct bcma_drv_cc *cc); | int bcma_nflash_init(struct bcma_drv_cc *cc); | ||||||
|  | extern struct platform_device bcma_nflash_dev; | ||||||
| #else | #else | ||||||
| static inline int bcma_nflash_init(struct bcma_drv_cc *cc) | static inline int bcma_nflash_init(struct bcma_drv_cc *cc) | ||||||
| { | { | ||||||
|  |  | ||||||
|  | @ -5,15 +5,37 @@ | ||||||
|  * Licensed under the GNU/GPL. See COPYING for details. |  * Licensed under the GNU/GPL. See COPYING for details. | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
|  | #include <linux/platform_device.h> | ||||||
| #include <linux/bcma/bcma.h> | #include <linux/bcma/bcma.h> | ||||||
| #include <linux/bcma/bcma_driver_chipcommon.h> |  | ||||||
| #include <linux/delay.h> |  | ||||||
| 
 | 
 | ||||||
| #include "bcma_private.h" | #include "bcma_private.h" | ||||||
| 
 | 
 | ||||||
|  | struct platform_device bcma_nflash_dev = { | ||||||
|  | 	.name		= "bcma_nflash", | ||||||
|  | 	.num_resources	= 0, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| /* Initialize NAND flash access */ | /* Initialize NAND flash access */ | ||||||
| int bcma_nflash_init(struct bcma_drv_cc *cc) | int bcma_nflash_init(struct bcma_drv_cc *cc) | ||||||
| { | { | ||||||
| 	bcma_err(cc->core->bus, "NAND flash support is broken\n"); | 	struct bcma_bus *bus = cc->core->bus; | ||||||
|  | 
 | ||||||
|  | 	if (bus->chipinfo.id != BCMA_CHIP_ID_BCM4706 && | ||||||
|  | 	    cc->core->id.rev != 0x38) { | ||||||
|  | 		bcma_err(bus, "NAND flash on unsupported board!\n"); | ||||||
|  | 		return -ENOTSUPP; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (!(cc->capabilities & BCMA_CC_CAP_NFLASH)) { | ||||||
|  | 		bcma_err(bus, "NAND flash not present according to ChipCommon\n"); | ||||||
|  | 		return -ENODEV; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	cc->nflash.present = true; | ||||||
|  | 
 | ||||||
|  | 	/* Prepare platform device, but don't register it yet. It's too early,
 | ||||||
|  | 	 * malloc (required by device_private_init) is not available yet. */ | ||||||
|  | 	bcma_nflash_dev.dev.platform_data = &cc->nflash; | ||||||
|  | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -5,15 +5,132 @@ | ||||||
|  * Licensed under the GNU/GPL. See COPYING for details. |  * Licensed under the GNU/GPL. See COPYING for details. | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
|  | #include <linux/platform_device.h> | ||||||
| #include <linux/bcma/bcma.h> | #include <linux/bcma/bcma.h> | ||||||
| #include <linux/bcma/bcma_driver_chipcommon.h> |  | ||||||
| #include <linux/delay.h> |  | ||||||
| 
 | 
 | ||||||
| #include "bcma_private.h" | #include "bcma_private.h" | ||||||
| 
 | 
 | ||||||
|  | static struct resource bcma_sflash_resource = { | ||||||
|  | 	.name	= "bcma_sflash", | ||||||
|  | 	.start	= BCMA_SFLASH, | ||||||
|  | 	.end	= 0, | ||||||
|  | 	.flags  = IORESOURCE_MEM | IORESOURCE_READONLY, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct platform_device bcma_sflash_dev = { | ||||||
|  | 	.name		= "bcma_sflash", | ||||||
|  | 	.resource	= &bcma_sflash_resource, | ||||||
|  | 	.num_resources	= 1, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct bcma_sflash_tbl_e { | ||||||
|  | 	char *name; | ||||||
|  | 	u32 id; | ||||||
|  | 	u32 blocksize; | ||||||
|  | 	u16 numblocks; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = { | ||||||
|  | 	{ "", 0x14, 0x10000, 32, }, | ||||||
|  | 	{ 0 }, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = { | ||||||
|  | 	{ 0 }, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static struct bcma_sflash_tbl_e bcma_sflash_at_tbl[] = { | ||||||
|  | 	{ 0 }, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static void bcma_sflash_cmd(struct bcma_drv_cc *cc, u32 opcode) | ||||||
|  | { | ||||||
|  | 	int i; | ||||||
|  | 	bcma_cc_write32(cc, BCMA_CC_FLASHCTL, | ||||||
|  | 			BCMA_CC_FLASHCTL_START | opcode); | ||||||
|  | 	for (i = 0; i < 1000; i++) { | ||||||
|  | 		if (!(bcma_cc_read32(cc, BCMA_CC_FLASHCTL) & | ||||||
|  | 		      BCMA_CC_FLASHCTL_BUSY)) | ||||||
|  | 			return; | ||||||
|  | 		cpu_relax(); | ||||||
|  | 	} | ||||||
|  | 	bcma_err(cc->core->bus, "SFLASH control command failed (timeout)!\n"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /* Initialize serial flash access */ | /* Initialize serial flash access */ | ||||||
| int bcma_sflash_init(struct bcma_drv_cc *cc) | int bcma_sflash_init(struct bcma_drv_cc *cc) | ||||||
| { | { | ||||||
| 	bcma_err(cc->core->bus, "Serial flash support is broken\n"); | 	struct bcma_bus *bus = cc->core->bus; | ||||||
|  | 	struct bcma_sflash *sflash = &cc->sflash; | ||||||
|  | 	struct bcma_sflash_tbl_e *e; | ||||||
|  | 	u32 id, id2; | ||||||
|  | 
 | ||||||
|  | 	switch (cc->capabilities & BCMA_CC_CAP_FLASHT) { | ||||||
|  | 	case BCMA_CC_FLASHT_STSER: | ||||||
|  | 		bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_DP); | ||||||
|  | 
 | ||||||
|  | 		bcma_cc_write32(cc, BCMA_CC_FLASHADDR, 0); | ||||||
|  | 		bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_RES); | ||||||
|  | 		id = bcma_cc_read32(cc, BCMA_CC_FLASHDATA); | ||||||
|  | 
 | ||||||
|  | 		bcma_cc_write32(cc, BCMA_CC_FLASHADDR, 1); | ||||||
|  | 		bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_RES); | ||||||
|  | 		id2 = bcma_cc_read32(cc, BCMA_CC_FLASHDATA); | ||||||
|  | 
 | ||||||
|  | 		switch (id) { | ||||||
|  | 		case 0xbf: | ||||||
|  | 			for (e = bcma_sflash_sst_tbl; e->name; e++) { | ||||||
|  | 				if (e->id == id2) | ||||||
|  | 					break; | ||||||
|  | 			} | ||||||
|  | 			break; | ||||||
|  | 		default: | ||||||
|  | 			for (e = bcma_sflash_st_tbl; e->name; e++) { | ||||||
|  | 				if (e->id == id) | ||||||
|  | 					break; | ||||||
|  | 			} | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 		if (!e->name) { | ||||||
|  | 			bcma_err(bus, "Unsupported ST serial flash (id: 0x%X, id2: 0x%X)\n", id, id2); | ||||||
|  | 			return -ENOTSUPP; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		break; | ||||||
|  | 	case BCMA_CC_FLASHT_ATSER: | ||||||
|  | 		bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_STATUS); | ||||||
|  | 		id = bcma_cc_read32(cc, BCMA_CC_FLASHDATA) & 0x3c; | ||||||
|  | 
 | ||||||
|  | 		for (e = bcma_sflash_at_tbl; e->name; e++) { | ||||||
|  | 			if (e->id == id) | ||||||
|  | 				break; | ||||||
|  | 		} | ||||||
|  | 		if (!e->name) { | ||||||
|  | 			bcma_err(bus, "Unsupported Atmel serial flash (id: 0x%X)\n", id); | ||||||
|  | 			return -ENOTSUPP; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		break; | ||||||
|  | 	default: | ||||||
|  | 		bcma_err(bus, "Unsupported flash type\n"); | ||||||
|  | 		return -ENOTSUPP; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	sflash->window = BCMA_SFLASH; | ||||||
|  | 	sflash->blocksize = e->blocksize; | ||||||
|  | 	sflash->numblocks = e->numblocks; | ||||||
|  | 	sflash->size = sflash->blocksize * sflash->numblocks; | ||||||
|  | 	sflash->present = true; | ||||||
|  | 
 | ||||||
|  | 	bcma_info(bus, "Found %s serial flash (size: %dKiB, blocksize: 0x%X, blocks: %d)\n", | ||||||
|  | 		  e->name, sflash->size / 1024, sflash->blocksize, | ||||||
|  | 		  sflash->numblocks); | ||||||
|  | 
 | ||||||
|  | 	/* Prepare platform device, but don't register it yet. It's too early,
 | ||||||
|  | 	 * malloc (required by device_private_init) is not available yet. */ | ||||||
|  | 	bcma_sflash_dev.resource[0].end = bcma_sflash_dev.resource[0].start + | ||||||
|  | 					  sflash->size; | ||||||
|  | 	bcma_sflash_dev.dev.platform_data = sflash; | ||||||
|  | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -7,6 +7,7 @@ | ||||||
| 
 | 
 | ||||||
| #include "bcma_private.h" | #include "bcma_private.h" | ||||||
| #include <linux/module.h> | #include <linux/module.h> | ||||||
|  | #include <linux/platform_device.h> | ||||||
| #include <linux/bcma/bcma.h> | #include <linux/bcma/bcma.h> | ||||||
| #include <linux/slab.h> | #include <linux/slab.h> | ||||||
| 
 | 
 | ||||||
|  | @ -136,6 +137,22 @@ static int bcma_register_cores(struct bcma_bus *bus) | ||||||
| 		dev_id++; | 		dev_id++; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | #ifdef CONFIG_BCMA_SFLASH | ||||||
|  | 	if (bus->drv_cc.sflash.present) { | ||||||
|  | 		err = platform_device_register(&bcma_sflash_dev); | ||||||
|  | 		if (err) | ||||||
|  | 			bcma_err(bus, "Error registering serial flash\n"); | ||||||
|  | 	} | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #ifdef CONFIG_BCMA_NFLASH | ||||||
|  | 	if (bus->drv_cc.nflash.present) { | ||||||
|  | 		err = platform_device_register(&bcma_nflash_dev); | ||||||
|  | 		if (err) | ||||||
|  | 			bcma_err(bus, "Error registering NAND flash\n"); | ||||||
|  | 	} | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1661,7 +1661,9 @@ static void adm8211_tx_raw(struct ieee80211_hw *dev, struct sk_buff *skb, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* Put adm8211_tx_hdr on skb and transmit */ | /* Put adm8211_tx_hdr on skb and transmit */ | ||||||
| static void adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb) | static void adm8211_tx(struct ieee80211_hw *dev, | ||||||
|  | 		       struct ieee80211_tx_control *control, | ||||||
|  | 		       struct sk_buff *skb) | ||||||
| { | { | ||||||
| 	struct adm8211_tx_hdr *txhdr; | 	struct adm8211_tx_hdr *txhdr; | ||||||
| 	size_t payload_len, hdrlen; | 	size_t payload_len, hdrlen; | ||||||
|  |  | ||||||
|  | @ -1726,7 +1726,9 @@ static void at76_mac80211_tx_callback(struct urb *urb) | ||||||
| 	ieee80211_wake_queues(priv->hw); | 	ieee80211_wake_queues(priv->hw); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void at76_mac80211_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | static void at76_mac80211_tx(struct ieee80211_hw *hw, | ||||||
|  | 			     struct ieee80211_tx_control *control, | ||||||
|  | 			     struct sk_buff *skb) | ||||||
| { | { | ||||||
| 	struct at76_priv *priv = hw->priv; | 	struct at76_priv *priv = hw->priv; | ||||||
| 	struct at76_tx_buffer *tx_buffer = priv->bulk_out_buffer; | 	struct at76_tx_buffer *tx_buffer = priv->bulk_out_buffer; | ||||||
|  |  | ||||||
|  | @ -55,7 +55,8 @@ | ||||||
| \********************/ | \********************/ | ||||||
| 
 | 
 | ||||||
| static void | static void | ||||||
| ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | ath5k_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, | ||||||
|  | 	 struct sk_buff *skb) | ||||||
| { | { | ||||||
| 	struct ath5k_hw *ah = hw->priv; | 	struct ath5k_hw *ah = hw->priv; | ||||||
| 	u16 qnum = skb_get_queue_mapping(skb); | 	u16 qnum = skb_get_queue_mapping(skb); | ||||||
|  |  | ||||||
|  | @ -280,6 +280,7 @@ struct ath_tx_control { | ||||||
| 	struct ath_txq *txq; | 	struct ath_txq *txq; | ||||||
| 	struct ath_node *an; | 	struct ath_node *an; | ||||||
| 	u8 paprd; | 	u8 paprd; | ||||||
|  | 	struct ieee80211_sta *sta; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| #define ATH_TX_ERROR        0x01 | #define ATH_TX_ERROR        0x01 | ||||||
|  |  | ||||||
|  | @ -542,6 +542,7 @@ void ath9k_htc_stop_ani(struct ath9k_htc_priv *priv); | ||||||
| 
 | 
 | ||||||
| int ath9k_tx_init(struct ath9k_htc_priv *priv); | int ath9k_tx_init(struct ath9k_htc_priv *priv); | ||||||
| int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, | int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, | ||||||
|  | 		       struct ieee80211_sta *sta, | ||||||
| 		       struct sk_buff *skb, u8 slot, bool is_cab); | 		       struct sk_buff *skb, u8 slot, bool is_cab); | ||||||
| void ath9k_tx_cleanup(struct ath9k_htc_priv *priv); | void ath9k_tx_cleanup(struct ath9k_htc_priv *priv); | ||||||
| bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv, int subtype); | bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv, int subtype); | ||||||
|  |  | ||||||
|  | @ -326,7 +326,7 @@ static void ath9k_htc_send_buffered(struct ath9k_htc_priv *priv, | ||||||
| 			goto next; | 			goto next; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		ret = ath9k_htc_tx_start(priv, skb, tx_slot, true); | 		ret = ath9k_htc_tx_start(priv, NULL, skb, tx_slot, true); | ||||||
| 		if (ret != 0) { | 		if (ret != 0) { | ||||||
| 			ath9k_htc_tx_clear_slot(priv, tx_slot); | 			ath9k_htc_tx_clear_slot(priv, tx_slot); | ||||||
| 			dev_kfree_skb_any(skb); | 			dev_kfree_skb_any(skb); | ||||||
|  |  | ||||||
|  | @ -856,7 +856,9 @@ set_timer: | ||||||
| /* mac80211 Callbacks */ | /* mac80211 Callbacks */ | ||||||
| /**********************/ | /**********************/ | ||||||
| 
 | 
 | ||||||
| static void ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | static void ath9k_htc_tx(struct ieee80211_hw *hw, | ||||||
|  | 			 struct ieee80211_tx_control *control, | ||||||
|  | 			 struct sk_buff *skb) | ||||||
| { | { | ||||||
| 	struct ieee80211_hdr *hdr; | 	struct ieee80211_hdr *hdr; | ||||||
| 	struct ath9k_htc_priv *priv = hw->priv; | 	struct ath9k_htc_priv *priv = hw->priv; | ||||||
|  | @ -883,7 +885,7 @@ static void ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | ||||||
| 		goto fail_tx; | 		goto fail_tx; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	ret = ath9k_htc_tx_start(priv, skb, slot, false); | 	ret = ath9k_htc_tx_start(priv, control->sta, skb, slot, false); | ||||||
| 	if (ret != 0) { | 	if (ret != 0) { | ||||||
| 		ath_dbg(common, XMIT, "Tx failed\n"); | 		ath_dbg(common, XMIT, "Tx failed\n"); | ||||||
| 		goto clear_slot; | 		goto clear_slot; | ||||||
|  | @ -1331,6 +1333,34 @@ static int ath9k_htc_sta_remove(struct ieee80211_hw *hw, | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void ath9k_htc_sta_rc_update(struct ieee80211_hw *hw, | ||||||
|  | 				    struct ieee80211_vif *vif, | ||||||
|  | 				    struct ieee80211_sta *sta, u32 changed) | ||||||
|  | { | ||||||
|  | 	struct ath9k_htc_priv *priv = hw->priv; | ||||||
|  | 	struct ath_common *common = ath9k_hw_common(priv->ah); | ||||||
|  | 	struct ath9k_htc_target_rate trate; | ||||||
|  | 
 | ||||||
|  | 	mutex_lock(&priv->mutex); | ||||||
|  | 	ath9k_htc_ps_wakeup(priv); | ||||||
|  | 
 | ||||||
|  | 	if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) { | ||||||
|  | 		memset(&trate, 0, sizeof(struct ath9k_htc_target_rate)); | ||||||
|  | 		ath9k_htc_setup_rate(priv, sta, &trate); | ||||||
|  | 		if (!ath9k_htc_send_rate_cmd(priv, &trate)) | ||||||
|  | 			ath_dbg(common, CONFIG, | ||||||
|  | 				"Supported rates for sta: %pM updated, rate caps: 0x%X\n", | ||||||
|  | 				sta->addr, be32_to_cpu(trate.capflags)); | ||||||
|  | 		else | ||||||
|  | 			ath_dbg(common, CONFIG, | ||||||
|  | 				"Unable to update supported rates for sta: %pM\n", | ||||||
|  | 				sta->addr); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	ath9k_htc_ps_restore(priv); | ||||||
|  | 	mutex_unlock(&priv->mutex); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, | static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, | ||||||
| 			     struct ieee80211_vif *vif, u16 queue, | 			     struct ieee80211_vif *vif, u16 queue, | ||||||
| 			     const struct ieee80211_tx_queue_params *params) | 			     const struct ieee80211_tx_queue_params *params) | ||||||
|  | @ -1758,6 +1788,7 @@ struct ieee80211_ops ath9k_htc_ops = { | ||||||
| 	.sta_add            = ath9k_htc_sta_add, | 	.sta_add            = ath9k_htc_sta_add, | ||||||
| 	.sta_remove         = ath9k_htc_sta_remove, | 	.sta_remove         = ath9k_htc_sta_remove, | ||||||
| 	.conf_tx            = ath9k_htc_conf_tx, | 	.conf_tx            = ath9k_htc_conf_tx, | ||||||
|  | 	.sta_rc_update      = ath9k_htc_sta_rc_update, | ||||||
| 	.bss_info_changed   = ath9k_htc_bss_info_changed, | 	.bss_info_changed   = ath9k_htc_bss_info_changed, | ||||||
| 	.set_key            = ath9k_htc_set_key, | 	.set_key            = ath9k_htc_set_key, | ||||||
| 	.get_tsf            = ath9k_htc_get_tsf, | 	.get_tsf            = ath9k_htc_get_tsf, | ||||||
|  |  | ||||||
|  | @ -333,12 +333,12 @@ static void ath9k_htc_tx_data(struct ath9k_htc_priv *priv, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, | int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, | ||||||
|  | 		       struct ieee80211_sta *sta, | ||||||
| 		       struct sk_buff *skb, | 		       struct sk_buff *skb, | ||||||
| 		       u8 slot, bool is_cab) | 		       u8 slot, bool is_cab) | ||||||
| { | { | ||||||
| 	struct ieee80211_hdr *hdr; | 	struct ieee80211_hdr *hdr; | ||||||
| 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | ||||||
| 	struct ieee80211_sta *sta = tx_info->control.sta; |  | ||||||
| 	struct ieee80211_vif *vif = tx_info->control.vif; | 	struct ieee80211_vif *vif = tx_info->control.vif; | ||||||
| 	struct ath9k_htc_sta *ista; | 	struct ath9k_htc_sta *ista; | ||||||
| 	struct ath9k_htc_vif *avp = NULL; | 	struct ath9k_htc_vif *avp = NULL; | ||||||
|  |  | ||||||
|  | @ -696,7 +696,9 @@ mutex_unlock: | ||||||
| 	return r; | 	return r; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | static void ath9k_tx(struct ieee80211_hw *hw, | ||||||
|  | 		     struct ieee80211_tx_control *control, | ||||||
|  | 		     struct sk_buff *skb) | ||||||
| { | { | ||||||
| 	struct ath_softc *sc = hw->priv; | 	struct ath_softc *sc = hw->priv; | ||||||
| 	struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 	struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||||||
|  | @ -756,6 +758,7 @@ static void ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | ||||||
| 
 | 
 | ||||||
| 	memset(&txctl, 0, sizeof(struct ath_tx_control)); | 	memset(&txctl, 0, sizeof(struct ath_tx_control)); | ||||||
| 	txctl.txq = sc->tx.txq_map[skb_get_queue_mapping(skb)]; | 	txctl.txq = sc->tx.txq_map[skb_get_queue_mapping(skb)]; | ||||||
|  | 	txctl.sta = control->sta; | ||||||
| 
 | 
 | ||||||
| 	ath_dbg(common, XMIT, "transmitting packet, skb: %p\n", skb); | 	ath_dbg(common, XMIT, "transmitting packet, skb: %p\n", skb); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1773,11 +1773,12 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, | ||||||
| 	TX_STAT_INC(txq->axq_qnum, queued); | 	TX_STAT_INC(txq->axq_qnum, queued); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb, | static void setup_frame_info(struct ieee80211_hw *hw, | ||||||
|  | 			     struct ieee80211_sta *sta, | ||||||
|  | 			     struct sk_buff *skb, | ||||||
| 			     int framelen) | 			     int framelen) | ||||||
| { | { | ||||||
| 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | ||||||
| 	struct ieee80211_sta *sta = tx_info->control.sta; |  | ||||||
| 	struct ieee80211_key_conf *hw_key = tx_info->control.hw_key; | 	struct ieee80211_key_conf *hw_key = tx_info->control.hw_key; | ||||||
| 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||||||
| 	const struct ieee80211_rate *rate; | 	const struct ieee80211_rate *rate; | ||||||
|  | @ -1935,7 +1936,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, | ||||||
| { | { | ||||||
| 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | ||||||
| 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||||||
| 	struct ieee80211_sta *sta = info->control.sta; | 	struct ieee80211_sta *sta = txctl->sta; | ||||||
| 	struct ieee80211_vif *vif = info->control.vif; | 	struct ieee80211_vif *vif = info->control.vif; | ||||||
| 	struct ath_softc *sc = hw->priv; | 	struct ath_softc *sc = hw->priv; | ||||||
| 	struct ath_txq *txq = txctl->txq; | 	struct ath_txq *txq = txctl->txq; | ||||||
|  | @ -1979,7 +1980,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, | ||||||
| 	    !ieee80211_is_data(hdr->frame_control)) | 	    !ieee80211_is_data(hdr->frame_control)) | ||||||
| 		info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; | 		info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; | ||||||
| 
 | 
 | ||||||
| 	setup_frame_info(hw, skb, frmlen); | 	setup_frame_info(hw, sta, skb, frmlen); | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * At this point, the vif, hw_key and sta pointers in the tx control | 	 * At this point, the vif, hw_key and sta pointers in the tx control | ||||||
|  |  | ||||||
|  | @ -425,6 +425,7 @@ struct ar9170 { | ||||||
| 	bool rx_has_plcp; | 	bool rx_has_plcp; | ||||||
| 	struct sk_buff *rx_failover; | 	struct sk_buff *rx_failover; | ||||||
| 	int rx_failover_missing; | 	int rx_failover_missing; | ||||||
|  | 	u32 ampdu_ref; | ||||||
| 
 | 
 | ||||||
| 	/* FIFO for collecting outstanding BlockAckRequest */ | 	/* FIFO for collecting outstanding BlockAckRequest */ | ||||||
| 	struct list_head bar_list[__AR9170_NUM_TXQ]; | 	struct list_head bar_list[__AR9170_NUM_TXQ]; | ||||||
|  | @ -577,7 +578,9 @@ void carl9170_rx(struct ar9170 *ar, void *buf, unsigned int len); | ||||||
| void carl9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len); | void carl9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len); | ||||||
| 
 | 
 | ||||||
| /* TX */ | /* TX */ | ||||||
| void carl9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb); | void carl9170_op_tx(struct ieee80211_hw *hw, | ||||||
|  | 		    struct ieee80211_tx_control *control, | ||||||
|  | 		    struct sk_buff *skb); | ||||||
| void carl9170_tx_janitor(struct work_struct *work); | void carl9170_tx_janitor(struct work_struct *work); | ||||||
| void carl9170_tx_process_status(struct ar9170 *ar, | void carl9170_tx_process_status(struct ar9170 *ar, | ||||||
| 				const struct carl9170_rsp *cmd); | 				const struct carl9170_rsp *cmd); | ||||||
|  |  | ||||||
|  | @ -624,7 +624,8 @@ static void carl9170_ba_check(struct ar9170 *ar, void *data, unsigned int len) | ||||||
| #undef TID_CHECK | #undef TID_CHECK | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool carl9170_ampdu_check(struct ar9170 *ar, u8 *buf, u8 ms) | static bool carl9170_ampdu_check(struct ar9170 *ar, u8 *buf, u8 ms, | ||||||
|  | 				 struct ieee80211_rx_status *rx_status) | ||||||
| { | { | ||||||
| 	__le16 fc; | 	__le16 fc; | ||||||
| 
 | 
 | ||||||
|  | @ -637,6 +638,9 @@ static bool carl9170_ampdu_check(struct ar9170 *ar, u8 *buf, u8 ms) | ||||||
| 		return true; | 		return true; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	rx_status->flag |= RX_FLAG_AMPDU_DETAILS | RX_FLAG_AMPDU_LAST_KNOWN; | ||||||
|  | 	rx_status->ampdu_reference = ar->ampdu_ref; | ||||||
|  | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * "802.11n - 7.4a.3 A-MPDU contents" describes in which contexts | 	 * "802.11n - 7.4a.3 A-MPDU contents" describes in which contexts | ||||||
| 	 * certain frame types can be part of an aMPDU. | 	 * certain frame types can be part of an aMPDU. | ||||||
|  | @ -685,12 +689,15 @@ static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) | ||||||
| 	if (unlikely(len < sizeof(*mac))) | 	if (unlikely(len < sizeof(*mac))) | ||||||
| 		goto drop; | 		goto drop; | ||||||
| 
 | 
 | ||||||
|  | 	memset(&status, 0, sizeof(status)); | ||||||
|  | 
 | ||||||
| 	mpdu_len = len - sizeof(*mac); | 	mpdu_len = len - sizeof(*mac); | ||||||
| 
 | 
 | ||||||
| 	mac = (void *)(buf + mpdu_len); | 	mac = (void *)(buf + mpdu_len); | ||||||
| 	mac_status = mac->status; | 	mac_status = mac->status; | ||||||
| 	switch (mac_status & AR9170_RX_STATUS_MPDU) { | 	switch (mac_status & AR9170_RX_STATUS_MPDU) { | ||||||
| 	case AR9170_RX_STATUS_MPDU_FIRST: | 	case AR9170_RX_STATUS_MPDU_FIRST: | ||||||
|  | 		ar->ampdu_ref++; | ||||||
| 		/* Aggregated MPDUs start with an PLCP header */ | 		/* Aggregated MPDUs start with an PLCP header */ | ||||||
| 		if (likely(mpdu_len >= sizeof(struct ar9170_rx_head))) { | 		if (likely(mpdu_len >= sizeof(struct ar9170_rx_head))) { | ||||||
| 			head = (void *) buf; | 			head = (void *) buf; | ||||||
|  | @ -721,12 +728,13 @@ static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) | ||||||
| 		break; | 		break; | ||||||
| 
 | 
 | ||||||
| 	case AR9170_RX_STATUS_MPDU_LAST: | 	case AR9170_RX_STATUS_MPDU_LAST: | ||||||
|  | 		status.flag |= RX_FLAG_AMPDU_IS_LAST; | ||||||
|  | 
 | ||||||
| 		/*
 | 		/*
 | ||||||
| 		 * The last frame of an A-MPDU has an extra tail | 		 * The last frame of an A-MPDU has an extra tail | ||||||
| 		 * which does contain the phy status of the whole | 		 * which does contain the phy status of the whole | ||||||
| 		 * aggregate. | 		 * aggregate. | ||||||
| 		 */ | 		 */ | ||||||
| 
 |  | ||||||
| 		if (likely(mpdu_len >= sizeof(struct ar9170_rx_phystatus))) { | 		if (likely(mpdu_len >= sizeof(struct ar9170_rx_phystatus))) { | ||||||
| 			mpdu_len -= sizeof(struct ar9170_rx_phystatus); | 			mpdu_len -= sizeof(struct ar9170_rx_phystatus); | ||||||
| 			phy = (void *)(buf + mpdu_len); | 			phy = (void *)(buf + mpdu_len); | ||||||
|  | @ -774,11 +782,10 @@ static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) | ||||||
| 	if (unlikely(mpdu_len < (2 + 2 + ETH_ALEN + FCS_LEN))) | 	if (unlikely(mpdu_len < (2 + 2 + ETH_ALEN + FCS_LEN))) | ||||||
| 		goto drop; | 		goto drop; | ||||||
| 
 | 
 | ||||||
| 	memset(&status, 0, sizeof(status)); |  | ||||||
| 	if (unlikely(carl9170_rx_mac_status(ar, head, mac, &status))) | 	if (unlikely(carl9170_rx_mac_status(ar, head, mac, &status))) | ||||||
| 		goto drop; | 		goto drop; | ||||||
| 
 | 
 | ||||||
| 	if (!carl9170_ampdu_check(ar, buf, mac_status)) | 	if (!carl9170_ampdu_check(ar, buf, mac_status, &status)) | ||||||
| 		goto drop; | 		goto drop; | ||||||
| 
 | 
 | ||||||
| 	if (phy) | 	if (phy) | ||||||
|  |  | ||||||
|  | @ -867,14 +867,15 @@ static bool carl9170_tx_cts_check(struct ar9170 *ar, | ||||||
| 	return false; | 	return false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int carl9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb) | static int carl9170_tx_prepare(struct ar9170 *ar, | ||||||
|  | 			       struct ieee80211_sta *sta, | ||||||
|  | 			       struct sk_buff *skb) | ||||||
| { | { | ||||||
| 	struct ieee80211_hdr *hdr; | 	struct ieee80211_hdr *hdr; | ||||||
| 	struct _carl9170_tx_superframe *txc; | 	struct _carl9170_tx_superframe *txc; | ||||||
| 	struct carl9170_vif_info *cvif; | 	struct carl9170_vif_info *cvif; | ||||||
| 	struct ieee80211_tx_info *info; | 	struct ieee80211_tx_info *info; | ||||||
| 	struct ieee80211_tx_rate *txrate; | 	struct ieee80211_tx_rate *txrate; | ||||||
| 	struct ieee80211_sta *sta; |  | ||||||
| 	struct carl9170_tx_info *arinfo; | 	struct carl9170_tx_info *arinfo; | ||||||
| 	unsigned int hw_queue; | 	unsigned int hw_queue; | ||||||
| 	int i; | 	int i; | ||||||
|  | @ -910,8 +911,6 @@ static int carl9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb) | ||||||
| 	else | 	else | ||||||
| 		cvif = NULL; | 		cvif = NULL; | ||||||
| 
 | 
 | ||||||
| 	sta = info->control.sta; |  | ||||||
| 
 |  | ||||||
| 	txc = (void *)skb_push(skb, sizeof(*txc)); | 	txc = (void *)skb_push(skb, sizeof(*txc)); | ||||||
| 	memset(txc, 0, sizeof(*txc)); | 	memset(txc, 0, sizeof(*txc)); | ||||||
| 
 | 
 | ||||||
|  | @ -1457,20 +1456,21 @@ err_unlock_rcu: | ||||||
| 	return false; | 	return false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void carl9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | void carl9170_op_tx(struct ieee80211_hw *hw, | ||||||
|  | 		    struct ieee80211_tx_control *control, | ||||||
|  | 		    struct sk_buff *skb) | ||||||
| { | { | ||||||
| 	struct ar9170 *ar = hw->priv; | 	struct ar9170 *ar = hw->priv; | ||||||
| 	struct ieee80211_tx_info *info; | 	struct ieee80211_tx_info *info; | ||||||
| 	struct ieee80211_sta *sta; | 	struct ieee80211_sta *sta = control->sta; | ||||||
| 	bool run; | 	bool run; | ||||||
| 
 | 
 | ||||||
| 	if (unlikely(!IS_STARTED(ar))) | 	if (unlikely(!IS_STARTED(ar))) | ||||||
| 		goto err_free; | 		goto err_free; | ||||||
| 
 | 
 | ||||||
| 	info = IEEE80211_SKB_CB(skb); | 	info = IEEE80211_SKB_CB(skb); | ||||||
| 	sta = info->control.sta; |  | ||||||
| 
 | 
 | ||||||
| 	if (unlikely(carl9170_tx_prepare(ar, skb))) | 	if (unlikely(carl9170_tx_prepare(ar, sta, skb))) | ||||||
| 		goto err_free; | 		goto err_free; | ||||||
| 
 | 
 | ||||||
| 	carl9170_tx_accounting(ar, skb); | 	carl9170_tx_accounting(ar, skb); | ||||||
|  |  | ||||||
|  | @ -3412,6 +3412,7 @@ static void b43_tx_work(struct work_struct *work) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void b43_op_tx(struct ieee80211_hw *hw, | static void b43_op_tx(struct ieee80211_hw *hw, | ||||||
|  | 		      struct ieee80211_tx_control *control, | ||||||
| 		      struct sk_buff *skb) | 		      struct sk_buff *skb) | ||||||
| { | { | ||||||
| 	struct b43_wl *wl = hw_to_b43_wl(hw); | 	struct b43_wl *wl = hw_to_b43_wl(hw); | ||||||
|  |  | ||||||
|  | @ -2492,6 +2492,7 @@ static void b43legacy_tx_work(struct work_struct *work) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void b43legacy_op_tx(struct ieee80211_hw *hw, | static void b43legacy_op_tx(struct ieee80211_hw *hw, | ||||||
|  | 			    struct ieee80211_tx_control *control, | ||||||
| 			    struct sk_buff *skb) | 			    struct sk_buff *skb) | ||||||
| { | { | ||||||
| 	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); | 	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); | ||||||
|  |  | ||||||
|  | @ -267,7 +267,9 @@ static void brcms_set_basic_rate(struct brcm_rateset *rs, u16 rate, bool is_br) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void brcms_ops_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | static void brcms_ops_tx(struct ieee80211_hw *hw, | ||||||
|  | 			 struct ieee80211_tx_control *control, | ||||||
|  | 			 struct sk_buff *skb) | ||||||
| { | { | ||||||
| 	struct brcms_info *wl = hw->priv; | 	struct brcms_info *wl = hw->priv; | ||||||
| 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | ||||||
|  | @ -279,7 +281,7 @@ static void brcms_ops_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | ||||||
| 		goto done; | 		goto done; | ||||||
| 	} | 	} | ||||||
| 	brcms_c_sendpkt_mac80211(wl->wlc, skb, hw); | 	brcms_c_sendpkt_mac80211(wl->wlc, skb, hw); | ||||||
| 	tx_info->rate_driver_data[0] = tx_info->control.sta; | 	tx_info->rate_driver_data[0] = control->sta; | ||||||
|  done: |  done: | ||||||
| 	spin_unlock_bh(&wl->lock); | 	spin_unlock_bh(&wl->lock); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -460,7 +460,9 @@ il3945_build_tx_cmd_basic(struct il_priv *il, struct il_device_cmd *cmd, | ||||||
|  * start C_TX command process |  * start C_TX command process | ||||||
|  */ |  */ | ||||||
| static int | static int | ||||||
| il3945_tx_skb(struct il_priv *il, struct sk_buff *skb) | il3945_tx_skb(struct il_priv *il, | ||||||
|  | 	      struct ieee80211_sta *sta, | ||||||
|  | 	      struct sk_buff *skb) | ||||||
| { | { | ||||||
| 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||||||
| 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||||||
|  | @ -512,7 +514,7 @@ il3945_tx_skb(struct il_priv *il, struct sk_buff *skb) | ||||||
| 	hdr_len = ieee80211_hdrlen(fc); | 	hdr_len = ieee80211_hdrlen(fc); | ||||||
| 
 | 
 | ||||||
| 	/* Find idx into station table for destination station */ | 	/* Find idx into station table for destination station */ | ||||||
| 	sta_id = il_sta_id_or_broadcast(il, info->control.sta); | 	sta_id = il_sta_id_or_broadcast(il, sta); | ||||||
| 	if (sta_id == IL_INVALID_STATION) { | 	if (sta_id == IL_INVALID_STATION) { | ||||||
| 		D_DROP("Dropping - INVALID STATION: %pM\n", hdr->addr1); | 		D_DROP("Dropping - INVALID STATION: %pM\n", hdr->addr1); | ||||||
| 		goto drop; | 		goto drop; | ||||||
|  | @ -2859,7 +2861,9 @@ il3945_mac_stop(struct ieee80211_hw *hw) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void | static void | ||||||
| il3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | il3945_mac_tx(struct ieee80211_hw *hw, | ||||||
|  | 	       struct ieee80211_tx_control *control, | ||||||
|  | 	       struct sk_buff *skb) | ||||||
| { | { | ||||||
| 	struct il_priv *il = hw->priv; | 	struct il_priv *il = hw->priv; | ||||||
| 
 | 
 | ||||||
|  | @ -2868,7 +2872,7 @@ il3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | ||||||
| 	D_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, | 	D_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, | ||||||
| 	     ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate); | 	     ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate); | ||||||
| 
 | 
 | ||||||
| 	if (il3945_tx_skb(il, skb)) | 	if (il3945_tx_skb(il, control->sta, skb)) | ||||||
| 		dev_kfree_skb_any(skb); | 		dev_kfree_skb_any(skb); | ||||||
| 
 | 
 | ||||||
| 	D_MAC80211("leave\n"); | 	D_MAC80211("leave\n"); | ||||||
|  |  | ||||||
|  | @ -1526,8 +1526,11 @@ il4965_tx_cmd_build_basic(struct il_priv *il, struct sk_buff *skb, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void | static void | ||||||
| il4965_tx_cmd_build_rate(struct il_priv *il, struct il_tx_cmd *tx_cmd, | il4965_tx_cmd_build_rate(struct il_priv *il, | ||||||
| 			 struct ieee80211_tx_info *info, __le16 fc) | 			 struct il_tx_cmd *tx_cmd, | ||||||
|  | 			 struct ieee80211_tx_info *info, | ||||||
|  | 			 struct ieee80211_sta *sta, | ||||||
|  | 			 __le16 fc) | ||||||
| { | { | ||||||
| 	const u8 rts_retry_limit = 60; | 	const u8 rts_retry_limit = 60; | ||||||
| 	u32 rate_flags; | 	u32 rate_flags; | ||||||
|  | @ -1561,9 +1564,7 @@ il4965_tx_cmd_build_rate(struct il_priv *il, struct il_tx_cmd *tx_cmd, | ||||||
| 	rate_idx = info->control.rates[0].idx; | 	rate_idx = info->control.rates[0].idx; | ||||||
| 	if ((info->control.rates[0].flags & IEEE80211_TX_RC_MCS) || rate_idx < 0 | 	if ((info->control.rates[0].flags & IEEE80211_TX_RC_MCS) || rate_idx < 0 | ||||||
| 	    || rate_idx > RATE_COUNT_LEGACY) | 	    || rate_idx > RATE_COUNT_LEGACY) | ||||||
| 		rate_idx = | 		rate_idx = rate_lowest_index(&il->bands[info->band], sta); | ||||||
| 		    rate_lowest_index(&il->bands[info->band], |  | ||||||
| 				      info->control.sta); |  | ||||||
| 	/* For 5 GHZ band, remap mac80211 rate indices into driver indices */ | 	/* For 5 GHZ band, remap mac80211 rate indices into driver indices */ | ||||||
| 	if (info->band == IEEE80211_BAND_5GHZ) | 	if (info->band == IEEE80211_BAND_5GHZ) | ||||||
| 		rate_idx += IL_FIRST_OFDM_RATE; | 		rate_idx += IL_FIRST_OFDM_RATE; | ||||||
|  | @ -1630,11 +1631,12 @@ il4965_tx_cmd_build_hwcrypto(struct il_priv *il, struct ieee80211_tx_info *info, | ||||||
|  * start C_TX command process |  * start C_TX command process | ||||||
|  */ |  */ | ||||||
| int | int | ||||||
| il4965_tx_skb(struct il_priv *il, struct sk_buff *skb) | il4965_tx_skb(struct il_priv *il, | ||||||
|  | 	      struct ieee80211_sta *sta, | ||||||
|  | 	      struct sk_buff *skb) | ||||||
| { | { | ||||||
| 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||||||
| 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||||||
| 	struct ieee80211_sta *sta = info->control.sta; |  | ||||||
| 	struct il_station_priv *sta_priv = NULL; | 	struct il_station_priv *sta_priv = NULL; | ||||||
| 	struct il_tx_queue *txq; | 	struct il_tx_queue *txq; | ||||||
| 	struct il_queue *q; | 	struct il_queue *q; | ||||||
|  | @ -1680,7 +1682,7 @@ il4965_tx_skb(struct il_priv *il, struct sk_buff *skb) | ||||||
| 		sta_id = il->hw_params.bcast_id; | 		sta_id = il->hw_params.bcast_id; | ||||||
| 	else { | 	else { | ||||||
| 		/* Find idx into station table for destination station */ | 		/* Find idx into station table for destination station */ | ||||||
| 		sta_id = il_sta_id_or_broadcast(il, info->control.sta); | 		sta_id = il_sta_id_or_broadcast(il, sta); | ||||||
| 
 | 
 | ||||||
| 		if (sta_id == IL_INVALID_STATION) { | 		if (sta_id == IL_INVALID_STATION) { | ||||||
| 			D_DROP("Dropping - INVALID STATION: %pM\n", hdr->addr1); | 			D_DROP("Dropping - INVALID STATION: %pM\n", hdr->addr1); | ||||||
|  | @ -1786,7 +1788,7 @@ il4965_tx_skb(struct il_priv *il, struct sk_buff *skb) | ||||||
| 	/* TODO need this for burst mode later on */ | 	/* TODO need this for burst mode later on */ | ||||||
| 	il4965_tx_cmd_build_basic(il, skb, tx_cmd, info, hdr, sta_id); | 	il4965_tx_cmd_build_basic(il, skb, tx_cmd, info, hdr, sta_id); | ||||||
| 
 | 
 | ||||||
| 	il4965_tx_cmd_build_rate(il, tx_cmd, info, fc); | 	il4965_tx_cmd_build_rate(il, tx_cmd, info, sta, fc); | ||||||
| 
 | 
 | ||||||
| 	il_update_stats(il, true, fc, len); | 	il_update_stats(il, true, fc, len); | ||||||
| 	/*
 | 	/*
 | ||||||
|  | @ -5828,7 +5830,9 @@ il4965_mac_stop(struct ieee80211_hw *hw) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void | void | ||||||
| il4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | il4965_mac_tx(struct ieee80211_hw *hw, | ||||||
|  | 	      struct ieee80211_tx_control *control, | ||||||
|  | 	      struct sk_buff *skb) | ||||||
| { | { | ||||||
| 	struct il_priv *il = hw->priv; | 	struct il_priv *il = hw->priv; | ||||||
| 
 | 
 | ||||||
|  | @ -5837,7 +5841,7 @@ il4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | ||||||
| 	D_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, | 	D_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, | ||||||
| 	     ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate); | 	     ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate); | ||||||
| 
 | 
 | ||||||
| 	if (il4965_tx_skb(il, skb)) | 	if (il4965_tx_skb(il, control->sta, skb)) | ||||||
| 		dev_kfree_skb_any(skb); | 		dev_kfree_skb_any(skb); | ||||||
| 
 | 
 | ||||||
| 	D_MACDUMP("leave\n"); | 	D_MACDUMP("leave\n"); | ||||||
|  |  | ||||||
|  | @ -78,7 +78,9 @@ int il4965_hw_txq_attach_buf_to_tfd(struct il_priv *il, struct il_tx_queue *txq, | ||||||
| int il4965_hw_tx_queue_init(struct il_priv *il, struct il_tx_queue *txq); | int il4965_hw_tx_queue_init(struct il_priv *il, struct il_tx_queue *txq); | ||||||
| void il4965_hwrate_to_tx_control(struct il_priv *il, u32 rate_n_flags, | void il4965_hwrate_to_tx_control(struct il_priv *il, u32 rate_n_flags, | ||||||
| 				 struct ieee80211_tx_info *info); | 				 struct ieee80211_tx_info *info); | ||||||
| int il4965_tx_skb(struct il_priv *il, struct sk_buff *skb); | int il4965_tx_skb(struct il_priv *il, | ||||||
|  | 		  struct ieee80211_sta *sta, | ||||||
|  | 		  struct sk_buff *skb); | ||||||
| int il4965_tx_agg_start(struct il_priv *il, struct ieee80211_vif *vif, | int il4965_tx_agg_start(struct il_priv *il, struct ieee80211_vif *vif, | ||||||
| 			struct ieee80211_sta *sta, u16 tid, u16 * ssn); | 			struct ieee80211_sta *sta, u16 tid, u16 * ssn); | ||||||
| int il4965_tx_agg_stop(struct il_priv *il, struct ieee80211_vif *vif, | int il4965_tx_agg_stop(struct il_priv *il, struct ieee80211_vif *vif, | ||||||
|  | @ -163,7 +165,9 @@ void il4965_eeprom_release_semaphore(struct il_priv *il); | ||||||
| int il4965_eeprom_check_version(struct il_priv *il); | int il4965_eeprom_check_version(struct il_priv *il); | ||||||
| 
 | 
 | ||||||
| /* mac80211 handlers (for 4965) */ | /* mac80211 handlers (for 4965) */ | ||||||
| void il4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb); | void il4965_mac_tx(struct ieee80211_hw *hw, | ||||||
|  | 		   struct ieee80211_tx_control *control, | ||||||
|  | 		   struct sk_buff *skb); | ||||||
| int il4965_mac_start(struct ieee80211_hw *hw); | int il4965_mac_start(struct ieee80211_hw *hw); | ||||||
| void il4965_mac_stop(struct ieee80211_hw *hw); | void il4965_mac_stop(struct ieee80211_hw *hw); | ||||||
| void il4965_configure_filter(struct ieee80211_hw *hw, | void il4965_configure_filter(struct ieee80211_hw *hw, | ||||||
|  |  | ||||||
|  | @ -201,7 +201,9 @@ void iwl_chswitch_done(struct iwl_priv *priv, bool is_success); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /* tx */ | /* tx */ | ||||||
| int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb); | int iwlagn_tx_skb(struct iwl_priv *priv, | ||||||
|  | 		  struct ieee80211_sta *sta, | ||||||
|  | 		  struct sk_buff *skb); | ||||||
| int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif, | int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif, | ||||||
| 			struct ieee80211_sta *sta, u16 tid, u16 *ssn); | 			struct ieee80211_sta *sta, u16 tid, u16 *ssn); | ||||||
| int iwlagn_tx_agg_oper(struct iwl_priv *priv, struct ieee80211_vif *vif, | int iwlagn_tx_agg_oper(struct iwl_priv *priv, struct ieee80211_vif *vif, | ||||||
|  | @ -485,16 +487,13 @@ static inline void iwl_dvm_set_pmi(struct iwl_priv *priv, bool state) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #ifdef CONFIG_IWLWIFI_DEBUGFS | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||||||
| int iwl_dbgfs_register(struct iwl_priv *priv, const char *name); | int iwl_dbgfs_register(struct iwl_priv *priv, struct dentry *dbgfs_dir); | ||||||
| void iwl_dbgfs_unregister(struct iwl_priv *priv); |  | ||||||
| #else | #else | ||||||
| static inline int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) | static inline int iwl_dbgfs_register(struct iwl_priv *priv, | ||||||
|  | 				     struct dentry *dbgfs_dir) | ||||||
| { | { | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| static inline void iwl_dbgfs_unregister(struct iwl_priv *priv) |  | ||||||
| { |  | ||||||
| } |  | ||||||
| #endif /* CONFIG_IWLWIFI_DEBUGFS */ | #endif /* CONFIG_IWLWIFI_DEBUGFS */ | ||||||
| 
 | 
 | ||||||
| #ifdef CONFIG_IWLWIFI_DEBUG | #ifdef CONFIG_IWLWIFI_DEBUG | ||||||
|  |  | ||||||
|  | @ -2349,24 +2349,19 @@ DEBUGFS_READ_WRITE_FILE_OPS(calib_disabled); | ||||||
|  * Create the debugfs files and directories |  * Create the debugfs files and directories | ||||||
|  * |  * | ||||||
|  */ |  */ | ||||||
| int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) | int iwl_dbgfs_register(struct iwl_priv *priv, struct dentry *dbgfs_dir) | ||||||
| { | { | ||||||
| 	struct dentry *phyd = priv->hw->wiphy->debugfsdir; | 	struct dentry *dir_data, *dir_rf, *dir_debug; | ||||||
| 	struct dentry *dir_drv, *dir_data, *dir_rf, *dir_debug; |  | ||||||
| 
 | 
 | ||||||
| 	dir_drv = debugfs_create_dir(name, phyd); | 	priv->debugfs_dir = dbgfs_dir; | ||||||
| 	if (!dir_drv) |  | ||||||
| 		return -ENOMEM; |  | ||||||
| 
 | 
 | ||||||
| 	priv->debugfs_dir = dir_drv; | 	dir_data = debugfs_create_dir("data", dbgfs_dir); | ||||||
| 
 |  | ||||||
| 	dir_data = debugfs_create_dir("data", dir_drv); |  | ||||||
| 	if (!dir_data) | 	if (!dir_data) | ||||||
| 		goto err; | 		goto err; | ||||||
| 	dir_rf = debugfs_create_dir("rf", dir_drv); | 	dir_rf = debugfs_create_dir("rf", dbgfs_dir); | ||||||
| 	if (!dir_rf) | 	if (!dir_rf) | ||||||
| 		goto err; | 		goto err; | ||||||
| 	dir_debug = debugfs_create_dir("debug", dir_drv); | 	dir_debug = debugfs_create_dir("debug", dbgfs_dir); | ||||||
| 	if (!dir_debug) | 	if (!dir_debug) | ||||||
| 		goto err; | 		goto err; | ||||||
| 
 | 
 | ||||||
|  | @ -2412,25 +2407,30 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) | ||||||
| 	/* Calibrations disabled/enabled status*/ | 	/* Calibrations disabled/enabled status*/ | ||||||
| 	DEBUGFS_ADD_FILE(calib_disabled, dir_rf, S_IWUSR | S_IRUSR); | 	DEBUGFS_ADD_FILE(calib_disabled, dir_rf, S_IWUSR | S_IRUSR); | ||||||
| 
 | 
 | ||||||
| 	if (iwl_trans_dbgfs_register(priv->trans, dir_debug)) | 	/*
 | ||||||
|  | 	 * Create a symlink with mac80211. This is not very robust, as it does | ||||||
|  | 	 * not remove the symlink created. The implicit assumption is that | ||||||
|  | 	 * when the opmode exits, mac80211 will also exit, and will remove | ||||||
|  | 	 * this symlink as part of its cleanup. | ||||||
|  | 	 */ | ||||||
|  | 	if (priv->mac80211_registered) { | ||||||
|  | 		char buf[100]; | ||||||
|  | 		struct dentry *mac80211_dir, *dev_dir, *root_dir; | ||||||
|  | 
 | ||||||
|  | 		dev_dir = dbgfs_dir->d_parent; | ||||||
|  | 		root_dir = dev_dir->d_parent; | ||||||
|  | 		mac80211_dir = priv->hw->wiphy->debugfsdir; | ||||||
|  | 
 | ||||||
|  | 		snprintf(buf, 100, "../../%s/%s", root_dir->d_name.name, | ||||||
|  | 			 dev_dir->d_name.name); | ||||||
|  | 
 | ||||||
|  | 		if (!debugfs_create_symlink("iwlwifi", mac80211_dir, buf)) | ||||||
| 			goto err; | 			goto err; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| 
 | 
 | ||||||
| err: | err: | ||||||
| 	IWL_ERR(priv, "Can't create the debugfs directory\n"); | 	IWL_ERR(priv, "failed to create the dvm debugfs entries\n"); | ||||||
| 	iwl_dbgfs_unregister(priv); |  | ||||||
| 	return -ENOMEM; | 	return -ENOMEM; | ||||||
| } | } | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * Remove the debugfs files and directories |  | ||||||
|  * |  | ||||||
|  */ |  | ||||||
| void iwl_dbgfs_unregister(struct iwl_priv *priv) |  | ||||||
| { |  | ||||||
| 	if (!priv->debugfs_dir) |  | ||||||
| 		return; |  | ||||||
| 
 |  | ||||||
| 	debugfs_remove_recursive(priv->debugfs_dir); |  | ||||||
| 	priv->debugfs_dir = NULL; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  | @ -195,7 +195,7 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv, | ||||||
| 			ARRAY_SIZE(iwlagn_iface_combinations_dualmode); | 			ARRAY_SIZE(iwlagn_iface_combinations_dualmode); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	hw->wiphy->max_remain_on_channel_duration = 1000; | 	hw->wiphy->max_remain_on_channel_duration = 500; | ||||||
| 
 | 
 | ||||||
| 	hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY | | 	hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY | | ||||||
| 			    WIPHY_FLAG_DISABLE_BEACON_HINTS | | 			    WIPHY_FLAG_DISABLE_BEACON_HINTS | | ||||||
|  | @ -511,14 +511,16 @@ static void iwlagn_mac_set_wakeup(struct ieee80211_hw *hw, bool enabled) | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| static void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | static void iwlagn_mac_tx(struct ieee80211_hw *hw, | ||||||
|  | 			  struct ieee80211_tx_control *control, | ||||||
|  | 			  struct sk_buff *skb) | ||||||
| { | { | ||||||
| 	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); | 	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); | ||||||
| 
 | 
 | ||||||
| 	IWL_DEBUG_TX(priv, "dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, | 	IWL_DEBUG_TX(priv, "dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, | ||||||
| 		     ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate); | 		     ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate); | ||||||
| 
 | 
 | ||||||
| 	if (iwlagn_tx_skb(priv, skb)) | 	if (iwlagn_tx_skb(priv, control->sta, skb)) | ||||||
| 		dev_kfree_skb_any(skb); | 		dev_kfree_skb_any(skb); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -862,6 +862,7 @@ void iwl_down(struct iwl_priv *priv) | ||||||
| 	 * No race since we hold the mutex here and a new one | 	 * No race since we hold the mutex here and a new one | ||||||
| 	 * can't come in at this time. | 	 * can't come in at this time. | ||||||
| 	 */ | 	 */ | ||||||
|  | 	if (priv->ucode_loaded && priv->cur_ucode != IWL_UCODE_INIT) | ||||||
| 		ieee80211_remain_on_channel_expired(priv->hw); | 		ieee80211_remain_on_channel_expired(priv->hw); | ||||||
| 
 | 
 | ||||||
| 	exit_pending = | 	exit_pending = | ||||||
|  | @ -994,7 +995,11 @@ static void iwl_bg_restart(struct work_struct *data) | ||||||
| 		iwlagn_prepare_restart(priv); | 		iwlagn_prepare_restart(priv); | ||||||
| 		mutex_unlock(&priv->mutex); | 		mutex_unlock(&priv->mutex); | ||||||
| 		iwl_cancel_deferred_work(priv); | 		iwl_cancel_deferred_work(priv); | ||||||
|  | 		if (priv->mac80211_registered) | ||||||
| 			ieee80211_restart_hw(priv->hw); | 			ieee80211_restart_hw(priv->hw); | ||||||
|  | 		else | ||||||
|  | 			IWL_ERR(priv, | ||||||
|  | 				"Cannot request restart before registrating with mac80211"); | ||||||
| 	} else { | 	} else { | ||||||
| 		WARN_ON(1); | 		WARN_ON(1); | ||||||
| 	} | 	} | ||||||
|  | @ -1222,7 +1227,8 @@ static int iwl_eeprom_init_hw_params(struct iwl_priv *priv) | ||||||
| 
 | 
 | ||||||
| static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, | static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, | ||||||
| 						 const struct iwl_cfg *cfg, | 						 const struct iwl_cfg *cfg, | ||||||
| 						 const struct iwl_fw *fw) | 						 const struct iwl_fw *fw, | ||||||
|  | 						 struct dentry *dbgfs_dir) | ||||||
| { | { | ||||||
| 	struct iwl_priv *priv; | 	struct iwl_priv *priv; | ||||||
| 	struct ieee80211_hw *hw; | 	struct ieee80211_hw *hw; | ||||||
|  | @ -1466,13 +1472,17 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, | ||||||
| 	if (iwlagn_mac_setup_register(priv, &fw->ucode_capa)) | 	if (iwlagn_mac_setup_register(priv, &fw->ucode_capa)) | ||||||
| 		goto out_destroy_workqueue; | 		goto out_destroy_workqueue; | ||||||
| 
 | 
 | ||||||
| 	if (iwl_dbgfs_register(priv, DRV_NAME)) | 	if (iwl_dbgfs_register(priv, dbgfs_dir)) | ||||||
| 		IWL_ERR(priv, | 		goto out_mac80211_unregister; | ||||||
| 			"failed to create debugfs files. Ignoring error\n"); |  | ||||||
| 
 | 
 | ||||||
| 	return op_mode; | 	return op_mode; | ||||||
| 
 | 
 | ||||||
|  | out_mac80211_unregister: | ||||||
|  | 	iwlagn_mac_unregister(priv); | ||||||
| out_destroy_workqueue: | out_destroy_workqueue: | ||||||
|  | 	iwl_tt_exit(priv); | ||||||
|  | 	iwl_testmode_free(priv); | ||||||
|  | 	iwl_cancel_deferred_work(priv); | ||||||
| 	destroy_workqueue(priv->workqueue); | 	destroy_workqueue(priv->workqueue); | ||||||
| 	priv->workqueue = NULL; | 	priv->workqueue = NULL; | ||||||
| 	iwl_uninit_drv(priv); | 	iwl_uninit_drv(priv); | ||||||
|  | @ -1493,8 +1503,6 @@ static void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode) | ||||||
| 
 | 
 | ||||||
| 	IWL_DEBUG_INFO(priv, "*** UNLOAD DRIVER ***\n"); | 	IWL_DEBUG_INFO(priv, "*** UNLOAD DRIVER ***\n"); | ||||||
| 
 | 
 | ||||||
| 	iwl_dbgfs_unregister(priv); |  | ||||||
| 
 |  | ||||||
| 	iwl_testmode_free(priv); | 	iwl_testmode_free(priv); | ||||||
| 	iwlagn_mac_unregister(priv); | 	iwlagn_mac_unregister(priv); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -150,7 +150,7 @@ int iwl_send_add_sta(struct iwl_priv *priv, | ||||||
| 		       sta_id, sta->sta.addr, flags & CMD_ASYNC ?  "a" : ""); | 		       sta_id, sta->sta.addr, flags & CMD_ASYNC ?  "a" : ""); | ||||||
| 
 | 
 | ||||||
| 	if (!(flags & CMD_ASYNC)) { | 	if (!(flags & CMD_ASYNC)) { | ||||||
| 		cmd.flags |= CMD_WANT_SKB; | 		cmd.flags |= CMD_WANT_SKB | CMD_WANT_HCMD; | ||||||
| 		might_sleep(); | 		might_sleep(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -127,6 +127,7 @@ static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv, | ||||||
| static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv, | static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv, | ||||||
| 				     struct iwl_tx_cmd *tx_cmd, | 				     struct iwl_tx_cmd *tx_cmd, | ||||||
| 				     struct ieee80211_tx_info *info, | 				     struct ieee80211_tx_info *info, | ||||||
|  | 				     struct ieee80211_sta *sta, | ||||||
| 				     __le16 fc) | 				     __le16 fc) | ||||||
| { | { | ||||||
| 	u32 rate_flags; | 	u32 rate_flags; | ||||||
|  | @ -187,8 +188,7 @@ static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv, | ||||||
| 	if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS || | 	if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS || | ||||||
| 			(rate_idx < 0) || (rate_idx > IWL_RATE_COUNT_LEGACY)) | 			(rate_idx < 0) || (rate_idx > IWL_RATE_COUNT_LEGACY)) | ||||||
| 		rate_idx = rate_lowest_index( | 		rate_idx = rate_lowest_index( | ||||||
| 				&priv->eeprom_data->bands[info->band], | 				&priv->eeprom_data->bands[info->band], sta); | ||||||
| 				info->control.sta); |  | ||||||
| 	/* For 5 GHZ band, remap mac80211 rate indices into driver indices */ | 	/* For 5 GHZ band, remap mac80211 rate indices into driver indices */ | ||||||
| 	if (info->band == IEEE80211_BAND_5GHZ) | 	if (info->band == IEEE80211_BAND_5GHZ) | ||||||
| 		rate_idx += IWL_FIRST_OFDM_RATE; | 		rate_idx += IWL_FIRST_OFDM_RATE; | ||||||
|  | @ -291,7 +291,9 @@ static int iwl_sta_id_or_broadcast(struct iwl_rxon_context *context, | ||||||
| /*
 | /*
 | ||||||
|  * start REPLY_TX command process |  * start REPLY_TX command process | ||||||
|  */ |  */ | ||||||
| int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | int iwlagn_tx_skb(struct iwl_priv *priv, | ||||||
|  | 		  struct ieee80211_sta *sta, | ||||||
|  | 		  struct sk_buff *skb) | ||||||
| { | { | ||||||
| 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||||||
| 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||||||
|  | @ -345,7 +347,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | ||||||
| 		sta_id = ctx->bcast_sta_id; | 		sta_id = ctx->bcast_sta_id; | ||||||
| 	else { | 	else { | ||||||
| 		/* Find index into station table for destination station */ | 		/* Find index into station table for destination station */ | ||||||
| 		sta_id = iwl_sta_id_or_broadcast(ctx, info->control.sta); | 		sta_id = iwl_sta_id_or_broadcast(ctx, sta); | ||||||
| 		if (sta_id == IWL_INVALID_STATION) { | 		if (sta_id == IWL_INVALID_STATION) { | ||||||
| 			IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n", | 			IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n", | ||||||
| 				       hdr->addr1); | 				       hdr->addr1); | ||||||
|  | @ -355,8 +357,8 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | ||||||
| 
 | 
 | ||||||
| 	IWL_DEBUG_TX(priv, "station Id %d\n", sta_id); | 	IWL_DEBUG_TX(priv, "station Id %d\n", sta_id); | ||||||
| 
 | 
 | ||||||
| 	if (info->control.sta) | 	if (sta) | ||||||
| 		sta_priv = (void *)info->control.sta->drv_priv; | 		sta_priv = (void *)sta->drv_priv; | ||||||
| 
 | 
 | ||||||
| 	if (sta_priv && sta_priv->asleep && | 	if (sta_priv && sta_priv->asleep && | ||||||
| 	    (info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER)) { | 	    (info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER)) { | ||||||
|  | @ -397,7 +399,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | ||||||
| 	/* TODO need this for burst mode later on */ | 	/* TODO need this for burst mode later on */ | ||||||
| 	iwlagn_tx_cmd_build_basic(priv, skb, tx_cmd, info, hdr, sta_id); | 	iwlagn_tx_cmd_build_basic(priv, skb, tx_cmd, info, hdr, sta_id); | ||||||
| 
 | 
 | ||||||
| 	iwlagn_tx_cmd_build_rate(priv, tx_cmd, info, fc); | 	iwlagn_tx_cmd_build_rate(priv, tx_cmd, info, sta, fc); | ||||||
| 
 | 
 | ||||||
| 	memset(&info->status, 0, sizeof(info->status)); | 	memset(&info->status, 0, sizeof(info->status)); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -101,6 +101,10 @@ MODULE_VERSION(DRV_VERSION); | ||||||
| MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); | MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); | ||||||
| MODULE_LICENSE("GPL"); | MODULE_LICENSE("GPL"); | ||||||
| 
 | 
 | ||||||
|  | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||||||
|  | static struct dentry *iwl_dbgfs_root; | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * struct iwl_drv - drv common data |  * struct iwl_drv - drv common data | ||||||
|  * @list: list of drv structures using this opmode |  * @list: list of drv structures using this opmode | ||||||
|  | @ -126,6 +130,12 @@ struct iwl_drv { | ||||||
| 	char firmware_name[25];         /* name of firmware file to load */ | 	char firmware_name[25];         /* name of firmware file to load */ | ||||||
| 
 | 
 | ||||||
| 	struct completion request_firmware_complete; | 	struct completion request_firmware_complete; | ||||||
|  | 
 | ||||||
|  | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||||||
|  | 	struct dentry *dbgfs_drv; | ||||||
|  | 	struct dentry *dbgfs_trans; | ||||||
|  | 	struct dentry *dbgfs_op_mode; | ||||||
|  | #endif | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| #define DVM_OP_MODE	0 | #define DVM_OP_MODE	0 | ||||||
|  | @ -194,7 +204,8 @@ static int iwl_alloc_fw_desc(struct iwl_drv *drv, struct fw_desc *desc, | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context); | static void iwl_req_fw_callback(const struct firmware *ucode_raw, | ||||||
|  | 				void *context); | ||||||
| 
 | 
 | ||||||
| #define UCODE_EXPERIMENTAL_INDEX	100 | #define UCODE_EXPERIMENTAL_INDEX	100 | ||||||
| #define UCODE_EXPERIMENTAL_TAG		"exp" | #define UCODE_EXPERIMENTAL_TAG		"exp" | ||||||
|  | @ -231,7 +242,7 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first) | ||||||
| 
 | 
 | ||||||
| 	return request_firmware_nowait(THIS_MODULE, 1, drv->firmware_name, | 	return request_firmware_nowait(THIS_MODULE, 1, drv->firmware_name, | ||||||
| 				       drv->trans->dev, | 				       drv->trans->dev, | ||||||
| 				       GFP_KERNEL, drv, iwl_ucode_callback); | 				       GFP_KERNEL, drv, iwl_req_fw_callback); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| struct fw_img_parsing { | struct fw_img_parsing { | ||||||
|  | @ -759,13 +770,57 @@ static int validate_sec_sizes(struct iwl_drv *drv, | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static struct iwl_op_mode * | ||||||
|  | _iwl_op_mode_start(struct iwl_drv *drv, struct iwlwifi_opmode_table *op) | ||||||
|  | { | ||||||
|  | 	const struct iwl_op_mode_ops *ops = op->ops; | ||||||
|  | 	struct dentry *dbgfs_dir = NULL; | ||||||
|  | 	struct iwl_op_mode *op_mode = NULL; | ||||||
|  | 
 | ||||||
|  | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||||||
|  | 	drv->dbgfs_op_mode = debugfs_create_dir(op->name, | ||||||
|  | 						drv->dbgfs_drv); | ||||||
|  | 	if (!drv->dbgfs_op_mode) { | ||||||
|  | 		IWL_ERR(drv, | ||||||
|  | 			"failed to create opmode debugfs directory\n"); | ||||||
|  | 		return op_mode; | ||||||
|  | 	} | ||||||
|  | 	dbgfs_dir = drv->dbgfs_op_mode; | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 	op_mode = ops->start(drv->trans, drv->cfg, &drv->fw, dbgfs_dir); | ||||||
|  | 
 | ||||||
|  | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||||||
|  | 	if (!op_mode) { | ||||||
|  | 		debugfs_remove_recursive(drv->dbgfs_op_mode); | ||||||
|  | 		drv->dbgfs_op_mode = NULL; | ||||||
|  | 	} | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 	return op_mode; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void _iwl_op_mode_stop(struct iwl_drv *drv) | ||||||
|  | { | ||||||
|  | 	/* op_mode can be NULL if its start failed */ | ||||||
|  | 	if (drv->op_mode) { | ||||||
|  | 		iwl_op_mode_stop(drv->op_mode); | ||||||
|  | 		drv->op_mode = NULL; | ||||||
|  | 
 | ||||||
|  | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||||||
|  | 		debugfs_remove_recursive(drv->dbgfs_op_mode); | ||||||
|  | 		drv->dbgfs_op_mode = NULL; | ||||||
|  | #endif | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * iwl_ucode_callback - callback when firmware was loaded |  * iwl_req_fw_callback - callback when firmware was loaded | ||||||
|  * |  * | ||||||
|  * If loaded successfully, copies the firmware into buffers |  * If loaded successfully, copies the firmware into buffers | ||||||
|  * for the card to fetch (via DMA). |  * for the card to fetch (via DMA). | ||||||
|  */ |  */ | ||||||
| static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) | static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) | ||||||
| { | { | ||||||
| 	struct iwl_drv *drv = context; | 	struct iwl_drv *drv = context; | ||||||
| 	struct iwl_fw *fw = &drv->fw; | 	struct iwl_fw *fw = &drv->fw; | ||||||
|  | @ -908,8 +963,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) | ||||||
| 	list_add_tail(&drv->list, &op->drv); | 	list_add_tail(&drv->list, &op->drv); | ||||||
| 
 | 
 | ||||||
| 	if (op->ops) { | 	if (op->ops) { | ||||||
| 		const struct iwl_op_mode_ops *ops = op->ops; | 		drv->op_mode = _iwl_op_mode_start(drv, op); | ||||||
| 		drv->op_mode = ops->start(drv->trans, drv->cfg, &drv->fw); |  | ||||||
| 
 | 
 | ||||||
| 		if (!drv->op_mode) { | 		if (!drv->op_mode) { | ||||||
| 			mutex_unlock(&iwlwifi_opmode_table_mtx); | 			mutex_unlock(&iwlwifi_opmode_table_mtx); | ||||||
|  | @ -969,13 +1023,42 @@ struct iwl_drv *iwl_drv_start(struct iwl_trans *trans, | ||||||
| 	init_completion(&drv->request_firmware_complete); | 	init_completion(&drv->request_firmware_complete); | ||||||
| 	INIT_LIST_HEAD(&drv->list); | 	INIT_LIST_HEAD(&drv->list); | ||||||
| 
 | 
 | ||||||
|  | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||||||
|  | 	/* Create the device debugfs entries. */ | ||||||
|  | 	drv->dbgfs_drv = debugfs_create_dir(dev_name(trans->dev), | ||||||
|  | 					    iwl_dbgfs_root); | ||||||
|  | 
 | ||||||
|  | 	if (!drv->dbgfs_drv) { | ||||||
|  | 		IWL_ERR(drv, "failed to create debugfs directory\n"); | ||||||
|  | 		goto err_free_drv; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* Create transport layer debugfs dir */ | ||||||
|  | 	drv->trans->dbgfs_dir = debugfs_create_dir("trans", drv->dbgfs_drv); | ||||||
|  | 
 | ||||||
|  | 	if (!drv->trans->dbgfs_dir) { | ||||||
|  | 		IWL_ERR(drv, "failed to create transport debugfs directory\n"); | ||||||
|  | 		goto err_free_dbgfs; | ||||||
|  | 	} | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| 	ret = iwl_request_firmware(drv, true); | 	ret = iwl_request_firmware(drv, true); | ||||||
| 
 | 
 | ||||||
| 	if (ret) { | 	if (ret) { | ||||||
| 		IWL_ERR(trans, "Couldn't request the fw\n"); | 		IWL_ERR(trans, "Couldn't request the fw\n"); | ||||||
|  | 		goto err_fw; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return drv; | ||||||
|  | 
 | ||||||
|  | err_fw: | ||||||
|  | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||||||
|  | err_free_dbgfs: | ||||||
|  | 	debugfs_remove_recursive(drv->dbgfs_drv); | ||||||
|  | err_free_drv: | ||||||
|  | #endif | ||||||
| 	kfree(drv); | 	kfree(drv); | ||||||
| 	drv = NULL; | 	drv = NULL; | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	return drv; | 	return drv; | ||||||
| } | } | ||||||
|  | @ -984,9 +1067,7 @@ void iwl_drv_stop(struct iwl_drv *drv) | ||||||
| { | { | ||||||
| 	wait_for_completion(&drv->request_firmware_complete); | 	wait_for_completion(&drv->request_firmware_complete); | ||||||
| 
 | 
 | ||||||
| 	/* op_mode can be NULL if its start failed */ | 	_iwl_op_mode_stop(drv); | ||||||
| 	if (drv->op_mode) |  | ||||||
| 		iwl_op_mode_stop(drv->op_mode); |  | ||||||
| 
 | 
 | ||||||
| 	iwl_dealloc_ucode(drv); | 	iwl_dealloc_ucode(drv); | ||||||
| 
 | 
 | ||||||
|  | @ -1000,6 +1081,10 @@ void iwl_drv_stop(struct iwl_drv *drv) | ||||||
| 		list_del(&drv->list); | 		list_del(&drv->list); | ||||||
| 	mutex_unlock(&iwlwifi_opmode_table_mtx); | 	mutex_unlock(&iwlwifi_opmode_table_mtx); | ||||||
| 
 | 
 | ||||||
|  | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||||||
|  | 	debugfs_remove_recursive(drv->dbgfs_drv); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| 	kfree(drv); | 	kfree(drv); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -1022,15 +1107,18 @@ int iwl_opmode_register(const char *name, const struct iwl_op_mode_ops *ops) | ||||||
| { | { | ||||||
| 	int i; | 	int i; | ||||||
| 	struct iwl_drv *drv; | 	struct iwl_drv *drv; | ||||||
|  | 	struct iwlwifi_opmode_table *op; | ||||||
| 
 | 
 | ||||||
| 	mutex_lock(&iwlwifi_opmode_table_mtx); | 	mutex_lock(&iwlwifi_opmode_table_mtx); | ||||||
| 	for (i = 0; i < ARRAY_SIZE(iwlwifi_opmode_table); i++) { | 	for (i = 0; i < ARRAY_SIZE(iwlwifi_opmode_table); i++) { | ||||||
| 		if (strcmp(iwlwifi_opmode_table[i].name, name)) | 		op = &iwlwifi_opmode_table[i]; | ||||||
|  | 		if (strcmp(op->name, name)) | ||||||
| 			continue; | 			continue; | ||||||
| 		iwlwifi_opmode_table[i].ops = ops; | 		op->ops = ops; | ||||||
| 		list_for_each_entry(drv, &iwlwifi_opmode_table[i].drv, list) | 		/* TODO: need to handle exceptional case */ | ||||||
| 			drv->op_mode = ops->start(drv->trans, drv->cfg, | 		list_for_each_entry(drv, &op->drv, list) | ||||||
| 						  &drv->fw); | 			drv->op_mode = _iwl_op_mode_start(drv, op); | ||||||
|  | 
 | ||||||
| 		mutex_unlock(&iwlwifi_opmode_table_mtx); | 		mutex_unlock(&iwlwifi_opmode_table_mtx); | ||||||
| 		return 0; | 		return 0; | ||||||
| 	} | 	} | ||||||
|  | @ -1051,12 +1139,9 @@ void iwl_opmode_deregister(const char *name) | ||||||
| 		iwlwifi_opmode_table[i].ops = NULL; | 		iwlwifi_opmode_table[i].ops = NULL; | ||||||
| 
 | 
 | ||||||
| 		/* call the stop routine for all devices */ | 		/* call the stop routine for all devices */ | ||||||
| 		list_for_each_entry(drv, &iwlwifi_opmode_table[i].drv, list) { | 		list_for_each_entry(drv, &iwlwifi_opmode_table[i].drv, list) | ||||||
| 			if (drv->op_mode) { | 			_iwl_op_mode_stop(drv); | ||||||
| 				iwl_op_mode_stop(drv->op_mode); | 
 | ||||||
| 				drv->op_mode = NULL; |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		mutex_unlock(&iwlwifi_opmode_table_mtx); | 		mutex_unlock(&iwlwifi_opmode_table_mtx); | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
|  | @ -1076,6 +1161,14 @@ static int __init iwl_drv_init(void) | ||||||
| 	pr_info(DRV_DESCRIPTION ", " DRV_VERSION "\n"); | 	pr_info(DRV_DESCRIPTION ", " DRV_VERSION "\n"); | ||||||
| 	pr_info(DRV_COPYRIGHT "\n"); | 	pr_info(DRV_COPYRIGHT "\n"); | ||||||
| 
 | 
 | ||||||
|  | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||||||
|  | 	/* Create the root of iwlwifi debugfs subsystem. */ | ||||||
|  | 	iwl_dbgfs_root = debugfs_create_dir(DRV_NAME, NULL); | ||||||
|  | 
 | ||||||
|  | 	if (!iwl_dbgfs_root) | ||||||
|  | 		return -EFAULT; | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| 	return iwl_pci_register_driver(); | 	return iwl_pci_register_driver(); | ||||||
| } | } | ||||||
| module_init(iwl_drv_init); | module_init(iwl_drv_init); | ||||||
|  | @ -1083,6 +1176,10 @@ module_init(iwl_drv_init); | ||||||
| static void __exit iwl_drv_exit(void) | static void __exit iwl_drv_exit(void) | ||||||
| { | { | ||||||
| 	iwl_pci_unregister_driver(); | 	iwl_pci_unregister_driver(); | ||||||
|  | 
 | ||||||
|  | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||||||
|  | 	debugfs_remove_recursive(iwl_dbgfs_root); | ||||||
|  | #endif | ||||||
| } | } | ||||||
| module_exit(iwl_drv_exit); | module_exit(iwl_drv_exit); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -90,9 +90,9 @@ | ||||||
|  * 4) The bus specific component configures the bus |  * 4) The bus specific component configures the bus | ||||||
|  * 5) The bus specific component calls to the drv bus agnostic part |  * 5) The bus specific component calls to the drv bus agnostic part | ||||||
|  *    (iwl_drv_start) |  *    (iwl_drv_start) | ||||||
|  * 6) iwl_drv_start fetches the fw ASYNC, iwl_ucode_callback |  * 6) iwl_drv_start fetches the fw ASYNC, iwl_req_fw_callback | ||||||
|  * 7) iwl_ucode_callback parses the fw file |  * 7) iwl_req_fw_callback parses the fw file | ||||||
|  * 8) iwl_ucode_callback starts the wifi implementation to matches the fw |  * 8) iwl_req_fw_callback starts the wifi implementation to matches the fw | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| struct iwl_drv; | struct iwl_drv; | ||||||
|  |  | ||||||
|  | @ -134,7 +134,8 @@ struct iwl_cfg; | ||||||
| struct iwl_op_mode_ops { | struct iwl_op_mode_ops { | ||||||
| 	struct iwl_op_mode *(*start)(struct iwl_trans *trans, | 	struct iwl_op_mode *(*start)(struct iwl_trans *trans, | ||||||
| 				     const struct iwl_cfg *cfg, | 				     const struct iwl_cfg *cfg, | ||||||
| 				     const struct iwl_fw *fw); | 				     const struct iwl_fw *fw, | ||||||
|  | 				     struct dentry *dbgfs_dir); | ||||||
| 	void (*stop)(struct iwl_op_mode *op_mode); | 	void (*stop)(struct iwl_op_mode *op_mode); | ||||||
| 	int (*rx)(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb, | 	int (*rx)(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb, | ||||||
| 		  struct iwl_device_cmd *cmd); | 		  struct iwl_device_cmd *cmd); | ||||||
|  |  | ||||||
|  | @ -184,14 +184,20 @@ struct iwl_rx_packet { | ||||||
|  * @CMD_SYNC: The caller will be stalled until the fw responds to the command |  * @CMD_SYNC: The caller will be stalled until the fw responds to the command | ||||||
|  * @CMD_ASYNC: Return right away and don't want for the response |  * @CMD_ASYNC: Return right away and don't want for the response | ||||||
|  * @CMD_WANT_SKB: valid only with CMD_SYNC. The caller needs the buffer of the |  * @CMD_WANT_SKB: valid only with CMD_SYNC. The caller needs the buffer of the | ||||||
|  *	response. |  *	response. The caller needs to call iwl_free_resp when done. | ||||||
|  |  * @CMD_WANT_HCMD: The caller needs to get the HCMD that was sent in the | ||||||
|  |  *	response handler. Chunks flagged by %IWL_HCMD_DFL_NOCOPY won't be | ||||||
|  |  *	copied. The pointer passed to the response handler is in the transport | ||||||
|  |  *	ownership and don't need to be freed by the op_mode. This also means | ||||||
|  |  *	that the pointer is invalidated after the op_mode's handler returns. | ||||||
|  * @CMD_ON_DEMAND: This command is sent by the test mode pipe. |  * @CMD_ON_DEMAND: This command is sent by the test mode pipe. | ||||||
|  */ |  */ | ||||||
| enum CMD_MODE { | enum CMD_MODE { | ||||||
| 	CMD_SYNC = 0, | 	CMD_SYNC = 0, | ||||||
| 	CMD_ASYNC = BIT(0), | 	CMD_ASYNC = BIT(0), | ||||||
| 	CMD_WANT_SKB = BIT(1), | 	CMD_WANT_SKB = BIT(1), | ||||||
| 	CMD_ON_DEMAND = BIT(2), | 	CMD_WANT_HCMD = BIT(2), | ||||||
|  | 	CMD_ON_DEMAND = BIT(3), | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| #define DEF_CMD_PAYLOAD_SIZE 320 | #define DEF_CMD_PAYLOAD_SIZE 320 | ||||||
|  | @ -460,6 +466,8 @@ struct iwl_trans { | ||||||
| 	size_t dev_cmd_headroom; | 	size_t dev_cmd_headroom; | ||||||
| 	char dev_cmd_pool_name[50]; | 	char dev_cmd_pool_name[50]; | ||||||
| 
 | 
 | ||||||
|  | 	struct dentry *dbgfs_dir; | ||||||
|  | 
 | ||||||
| 	/* pointer to trans specific struct */ | 	/* pointer to trans specific struct */ | ||||||
| 	/*Ensure that this pointer will always be aligned to sizeof pointer */ | 	/*Ensure that this pointer will always be aligned to sizeof pointer */ | ||||||
| 	char trans_specific[0] __aligned(sizeof(void *)); | 	char trans_specific[0] __aligned(sizeof(void *)); | ||||||
|  |  | ||||||
|  | @ -282,8 +282,14 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | ||||||
| 	if (!trans_pcie->drv) | 	if (!trans_pcie->drv) | ||||||
| 		goto out_free_trans; | 		goto out_free_trans; | ||||||
| 
 | 
 | ||||||
|  | 	/* register transport layer debugfs here */ | ||||||
|  | 	if (iwl_trans_dbgfs_register(iwl_trans, iwl_trans->dbgfs_dir)) | ||||||
|  | 		goto out_free_drv; | ||||||
|  | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| 
 | 
 | ||||||
|  | out_free_drv: | ||||||
|  | 	iwl_drv_stop(trans_pcie->drv); | ||||||
| out_free_trans: | out_free_trans: | ||||||
| 	iwl_trans_pcie_free(iwl_trans); | 	iwl_trans_pcie_free(iwl_trans); | ||||||
| 	pci_set_drvdata(pdev, NULL); | 	pci_set_drvdata(pdev, NULL); | ||||||
|  |  | ||||||
|  | @ -184,6 +184,7 @@ struct iwl_queue { | ||||||
| 
 | 
 | ||||||
| struct iwl_pcie_tx_queue_entry { | struct iwl_pcie_tx_queue_entry { | ||||||
| 	struct iwl_device_cmd *cmd; | 	struct iwl_device_cmd *cmd; | ||||||
|  | 	struct iwl_device_cmd *copy_cmd; | ||||||
| 	struct sk_buff *skb; | 	struct sk_buff *skb; | ||||||
| 	struct iwl_cmd_meta meta; | 	struct iwl_cmd_meta meta; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -421,13 +421,23 @@ static void iwl_rx_handle_rxbuf(struct iwl_trans *trans, | ||||||
| 		index = SEQ_TO_INDEX(sequence); | 		index = SEQ_TO_INDEX(sequence); | ||||||
| 		cmd_index = get_cmd_index(&txq->q, index); | 		cmd_index = get_cmd_index(&txq->q, index); | ||||||
| 
 | 
 | ||||||
| 		if (reclaim) | 		if (reclaim) { | ||||||
| 			cmd = txq->entries[cmd_index].cmd; | 			struct iwl_pcie_tx_queue_entry *ent; | ||||||
| 		else | 			ent = &txq->entries[cmd_index]; | ||||||
|  | 			cmd = ent->copy_cmd; | ||||||
|  | 			WARN_ON_ONCE(!cmd && ent->meta.flags & CMD_WANT_HCMD); | ||||||
|  | 		} else { | ||||||
| 			cmd = NULL; | 			cmd = NULL; | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 		err = iwl_op_mode_rx(trans->op_mode, &rxcb, cmd); | 		err = iwl_op_mode_rx(trans->op_mode, &rxcb, cmd); | ||||||
| 
 | 
 | ||||||
|  | 		if (reclaim) { | ||||||
|  | 			/* The original command isn't needed any more */ | ||||||
|  | 			kfree(txq->entries[cmd_index].copy_cmd); | ||||||
|  | 			txq->entries[cmd_index].copy_cmd = NULL; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		/*
 | 		/*
 | ||||||
| 		 * After here, we should always check rxcb._page_stolen, | 		 * After here, we should always check rxcb._page_stolen, | ||||||
| 		 * if it is true then one of the handlers took the page. | 		 * if it is true then one of the handlers took the page. | ||||||
|  |  | ||||||
|  | @ -492,10 +492,11 @@ static void iwl_tx_queue_free(struct iwl_trans *trans, int txq_id) | ||||||
| 	iwl_tx_queue_unmap(trans, txq_id); | 	iwl_tx_queue_unmap(trans, txq_id); | ||||||
| 
 | 
 | ||||||
| 	/* De-alloc array of command/tx buffers */ | 	/* De-alloc array of command/tx buffers */ | ||||||
| 
 |  | ||||||
| 	if (txq_id == trans_pcie->cmd_queue) | 	if (txq_id == trans_pcie->cmd_queue) | ||||||
| 		for (i = 0; i < txq->q.n_window; i++) | 		for (i = 0; i < txq->q.n_window; i++) { | ||||||
| 			kfree(txq->entries[i].cmd); | 			kfree(txq->entries[i].cmd); | ||||||
|  | 			kfree(txq->entries[i].copy_cmd); | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 	/* De-alloc circular buffer of TFDs */ | 	/* De-alloc circular buffer of TFDs */ | ||||||
| 	if (txq->q.n_bd) { | 	if (txq->q.n_bd) { | ||||||
|  | @ -896,6 +897,7 @@ static int iwl_set_hw_ready(struct iwl_trans *trans) | ||||||
| static int iwl_prepare_card_hw(struct iwl_trans *trans) | static int iwl_prepare_card_hw(struct iwl_trans *trans) | ||||||
| { | { | ||||||
| 	int ret; | 	int ret; | ||||||
|  | 	int t = 0; | ||||||
| 
 | 
 | ||||||
| 	IWL_DEBUG_INFO(trans, "iwl_trans_prepare_card_hw enter\n"); | 	IWL_DEBUG_INFO(trans, "iwl_trans_prepare_card_hw enter\n"); | ||||||
| 
 | 
 | ||||||
|  | @ -908,17 +910,15 @@ static int iwl_prepare_card_hw(struct iwl_trans *trans) | ||||||
| 	iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, | 	iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, | ||||||
| 		    CSR_HW_IF_CONFIG_REG_PREPARE); | 		    CSR_HW_IF_CONFIG_REG_PREPARE); | ||||||
| 
 | 
 | ||||||
| 	ret = iwl_poll_bit(trans, CSR_HW_IF_CONFIG_REG, | 	do { | ||||||
| 			   ~CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, |  | ||||||
| 			   CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, 150000); |  | ||||||
| 
 |  | ||||||
| 	if (ret < 0) |  | ||||||
| 		return ret; |  | ||||||
| 
 |  | ||||||
| 	/* HW should be ready by now, check again. */ |  | ||||||
| 		ret = iwl_set_hw_ready(trans); | 		ret = iwl_set_hw_ready(trans); | ||||||
| 		if (ret >= 0) | 		if (ret >= 0) | ||||||
| 			return 0; | 			return 0; | ||||||
|  | 
 | ||||||
|  | 		usleep_range(200, 1000); | ||||||
|  | 		t += 200; | ||||||
|  | 	} while (t < 150000); | ||||||
|  | 
 | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -1769,7 +1769,7 @@ void iwl_dump_csr(struct iwl_trans *trans) | ||||||
| #define DEBUGFS_ADD_FILE(name, parent, mode) do {			\ | #define DEBUGFS_ADD_FILE(name, parent, mode) do {			\ | ||||||
| 	if (!debugfs_create_file(#name, mode, parent, trans,		\ | 	if (!debugfs_create_file(#name, mode, parent, trans,		\ | ||||||
| 				 &iwl_dbgfs_##name##_ops))		\ | 				 &iwl_dbgfs_##name##_ops))		\ | ||||||
| 		return -ENOMEM;						\ | 		goto err;						\ | ||||||
| } while (0) | } while (0) | ||||||
| 
 | 
 | ||||||
| /* file operation */ | /* file operation */ | ||||||
|  | @ -2033,6 +2033,10 @@ static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans, | ||||||
| 	DEBUGFS_ADD_FILE(fh_reg, dir, S_IRUSR); | 	DEBUGFS_ADD_FILE(fh_reg, dir, S_IRUSR); | ||||||
| 	DEBUGFS_ADD_FILE(fw_restart, dir, S_IWUSR); | 	DEBUGFS_ADD_FILE(fw_restart, dir, S_IWUSR); | ||||||
| 	return 0; | 	return 0; | ||||||
|  | 
 | ||||||
|  | err: | ||||||
|  | 	IWL_ERR(trans, "failed to create the trans debugfs entry\n"); | ||||||
|  | 	return -ENOMEM; | ||||||
| } | } | ||||||
| #else | #else | ||||||
| static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans, | static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans, | ||||||
|  |  | ||||||
|  | @ -521,7 +521,7 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) | ||||||
| 	u16 copy_size, cmd_size; | 	u16 copy_size, cmd_size; | ||||||
| 	bool had_nocopy = false; | 	bool had_nocopy = false; | ||||||
| 	int i; | 	int i; | ||||||
| 	u8 *cmd_dest; | 	u32 cmd_pos; | ||||||
| #ifdef CONFIG_IWLWIFI_DEVICE_TRACING | #ifdef CONFIG_IWLWIFI_DEVICE_TRACING | ||||||
| 	const void *trace_bufs[IWL_MAX_CMD_TFDS + 1] = {}; | 	const void *trace_bufs[IWL_MAX_CMD_TFDS + 1] = {}; | ||||||
| 	int trace_lens[IWL_MAX_CMD_TFDS + 1] = {}; | 	int trace_lens[IWL_MAX_CMD_TFDS + 1] = {}; | ||||||
|  | @ -584,15 +584,31 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) | ||||||
| 					 INDEX_TO_SEQ(q->write_ptr)); | 					 INDEX_TO_SEQ(q->write_ptr)); | ||||||
| 
 | 
 | ||||||
| 	/* and copy the data that needs to be copied */ | 	/* and copy the data that needs to be copied */ | ||||||
| 
 | 	cmd_pos = offsetof(struct iwl_device_cmd, payload); | ||||||
| 	cmd_dest = out_cmd->payload; |  | ||||||
| 	for (i = 0; i < IWL_MAX_CMD_TFDS; i++) { | 	for (i = 0; i < IWL_MAX_CMD_TFDS; i++) { | ||||||
| 		if (!cmd->len[i]) | 		if (!cmd->len[i]) | ||||||
| 			continue; | 			continue; | ||||||
| 		if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY) | 		if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY) | ||||||
| 			break; | 			break; | ||||||
| 		memcpy(cmd_dest, cmd->data[i], cmd->len[i]); | 		memcpy((u8 *)out_cmd + cmd_pos, cmd->data[i], cmd->len[i]); | ||||||
| 		cmd_dest += cmd->len[i]; | 		cmd_pos += cmd->len[i]; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	WARN_ON_ONCE(txq->entries[idx].copy_cmd); | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * since out_cmd will be the source address of the FH, it will write | ||||||
|  | 	 * the retry count there. So when the user needs to receivce the HCMD | ||||||
|  | 	 * that corresponds to the response in the response handler, it needs | ||||||
|  | 	 * to set CMD_WANT_HCMD. | ||||||
|  | 	 */ | ||||||
|  | 	if (cmd->flags & CMD_WANT_HCMD) { | ||||||
|  | 		txq->entries[idx].copy_cmd = | ||||||
|  | 			kmemdup(out_cmd, cmd_pos, GFP_ATOMIC); | ||||||
|  | 		if (unlikely(!txq->entries[idx].copy_cmd)) { | ||||||
|  | 			idx = -ENOMEM; | ||||||
|  | 			goto out; | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	IWL_DEBUG_HC(trans, | 	IWL_DEBUG_HC(trans, | ||||||
|  |  | ||||||
|  | @ -227,7 +227,9 @@ static void lbtf_free_adapter(struct lbtf_private *priv) | ||||||
| 	lbtf_deb_leave(LBTF_DEB_MAIN); | 	lbtf_deb_leave(LBTF_DEB_MAIN); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void lbtf_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | static void lbtf_op_tx(struct ieee80211_hw *hw, | ||||||
|  | 		       struct ieee80211_tx_control *control, | ||||||
|  | 		       struct sk_buff *skb) | ||||||
| { | { | ||||||
| 	struct lbtf_private *priv = hw->priv; | 	struct lbtf_private *priv = hw->priv; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -709,7 +709,9 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, | ||||||
| 	return ack; | 	return ack; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | static void mac80211_hwsim_tx(struct ieee80211_hw *hw, | ||||||
|  | 			      struct ieee80211_tx_control *control, | ||||||
|  | 			      struct sk_buff *skb) | ||||||
| { | { | ||||||
| 	bool ack; | 	bool ack; | ||||||
| 	struct ieee80211_tx_info *txi; | 	struct ieee80211_tx_info *txi; | ||||||
|  | @ -1727,6 +1729,7 @@ static const struct ieee80211_iface_limit hwsim_if_limits[] = { | ||||||
| #endif | #endif | ||||||
| 				 BIT(NL80211_IFTYPE_AP) | | 				 BIT(NL80211_IFTYPE_AP) | | ||||||
| 				 BIT(NL80211_IFTYPE_P2P_GO) }, | 				 BIT(NL80211_IFTYPE_P2P_GO) }, | ||||||
|  | 	{ .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) }, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct ieee80211_iface_combination hwsim_if_comb = { | static const struct ieee80211_iface_combination hwsim_if_comb = { | ||||||
|  | @ -1813,7 +1816,8 @@ static int __init init_mac80211_hwsim(void) | ||||||
| 			BIT(NL80211_IFTYPE_P2P_CLIENT) | | 			BIT(NL80211_IFTYPE_P2P_CLIENT) | | ||||||
| 			BIT(NL80211_IFTYPE_P2P_GO) | | 			BIT(NL80211_IFTYPE_P2P_GO) | | ||||||
| 			BIT(NL80211_IFTYPE_ADHOC) | | 			BIT(NL80211_IFTYPE_ADHOC) | | ||||||
| 			BIT(NL80211_IFTYPE_MESH_POINT); | 			BIT(NL80211_IFTYPE_MESH_POINT) | | ||||||
|  | 			BIT(NL80211_IFTYPE_P2P_DEVICE); | ||||||
| 
 | 
 | ||||||
| 		hw->flags = IEEE80211_HW_MFP_CAPABLE | | 		hw->flags = IEEE80211_HW_MFP_CAPABLE | | ||||||
| 			    IEEE80211_HW_SIGNAL_DBM | | 			    IEEE80211_HW_SIGNAL_DBM | | ||||||
|  |  | ||||||
|  | @ -1830,12 +1830,14 @@ static inline void mwl8k_tx_count_packet(struct ieee80211_sta *sta, u8 tid) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void | static void | ||||||
| mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) | mwl8k_txq_xmit(struct ieee80211_hw *hw, | ||||||
|  | 	       int index, | ||||||
|  | 	       struct ieee80211_sta *sta, | ||||||
|  | 	       struct sk_buff *skb) | ||||||
| { | { | ||||||
| 	struct mwl8k_priv *priv = hw->priv; | 	struct mwl8k_priv *priv = hw->priv; | ||||||
| 	struct ieee80211_tx_info *tx_info; | 	struct ieee80211_tx_info *tx_info; | ||||||
| 	struct mwl8k_vif *mwl8k_vif; | 	struct mwl8k_vif *mwl8k_vif; | ||||||
| 	struct ieee80211_sta *sta; |  | ||||||
| 	struct ieee80211_hdr *wh; | 	struct ieee80211_hdr *wh; | ||||||
| 	struct mwl8k_tx_queue *txq; | 	struct mwl8k_tx_queue *txq; | ||||||
| 	struct mwl8k_tx_desc *tx; | 	struct mwl8k_tx_desc *tx; | ||||||
|  | @ -1867,7 +1869,6 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) | ||||||
| 	wh = &((struct mwl8k_dma_data *)skb->data)->wh; | 	wh = &((struct mwl8k_dma_data *)skb->data)->wh; | ||||||
| 
 | 
 | ||||||
| 	tx_info = IEEE80211_SKB_CB(skb); | 	tx_info = IEEE80211_SKB_CB(skb); | ||||||
| 	sta = tx_info->control.sta; |  | ||||||
| 	mwl8k_vif = MWL8K_VIF(tx_info->control.vif); | 	mwl8k_vif = MWL8K_VIF(tx_info->control.vif); | ||||||
| 
 | 
 | ||||||
| 	if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { | 	if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { | ||||||
|  | @ -2019,8 +2020,8 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) | ||||||
| 	tx->pkt_phys_addr = cpu_to_le32(dma); | 	tx->pkt_phys_addr = cpu_to_le32(dma); | ||||||
| 	tx->pkt_len = cpu_to_le16(skb->len); | 	tx->pkt_len = cpu_to_le16(skb->len); | ||||||
| 	tx->rate_info = 0; | 	tx->rate_info = 0; | ||||||
| 	if (!priv->ap_fw && tx_info->control.sta != NULL) | 	if (!priv->ap_fw && sta != NULL) | ||||||
| 		tx->peer_id = MWL8K_STA(tx_info->control.sta)->peer_id; | 		tx->peer_id = MWL8K_STA(sta)->peer_id; | ||||||
| 	else | 	else | ||||||
| 		tx->peer_id = 0; | 		tx->peer_id = 0; | ||||||
| 
 | 
 | ||||||
|  | @ -4364,7 +4365,9 @@ static void mwl8k_rx_poll(unsigned long data) | ||||||
| /*
 | /*
 | ||||||
|  * Core driver operations. |  * Core driver operations. | ||||||
|  */ |  */ | ||||||
| static void mwl8k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | static void mwl8k_tx(struct ieee80211_hw *hw, | ||||||
|  | 		     struct ieee80211_tx_control *control, | ||||||
|  | 		     struct sk_buff *skb) | ||||||
| { | { | ||||||
| 	struct mwl8k_priv *priv = hw->priv; | 	struct mwl8k_priv *priv = hw->priv; | ||||||
| 	int index = skb_get_queue_mapping(skb); | 	int index = skb_get_queue_mapping(skb); | ||||||
|  | @ -4376,7 +4379,7 @@ static void mwl8k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	mwl8k_txq_xmit(hw, index, skb); | 	mwl8k_txq_xmit(hw, index, control->sta, skb); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int mwl8k_start(struct ieee80211_hw *hw) | static int mwl8k_start(struct ieee80211_hw *hw) | ||||||
|  |  | ||||||
|  | @ -526,7 +526,9 @@ int p54_init_leds(struct p54_common *priv); | ||||||
| void p54_unregister_leds(struct p54_common *priv); | void p54_unregister_leds(struct p54_common *priv); | ||||||
| 
 | 
 | ||||||
| /* xmit functions */ | /* xmit functions */ | ||||||
| void p54_tx_80211(struct ieee80211_hw *dev, struct sk_buff *skb); | void p54_tx_80211(struct ieee80211_hw *dev, | ||||||
|  | 		  struct ieee80211_tx_control *control, | ||||||
|  | 		  struct sk_buff *skb); | ||||||
| int p54_tx_cancel(struct p54_common *priv, __le32 req_id); | int p54_tx_cancel(struct p54_common *priv, __le32 req_id); | ||||||
| void p54_tx(struct p54_common *priv, struct sk_buff *skb); | void p54_tx(struct p54_common *priv, struct sk_buff *skb); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -158,7 +158,7 @@ static int p54_beacon_update(struct p54_common *priv, | ||||||
| 	 * to cancel the old beacon template by hand, instead the firmware | 	 * to cancel the old beacon template by hand, instead the firmware | ||||||
| 	 * will release the previous one through the feedback mechanism. | 	 * will release the previous one through the feedback mechanism. | ||||||
| 	 */ | 	 */ | ||||||
| 	p54_tx_80211(priv->hw, beacon); | 	p54_tx_80211(priv->hw, NULL, beacon); | ||||||
| 	priv->tsf_high32 = 0; | 	priv->tsf_high32 = 0; | ||||||
| 	priv->tsf_low32 = 0; | 	priv->tsf_low32 = 0; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -676,8 +676,9 @@ int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb) | ||||||
| EXPORT_SYMBOL_GPL(p54_rx); | EXPORT_SYMBOL_GPL(p54_rx); | ||||||
| 
 | 
 | ||||||
| static void p54_tx_80211_header(struct p54_common *priv, struct sk_buff *skb, | static void p54_tx_80211_header(struct p54_common *priv, struct sk_buff *skb, | ||||||
| 				struct ieee80211_tx_info *info, u8 *queue, | 				struct ieee80211_tx_info *info, | ||||||
| 				u32 *extra_len, u16 *flags, u16 *aid, | 				struct ieee80211_sta *sta, | ||||||
|  | 				u8 *queue, u32 *extra_len, u16 *flags, u16 *aid, | ||||||
| 				bool *burst_possible) | 				bool *burst_possible) | ||||||
| { | { | ||||||
| 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||||||
|  | @ -746,8 +747,8 @@ static void p54_tx_80211_header(struct p54_common *priv, struct sk_buff *skb, | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (info->control.sta) | 		if (sta) | ||||||
| 			*aid = info->control.sta->aid; | 			*aid = sta->aid; | ||||||
| 		break; | 		break; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | @ -767,7 +768,9 @@ static u8 p54_convert_algo(u32 cipher) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void p54_tx_80211(struct ieee80211_hw *dev, struct sk_buff *skb) | void p54_tx_80211(struct ieee80211_hw *dev, | ||||||
|  | 		  struct ieee80211_tx_control *control, | ||||||
|  | 		  struct sk_buff *skb) | ||||||
| { | { | ||||||
| 	struct p54_common *priv = dev->priv; | 	struct p54_common *priv = dev->priv; | ||||||
| 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||||||
|  | @ -784,7 +787,7 @@ void p54_tx_80211(struct ieee80211_hw *dev, struct sk_buff *skb) | ||||||
| 	u8 nrates = 0, nremaining = 8; | 	u8 nrates = 0, nremaining = 8; | ||||||
| 	bool burst_allowed = false; | 	bool burst_allowed = false; | ||||||
| 
 | 
 | ||||||
| 	p54_tx_80211_header(priv, skb, info, &queue, &extra_len, | 	p54_tx_80211_header(priv, skb, info, control->sta, &queue, &extra_len, | ||||||
| 			    &hdr_flags, &aid, &burst_allowed); | 			    &hdr_flags, &aid, &burst_allowed); | ||||||
| 
 | 
 | ||||||
| 	if (p54_tx_qos_accounting_alloc(priv, skb, queue)) { | 	if (p54_tx_qos_accounting_alloc(priv, skb, queue)) { | ||||||
|  |  | ||||||
|  | @ -1287,7 +1287,9 @@ void rt2x00lib_rxdone(struct queue_entry *entry, gfp_t gfp); | ||||||
| /*
 | /*
 | ||||||
|  * mac80211 handlers. |  * mac80211 handlers. | ||||||
|  */ |  */ | ||||||
| void rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb); | void rt2x00mac_tx(struct ieee80211_hw *hw, | ||||||
|  | 		  struct ieee80211_tx_control *control, | ||||||
|  | 		  struct sk_buff *skb); | ||||||
| int rt2x00mac_start(struct ieee80211_hw *hw); | int rt2x00mac_start(struct ieee80211_hw *hw); | ||||||
| void rt2x00mac_stop(struct ieee80211_hw *hw); | void rt2x00mac_stop(struct ieee80211_hw *hw); | ||||||
| int rt2x00mac_add_interface(struct ieee80211_hw *hw, | int rt2x00mac_add_interface(struct ieee80211_hw *hw, | ||||||
|  |  | ||||||
|  | @ -194,7 +194,7 @@ static void rt2x00lib_bc_buffer_iter(void *data, u8 *mac, | ||||||
| 	 */ | 	 */ | ||||||
| 	skb = ieee80211_get_buffered_bc(rt2x00dev->hw, vif); | 	skb = ieee80211_get_buffered_bc(rt2x00dev->hw, vif); | ||||||
| 	while (skb) { | 	while (skb) { | ||||||
| 		rt2x00mac_tx(rt2x00dev->hw, skb); | 		rt2x00mac_tx(rt2x00dev->hw, NULL, skb); | ||||||
| 		skb = ieee80211_get_buffered_bc(rt2x00dev->hw, vif); | 		skb = ieee80211_get_buffered_bc(rt2x00dev->hw, vif); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -99,7 +99,9 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, | ||||||
| 	return retval; | 	return retval; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | void rt2x00mac_tx(struct ieee80211_hw *hw, | ||||||
|  | 		  struct ieee80211_tx_control *control, | ||||||
|  | 		  struct sk_buff *skb) | ||||||
| { | { | ||||||
| 	struct rt2x00_dev *rt2x00dev = hw->priv; | 	struct rt2x00_dev *rt2x00dev = hw->priv; | ||||||
| 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | ||||||
|  |  | ||||||
|  | @ -315,6 +315,7 @@ static void rt2x00queue_create_tx_descriptor_plcp(struct rt2x00_dev *rt2x00dev, | ||||||
| static void rt2x00queue_create_tx_descriptor_ht(struct rt2x00_dev *rt2x00dev, | static void rt2x00queue_create_tx_descriptor_ht(struct rt2x00_dev *rt2x00dev, | ||||||
| 						struct sk_buff *skb, | 						struct sk_buff *skb, | ||||||
| 						struct txentry_desc *txdesc, | 						struct txentry_desc *txdesc, | ||||||
|  | 						struct ieee80211_sta *sta, | ||||||
| 						const struct rt2x00_rate *hwrate) | 						const struct rt2x00_rate *hwrate) | ||||||
| { | { | ||||||
| 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | ||||||
|  | @ -322,11 +323,11 @@ static void rt2x00queue_create_tx_descriptor_ht(struct rt2x00_dev *rt2x00dev, | ||||||
| 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||||||
| 	struct rt2x00_sta *sta_priv = NULL; | 	struct rt2x00_sta *sta_priv = NULL; | ||||||
| 
 | 
 | ||||||
| 	if (tx_info->control.sta) { | 	if (sta) { | ||||||
| 		txdesc->u.ht.mpdu_density = | 		txdesc->u.ht.mpdu_density = | ||||||
| 		    tx_info->control.sta->ht_cap.ampdu_density; | 		    sta->ht_cap.ampdu_density; | ||||||
| 
 | 
 | ||||||
| 		sta_priv = sta_to_rt2x00_sta(tx_info->control.sta); | 		sta_priv = sta_to_rt2x00_sta(sta); | ||||||
| 		txdesc->u.ht.wcid = sta_priv->wcid; | 		txdesc->u.ht.wcid = sta_priv->wcid; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -341,8 +342,8 @@ static void rt2x00queue_create_tx_descriptor_ht(struct rt2x00_dev *rt2x00dev, | ||||||
| 		 * MIMO PS should be set to 1 for STA's using dynamic SM PS | 		 * MIMO PS should be set to 1 for STA's using dynamic SM PS | ||||||
| 		 * when using more then one tx stream (>MCS7). | 		 * when using more then one tx stream (>MCS7). | ||||||
| 		 */ | 		 */ | ||||||
| 		if (tx_info->control.sta && txdesc->u.ht.mcs > 7 && | 		if (sta && txdesc->u.ht.mcs > 7 && | ||||||
| 		    ((tx_info->control.sta->ht_cap.cap & | 		    ((sta->ht_cap.cap & | ||||||
| 		      IEEE80211_HT_CAP_SM_PS) >> | 		      IEEE80211_HT_CAP_SM_PS) >> | ||||||
| 		     IEEE80211_HT_CAP_SM_PS_SHIFT) == | 		     IEEE80211_HT_CAP_SM_PS_SHIFT) == | ||||||
| 		    WLAN_HT_CAP_SM_PS_DYNAMIC) | 		    WLAN_HT_CAP_SM_PS_DYNAMIC) | ||||||
|  | @ -409,7 +410,8 @@ static void rt2x00queue_create_tx_descriptor_ht(struct rt2x00_dev *rt2x00dev, | ||||||
| 
 | 
 | ||||||
| static void rt2x00queue_create_tx_descriptor(struct rt2x00_dev *rt2x00dev, | static void rt2x00queue_create_tx_descriptor(struct rt2x00_dev *rt2x00dev, | ||||||
| 					     struct sk_buff *skb, | 					     struct sk_buff *skb, | ||||||
| 					     struct txentry_desc *txdesc) | 					     struct txentry_desc *txdesc, | ||||||
|  | 					     struct ieee80211_sta *sta) | ||||||
| { | { | ||||||
| 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | ||||||
| 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||||||
|  | @ -503,7 +505,7 @@ static void rt2x00queue_create_tx_descriptor(struct rt2x00_dev *rt2x00dev, | ||||||
| 
 | 
 | ||||||
| 	if (test_bit(REQUIRE_HT_TX_DESC, &rt2x00dev->cap_flags)) | 	if (test_bit(REQUIRE_HT_TX_DESC, &rt2x00dev->cap_flags)) | ||||||
| 		rt2x00queue_create_tx_descriptor_ht(rt2x00dev, skb, txdesc, | 		rt2x00queue_create_tx_descriptor_ht(rt2x00dev, skb, txdesc, | ||||||
| 						    hwrate); | 						   sta, hwrate); | ||||||
| 	else | 	else | ||||||
| 		rt2x00queue_create_tx_descriptor_plcp(rt2x00dev, skb, txdesc, | 		rt2x00queue_create_tx_descriptor_plcp(rt2x00dev, skb, txdesc, | ||||||
| 						      hwrate); | 						      hwrate); | ||||||
|  | @ -595,7 +597,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, | ||||||
| 	 * after that we are free to use the skb->cb array | 	 * after that we are free to use the skb->cb array | ||||||
| 	 * for our information. | 	 * for our information. | ||||||
| 	 */ | 	 */ | ||||||
| 	rt2x00queue_create_tx_descriptor(queue->rt2x00dev, skb, &txdesc); | 	rt2x00queue_create_tx_descriptor(queue->rt2x00dev, skb, &txdesc, NULL); | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * All information is retrieved from the skb->cb array, | 	 * All information is retrieved from the skb->cb array, | ||||||
|  | @ -740,7 +742,7 @@ int rt2x00queue_update_beacon_locked(struct rt2x00_dev *rt2x00dev, | ||||||
| 	 * after that we are free to use the skb->cb array | 	 * after that we are free to use the skb->cb array | ||||||
| 	 * for our information. | 	 * for our information. | ||||||
| 	 */ | 	 */ | ||||||
| 	rt2x00queue_create_tx_descriptor(rt2x00dev, intf->beacon->skb, &txdesc); | 	rt2x00queue_create_tx_descriptor(rt2x00dev, intf->beacon->skb, &txdesc, NULL); | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Fill in skb descriptor | 	 * Fill in skb descriptor | ||||||
|  |  | ||||||
|  | @ -244,7 +244,9 @@ static irqreturn_t rtl8180_interrupt(int irq, void *dev_id) | ||||||
| 	return IRQ_HANDLED; | 	return IRQ_HANDLED; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb) | static void rtl8180_tx(struct ieee80211_hw *dev, | ||||||
|  | 		       struct ieee80211_tx_control *control, | ||||||
|  | 		       struct sk_buff *skb) | ||||||
| { | { | ||||||
| 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||||||
| 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||||||
|  | @ -710,7 +712,7 @@ static void rtl8180_beacon_work(struct work_struct *work) | ||||||
| 	/* TODO: use actual beacon queue */ | 	/* TODO: use actual beacon queue */ | ||||||
| 	skb_set_queue_mapping(skb, 0); | 	skb_set_queue_mapping(skb, 0); | ||||||
| 
 | 
 | ||||||
| 	rtl8180_tx(dev, skb); | 	rtl8180_tx(dev, NULL, skb); | ||||||
| 
 | 
 | ||||||
| resched: | resched: | ||||||
| 	/*
 | 	/*
 | ||||||
|  |  | ||||||
|  | @ -228,7 +228,9 @@ static void rtl8187_tx_cb(struct urb *urb) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) | static void rtl8187_tx(struct ieee80211_hw *dev, | ||||||
|  | 		       struct ieee80211_tx_control *control, | ||||||
|  | 		       struct sk_buff *skb) | ||||||
| { | { | ||||||
| 	struct rtl8187_priv *priv = dev->priv; | 	struct rtl8187_priv *priv = dev->priv; | ||||||
| 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||||||
|  | @ -1076,7 +1078,7 @@ static void rtl8187_beacon_work(struct work_struct *work) | ||||||
| 	/* TODO: use actual beacon queue */ | 	/* TODO: use actual beacon queue */ | ||||||
| 	skb_set_queue_mapping(skb, 0); | 	skb_set_queue_mapping(skb, 0); | ||||||
| 
 | 
 | ||||||
| 	rtl8187_tx(dev, skb); | 	rtl8187_tx(dev, NULL, skb); | ||||||
| 
 | 
 | ||||||
| resched: | resched: | ||||||
| 	/*
 | 	/*
 | ||||||
|  |  | ||||||
|  | @ -1341,9 +1341,8 @@ int rtl_send_smps_action(struct ieee80211_hw *hw, | ||||||
| 		rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0); | 		rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0); | ||||||
| 
 | 
 | ||||||
| 		info->control.rates[0].idx = 0; | 		info->control.rates[0].idx = 0; | ||||||
| 		info->control.sta = sta; |  | ||||||
| 		info->band = hw->conf.channel->band; | 		info->band = hw->conf.channel->band; | ||||||
| 		rtlpriv->intf_ops->adapter_tx(hw, skb, &tcb_desc); | 		rtlpriv->intf_ops->adapter_tx(hw, sta, skb, &tcb_desc); | ||||||
| 	} | 	} | ||||||
| err_free: | err_free: | ||||||
| 	return 0; | 	return 0; | ||||||
|  |  | ||||||
|  | @ -124,7 +124,9 @@ static void rtl_op_stop(struct ieee80211_hw *hw) | ||||||
| 	mutex_unlock(&rtlpriv->locks.conf_mutex); | 	mutex_unlock(&rtlpriv->locks.conf_mutex); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void rtl_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | static void rtl_op_tx(struct ieee80211_hw *hw, | ||||||
|  | 		      struct ieee80211_tx_control *control, | ||||||
|  | 		      struct sk_buff *skb) | ||||||
| { | { | ||||||
| 	struct rtl_priv *rtlpriv = rtl_priv(hw); | 	struct rtl_priv *rtlpriv = rtl_priv(hw); | ||||||
| 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); | 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); | ||||||
|  | @ -138,8 +140,8 @@ static void rtl_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | ||||||
| 	if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status)) | 	if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status)) | ||||||
| 		goto err_free; | 		goto err_free; | ||||||
| 
 | 
 | ||||||
| 	if (!rtlpriv->intf_ops->waitq_insert(hw, skb)) | 	if (!rtlpriv->intf_ops->waitq_insert(hw, control->sta, skb)) | ||||||
| 		rtlpriv->intf_ops->adapter_tx(hw, skb, &tcb_desc); | 		rtlpriv->intf_ops->adapter_tx(hw, control->sta, skb, &tcb_desc); | ||||||
| 
 | 
 | ||||||
| 	return; | 	return; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -504,7 +504,7 @@ static void _rtl_pci_tx_chk_waitq(struct ieee80211_hw *hw) | ||||||
| 				_rtl_update_earlymode_info(hw, skb, | 				_rtl_update_earlymode_info(hw, skb, | ||||||
| 							   &tcb_desc, tid); | 							   &tcb_desc, tid); | ||||||
| 
 | 
 | ||||||
| 			rtlpriv->intf_ops->adapter_tx(hw, skb, &tcb_desc); | 			rtlpriv->intf_ops->adapter_tx(hw, NULL, skb, &tcb_desc); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | @ -929,7 +929,7 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw) | ||||||
| 	info = IEEE80211_SKB_CB(pskb); | 	info = IEEE80211_SKB_CB(pskb); | ||||||
| 	pdesc = &ring->desc[0]; | 	pdesc = &ring->desc[0]; | ||||||
| 	rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *) pdesc, | 	rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *) pdesc, | ||||||
| 		info, pskb, BEACON_QUEUE, &tcb_desc); | 		info, NULL, pskb, BEACON_QUEUE, &tcb_desc); | ||||||
| 
 | 
 | ||||||
| 	__skb_queue_tail(&ring->queue, pskb); | 	__skb_queue_tail(&ring->queue, pskb); | ||||||
| 
 | 
 | ||||||
|  | @ -1305,11 +1305,10 @@ int rtl_pci_reset_trx_ring(struct ieee80211_hw *hw) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool rtl_pci_tx_chk_waitq_insert(struct ieee80211_hw *hw, | static bool rtl_pci_tx_chk_waitq_insert(struct ieee80211_hw *hw, | ||||||
|  | 					struct ieee80211_sta *sta, | ||||||
| 					struct sk_buff *skb) | 					struct sk_buff *skb) | ||||||
| { | { | ||||||
| 	struct rtl_priv *rtlpriv = rtl_priv(hw); | 	struct rtl_priv *rtlpriv = rtl_priv(hw); | ||||||
| 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |  | ||||||
| 	struct ieee80211_sta *sta = info->control.sta; |  | ||||||
| 	struct rtl_sta_info *sta_entry = NULL; | 	struct rtl_sta_info *sta_entry = NULL; | ||||||
| 	u8 tid = rtl_get_tid(skb); | 	u8 tid = rtl_get_tid(skb); | ||||||
| 
 | 
 | ||||||
|  | @ -1337,13 +1336,14 @@ static bool rtl_pci_tx_chk_waitq_insert(struct ieee80211_hw *hw, | ||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb, | static int rtl_pci_tx(struct ieee80211_hw *hw, | ||||||
|  | 		      struct ieee80211_sta *sta, | ||||||
|  | 		      struct sk_buff *skb, | ||||||
| 		      struct rtl_tcb_desc *ptcb_desc) | 		      struct rtl_tcb_desc *ptcb_desc) | ||||||
| { | { | ||||||
| 	struct rtl_priv *rtlpriv = rtl_priv(hw); | 	struct rtl_priv *rtlpriv = rtl_priv(hw); | ||||||
| 	struct rtl_sta_info *sta_entry = NULL; | 	struct rtl_sta_info *sta_entry = NULL; | ||||||
| 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||||||
| 	struct ieee80211_sta *sta = info->control.sta; |  | ||||||
| 	struct rtl8192_tx_ring *ring; | 	struct rtl8192_tx_ring *ring; | ||||||
| 	struct rtl_tx_desc *pdesc; | 	struct rtl_tx_desc *pdesc; | ||||||
| 	u8 idx; | 	u8 idx; | ||||||
|  | @ -1418,7 +1418,7 @@ static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb, | ||||||
| 		rtlpriv->cfg->ops->led_control(hw, LED_CTL_TX); | 		rtlpriv->cfg->ops->led_control(hw, LED_CTL_TX); | ||||||
| 
 | 
 | ||||||
| 	rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc, | 	rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc, | ||||||
| 			info, skb, hw_queue, ptcb_desc); | 			info, sta, skb, hw_queue, ptcb_desc); | ||||||
| 
 | 
 | ||||||
| 	__skb_queue_tail(&ring->queue, skb); | 	__skb_queue_tail(&ring->queue, skb); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -596,7 +596,9 @@ bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw, | ||||||
| 
 | 
 | ||||||
| void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, | void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, | ||||||
| 			  struct ieee80211_hdr *hdr, u8 *pdesc_tx, | 			  struct ieee80211_hdr *hdr, u8 *pdesc_tx, | ||||||
| 			  struct ieee80211_tx_info *info, struct sk_buff *skb, | 			  struct ieee80211_tx_info *info, | ||||||
|  | 			  struct ieee80211_sta *sta, | ||||||
|  | 			  struct sk_buff *skb, | ||||||
| 			  u8 hw_queue, struct rtl_tcb_desc *tcb_desc) | 			  u8 hw_queue, struct rtl_tcb_desc *tcb_desc) | ||||||
| { | { | ||||||
| 	struct rtl_priv *rtlpriv = rtl_priv(hw); | 	struct rtl_priv *rtlpriv = rtl_priv(hw); | ||||||
|  | @ -604,7 +606,6 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, | ||||||
| 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); | 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); | ||||||
| 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); | 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); | ||||||
| 	bool defaultadapter = true; | 	bool defaultadapter = true; | ||||||
| 	struct ieee80211_sta *sta; |  | ||||||
| 	u8 *pdesc = pdesc_tx; | 	u8 *pdesc = pdesc_tx; | ||||||
| 	u16 seq_number; | 	u16 seq_number; | ||||||
| 	__le16 fc = hdr->frame_control; | 	__le16 fc = hdr->frame_control; | ||||||
|  |  | ||||||
|  | @ -713,6 +713,7 @@ struct rx_desc_92c { | ||||||
| void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, | void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, | ||||||
| 			  struct ieee80211_hdr *hdr, | 			  struct ieee80211_hdr *hdr, | ||||||
| 			  u8 *pdesc, struct ieee80211_tx_info *info, | 			  u8 *pdesc, struct ieee80211_tx_info *info, | ||||||
|  | 			  struct ieee80211_sta *sta, | ||||||
| 			  struct sk_buff *skb, u8 hw_queue, | 			  struct sk_buff *skb, u8 hw_queue, | ||||||
| 			  struct rtl_tcb_desc *ptcb_desc); | 			  struct rtl_tcb_desc *ptcb_desc); | ||||||
| bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw, | bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw, | ||||||
|  |  | ||||||
|  | @ -496,7 +496,9 @@ static void _rtl_tx_desc_checksum(u8 *txdesc) | ||||||
| 
 | 
 | ||||||
| void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, | void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, | ||||||
| 			  struct ieee80211_hdr *hdr, u8 *pdesc_tx, | 			  struct ieee80211_hdr *hdr, u8 *pdesc_tx, | ||||||
| 			  struct ieee80211_tx_info *info, struct sk_buff *skb, | 			  struct ieee80211_tx_info *info, | ||||||
|  | 			  struct ieee80211_sta *sta, | ||||||
|  | 			  struct sk_buff *skb, | ||||||
| 			  u8 queue_index, | 			  u8 queue_index, | ||||||
| 			  struct rtl_tcb_desc *tcb_desc) | 			  struct rtl_tcb_desc *tcb_desc) | ||||||
| { | { | ||||||
|  | @ -504,7 +506,6 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, | ||||||
| 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); | 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); | ||||||
| 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); | 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); | ||||||
| 	bool defaultadapter = true; | 	bool defaultadapter = true; | ||||||
| 	struct ieee80211_sta *sta = info->control.sta = info->control.sta; |  | ||||||
| 	u8 *qc = ieee80211_get_qos_ctl(hdr); | 	u8 *qc = ieee80211_get_qos_ctl(hdr); | ||||||
| 	u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; | 	u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; | ||||||
| 	u16 seq_number; | 	u16 seq_number; | ||||||
|  |  | ||||||
|  | @ -420,7 +420,9 @@ struct sk_buff *rtl8192c_tx_aggregate_hdl(struct ieee80211_hw *, | ||||||
| 					   struct sk_buff_head *); | 					   struct sk_buff_head *); | ||||||
| void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, | void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, | ||||||
| 			  struct ieee80211_hdr *hdr, u8 *pdesc_tx, | 			  struct ieee80211_hdr *hdr, u8 *pdesc_tx, | ||||||
| 			  struct ieee80211_tx_info *info, struct sk_buff *skb, | 			  struct ieee80211_tx_info *info, | ||||||
|  | 			  struct ieee80211_sta *sta, | ||||||
|  | 			  struct sk_buff *skb, | ||||||
| 			  u8 queue_index, | 			  u8 queue_index, | ||||||
| 			  struct rtl_tcb_desc *tcb_desc); | 			  struct rtl_tcb_desc *tcb_desc); | ||||||
| void rtl92cu_fill_fake_txdesc(struct ieee80211_hw *hw, u8 * pDesc, | void rtl92cu_fill_fake_txdesc(struct ieee80211_hw *hw, u8 * pDesc, | ||||||
|  |  | ||||||
|  | @ -551,7 +551,9 @@ static void _rtl92de_insert_emcontent(struct rtl_tcb_desc *ptcb_desc, | ||||||
| 
 | 
 | ||||||
| void rtl92de_tx_fill_desc(struct ieee80211_hw *hw, | void rtl92de_tx_fill_desc(struct ieee80211_hw *hw, | ||||||
| 			  struct ieee80211_hdr *hdr, u8 *pdesc_tx, | 			  struct ieee80211_hdr *hdr, u8 *pdesc_tx, | ||||||
| 			  struct ieee80211_tx_info *info, struct sk_buff *skb, | 			  struct ieee80211_tx_info *info, | ||||||
|  | 			  struct ieee80211_sta *sta, | ||||||
|  | 			  struct sk_buff *skb, | ||||||
| 			  u8 hw_queue, struct rtl_tcb_desc *ptcb_desc) | 			  u8 hw_queue, struct rtl_tcb_desc *ptcb_desc) | ||||||
| { | { | ||||||
| 	struct rtl_priv *rtlpriv = rtl_priv(hw); | 	struct rtl_priv *rtlpriv = rtl_priv(hw); | ||||||
|  | @ -559,7 +561,6 @@ void rtl92de_tx_fill_desc(struct ieee80211_hw *hw, | ||||||
| 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); | 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); | ||||||
| 	struct rtl_hal *rtlhal = rtl_hal(rtlpriv); | 	struct rtl_hal *rtlhal = rtl_hal(rtlpriv); | ||||||
| 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); | 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); | ||||||
| 	struct ieee80211_sta *sta = info->control.sta; |  | ||||||
| 	u8 *pdesc = pdesc_tx; | 	u8 *pdesc = pdesc_tx; | ||||||
| 	u16 seq_number; | 	u16 seq_number; | ||||||
| 	__le16 fc = hdr->frame_control; | 	__le16 fc = hdr->frame_control; | ||||||
|  |  | ||||||
|  | @ -730,6 +730,7 @@ struct rx_desc_92d { | ||||||
| void rtl92de_tx_fill_desc(struct ieee80211_hw *hw, | void rtl92de_tx_fill_desc(struct ieee80211_hw *hw, | ||||||
| 			  struct ieee80211_hdr *hdr, | 			  struct ieee80211_hdr *hdr, | ||||||
| 			  u8 *pdesc, struct ieee80211_tx_info *info, | 			  u8 *pdesc, struct ieee80211_tx_info *info, | ||||||
|  | 			  struct ieee80211_sta *sta, | ||||||
| 			  struct sk_buff *skb, u8 hw_queue, | 			  struct sk_buff *skb, u8 hw_queue, | ||||||
| 			  struct rtl_tcb_desc *ptcb_desc); | 			  struct rtl_tcb_desc *ptcb_desc); | ||||||
| bool rtl92de_rx_query_desc(struct ieee80211_hw *hw, | bool rtl92de_rx_query_desc(struct ieee80211_hw *hw, | ||||||
|  |  | ||||||
|  | @ -591,14 +591,15 @@ bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, | ||||||
| 
 | 
 | ||||||
| void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, | void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, | ||||||
| 		struct ieee80211_hdr *hdr, u8 *pdesc_tx, | 		struct ieee80211_hdr *hdr, u8 *pdesc_tx, | ||||||
| 		struct ieee80211_tx_info *info, struct sk_buff *skb, | 		struct ieee80211_tx_info *info, | ||||||
|  | 		struct ieee80211_sta *sta, | ||||||
|  | 		struct sk_buff *skb, | ||||||
| 		u8 hw_queue, struct rtl_tcb_desc *ptcb_desc) | 		u8 hw_queue, struct rtl_tcb_desc *ptcb_desc) | ||||||
| { | { | ||||||
| 	struct rtl_priv *rtlpriv = rtl_priv(hw); | 	struct rtl_priv *rtlpriv = rtl_priv(hw); | ||||||
| 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); | 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); | ||||||
| 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); | 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); | ||||||
| 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); | 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); | ||||||
| 	struct ieee80211_sta *sta = info->control.sta; |  | ||||||
| 	u8 *pdesc = pdesc_tx; | 	u8 *pdesc = pdesc_tx; | ||||||
| 	u16 seq_number; | 	u16 seq_number; | ||||||
| 	__le16 fc = hdr->frame_control; | 	__le16 fc = hdr->frame_control; | ||||||
|  |  | ||||||
|  | @ -31,6 +31,7 @@ | ||||||
| 
 | 
 | ||||||
| void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, | void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, | ||||||
| 			  u8 *pdesc, struct ieee80211_tx_info *info, | 			  u8 *pdesc, struct ieee80211_tx_info *info, | ||||||
|  | 			  struct ieee80211_sta *sta, | ||||||
| 			  struct sk_buff *skb, u8 hw_queue, | 			  struct sk_buff *skb, u8 hw_queue, | ||||||
| 			  struct rtl_tcb_desc *ptcb_desc); | 			  struct rtl_tcb_desc *ptcb_desc); | ||||||
| void rtl92se_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, bool firstseg, | void rtl92se_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, bool firstseg, | ||||||
|  |  | ||||||
|  | @ -848,7 +848,9 @@ static void _rtl_usb_transmit(struct ieee80211_hw *hw, struct sk_buff *skb, | ||||||
| 	_rtl_submit_tx_urb(hw, _urb); | 	_rtl_submit_tx_urb(hw, _urb); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void _rtl_usb_tx_preprocess(struct ieee80211_hw *hw, struct sk_buff *skb, | static void _rtl_usb_tx_preprocess(struct ieee80211_hw *hw, | ||||||
|  | 				   struct ieee80211_sta *sta, | ||||||
|  | 				   struct sk_buff *skb, | ||||||
| 				   u16 hw_queue) | 				   u16 hw_queue) | ||||||
| { | { | ||||||
| 	struct rtl_priv *rtlpriv = rtl_priv(hw); | 	struct rtl_priv *rtlpriv = rtl_priv(hw); | ||||||
|  | @ -891,7 +893,7 @@ static void _rtl_usb_tx_preprocess(struct ieee80211_hw *hw, struct sk_buff *skb, | ||||||
| 		seq_number += 1; | 		seq_number += 1; | ||||||
| 		seq_number <<= 4; | 		seq_number <<= 4; | ||||||
| 	} | 	} | ||||||
| 	rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc, info, skb, | 	rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc, info, sta, skb, | ||||||
| 					hw_queue, &tcb_desc); | 					hw_queue, &tcb_desc); | ||||||
| 	if (!ieee80211_has_morefrags(hdr->frame_control)) { | 	if (!ieee80211_has_morefrags(hdr->frame_control)) { | ||||||
| 		if (qc) | 		if (qc) | ||||||
|  | @ -901,7 +903,9 @@ static void _rtl_usb_tx_preprocess(struct ieee80211_hw *hw, struct sk_buff *skb, | ||||||
| 		rtlpriv->cfg->ops->led_control(hw, LED_CTL_TX); | 		rtlpriv->cfg->ops->led_control(hw, LED_CTL_TX); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int rtl_usb_tx(struct ieee80211_hw *hw, struct sk_buff *skb, | static int rtl_usb_tx(struct ieee80211_hw *hw, | ||||||
|  | 		      struct ieee80211_sta *sta, | ||||||
|  | 		      struct sk_buff *skb, | ||||||
| 		      struct rtl_tcb_desc *dummy) | 		      struct rtl_tcb_desc *dummy) | ||||||
| { | { | ||||||
| 	struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); | 	struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); | ||||||
|  | @ -913,7 +917,7 @@ static int rtl_usb_tx(struct ieee80211_hw *hw, struct sk_buff *skb, | ||||||
| 	if (unlikely(is_hal_stop(rtlhal))) | 	if (unlikely(is_hal_stop(rtlhal))) | ||||||
| 		goto err_free; | 		goto err_free; | ||||||
| 	hw_queue = rtlusb->usb_mq_to_hwq(fc, skb_get_queue_mapping(skb)); | 	hw_queue = rtlusb->usb_mq_to_hwq(fc, skb_get_queue_mapping(skb)); | ||||||
| 	_rtl_usb_tx_preprocess(hw, skb, hw_queue); | 	_rtl_usb_tx_preprocess(hw, sta, skb, hw_queue); | ||||||
| 	_rtl_usb_transmit(hw, skb, hw_queue); | 	_rtl_usb_transmit(hw, skb, hw_queue); | ||||||
| 	return NETDEV_TX_OK; | 	return NETDEV_TX_OK; | ||||||
| 
 | 
 | ||||||
|  | @ -923,6 +927,7 @@ err_free: | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool rtl_usb_tx_chk_waitq_insert(struct ieee80211_hw *hw, | static bool rtl_usb_tx_chk_waitq_insert(struct ieee80211_hw *hw, | ||||||
|  | 					struct ieee80211_sta *sta, | ||||||
| 					struct sk_buff *skb) | 					struct sk_buff *skb) | ||||||
| { | { | ||||||
| 	return false; | 	return false; | ||||||
|  |  | ||||||
|  | @ -122,7 +122,7 @@ enum rt_eeprom_type { | ||||||
| 	EEPROM_BOOT_EFUSE, | 	EEPROM_BOOT_EFUSE, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| enum rtl_status { | enum ttl_status { | ||||||
| 	RTL_STATUS_INTERFACE_START = 0, | 	RTL_STATUS_INTERFACE_START = 0, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | @ -1418,6 +1418,7 @@ struct rtl_hal_ops { | ||||||
| 	void (*fill_tx_desc) (struct ieee80211_hw *hw, | 	void (*fill_tx_desc) (struct ieee80211_hw *hw, | ||||||
| 			      struct ieee80211_hdr *hdr, u8 *pdesc_tx, | 			      struct ieee80211_hdr *hdr, u8 *pdesc_tx, | ||||||
| 			      struct ieee80211_tx_info *info, | 			      struct ieee80211_tx_info *info, | ||||||
|  | 			      struct ieee80211_sta *sta, | ||||||
| 			      struct sk_buff *skb, u8 hw_queue, | 			      struct sk_buff *skb, u8 hw_queue, | ||||||
| 			      struct rtl_tcb_desc *ptcb_desc); | 			      struct rtl_tcb_desc *ptcb_desc); | ||||||
| 	void (*fill_fake_txdesc) (struct ieee80211_hw *hw, u8 *pDesc, | 	void (*fill_fake_txdesc) (struct ieee80211_hw *hw, u8 *pDesc, | ||||||
|  | @ -1475,11 +1476,15 @@ struct rtl_intf_ops { | ||||||
| 	int (*adapter_start) (struct ieee80211_hw *hw); | 	int (*adapter_start) (struct ieee80211_hw *hw); | ||||||
| 	void (*adapter_stop) (struct ieee80211_hw *hw); | 	void (*adapter_stop) (struct ieee80211_hw *hw); | ||||||
| 
 | 
 | ||||||
| 	int (*adapter_tx) (struct ieee80211_hw *hw, struct sk_buff *skb, | 	int (*adapter_tx) (struct ieee80211_hw *hw, | ||||||
|  | 			   struct ieee80211_sta *sta, | ||||||
|  | 			   struct sk_buff *skb, | ||||||
| 			   struct rtl_tcb_desc *ptcb_desc); | 			   struct rtl_tcb_desc *ptcb_desc); | ||||||
| 	void (*flush)(struct ieee80211_hw *hw, bool drop); | 	void (*flush)(struct ieee80211_hw *hw, bool drop); | ||||||
| 	int (*reset_trx_ring) (struct ieee80211_hw *hw); | 	int (*reset_trx_ring) (struct ieee80211_hw *hw); | ||||||
| 	bool (*waitq_insert) (struct ieee80211_hw *hw, struct sk_buff *skb); | 	bool (*waitq_insert) (struct ieee80211_hw *hw, | ||||||
|  | 			      struct ieee80211_sta *sta, | ||||||
|  | 			      struct sk_buff *skb); | ||||||
| 
 | 
 | ||||||
| 	/*pci */ | 	/*pci */ | ||||||
| 	void (*disable_aspm) (struct ieee80211_hw *hw); | 	void (*disable_aspm) (struct ieee80211_hw *hw); | ||||||
|  |  | ||||||
|  | @ -354,7 +354,9 @@ out: | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | static void wl1251_op_tx(struct ieee80211_hw *hw, | ||||||
|  | 			 struct ieee80211_tx_control *control, | ||||||
|  | 			 struct sk_buff *skb) | ||||||
| { | { | ||||||
| 	struct wl1251 *wl = hw->priv; | 	struct wl1251 *wl = hw->priv; | ||||||
| 	unsigned long flags; | 	unsigned long flags; | ||||||
|  |  | ||||||
|  | @ -1181,7 +1181,9 @@ out: | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | static void wl1271_op_tx(struct ieee80211_hw *hw, | ||||||
|  | 			 struct ieee80211_tx_control *control, | ||||||
|  | 			 struct sk_buff *skb) | ||||||
| { | { | ||||||
| 	struct wl1271 *wl = hw->priv; | 	struct wl1271 *wl = hw->priv; | ||||||
| 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||||||
|  | @ -1197,7 +1199,7 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | ||||||
| 	mapping = skb_get_queue_mapping(skb); | 	mapping = skb_get_queue_mapping(skb); | ||||||
| 	q = wl1271_tx_get_queue(mapping); | 	q = wl1271_tx_get_queue(mapping); | ||||||
| 
 | 
 | ||||||
| 	hlid = wl12xx_tx_get_hlid(wl, wlvif, skb); | 	hlid = wl12xx_tx_get_hlid(wl, wlvif, skb, control->sta); | ||||||
| 
 | 
 | ||||||
| 	spin_lock_irqsave(&wl->wl_lock, flags); | 	spin_lock_irqsave(&wl->wl_lock, flags); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -130,16 +130,13 @@ bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb) | ||||||
| } | } | ||||||
| EXPORT_SYMBOL(wl12xx_is_dummy_packet); | EXPORT_SYMBOL(wl12xx_is_dummy_packet); | ||||||
| 
 | 
 | ||||||
| u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif, | static u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||||||
| 			 struct sk_buff *skb) | 				struct sk_buff *skb, struct ieee80211_sta *sta) | ||||||
| { | { | ||||||
| 	struct ieee80211_tx_info *control = IEEE80211_SKB_CB(skb); | 	if (sta) { | ||||||
| 
 |  | ||||||
| 	if (control->control.sta) { |  | ||||||
| 		struct wl1271_station *wl_sta; | 		struct wl1271_station *wl_sta; | ||||||
| 
 | 
 | ||||||
| 		wl_sta = (struct wl1271_station *) | 		wl_sta = (struct wl1271_station *)sta->drv_priv; | ||||||
| 				control->control.sta->drv_priv; |  | ||||||
| 		return wl_sta->hlid; | 		return wl_sta->hlid; | ||||||
| 	} else { | 	} else { | ||||||
| 		struct ieee80211_hdr *hdr; | 		struct ieee80211_hdr *hdr; | ||||||
|  | @ -156,7 +153,7 @@ u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| u8 wl12xx_tx_get_hlid(struct wl1271 *wl, struct wl12xx_vif *wlvif, | u8 wl12xx_tx_get_hlid(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||||||
| 		      struct sk_buff *skb) | 		      struct sk_buff *skb, struct ieee80211_sta *sta) | ||||||
| { | { | ||||||
| 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||||||
| 
 | 
 | ||||||
|  | @ -164,7 +161,7 @@ u8 wl12xx_tx_get_hlid(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||||||
| 		return wl->system_hlid; | 		return wl->system_hlid; | ||||||
| 
 | 
 | ||||||
| 	if (wlvif->bss_type == BSS_TYPE_AP_BSS) | 	if (wlvif->bss_type == BSS_TYPE_AP_BSS) | ||||||
| 		return wl12xx_tx_get_hlid_ap(wl, wlvif, skb); | 		return wl12xx_tx_get_hlid_ap(wl, wlvif, skb, sta); | ||||||
| 
 | 
 | ||||||
| 	if ((test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) || | 	if ((test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) || | ||||||
| 	     test_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags)) && | 	     test_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags)) && | ||||||
|  | @ -344,13 +341,12 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||||||
| 
 | 
 | ||||||
| /* caller must hold wl->mutex */ | /* caller must hold wl->mutex */ | ||||||
| static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif, | static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||||||
| 				   struct sk_buff *skb, u32 buf_offset) | 				   struct sk_buff *skb, u32 buf_offset, u8 hlid) | ||||||
| { | { | ||||||
| 	struct ieee80211_tx_info *info; | 	struct ieee80211_tx_info *info; | ||||||
| 	u32 extra = 0; | 	u32 extra = 0; | ||||||
| 	int ret = 0; | 	int ret = 0; | ||||||
| 	u32 total_len; | 	u32 total_len; | ||||||
| 	u8 hlid; |  | ||||||
| 	bool is_dummy; | 	bool is_dummy; | ||||||
| 	bool is_gem = false; | 	bool is_gem = false; | ||||||
| 
 | 
 | ||||||
|  | @ -359,9 +355,13 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if (hlid == WL12XX_INVALID_LINK_ID) { | ||||||
|  | 		wl1271_error("invalid hlid. dropping skb 0x%p", skb); | ||||||
|  | 		return -EINVAL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	info = IEEE80211_SKB_CB(skb); | 	info = IEEE80211_SKB_CB(skb); | ||||||
| 
 | 
 | ||||||
| 	/* TODO: handle dummy packets on multi-vifs */ |  | ||||||
| 	is_dummy = wl12xx_is_dummy_packet(wl, skb); | 	is_dummy = wl12xx_is_dummy_packet(wl, skb); | ||||||
| 
 | 
 | ||||||
| 	if ((wl->quirks & WLCORE_QUIRK_TKIP_HEADER_SPACE) && | 	if ((wl->quirks & WLCORE_QUIRK_TKIP_HEADER_SPACE) && | ||||||
|  | @ -386,11 +386,6 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||||||
| 
 | 
 | ||||||
| 		is_gem = (cipher == WL1271_CIPHER_SUITE_GEM); | 		is_gem = (cipher == WL1271_CIPHER_SUITE_GEM); | ||||||
| 	} | 	} | ||||||
| 	hlid = wl12xx_tx_get_hlid(wl, wlvif, skb); |  | ||||||
| 	if (hlid == WL12XX_INVALID_LINK_ID) { |  | ||||||
| 		wl1271_error("invalid hlid. dropping skb 0x%p", skb); |  | ||||||
| 		return -EINVAL; |  | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	ret = wl1271_tx_allocate(wl, wlvif, skb, extra, buf_offset, hlid, | 	ret = wl1271_tx_allocate(wl, wlvif, skb, extra, buf_offset, hlid, | ||||||
| 				 is_gem); | 				 is_gem); | ||||||
|  | @ -517,7 +512,8 @@ static struct sk_buff *wl12xx_lnk_skb_dequeue(struct wl1271 *wl, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static struct sk_buff *wl12xx_vif_skb_dequeue(struct wl1271 *wl, | static struct sk_buff *wl12xx_vif_skb_dequeue(struct wl1271 *wl, | ||||||
| 					      struct wl12xx_vif *wlvif) | 					      struct wl12xx_vif *wlvif, | ||||||
|  | 					      u8 *hlid) | ||||||
| { | { | ||||||
| 	struct sk_buff *skb = NULL; | 	struct sk_buff *skb = NULL; | ||||||
| 	int i, h, start_hlid; | 	int i, h, start_hlid; | ||||||
|  | @ -544,10 +540,11 @@ static struct sk_buff *wl12xx_vif_skb_dequeue(struct wl1271 *wl, | ||||||
| 	if (!skb) | 	if (!skb) | ||||||
| 		wlvif->last_tx_hlid = 0; | 		wlvif->last_tx_hlid = 0; | ||||||
| 
 | 
 | ||||||
|  | 	*hlid = wlvif->last_tx_hlid; | ||||||
| 	return skb; | 	return skb; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl) | static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl, u8 *hlid) | ||||||
| { | { | ||||||
| 	unsigned long flags; | 	unsigned long flags; | ||||||
| 	struct wl12xx_vif *wlvif = wl->last_wlvif; | 	struct wl12xx_vif *wlvif = wl->last_wlvif; | ||||||
|  | @ -556,7 +553,7 @@ static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl) | ||||||
| 	/* continue from last wlvif (round robin) */ | 	/* continue from last wlvif (round robin) */ | ||||||
| 	if (wlvif) { | 	if (wlvif) { | ||||||
| 		wl12xx_for_each_wlvif_continue(wl, wlvif) { | 		wl12xx_for_each_wlvif_continue(wl, wlvif) { | ||||||
| 			skb = wl12xx_vif_skb_dequeue(wl, wlvif); | 			skb = wl12xx_vif_skb_dequeue(wl, wlvif, hlid); | ||||||
| 			if (skb) { | 			if (skb) { | ||||||
| 				wl->last_wlvif = wlvif; | 				wl->last_wlvif = wlvif; | ||||||
| 				break; | 				break; | ||||||
|  | @ -565,13 +562,15 @@ static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* dequeue from the system HLID before the restarting wlvif list */ | 	/* dequeue from the system HLID before the restarting wlvif list */ | ||||||
| 	if (!skb) | 	if (!skb) { | ||||||
| 		skb = wl12xx_lnk_skb_dequeue(wl, &wl->links[wl->system_hlid]); | 		skb = wl12xx_lnk_skb_dequeue(wl, &wl->links[wl->system_hlid]); | ||||||
|  | 		*hlid = wl->system_hlid; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	/* do a new pass over the wlvif list */ | 	/* do a new pass over the wlvif list */ | ||||||
| 	if (!skb) { | 	if (!skb) { | ||||||
| 		wl12xx_for_each_wlvif(wl, wlvif) { | 		wl12xx_for_each_wlvif(wl, wlvif) { | ||||||
| 			skb = wl12xx_vif_skb_dequeue(wl, wlvif); | 			skb = wl12xx_vif_skb_dequeue(wl, wlvif, hlid); | ||||||
| 			if (skb) { | 			if (skb) { | ||||||
| 				wl->last_wlvif = wlvif; | 				wl->last_wlvif = wlvif; | ||||||
| 				break; | 				break; | ||||||
|  | @ -591,6 +590,7 @@ static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl) | ||||||
| 		int q; | 		int q; | ||||||
| 
 | 
 | ||||||
| 		skb = wl->dummy_packet; | 		skb = wl->dummy_packet; | ||||||
|  | 		*hlid = wl->system_hlid; | ||||||
| 		q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); | 		q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); | ||||||
| 		spin_lock_irqsave(&wl->wl_lock, flags); | 		spin_lock_irqsave(&wl->wl_lock, flags); | ||||||
| 		WARN_ON_ONCE(wl->tx_queue_count[q] <= 0); | 		WARN_ON_ONCE(wl->tx_queue_count[q] <= 0); | ||||||
|  | @ -602,7 +602,7 @@ static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void wl1271_skb_queue_head(struct wl1271 *wl, struct wl12xx_vif *wlvif, | static void wl1271_skb_queue_head(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||||||
| 				  struct sk_buff *skb) | 				  struct sk_buff *skb, u8 hlid) | ||||||
| { | { | ||||||
| 	unsigned long flags; | 	unsigned long flags; | ||||||
| 	int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); | 	int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); | ||||||
|  | @ -610,7 +610,6 @@ static void wl1271_skb_queue_head(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||||||
| 	if (wl12xx_is_dummy_packet(wl, skb)) { | 	if (wl12xx_is_dummy_packet(wl, skb)) { | ||||||
| 		set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags); | 		set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags); | ||||||
| 	} else { | 	} else { | ||||||
| 		u8 hlid = wl12xx_tx_get_hlid(wl, wlvif, skb); |  | ||||||
| 		skb_queue_head(&wl->links[hlid].tx_queue[q], skb); | 		skb_queue_head(&wl->links[hlid].tx_queue[q], skb); | ||||||
| 
 | 
 | ||||||
| 		/* make sure we dequeue the same packet next time */ | 		/* make sure we dequeue the same packet next time */ | ||||||
|  | @ -686,26 +685,30 @@ int wlcore_tx_work_locked(struct wl1271 *wl) | ||||||
| 	unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0}; | 	unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0}; | ||||||
| 	int ret = 0; | 	int ret = 0; | ||||||
| 	int bus_ret = 0; | 	int bus_ret = 0; | ||||||
|  | 	u8 hlid; | ||||||
| 
 | 
 | ||||||
| 	if (unlikely(wl->state == WL1271_STATE_OFF)) | 	if (unlikely(wl->state == WL1271_STATE_OFF)) | ||||||
| 		return 0; | 		return 0; | ||||||
| 
 | 
 | ||||||
| 	while ((skb = wl1271_skb_dequeue(wl))) { | 	while ((skb = wl1271_skb_dequeue(wl, &hlid))) { | ||||||
| 		struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 		struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||||||
| 		bool has_data = false; | 		bool has_data = false; | ||||||
| 
 | 
 | ||||||
| 		wlvif = NULL; | 		wlvif = NULL; | ||||||
| 		if (!wl12xx_is_dummy_packet(wl, skb) && info->control.vif) | 		if (!wl12xx_is_dummy_packet(wl, skb) && info->control.vif) | ||||||
| 			wlvif = wl12xx_vif_to_data(info->control.vif); | 			wlvif = wl12xx_vif_to_data(info->control.vif); | ||||||
|  | 		else | ||||||
|  | 			hlid = wl->system_hlid; | ||||||
| 
 | 
 | ||||||
| 		has_data = wlvif && wl1271_tx_is_data_present(skb); | 		has_data = wlvif && wl1271_tx_is_data_present(skb); | ||||||
| 		ret = wl1271_prepare_tx_frame(wl, wlvif, skb, buf_offset); | 		ret = wl1271_prepare_tx_frame(wl, wlvif, skb, buf_offset, | ||||||
|  | 					      hlid); | ||||||
| 		if (ret == -EAGAIN) { | 		if (ret == -EAGAIN) { | ||||||
| 			/*
 | 			/*
 | ||||||
| 			 * Aggregation buffer is full. | 			 * Aggregation buffer is full. | ||||||
| 			 * Flush buffer and try again. | 			 * Flush buffer and try again. | ||||||
| 			 */ | 			 */ | ||||||
| 			wl1271_skb_queue_head(wl, wlvif, skb); | 			wl1271_skb_queue_head(wl, wlvif, skb, hlid); | ||||||
| 
 | 
 | ||||||
| 			buf_offset = wlcore_hw_pre_pkt_send(wl, buf_offset, | 			buf_offset = wlcore_hw_pre_pkt_send(wl, buf_offset, | ||||||
| 							    last_len); | 							    last_len); | ||||||
|  | @ -722,7 +725,7 @@ int wlcore_tx_work_locked(struct wl1271 *wl) | ||||||
| 			 * Firmware buffer is full. | 			 * Firmware buffer is full. | ||||||
| 			 * Queue back last skb, and stop aggregating. | 			 * Queue back last skb, and stop aggregating. | ||||||
| 			 */ | 			 */ | ||||||
| 			wl1271_skb_queue_head(wl, wlvif, skb); | 			wl1271_skb_queue_head(wl, wlvif, skb, hlid); | ||||||
| 			/* No work left, avoid scheduling redundant tx work */ | 			/* No work left, avoid scheduling redundant tx work */ | ||||||
| 			set_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); | 			set_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); | ||||||
| 			goto out_ack; | 			goto out_ack; | ||||||
|  | @ -732,7 +735,7 @@ int wlcore_tx_work_locked(struct wl1271 *wl) | ||||||
| 				 * fw still expects dummy packet, | 				 * fw still expects dummy packet, | ||||||
| 				 * so re-enqueue it | 				 * so re-enqueue it | ||||||
| 				 */ | 				 */ | ||||||
| 				wl1271_skb_queue_head(wl, wlvif, skb); | 				wl1271_skb_queue_head(wl, wlvif, skb, hlid); | ||||||
| 			else | 			else | ||||||
| 				ieee80211_free_txskb(wl->hw, skb); | 				ieee80211_free_txskb(wl->hw, skb); | ||||||
| 			goto out_ack; | 			goto out_ack; | ||||||
|  |  | ||||||
|  | @ -243,10 +243,8 @@ u8 wlcore_rate_to_idx(struct wl1271 *wl, u8 rate, enum ieee80211_band band); | ||||||
| u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set, | u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set, | ||||||
| 				enum ieee80211_band rate_band); | 				enum ieee80211_band rate_band); | ||||||
| u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set); | u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set); | ||||||
| u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif, |  | ||||||
| 			 struct sk_buff *skb); |  | ||||||
| u8 wl12xx_tx_get_hlid(struct wl1271 *wl, struct wl12xx_vif *wlvif, | u8 wl12xx_tx_get_hlid(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||||||
| 		      struct sk_buff *skb); | 		      struct sk_buff *skb, struct ieee80211_sta *sta); | ||||||
| void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid); | void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid); | ||||||
| void wl1271_handle_tx_low_watermark(struct wl1271 *wl); | void wl1271_handle_tx_low_watermark(struct wl1271 *wl); | ||||||
| bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb); | bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb); | ||||||
|  |  | ||||||
|  | @ -937,7 +937,9 @@ static int fill_ctrlset(struct zd_mac *mac, | ||||||
|  * control block of the skbuff will be initialized. If necessary the incoming |  * control block of the skbuff will be initialized. If necessary the incoming | ||||||
|  * mac80211 queues will be stopped. |  * mac80211 queues will be stopped. | ||||||
|  */ |  */ | ||||||
| static void zd_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | static void zd_op_tx(struct ieee80211_hw *hw, | ||||||
|  | 		     struct ieee80211_tx_control *control, | ||||||
|  | 		     struct sk_buff *skb) | ||||||
| { | { | ||||||
| 	struct zd_mac *mac = zd_hw_mac(hw); | 	struct zd_mac *mac = zd_hw_mac(hw); | ||||||
| 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||||||
|  | @ -1176,7 +1178,7 @@ static void zd_beacon_done(struct zd_mac *mac) | ||||||
| 		skb = ieee80211_get_buffered_bc(mac->hw, mac->vif); | 		skb = ieee80211_get_buffered_bc(mac->hw, mac->vif); | ||||||
| 		if (!skb) | 		if (!skb) | ||||||
| 			break; | 			break; | ||||||
| 		zd_op_tx(mac->hw, skb); | 		zd_op_tx(mac->hw, NULL, skb); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
|  |  | ||||||
|  | @ -119,7 +119,9 @@ static void wbsoft_configure_filter(struct ieee80211_hw *dev, | ||||||
| 	*total_flags = new_flags; | 	*total_flags = new_flags; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void wbsoft_tx(struct ieee80211_hw *dev, struct sk_buff *skb) | static void wbsoft_tx(struct ieee80211_hw *dev, | ||||||
|  | 		      struct ieee80211_tx_control *control, | ||||||
|  | 		      struct sk_buff *skb) | ||||||
| { | { | ||||||
| 	struct wbsoft_priv *priv = dev->priv; | 	struct wbsoft_priv *priv = dev->priv; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -515,6 +515,26 @@ struct bcma_pflash { | ||||||
| 	u32 window_size; | 	u32 window_size; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | #ifdef CONFIG_BCMA_SFLASH | ||||||
|  | struct bcma_sflash { | ||||||
|  | 	bool present; | ||||||
|  | 	u32 window; | ||||||
|  | 	u32 blocksize; | ||||||
|  | 	u16 numblocks; | ||||||
|  | 	u32 size; | ||||||
|  | }; | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #ifdef CONFIG_BCMA_NFLASH | ||||||
|  | struct mtd_info; | ||||||
|  | 
 | ||||||
|  | struct bcma_nflash { | ||||||
|  | 	bool present; | ||||||
|  | 
 | ||||||
|  | 	struct mtd_info *mtd; | ||||||
|  | }; | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| struct bcma_serial_port { | struct bcma_serial_port { | ||||||
| 	void *regs; | 	void *regs; | ||||||
| 	unsigned long clockspeed; | 	unsigned long clockspeed; | ||||||
|  | @ -535,6 +555,12 @@ struct bcma_drv_cc { | ||||||
| 	struct bcma_chipcommon_pmu pmu; | 	struct bcma_chipcommon_pmu pmu; | ||||||
| #ifdef CONFIG_BCMA_DRIVER_MIPS | #ifdef CONFIG_BCMA_DRIVER_MIPS | ||||||
| 	struct bcma_pflash pflash; | 	struct bcma_pflash pflash; | ||||||
|  | #ifdef CONFIG_BCMA_SFLASH | ||||||
|  | 	struct bcma_sflash sflash; | ||||||
|  | #endif | ||||||
|  | #ifdef CONFIG_BCMA_NFLASH | ||||||
|  | 	struct bcma_nflash nflash; | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
| 	int nr_serial_ports; | 	int nr_serial_ports; | ||||||
| 	struct bcma_serial_port serial_ports[4]; | 	struct bcma_serial_port serial_ports[4]; | ||||||
|  |  | ||||||
|  | @ -85,4 +85,6 @@ | ||||||
| 							 * (2 ZettaBytes), high 32 bits | 							 * (2 ZettaBytes), high 32 bits | ||||||
| 							 */ | 							 */ | ||||||
| 
 | 
 | ||||||
|  | #define BCMA_SFLASH			0x1c000000 | ||||||
|  | 
 | ||||||
| #endif /* LINUX_BCMA_REGS_H_ */ | #endif /* LINUX_BCMA_REGS_H_ */ | ||||||
|  |  | ||||||
|  | @ -565,6 +565,14 @@ | ||||||
|  *	%NL80211_ATTR_IFINDEX is now on %NL80211_ATTR_WIPHY_FREQ with |  *	%NL80211_ATTR_IFINDEX is now on %NL80211_ATTR_WIPHY_FREQ with | ||||||
|  *	%NL80211_ATTR_WIPHY_CHANNEL_TYPE. |  *	%NL80211_ATTR_WIPHY_CHANNEL_TYPE. | ||||||
|  * |  * | ||||||
|  |  * @NL80211_CMD_START_P2P_DEVICE: Start the given P2P Device, identified by | ||||||
|  |  *	its %NL80211_ATTR_WDEV identifier. It must have been created with | ||||||
|  |  *	%NL80211_CMD_NEW_INTERFACE previously. After it has been started, the | ||||||
|  |  *	P2P Device can be used for P2P operations, e.g. remain-on-channel and | ||||||
|  |  *	public action frame TX. | ||||||
|  |  * @NL80211_CMD_STOP_P2P_DEVICE: Stop the given P2P Device, identified by | ||||||
|  |  *	its %NL80211_ATTR_WDEV identifier. | ||||||
|  |  * | ||||||
|  * @NL80211_CMD_MAX: highest used command number |  * @NL80211_CMD_MAX: highest used command number | ||||||
|  * @__NL80211_CMD_AFTER_LAST: internal use |  * @__NL80211_CMD_AFTER_LAST: internal use | ||||||
|  */ |  */ | ||||||
|  | @ -708,6 +716,9 @@ enum nl80211_commands { | ||||||
| 
 | 
 | ||||||
| 	NL80211_CMD_CH_SWITCH_NOTIFY, | 	NL80211_CMD_CH_SWITCH_NOTIFY, | ||||||
| 
 | 
 | ||||||
|  | 	NL80211_CMD_START_P2P_DEVICE, | ||||||
|  | 	NL80211_CMD_STOP_P2P_DEVICE, | ||||||
|  | 
 | ||||||
| 	/* add new commands above here */ | 	/* add new commands above here */ | ||||||
| 
 | 
 | ||||||
| 	/* used to define NL80211_CMD_MAX below */ | 	/* used to define NL80211_CMD_MAX below */ | ||||||
|  | @ -1575,6 +1586,10 @@ enum nl80211_attrs { | ||||||
|  * @NL80211_IFTYPE_MESH_POINT: mesh point |  * @NL80211_IFTYPE_MESH_POINT: mesh point | ||||||
|  * @NL80211_IFTYPE_P2P_CLIENT: P2P client |  * @NL80211_IFTYPE_P2P_CLIENT: P2P client | ||||||
|  * @NL80211_IFTYPE_P2P_GO: P2P group owner |  * @NL80211_IFTYPE_P2P_GO: P2P group owner | ||||||
|  |  * @NL80211_IFTYPE_P2P_DEVICE: P2P device interface type, this is not a netdev | ||||||
|  |  *	and therefore can't be created in the normal ways, use the | ||||||
|  |  *	%NL80211_CMD_START_P2P_DEVICE and %NL80211_CMD_STOP_P2P_DEVICE | ||||||
|  |  *	commands to create and destroy one | ||||||
|  * @NL80211_IFTYPE_MAX: highest interface type number currently defined |  * @NL80211_IFTYPE_MAX: highest interface type number currently defined | ||||||
|  * @NUM_NL80211_IFTYPES: number of defined interface types |  * @NUM_NL80211_IFTYPES: number of defined interface types | ||||||
|  * |  * | ||||||
|  | @ -1593,6 +1608,7 @@ enum nl80211_iftype { | ||||||
| 	NL80211_IFTYPE_MESH_POINT, | 	NL80211_IFTYPE_MESH_POINT, | ||||||
| 	NL80211_IFTYPE_P2P_CLIENT, | 	NL80211_IFTYPE_P2P_CLIENT, | ||||||
| 	NL80211_IFTYPE_P2P_GO, | 	NL80211_IFTYPE_P2P_GO, | ||||||
|  | 	NL80211_IFTYPE_P2P_DEVICE, | ||||||
| 
 | 
 | ||||||
| 	/* keep last */ | 	/* keep last */ | ||||||
| 	NUM_NL80211_IFTYPES, | 	NUM_NL80211_IFTYPES, | ||||||
|  | @ -2994,12 +3010,18 @@ enum nl80211_ap_sme_features { | ||||||
|  * @NL80211_FEATURE_CELL_BASE_REG_HINTS: This driver has been tested |  * @NL80211_FEATURE_CELL_BASE_REG_HINTS: This driver has been tested | ||||||
|  *	to work properly to suppport receiving regulatory hints from |  *	to work properly to suppport receiving regulatory hints from | ||||||
|  *	cellular base stations. |  *	cellular base stations. | ||||||
|  |  * @NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL: If this is set, an active | ||||||
|  |  *	P2P Device (%NL80211_IFTYPE_P2P_DEVICE) requires its own channel | ||||||
|  |  *	in the interface combinations, even when it's only used for scan | ||||||
|  |  *	and remain-on-channel. This could be due to, for example, the | ||||||
|  |  *	remain-on-channel implementation requiring a channel context. | ||||||
|  */ |  */ | ||||||
| enum nl80211_feature_flags { | enum nl80211_feature_flags { | ||||||
| 	NL80211_FEATURE_SK_TX_STATUS			= 1 << 0, | 	NL80211_FEATURE_SK_TX_STATUS			= 1 << 0, | ||||||
| 	NL80211_FEATURE_HT_IBSS				= 1 << 1, | 	NL80211_FEATURE_HT_IBSS				= 1 << 1, | ||||||
| 	NL80211_FEATURE_INACTIVITY_TIMER		= 1 << 2, | 	NL80211_FEATURE_INACTIVITY_TIMER		= 1 << 2, | ||||||
| 	NL80211_FEATURE_CELL_BASE_REG_HINTS		= 1 << 3, | 	NL80211_FEATURE_CELL_BASE_REG_HINTS		= 1 << 3, | ||||||
|  | 	NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL	= 1 << 4, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  |  | ||||||
|  | @ -354,6 +354,37 @@ static inline bool rfkill_blocked(struct rfkill *rfkill) | ||||||
| } | } | ||||||
| #endif /* RFKILL || RFKILL_MODULE */ | #endif /* RFKILL || RFKILL_MODULE */ | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | #ifdef CONFIG_RFKILL_LEDS | ||||||
|  | /**
 | ||||||
|  |  * rfkill_get_led_trigger_name - Get the LED trigger name for the button's LED. | ||||||
|  |  * This function might return a NULL pointer if registering of the | ||||||
|  |  * LED trigger failed. Use this as "default_trigger" for the LED. | ||||||
|  |  */ | ||||||
|  | const char *rfkill_get_led_trigger_name(struct rfkill *rfkill); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * rfkill_set_led_trigger_name -- set the LED trigger name | ||||||
|  |  * @rfkill: rfkill struct | ||||||
|  |  * @name: LED trigger name | ||||||
|  |  * | ||||||
|  |  * This function sets the LED trigger name of the radio LED | ||||||
|  |  * trigger that rfkill creates. It is optional, but if called | ||||||
|  |  * must be called before rfkill_register() to be effective. | ||||||
|  |  */ | ||||||
|  | void rfkill_set_led_trigger_name(struct rfkill *rfkill, const char *name); | ||||||
|  | #else | ||||||
|  | static inline const char *rfkill_get_led_trigger_name(struct rfkill *rfkill) | ||||||
|  | { | ||||||
|  | 	return NULL; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline void | ||||||
|  | rfkill_set_led_trigger_name(struct rfkill *rfkill, const char *name) | ||||||
|  | { | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| #endif /* __KERNEL__ */ | #endif /* __KERNEL__ */ | ||||||
| 
 | 
 | ||||||
| #endif /* RFKILL_H */ | #endif /* RFKILL_H */ | ||||||
|  |  | ||||||
|  | @ -1439,7 +1439,8 @@ struct cfg80211_gtk_rekey_data { | ||||||
|  * @add_virtual_intf: create a new virtual interface with the given name, |  * @add_virtual_intf: create a new virtual interface with the given name, | ||||||
|  *	must set the struct wireless_dev's iftype. Beware: You must create |  *	must set the struct wireless_dev's iftype. Beware: You must create | ||||||
|  *	the new netdev in the wiphy's network namespace! Returns the struct |  *	the new netdev in the wiphy's network namespace! Returns the struct | ||||||
|  *	wireless_dev, or an ERR_PTR. |  *	wireless_dev, or an ERR_PTR. For P2P device wdevs, the driver must | ||||||
|  |  *	also set the address member in the wdev. | ||||||
|  * |  * | ||||||
|  * @del_virtual_intf: remove the virtual interface |  * @del_virtual_intf: remove the virtual interface | ||||||
|  * |  * | ||||||
|  | @ -1618,6 +1619,9 @@ struct cfg80211_gtk_rekey_data { | ||||||
|  * @get_channel: Get the current operating channel for the virtual interface. |  * @get_channel: Get the current operating channel for the virtual interface. | ||||||
|  *	For monitor interfaces, it should return %NULL unless there's a single |  *	For monitor interfaces, it should return %NULL unless there's a single | ||||||
|  *	current monitoring channel. |  *	current monitoring channel. | ||||||
|  |  * | ||||||
|  |  * @start_p2p_device: Start the given P2P device. | ||||||
|  |  * @stop_p2p_device: Stop the given P2P device. | ||||||
|  */ |  */ | ||||||
| struct cfg80211_ops { | struct cfg80211_ops { | ||||||
| 	int	(*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); | 	int	(*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); | ||||||
|  | @ -1834,6 +1838,11 @@ struct cfg80211_ops { | ||||||
| 		(*get_channel)(struct wiphy *wiphy, | 		(*get_channel)(struct wiphy *wiphy, | ||||||
| 			       struct wireless_dev *wdev, | 			       struct wireless_dev *wdev, | ||||||
| 			       enum nl80211_channel_type *type); | 			       enum nl80211_channel_type *type); | ||||||
|  | 
 | ||||||
|  | 	int	(*start_p2p_device)(struct wiphy *wiphy, | ||||||
|  | 				    struct wireless_dev *wdev); | ||||||
|  | 	void	(*stop_p2p_device)(struct wiphy *wiphy, | ||||||
|  | 				   struct wireless_dev *wdev); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  | @ -2397,6 +2406,8 @@ struct cfg80211_cached_keys; | ||||||
|  * @cleanup_work: work struct used for cleanup that can't be done directly |  * @cleanup_work: work struct used for cleanup that can't be done directly | ||||||
|  * @beacon_interval: beacon interval used on this device for transmitting |  * @beacon_interval: beacon interval used on this device for transmitting | ||||||
|  *	beacons, 0 when not valid |  *	beacons, 0 when not valid | ||||||
|  |  * @address: The address for this device, valid only if @netdev is %NULL | ||||||
|  |  * @p2p_started: true if this is a P2P Device that has been started | ||||||
|  */ |  */ | ||||||
| struct wireless_dev { | struct wireless_dev { | ||||||
| 	struct wiphy *wiphy; | 	struct wiphy *wiphy; | ||||||
|  | @ -2415,7 +2426,9 @@ struct wireless_dev { | ||||||
| 
 | 
 | ||||||
| 	struct work_struct cleanup_work; | 	struct work_struct cleanup_work; | ||||||
| 
 | 
 | ||||||
| 	bool use_4addr; | 	bool use_4addr, p2p_started; | ||||||
|  | 
 | ||||||
|  | 	u8 address[ETH_ALEN] __aligned(sizeof(u16)); | ||||||
| 
 | 
 | ||||||
| 	/* currently used for IBSS and SME - might be rearranged later */ | 	/* currently used for IBSS and SME - might be rearranged later */ | ||||||
| 	u8 ssid[IEEE80211_MAX_SSID_LEN]; | 	u8 ssid[IEEE80211_MAX_SSID_LEN]; | ||||||
|  | @ -2463,6 +2476,13 @@ struct wireless_dev { | ||||||
| #endif | #endif | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | static inline u8 *wdev_address(struct wireless_dev *wdev) | ||||||
|  | { | ||||||
|  | 	if (wdev->netdev) | ||||||
|  | 		return wdev->netdev->dev_addr; | ||||||
|  | 	return wdev->address; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * wdev_priv - return wiphy priv from wireless_dev |  * wdev_priv - return wiphy priv from wireless_dev | ||||||
|  * |  * | ||||||
|  | @ -3530,6 +3550,22 @@ void cfg80211_ch_switch_notify(struct net_device *dev, int freq, | ||||||
|  */ |  */ | ||||||
| u32 cfg80211_calculate_bitrate(struct rate_info *rate); | u32 cfg80211_calculate_bitrate(struct rate_info *rate); | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * cfg80211_unregister_wdev - remove the given wdev | ||||||
|  |  * @wdev: struct wireless_dev to remove | ||||||
|  |  * | ||||||
|  |  * Call this function only for wdevs that have no netdev assigned, | ||||||
|  |  * e.g. P2P Devices. It removes the device from the list so that | ||||||
|  |  * it can no longer be used. It is necessary to call this function | ||||||
|  |  * even when cfg80211 requests the removal of the interface by | ||||||
|  |  * calling the del_virtual_intf() callback. The function must also | ||||||
|  |  * be called when the driver wishes to unregister the wdev, e.g. | ||||||
|  |  * when the device is unbound from the driver. | ||||||
|  |  * | ||||||
|  |  * Requires the RTNL to be held. | ||||||
|  |  */ | ||||||
|  | void cfg80211_unregister_wdev(struct wireless_dev *wdev); | ||||||
|  | 
 | ||||||
| /* Logging, debugging and troubleshooting/diagnostic helpers. */ | /* Logging, debugging and troubleshooting/diagnostic helpers. */ | ||||||
| 
 | 
 | ||||||
| /* wiphy_printk helpers, similar to dev_printk */ | /* wiphy_printk helpers, similar to dev_printk */ | ||||||
|  |  | ||||||
|  | @ -183,6 +183,9 @@ struct ieee80211_radiotap_header { | ||||||
|  *     Contains a bitmap of known fields/flags, the flags, and |  *     Contains a bitmap of known fields/flags, the flags, and | ||||||
|  *     the MCS index. |  *     the MCS index. | ||||||
|  * |  * | ||||||
|  |  * IEEE80211_RADIOTAP_AMPDU_STATUS	u32, u16, u8, u8	unitless | ||||||
|  |  * | ||||||
|  |  *	Contains the AMPDU information for the subframe. | ||||||
|  */ |  */ | ||||||
| enum ieee80211_radiotap_type { | enum ieee80211_radiotap_type { | ||||||
| 	IEEE80211_RADIOTAP_TSFT = 0, | 	IEEE80211_RADIOTAP_TSFT = 0, | ||||||
|  | @ -205,6 +208,7 @@ enum ieee80211_radiotap_type { | ||||||
| 	IEEE80211_RADIOTAP_DATA_RETRIES = 17, | 	IEEE80211_RADIOTAP_DATA_RETRIES = 17, | ||||||
| 
 | 
 | ||||||
| 	IEEE80211_RADIOTAP_MCS = 19, | 	IEEE80211_RADIOTAP_MCS = 19, | ||||||
|  | 	IEEE80211_RADIOTAP_AMPDU_STATUS = 20, | ||||||
| 
 | 
 | ||||||
| 	/* valid in every it_present bitmap, even vendor namespaces */ | 	/* valid in every it_present bitmap, even vendor namespaces */ | ||||||
| 	IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE = 29, | 	IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE = 29, | ||||||
|  | @ -270,6 +274,13 @@ enum ieee80211_radiotap_type { | ||||||
| #define IEEE80211_RADIOTAP_MCS_FMT_GF		0x08 | #define IEEE80211_RADIOTAP_MCS_FMT_GF		0x08 | ||||||
| #define IEEE80211_RADIOTAP_MCS_FEC_LDPC		0x10 | #define IEEE80211_RADIOTAP_MCS_FEC_LDPC		0x10 | ||||||
| 
 | 
 | ||||||
|  | /* For IEEE80211_RADIOTAP_AMPDU_STATUS */ | ||||||
|  | #define IEEE80211_RADIOTAP_AMPDU_REPORT_ZEROLEN		0x0001 | ||||||
|  | #define IEEE80211_RADIOTAP_AMPDU_IS_ZEROLEN		0x0002 | ||||||
|  | #define IEEE80211_RADIOTAP_AMPDU_LAST_KNOWN		0x0004 | ||||||
|  | #define IEEE80211_RADIOTAP_AMPDU_IS_LAST		0x0008 | ||||||
|  | #define IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_ERR		0x0010 | ||||||
|  | #define IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN	0x0020 | ||||||
| 
 | 
 | ||||||
| /* helpers */ | /* helpers */ | ||||||
| static inline int ieee80211_get_radiotap_len(unsigned char *data) | static inline int ieee80211_get_radiotap_len(unsigned char *data) | ||||||
|  |  | ||||||
|  | @ -171,6 +171,7 @@ struct ieee80211_low_level_stats { | ||||||
|  * @BSS_CHANGED_IDLE: Idle changed for this BSS/interface. |  * @BSS_CHANGED_IDLE: Idle changed for this BSS/interface. | ||||||
|  * @BSS_CHANGED_SSID: SSID changed for this BSS (AP mode) |  * @BSS_CHANGED_SSID: SSID changed for this BSS (AP mode) | ||||||
|  * @BSS_CHANGED_AP_PROBE_RESP: Probe Response changed for this BSS (AP mode) |  * @BSS_CHANGED_AP_PROBE_RESP: Probe Response changed for this BSS (AP mode) | ||||||
|  |  * @BSS_CHANGED_PS: PS changed for this BSS (STA mode) | ||||||
|  */ |  */ | ||||||
| enum ieee80211_bss_change { | enum ieee80211_bss_change { | ||||||
| 	BSS_CHANGED_ASSOC		= 1<<0, | 	BSS_CHANGED_ASSOC		= 1<<0, | ||||||
|  | @ -190,6 +191,7 @@ enum ieee80211_bss_change { | ||||||
| 	BSS_CHANGED_IDLE		= 1<<14, | 	BSS_CHANGED_IDLE		= 1<<14, | ||||||
| 	BSS_CHANGED_SSID		= 1<<15, | 	BSS_CHANGED_SSID		= 1<<15, | ||||||
| 	BSS_CHANGED_AP_PROBE_RESP	= 1<<16, | 	BSS_CHANGED_AP_PROBE_RESP	= 1<<16, | ||||||
|  | 	BSS_CHANGED_PS			= 1<<17, | ||||||
| 
 | 
 | ||||||
| 	/* when adding here, make sure to change ieee80211_reconfig */ | 	/* when adding here, make sure to change ieee80211_reconfig */ | ||||||
| }; | }; | ||||||
|  | @ -266,6 +268,8 @@ enum ieee80211_rssi_event { | ||||||
|  * @idle: This interface is idle. There's also a global idle flag in the |  * @idle: This interface is idle. There's also a global idle flag in the | ||||||
|  *	hardware config which may be more appropriate depending on what |  *	hardware config which may be more appropriate depending on what | ||||||
|  *	your driver/device needs to do. |  *	your driver/device needs to do. | ||||||
|  |  * @ps: power-save mode (STA only). This flag is NOT affected by | ||||||
|  |  *	offchannel/dynamic_ps operations. | ||||||
|  * @ssid: The SSID of the current vif. Only valid in AP-mode. |  * @ssid: The SSID of the current vif. Only valid in AP-mode. | ||||||
|  * @ssid_len: Length of SSID given in @ssid. |  * @ssid_len: Length of SSID given in @ssid. | ||||||
|  * @hidden_ssid: The SSID of the current vif is hidden. Only valid in AP-mode. |  * @hidden_ssid: The SSID of the current vif is hidden. Only valid in AP-mode. | ||||||
|  | @ -296,6 +300,7 @@ struct ieee80211_bss_conf { | ||||||
| 	bool arp_filter_enabled; | 	bool arp_filter_enabled; | ||||||
| 	bool qos; | 	bool qos; | ||||||
| 	bool idle; | 	bool idle; | ||||||
|  | 	bool ps; | ||||||
| 	u8 ssid[IEEE80211_MAX_SSID_LEN]; | 	u8 ssid[IEEE80211_MAX_SSID_LEN]; | ||||||
| 	size_t ssid_len; | 	size_t ssid_len; | ||||||
| 	bool hidden_ssid; | 	bool hidden_ssid; | ||||||
|  | @ -522,9 +527,6 @@ struct ieee80211_tx_rate { | ||||||
|  *  (2) driver internal use (if applicable) |  *  (2) driver internal use (if applicable) | ||||||
|  *  (3) TX status information - driver tells mac80211 what happened |  *  (3) TX status information - driver tells mac80211 what happened | ||||||
|  * |  * | ||||||
|  * The TX control's sta pointer is only valid during the ->tx call, |  | ||||||
|  * it may be NULL. |  | ||||||
|  * |  | ||||||
|  * @flags: transmit info flags, defined above |  * @flags: transmit info flags, defined above | ||||||
|  * @band: the band to transmit on (use for checking for races) |  * @band: the band to transmit on (use for checking for races) | ||||||
|  * @hw_queue: HW queue to put the frame on, skb_get_queue_mapping() gives the AC |  * @hw_queue: HW queue to put the frame on, skb_get_queue_mapping() gives the AC | ||||||
|  | @ -555,6 +557,7 @@ struct ieee80211_tx_info { | ||||||
| 					struct ieee80211_tx_rate rates[ | 					struct ieee80211_tx_rate rates[ | ||||||
| 						IEEE80211_TX_MAX_RATES]; | 						IEEE80211_TX_MAX_RATES]; | ||||||
| 					s8 rts_cts_rate_idx; | 					s8 rts_cts_rate_idx; | ||||||
|  | 					/* 3 bytes free */ | ||||||
| 				}; | 				}; | ||||||
| 				/* only needed before rate control */ | 				/* only needed before rate control */ | ||||||
| 				unsigned long jiffies; | 				unsigned long jiffies; | ||||||
|  | @ -562,7 +565,7 @@ struct ieee80211_tx_info { | ||||||
| 			/* NB: vif can be NULL for injected frames */ | 			/* NB: vif can be NULL for injected frames */ | ||||||
| 			struct ieee80211_vif *vif; | 			struct ieee80211_vif *vif; | ||||||
| 			struct ieee80211_key_conf *hw_key; | 			struct ieee80211_key_conf *hw_key; | ||||||
| 			struct ieee80211_sta *sta; | 			/* 8 bytes free */ | ||||||
| 		} control; | 		} control; | ||||||
| 		struct { | 		struct { | ||||||
| 			struct ieee80211_tx_rate rates[IEEE80211_TX_MAX_RATES]; | 			struct ieee80211_tx_rate rates[IEEE80211_TX_MAX_RATES]; | ||||||
|  | @ -673,21 +676,41 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info) | ||||||
|  * @RX_FLAG_HT_GF: This frame was received in a HT-greenfield transmission, if |  * @RX_FLAG_HT_GF: This frame was received in a HT-greenfield transmission, if | ||||||
|  *	the driver fills this value it should add %IEEE80211_RADIOTAP_MCS_HAVE_FMT |  *	the driver fills this value it should add %IEEE80211_RADIOTAP_MCS_HAVE_FMT | ||||||
|  *	to hw.radiotap_mcs_details to advertise that fact |  *	to hw.radiotap_mcs_details to advertise that fact | ||||||
|  |  * @RX_FLAG_AMPDU_DETAILS: A-MPDU details are known, in particular the reference | ||||||
|  |  *	number (@ampdu_reference) must be populated and be a distinct number for | ||||||
|  |  *	each A-MPDU | ||||||
|  |  * @RX_FLAG_AMPDU_REPORT_ZEROLEN: driver reports 0-length subframes | ||||||
|  |  * @RX_FLAG_AMPDU_IS_ZEROLEN: This is a zero-length subframe, for | ||||||
|  |  *	monitoring purposes only | ||||||
|  |  * @RX_FLAG_AMPDU_LAST_KNOWN: last subframe is known, should be set on all | ||||||
|  |  *	subframes of a single A-MPDU | ||||||
|  |  * @RX_FLAG_AMPDU_IS_LAST: this subframe is the last subframe of the A-MPDU | ||||||
|  |  * @RX_FLAG_AMPDU_DELIM_CRC_ERROR: A delimiter CRC error has been detected | ||||||
|  |  *	on this subframe | ||||||
|  |  * @RX_FLAG_AMPDU_DELIM_CRC_KNOWN: The delimiter CRC field is known (the CRC | ||||||
|  |  *	is stored in the @ampdu_delimiter_crc field) | ||||||
|  */ |  */ | ||||||
| enum mac80211_rx_flags { | enum mac80211_rx_flags { | ||||||
| 	RX_FLAG_MMIC_ERROR	= 1<<0, | 	RX_FLAG_MMIC_ERROR		= BIT(0), | ||||||
| 	RX_FLAG_DECRYPTED	= 1<<1, | 	RX_FLAG_DECRYPTED		= BIT(1), | ||||||
| 	RX_FLAG_MMIC_STRIPPED	= 1<<3, | 	RX_FLAG_MMIC_STRIPPED		= BIT(3), | ||||||
| 	RX_FLAG_IV_STRIPPED	= 1<<4, | 	RX_FLAG_IV_STRIPPED		= BIT(4), | ||||||
| 	RX_FLAG_FAILED_FCS_CRC	= 1<<5, | 	RX_FLAG_FAILED_FCS_CRC		= BIT(5), | ||||||
| 	RX_FLAG_FAILED_PLCP_CRC = 1<<6, | 	RX_FLAG_FAILED_PLCP_CRC 	= BIT(6), | ||||||
| 	RX_FLAG_MACTIME_MPDU	= 1<<7, | 	RX_FLAG_MACTIME_MPDU		= BIT(7), | ||||||
| 	RX_FLAG_SHORTPRE	= 1<<8, | 	RX_FLAG_SHORTPRE		= BIT(8), | ||||||
| 	RX_FLAG_HT		= 1<<9, | 	RX_FLAG_HT			= BIT(9), | ||||||
| 	RX_FLAG_40MHZ		= 1<<10, | 	RX_FLAG_40MHZ			= BIT(10), | ||||||
| 	RX_FLAG_SHORT_GI	= 1<<11, | 	RX_FLAG_SHORT_GI		= BIT(11), | ||||||
| 	RX_FLAG_NO_SIGNAL_VAL	= 1<<12, | 	RX_FLAG_NO_SIGNAL_VAL		= BIT(12), | ||||||
| 	RX_FLAG_HT_GF		= 1<<13, | 	RX_FLAG_HT_GF			= BIT(13), | ||||||
|  | 	RX_FLAG_AMPDU_DETAILS		= BIT(14), | ||||||
|  | 	RX_FLAG_AMPDU_REPORT_ZEROLEN	= BIT(15), | ||||||
|  | 	RX_FLAG_AMPDU_IS_ZEROLEN	= BIT(16), | ||||||
|  | 	RX_FLAG_AMPDU_LAST_KNOWN	= BIT(17), | ||||||
|  | 	RX_FLAG_AMPDU_IS_LAST		= BIT(18), | ||||||
|  | 	RX_FLAG_AMPDU_DELIM_CRC_ERROR	= BIT(19), | ||||||
|  | 	RX_FLAG_AMPDU_DELIM_CRC_KNOWN	= BIT(20), | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  | @ -711,17 +734,22 @@ enum mac80211_rx_flags { | ||||||
|  *	HT rates are use (RX_FLAG_HT) |  *	HT rates are use (RX_FLAG_HT) | ||||||
|  * @flag: %RX_FLAG_* |  * @flag: %RX_FLAG_* | ||||||
|  * @rx_flags: internal RX flags for mac80211 |  * @rx_flags: internal RX flags for mac80211 | ||||||
|  |  * @ampdu_reference: A-MPDU reference number, must be a different value for | ||||||
|  |  *	each A-MPDU but the same for each subframe within one A-MPDU | ||||||
|  |  * @ampdu_delimiter_crc: A-MPDU delimiter CRC | ||||||
|  */ |  */ | ||||||
| struct ieee80211_rx_status { | struct ieee80211_rx_status { | ||||||
| 	u64 mactime; | 	u64 mactime; | ||||||
| 	u32 device_timestamp; | 	u32 device_timestamp; | ||||||
| 	u16 flag; | 	u32 ampdu_reference; | ||||||
|  | 	u32 flag; | ||||||
| 	u16 freq; | 	u16 freq; | ||||||
| 	u8 rate_idx; | 	u8 rate_idx; | ||||||
| 	u8 rx_flags; | 	u8 rx_flags; | ||||||
| 	u8 band; | 	u8 band; | ||||||
| 	u8 antenna; | 	u8 antenna; | ||||||
| 	s8 signal; | 	s8 signal; | ||||||
|  | 	u8 ampdu_delimiter_crc; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  | @ -1073,6 +1101,16 @@ enum sta_notify_cmd { | ||||||
| 	STA_NOTIFY_SLEEP, STA_NOTIFY_AWAKE, | 	STA_NOTIFY_SLEEP, STA_NOTIFY_AWAKE, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * struct ieee80211_tx_control - TX control data | ||||||
|  |  * | ||||||
|  |  * @sta: station table entry, this sta pointer may be NULL and | ||||||
|  |  * 	it is not allowed to copy the pointer, due to RCU. | ||||||
|  |  */ | ||||||
|  | struct ieee80211_tx_control { | ||||||
|  | 	struct ieee80211_sta *sta; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * enum ieee80211_hw_flags - hardware flags |  * enum ieee80211_hw_flags - hardware flags | ||||||
|  * |  * | ||||||
|  | @ -1203,6 +1241,10 @@ enum sta_notify_cmd { | ||||||
|  *	queue mapping in order to use different queues (not just one per AC) |  *	queue mapping in order to use different queues (not just one per AC) | ||||||
|  *	for different virtual interfaces. See the doc section on HW queue |  *	for different virtual interfaces. See the doc section on HW queue | ||||||
|  *	control for more details. |  *	control for more details. | ||||||
|  |  * | ||||||
|  |  * @IEEE80211_HW_P2P_DEV_ADDR_FOR_INTF: Use the P2P Device address for any | ||||||
|  |  *	P2P Interface. This will be honoured even if more than one interface | ||||||
|  |  *	is supported. | ||||||
|  */ |  */ | ||||||
| enum ieee80211_hw_flags { | enum ieee80211_hw_flags { | ||||||
| 	IEEE80211_HW_HAS_RATE_CONTROL			= 1<<0, | 	IEEE80211_HW_HAS_RATE_CONTROL			= 1<<0, | ||||||
|  | @ -1230,6 +1272,7 @@ enum ieee80211_hw_flags { | ||||||
| 	IEEE80211_HW_AP_LINK_PS				= 1<<22, | 	IEEE80211_HW_AP_LINK_PS				= 1<<22, | ||||||
| 	IEEE80211_HW_TX_AMPDU_SETUP_IN_HW		= 1<<23, | 	IEEE80211_HW_TX_AMPDU_SETUP_IN_HW		= 1<<23, | ||||||
| 	IEEE80211_HW_SCAN_WHILE_IDLE			= 1<<24, | 	IEEE80211_HW_SCAN_WHILE_IDLE			= 1<<24, | ||||||
|  | 	IEEE80211_HW_P2P_DEV_ADDR_FOR_INTF		= 1<<25, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  | @ -1884,10 +1927,14 @@ enum ieee80211_frame_release_type { | ||||||
|  * @IEEE80211_RC_BW_CHANGED: The bandwidth that can be used to transmit |  * @IEEE80211_RC_BW_CHANGED: The bandwidth that can be used to transmit | ||||||
|  *	to this station changed. |  *	to this station changed. | ||||||
|  * @IEEE80211_RC_SMPS_CHANGED: The SMPS state of the station changed. |  * @IEEE80211_RC_SMPS_CHANGED: The SMPS state of the station changed. | ||||||
|  |  * @IEEE80211_RC_SUPP_RATES_CHANGED: The supported rate set of this peer | ||||||
|  |  *	changed (in IBSS mode) due to discovering more information about | ||||||
|  |  *	the peer. | ||||||
|  */ |  */ | ||||||
| enum ieee80211_rate_control_changed { | enum ieee80211_rate_control_changed { | ||||||
| 	IEEE80211_RC_BW_CHANGED		= BIT(0), | 	IEEE80211_RC_BW_CHANGED		= BIT(0), | ||||||
| 	IEEE80211_RC_SMPS_CHANGED	= BIT(1), | 	IEEE80211_RC_SMPS_CHANGED	= BIT(1), | ||||||
|  | 	IEEE80211_RC_SUPP_RATES_CHANGED	= BIT(2), | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  | @ -2264,7 +2311,9 @@ enum ieee80211_rate_control_changed { | ||||||
|  *	The callback is optional and can (should!) sleep. |  *	The callback is optional and can (should!) sleep. | ||||||
|  */ |  */ | ||||||
| struct ieee80211_ops { | struct ieee80211_ops { | ||||||
| 	void (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb); | 	void (*tx)(struct ieee80211_hw *hw, | ||||||
|  | 		   struct ieee80211_tx_control *control, | ||||||
|  | 		   struct sk_buff *skb); | ||||||
| 	int (*start)(struct ieee80211_hw *hw); | 	int (*start)(struct ieee80211_hw *hw); | ||||||
| 	void (*stop)(struct ieee80211_hw *hw); | 	void (*stop)(struct ieee80211_hw *hw); | ||||||
| #ifdef CONFIG_PM | #ifdef CONFIG_PM | ||||||
|  |  | ||||||
|  | @ -38,14 +38,10 @@ static void gf_mulx(u8 *pad) | ||||||
| static void aes_128_cmac_vector(struct crypto_cipher *tfm, size_t num_elem, | static void aes_128_cmac_vector(struct crypto_cipher *tfm, size_t num_elem, | ||||||
| 				const u8 *addr[], const size_t *len, u8 *mac) | 				const u8 *addr[], const size_t *len, u8 *mac) | ||||||
| { | { | ||||||
| 	u8 scratch[2 * AES_BLOCK_SIZE]; | 	u8 cbc[AES_BLOCK_SIZE], pad[AES_BLOCK_SIZE]; | ||||||
| 	u8 *cbc, *pad; |  | ||||||
| 	const u8 *pos, *end; | 	const u8 *pos, *end; | ||||||
| 	size_t i, e, left, total_len; | 	size_t i, e, left, total_len; | ||||||
| 
 | 
 | ||||||
| 	cbc = scratch; |  | ||||||
| 	pad = scratch + AES_BLOCK_SIZE; |  | ||||||
| 
 |  | ||||||
| 	memset(cbc, 0, AES_BLOCK_SIZE); | 	memset(cbc, 0, AES_BLOCK_SIZE); | ||||||
| 
 | 
 | ||||||
| 	total_len = 0; | 	total_len = 0; | ||||||
|  |  | ||||||
|  | @ -102,6 +102,18 @@ static int ieee80211_change_iface(struct wiphy *wiphy, | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static int ieee80211_start_p2p_device(struct wiphy *wiphy, | ||||||
|  | 				      struct wireless_dev *wdev) | ||||||
|  | { | ||||||
|  | 	return ieee80211_do_open(wdev, true); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void ieee80211_stop_p2p_device(struct wiphy *wiphy, | ||||||
|  | 				      struct wireless_dev *wdev) | ||||||
|  | { | ||||||
|  | 	ieee80211_sdata_stop(IEEE80211_WDEV_TO_SUB_IF(wdev)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static int ieee80211_set_noack_map(struct wiphy *wiphy, | static int ieee80211_set_noack_map(struct wiphy *wiphy, | ||||||
| 				  struct net_device *dev, | 				  struct net_device *dev, | ||||||
| 				  u16 noack_map) | 				  u16 noack_map) | ||||||
|  | @ -330,7 +342,7 @@ static void rate_idx_to_bitrate(struct rate_info *rate, struct sta_info *sta, in | ||||||
| 	if (!(rate->flags & RATE_INFO_FLAGS_MCS)) { | 	if (!(rate->flags & RATE_INFO_FLAGS_MCS)) { | ||||||
| 		struct ieee80211_supported_band *sband; | 		struct ieee80211_supported_band *sband; | ||||||
| 		sband = sta->local->hw.wiphy->bands[ | 		sband = sta->local->hw.wiphy->bands[ | ||||||
| 				sta->local->hw.conf.channel->band]; | 				sta->local->oper_channel->band]; | ||||||
| 		rate->legacy = sband->bitrates[idx].bitrate; | 		rate->legacy = sband->bitrates[idx].bitrate; | ||||||
| 	} else | 	} else | ||||||
| 		rate->mcs = idx; | 		rate->mcs = idx; | ||||||
|  | @ -725,25 +737,23 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy, | ||||||
| static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, | static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, | ||||||
| 				    const u8 *resp, size_t resp_len) | 				    const u8 *resp, size_t resp_len) | ||||||
| { | { | ||||||
| 	struct sk_buff *new, *old; | 	struct probe_resp *new, *old; | ||||||
| 
 | 
 | ||||||
| 	if (!resp || !resp_len) | 	if (!resp || !resp_len) | ||||||
| 		return 1; | 		return 1; | ||||||
| 
 | 
 | ||||||
| 	old = rtnl_dereference(sdata->u.ap.probe_resp); | 	old = rtnl_dereference(sdata->u.ap.probe_resp); | ||||||
| 
 | 
 | ||||||
| 	new = dev_alloc_skb(resp_len); | 	new = kzalloc(sizeof(struct probe_resp) + resp_len, GFP_KERNEL); | ||||||
| 	if (!new) | 	if (!new) | ||||||
| 		return -ENOMEM; | 		return -ENOMEM; | ||||||
| 
 | 
 | ||||||
| 	memcpy(skb_put(new, resp_len), resp, resp_len); | 	new->len = resp_len; | ||||||
|  | 	memcpy(new->data, resp, resp_len); | ||||||
| 
 | 
 | ||||||
| 	rcu_assign_pointer(sdata->u.ap.probe_resp, new); | 	rcu_assign_pointer(sdata->u.ap.probe_resp, new); | ||||||
| 	if (old) { | 	if (old) | ||||||
| 		/* TODO: use call_rcu() */ | 		kfree_rcu(old, rcu_head); | ||||||
| 		synchronize_rcu(); |  | ||||||
| 		dev_kfree_skb(old); |  | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  | @ -950,7 +960,7 @@ static void ieee80211_send_layer2_update(struct sta_info *sta) | ||||||
| 	/* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID)
 | 	/* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID)
 | ||||||
| 	 * Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */ | 	 * Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */ | ||||||
| 
 | 
 | ||||||
| 	memset(msg->da, 0xff, ETH_ALEN); | 	eth_broadcast_addr(msg->da); | ||||||
| 	memcpy(msg->sa, sta->sta.addr, ETH_ALEN); | 	memcpy(msg->sa, sta->sta.addr, ETH_ALEN); | ||||||
| 	msg->len = htons(6); | 	msg->len = htons(6); | ||||||
| 	msg->dsap = 0; | 	msg->dsap = 0; | ||||||
|  | @ -1285,9 +1295,10 @@ static int ieee80211_change_station(struct wiphy *wiphy, | ||||||
| 	mutex_unlock(&local->sta_mtx); | 	mutex_unlock(&local->sta_mtx); | ||||||
| 
 | 
 | ||||||
| 	if (sdata->vif.type == NL80211_IFTYPE_STATION && | 	if (sdata->vif.type == NL80211_IFTYPE_STATION && | ||||||
| 	    params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) | 	    params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) { | ||||||
| 		ieee80211_recalc_ps(local, -1); | 		ieee80211_recalc_ps(local, -1); | ||||||
| 
 | 		ieee80211_recalc_ps_vif(sdata); | ||||||
|  | 	} | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -1661,7 +1672,7 @@ static int ieee80211_change_bss(struct wiphy *wiphy, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (!sdata->vif.bss_conf.use_short_slot && | 	if (!sdata->vif.bss_conf.use_short_slot && | ||||||
| 	    sdata->local->hw.conf.channel->band == IEEE80211_BAND_5GHZ) { | 	    sdata->local->oper_channel->band == IEEE80211_BAND_5GHZ) { | ||||||
| 		sdata->vif.bss_conf.use_short_slot = true; | 		sdata->vif.bss_conf.use_short_slot = true; | ||||||
| 		changed |= BSS_CHANGED_ERP_SLOT; | 		changed |= BSS_CHANGED_ERP_SLOT; | ||||||
| 	} | 	} | ||||||
|  | @ -1775,6 +1786,7 @@ static int ieee80211_scan(struct wiphy *wiphy, | ||||||
| 	case NL80211_IFTYPE_ADHOC: | 	case NL80211_IFTYPE_ADHOC: | ||||||
| 	case NL80211_IFTYPE_MESH_POINT: | 	case NL80211_IFTYPE_MESH_POINT: | ||||||
| 	case NL80211_IFTYPE_P2P_CLIENT: | 	case NL80211_IFTYPE_P2P_CLIENT: | ||||||
|  | 	case NL80211_IFTYPE_P2P_DEVICE: | ||||||
| 		break; | 		break; | ||||||
| 	case NL80211_IFTYPE_P2P_GO: | 	case NL80211_IFTYPE_P2P_GO: | ||||||
| 		if (sdata->local->ops->hw_scan) | 		if (sdata->local->ops->hw_scan) | ||||||
|  | @ -1927,7 +1939,7 @@ static int ieee80211_set_tx_power(struct wiphy *wiphy, | ||||||
| 				  enum nl80211_tx_power_setting type, int mbm) | 				  enum nl80211_tx_power_setting type, int mbm) | ||||||
| { | { | ||||||
| 	struct ieee80211_local *local = wiphy_priv(wiphy); | 	struct ieee80211_local *local = wiphy_priv(wiphy); | ||||||
| 	struct ieee80211_channel *chan = local->hw.conf.channel; | 	struct ieee80211_channel *chan = local->oper_channel; | ||||||
| 	u32 changes = 0; | 	u32 changes = 0; | ||||||
| 
 | 
 | ||||||
| 	switch (type) { | 	switch (type) { | ||||||
|  | @ -2079,6 +2091,7 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, | ||||||
| 		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | 		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | ||||||
| 
 | 
 | ||||||
| 	ieee80211_recalc_ps(local, -1); | 	ieee80211_recalc_ps(local, -1); | ||||||
|  | 	ieee80211_recalc_ps_vif(sdata); | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  | @ -2461,6 +2474,9 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, | ||||||
| 		if (!sdata->u.mgd.associated) | 		if (!sdata->u.mgd.associated) | ||||||
| 			need_offchan = true; | 			need_offchan = true; | ||||||
| 		break; | 		break; | ||||||
|  | 	case NL80211_IFTYPE_P2P_DEVICE: | ||||||
|  | 		need_offchan = true; | ||||||
|  | 		break; | ||||||
| 	default: | 	default: | ||||||
| 		return -EOPNOTSUPP; | 		return -EOPNOTSUPP; | ||||||
| 	} | 	} | ||||||
|  | @ -2653,6 +2669,7 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, | ||||||
| 			       u16 status_code, struct sk_buff *skb) | 			       u16 status_code, struct sk_buff *skb) | ||||||
| { | { | ||||||
| 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||||||
|  | 	struct ieee80211_local *local = sdata->local; | ||||||
| 	struct ieee80211_tdls_data *tf; | 	struct ieee80211_tdls_data *tf; | ||||||
| 
 | 
 | ||||||
| 	tf = (void *)skb_put(skb, offsetof(struct ieee80211_tdls_data, u)); | 	tf = (void *)skb_put(skb, offsetof(struct ieee80211_tdls_data, u)); | ||||||
|  | @ -2672,8 +2689,10 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, | ||||||
| 		tf->u.setup_req.capability = | 		tf->u.setup_req.capability = | ||||||
| 			cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); | 			cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); | ||||||
| 
 | 
 | ||||||
| 		ieee80211_add_srates_ie(sdata, skb, false); | 		ieee80211_add_srates_ie(sdata, skb, false, | ||||||
| 		ieee80211_add_ext_srates_ie(sdata, skb, false); | 					local->oper_channel->band); | ||||||
|  | 		ieee80211_add_ext_srates_ie(sdata, skb, false, | ||||||
|  | 					    local->oper_channel->band); | ||||||
| 		ieee80211_tdls_add_ext_capab(skb); | 		ieee80211_tdls_add_ext_capab(skb); | ||||||
| 		break; | 		break; | ||||||
| 	case WLAN_TDLS_SETUP_RESPONSE: | 	case WLAN_TDLS_SETUP_RESPONSE: | ||||||
|  | @ -2686,8 +2705,10 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, | ||||||
| 		tf->u.setup_resp.capability = | 		tf->u.setup_resp.capability = | ||||||
| 			cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); | 			cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); | ||||||
| 
 | 
 | ||||||
| 		ieee80211_add_srates_ie(sdata, skb, false); | 		ieee80211_add_srates_ie(sdata, skb, false, | ||||||
| 		ieee80211_add_ext_srates_ie(sdata, skb, false); | 					local->oper_channel->band); | ||||||
|  | 		ieee80211_add_ext_srates_ie(sdata, skb, false, | ||||||
|  | 					    local->oper_channel->band); | ||||||
| 		ieee80211_tdls_add_ext_capab(skb); | 		ieee80211_tdls_add_ext_capab(skb); | ||||||
| 		break; | 		break; | ||||||
| 	case WLAN_TDLS_SETUP_CONFIRM: | 	case WLAN_TDLS_SETUP_CONFIRM: | ||||||
|  | @ -2725,6 +2746,7 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev, | ||||||
| 			   u16 status_code, struct sk_buff *skb) | 			   u16 status_code, struct sk_buff *skb) | ||||||
| { | { | ||||||
| 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||||||
|  | 	struct ieee80211_local *local = sdata->local; | ||||||
| 	struct ieee80211_mgmt *mgmt; | 	struct ieee80211_mgmt *mgmt; | ||||||
| 
 | 
 | ||||||
| 	mgmt = (void *)skb_put(skb, 24); | 	mgmt = (void *)skb_put(skb, 24); | ||||||
|  | @ -2747,8 +2769,10 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev, | ||||||
| 		mgmt->u.action.u.tdls_discover_resp.capability = | 		mgmt->u.action.u.tdls_discover_resp.capability = | ||||||
| 			cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); | 			cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); | ||||||
| 
 | 
 | ||||||
| 		ieee80211_add_srates_ie(sdata, skb, false); | 		ieee80211_add_srates_ie(sdata, skb, false, | ||||||
| 		ieee80211_add_ext_srates_ie(sdata, skb, false); | 					local->oper_channel->band); | ||||||
|  | 		ieee80211_add_ext_srates_ie(sdata, skb, false, | ||||||
|  | 					    local->oper_channel->band); | ||||||
| 		ieee80211_tdls_add_ext_capab(skb); | 		ieee80211_tdls_add_ext_capab(skb); | ||||||
| 		break; | 		break; | ||||||
| 	default: | 	default: | ||||||
|  | @ -3005,6 +3029,8 @@ struct cfg80211_ops mac80211_config_ops = { | ||||||
| 	.add_virtual_intf = ieee80211_add_iface, | 	.add_virtual_intf = ieee80211_add_iface, | ||||||
| 	.del_virtual_intf = ieee80211_del_iface, | 	.del_virtual_intf = ieee80211_del_iface, | ||||||
| 	.change_virtual_intf = ieee80211_change_iface, | 	.change_virtual_intf = ieee80211_change_iface, | ||||||
|  | 	.start_p2p_device = ieee80211_start_p2p_device, | ||||||
|  | 	.stop_p2p_device = ieee80211_stop_p2p_device, | ||||||
| 	.add_key = ieee80211_add_key, | 	.add_key = ieee80211_add_key, | ||||||
| 	.del_key = ieee80211_del_key, | 	.del_key = ieee80211_del_key, | ||||||
| 	.get_key = ieee80211_get_key, | 	.get_key = ieee80211_get_key, | ||||||
|  |  | ||||||
|  | @ -63,8 +63,6 @@ DEBUGFS_READONLY_FILE(user_power, "%d", | ||||||
| 		      local->user_power_level); | 		      local->user_power_level); | ||||||
| DEBUGFS_READONLY_FILE(power, "%d", | DEBUGFS_READONLY_FILE(power, "%d", | ||||||
| 		      local->hw.conf.power_level); | 		      local->hw.conf.power_level); | ||||||
| DEBUGFS_READONLY_FILE(frequency, "%d", |  | ||||||
| 		      local->hw.conf.channel->center_freq); |  | ||||||
| DEBUGFS_READONLY_FILE(total_ps_buffered, "%d", | DEBUGFS_READONLY_FILE(total_ps_buffered, "%d", | ||||||
| 		      local->total_ps_buffered); | 		      local->total_ps_buffered); | ||||||
| DEBUGFS_READONLY_FILE(wep_iv, "%#08x", | DEBUGFS_READONLY_FILE(wep_iv, "%#08x", | ||||||
|  | @ -91,33 +89,6 @@ static const struct file_operations reset_ops = { | ||||||
| 	.llseek = noop_llseek, | 	.llseek = noop_llseek, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static ssize_t channel_type_read(struct file *file, char __user *user_buf, |  | ||||||
| 		       size_t count, loff_t *ppos) |  | ||||||
| { |  | ||||||
| 	struct ieee80211_local *local = file->private_data; |  | ||||||
| 	const char *buf; |  | ||||||
| 
 |  | ||||||
| 	switch (local->hw.conf.channel_type) { |  | ||||||
| 	case NL80211_CHAN_NO_HT: |  | ||||||
| 		buf = "no ht\n"; |  | ||||||
| 		break; |  | ||||||
| 	case NL80211_CHAN_HT20: |  | ||||||
| 		buf = "ht20\n"; |  | ||||||
| 		break; |  | ||||||
| 	case NL80211_CHAN_HT40MINUS: |  | ||||||
| 		buf = "ht40-\n"; |  | ||||||
| 		break; |  | ||||||
| 	case NL80211_CHAN_HT40PLUS: |  | ||||||
| 		buf = "ht40+\n"; |  | ||||||
| 		break; |  | ||||||
| 	default: |  | ||||||
| 		buf = "???"; |  | ||||||
| 		break; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static ssize_t hwflags_read(struct file *file, char __user *user_buf, | static ssize_t hwflags_read(struct file *file, char __user *user_buf, | ||||||
| 			    size_t count, loff_t *ppos) | 			    size_t count, loff_t *ppos) | ||||||
| { | { | ||||||
|  | @ -205,7 +176,6 @@ static ssize_t queues_read(struct file *file, char __user *user_buf, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| DEBUGFS_READONLY_FILE_OPS(hwflags); | DEBUGFS_READONLY_FILE_OPS(hwflags); | ||||||
| DEBUGFS_READONLY_FILE_OPS(channel_type); |  | ||||||
| DEBUGFS_READONLY_FILE_OPS(queues); | DEBUGFS_READONLY_FILE_OPS(queues); | ||||||
| 
 | 
 | ||||||
| /* statistics stuff */ | /* statistics stuff */ | ||||||
|  | @ -272,12 +242,10 @@ void debugfs_hw_add(struct ieee80211_local *local) | ||||||
| 
 | 
 | ||||||
| 	local->debugfs.keys = debugfs_create_dir("keys", phyd); | 	local->debugfs.keys = debugfs_create_dir("keys", phyd); | ||||||
| 
 | 
 | ||||||
| 	DEBUGFS_ADD(frequency); |  | ||||||
| 	DEBUGFS_ADD(total_ps_buffered); | 	DEBUGFS_ADD(total_ps_buffered); | ||||||
| 	DEBUGFS_ADD(wep_iv); | 	DEBUGFS_ADD(wep_iv); | ||||||
| 	DEBUGFS_ADD(queues); | 	DEBUGFS_ADD(queues); | ||||||
| 	DEBUGFS_ADD_MODE(reset, 0200); | 	DEBUGFS_ADD_MODE(reset, 0200); | ||||||
| 	DEBUGFS_ADD(channel_type); |  | ||||||
| 	DEBUGFS_ADD(hwflags); | 	DEBUGFS_ADD(hwflags); | ||||||
| 	DEBUGFS_ADD(user_power); | 	DEBUGFS_ADD(user_power); | ||||||
| 	DEBUGFS_ADD(power); | 	DEBUGFS_ADD(power); | ||||||
|  |  | ||||||
|  | @ -9,7 +9,7 @@ static inline void check_sdata_in_driver(struct ieee80211_sub_if_data *sdata) | ||||||
| { | { | ||||||
| 	WARN(!(sdata->flags & IEEE80211_SDATA_IN_DRIVER), | 	WARN(!(sdata->flags & IEEE80211_SDATA_IN_DRIVER), | ||||||
| 	     "%s:  Failed check-sdata-in-driver check, flags: 0x%x\n", | 	     "%s:  Failed check-sdata-in-driver check, flags: 0x%x\n", | ||||||
| 	     sdata->dev->name, sdata->flags); | 	     sdata->dev ? sdata->dev->name : sdata->name, sdata->flags); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static inline struct ieee80211_sub_if_data * | static inline struct ieee80211_sub_if_data * | ||||||
|  | @ -22,9 +22,11 @@ get_bss_sdata(struct ieee80211_sub_if_data *sdata) | ||||||
| 	return sdata; | 	return sdata; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static inline void drv_tx(struct ieee80211_local *local, struct sk_buff *skb) | static inline void drv_tx(struct ieee80211_local *local, | ||||||
|  | 			  struct ieee80211_tx_control *control, | ||||||
|  | 			  struct sk_buff *skb) | ||||||
| { | { | ||||||
| 	local->ops->tx(&local->hw, skb); | 	local->ops->tx(&local->hw, control, skb); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static inline void drv_get_et_strings(struct ieee80211_sub_if_data *sdata, | static inline void drv_get_et_strings(struct ieee80211_sub_if_data *sdata, | ||||||
|  | @ -526,6 +528,9 @@ static inline void drv_sta_rc_update(struct ieee80211_local *local, | ||||||
| 	sdata = get_bss_sdata(sdata); | 	sdata = get_bss_sdata(sdata); | ||||||
| 	check_sdata_in_driver(sdata); | 	check_sdata_in_driver(sdata); | ||||||
| 
 | 
 | ||||||
|  | 	WARN_ON(changed & IEEE80211_RC_SUPP_RATES_CHANGED && | ||||||
|  | 		sdata->vif.type != NL80211_IFTYPE_ADHOC); | ||||||
|  | 
 | ||||||
| 	trace_drv_sta_rc_update(local, sdata, sta, changed); | 	trace_drv_sta_rc_update(local, sdata, sta, changed); | ||||||
| 	if (local->ops->sta_rc_update) | 	if (local->ops->sta_rc_update) | ||||||
| 		local->ops->sta_rc_update(&local->hw, &sdata->vif, | 		local->ops->sta_rc_update(&local->hw, &sdata->vif, | ||||||
|  |  | ||||||
|  | @ -109,7 +109,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | ||||||
| 	memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon)); | 	memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon)); | ||||||
| 	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||||||
| 					  IEEE80211_STYPE_PROBE_RESP); | 					  IEEE80211_STYPE_PROBE_RESP); | ||||||
| 	memset(mgmt->da, 0xff, ETH_ALEN); | 	eth_broadcast_addr(mgmt->da); | ||||||
| 	memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); | 	memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); | ||||||
| 	memcpy(mgmt->bssid, ifibss->bssid, ETH_ALEN); | 	memcpy(mgmt->bssid, ifibss->bssid, ETH_ALEN); | ||||||
| 	mgmt->u.beacon.beacon_int = cpu_to_le16(beacon_int); | 	mgmt->u.beacon.beacon_int = cpu_to_le16(beacon_int); | ||||||
|  | @ -205,7 +205,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | ||||||
| 	mod_timer(&ifibss->timer, | 	mod_timer(&ifibss->timer, | ||||||
| 		  round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL)); | 		  round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL)); | ||||||
| 
 | 
 | ||||||
| 	bss = cfg80211_inform_bss_frame(local->hw.wiphy, local->hw.conf.channel, | 	bss = cfg80211_inform_bss_frame(local->hw.wiphy, chan, | ||||||
| 					mgmt, skb->len, 0, GFP_KERNEL); | 					mgmt, skb->len, 0, GFP_KERNEL); | ||||||
| 	cfg80211_put_bss(bss); | 	cfg80211_put_bss(bss); | ||||||
| 	netif_carrier_on(sdata->dev); | 	netif_carrier_on(sdata->dev); | ||||||
|  | @ -294,7 +294,7 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | ||||||
| 	struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 	struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||||||
| 	struct ieee80211_local *local = sdata->local; | 	struct ieee80211_local *local = sdata->local; | ||||||
| 	struct sta_info *sta; | 	struct sta_info *sta; | ||||||
| 	int band = local->hw.conf.channel->band; | 	int band = local->oper_channel->band; | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * XXX: Consider removing the least recently used entry and | 	 * XXX: Consider removing the least recently used entry and | ||||||
|  | @ -459,8 +459,11 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (sta && rates_updated) | 		if (sta && rates_updated) { | ||||||
|  | 			drv_sta_rc_update(local, sdata, &sta->sta, | ||||||
|  | 					  IEEE80211_RC_SUPP_RATES_CHANGED); | ||||||
| 			rate_control_rate_init(sta); | 			rate_control_rate_init(sta); | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 		rcu_read_unlock(); | 		rcu_read_unlock(); | ||||||
| 	} | 	} | ||||||
|  | @ -561,7 +564,7 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata, | ||||||
| 	struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 	struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||||||
| 	struct ieee80211_local *local = sdata->local; | 	struct ieee80211_local *local = sdata->local; | ||||||
| 	struct sta_info *sta; | 	struct sta_info *sta; | ||||||
| 	int band = local->hw.conf.channel->band; | 	int band = local->oper_channel->band; | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * XXX: Consider removing the least recently used entry and | 	 * XXX: Consider removing the least recently used entry and | ||||||
|  | @ -759,7 +762,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) | ||||||
| 				return; | 				return; | ||||||
| 			} | 			} | ||||||
| 			sdata_info(sdata, "IBSS not allowed on %d MHz\n", | 			sdata_info(sdata, "IBSS not allowed on %d MHz\n", | ||||||
| 				   local->hw.conf.channel->center_freq); | 				   local->oper_channel->center_freq); | ||||||
| 
 | 
 | ||||||
| 			/* No IBSS found - decrease scan interval and continue
 | 			/* No IBSS found - decrease scan interval and continue
 | ||||||
| 			 * scanning. */ | 			 * scanning. */ | ||||||
|  |  | ||||||
|  | @ -193,8 +193,6 @@ struct ieee80211_tx_data { | ||||||
| 	struct sta_info *sta; | 	struct sta_info *sta; | ||||||
| 	struct ieee80211_key *key; | 	struct ieee80211_key *key; | ||||||
| 
 | 
 | ||||||
| 	struct ieee80211_channel *channel; |  | ||||||
| 
 |  | ||||||
| 	unsigned int flags; | 	unsigned int flags; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | @ -274,9 +272,15 @@ struct beacon_data { | ||||||
| 	struct rcu_head rcu_head; | 	struct rcu_head rcu_head; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | struct probe_resp { | ||||||
|  | 	struct rcu_head rcu_head; | ||||||
|  | 	int len; | ||||||
|  | 	u8 data[0]; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| struct ieee80211_if_ap { | struct ieee80211_if_ap { | ||||||
| 	struct beacon_data __rcu *beacon; | 	struct beacon_data __rcu *beacon; | ||||||
| 	struct sk_buff __rcu *probe_resp; | 	struct probe_resp __rcu *probe_resp; | ||||||
| 
 | 
 | ||||||
| 	struct list_head vlans; | 	struct list_head vlans; | ||||||
| 
 | 
 | ||||||
|  | @ -359,6 +363,7 @@ enum ieee80211_sta_flags { | ||||||
| 	IEEE80211_STA_NULLFUNC_ACKED	= BIT(8), | 	IEEE80211_STA_NULLFUNC_ACKED	= BIT(8), | ||||||
| 	IEEE80211_STA_RESET_SIGNAL_AVE	= BIT(9), | 	IEEE80211_STA_RESET_SIGNAL_AVE	= BIT(9), | ||||||
| 	IEEE80211_STA_DISABLE_40MHZ	= BIT(10), | 	IEEE80211_STA_DISABLE_40MHZ	= BIT(10), | ||||||
|  | 	IEEE80211_STA_DISABLE_VHT	= BIT(11), | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct ieee80211_mgd_auth_data { | struct ieee80211_mgd_auth_data { | ||||||
|  | @ -1075,6 +1080,8 @@ struct ieee80211_local { | ||||||
| 	struct idr ack_status_frames; | 	struct idr ack_status_frames; | ||||||
| 	spinlock_t ack_status_lock; | 	spinlock_t ack_status_lock; | ||||||
| 
 | 
 | ||||||
|  | 	struct ieee80211_sub_if_data __rcu *p2p_sdata; | ||||||
|  | 
 | ||||||
| 	/* dummy netdev for use w/ NAPI */ | 	/* dummy netdev for use w/ NAPI */ | ||||||
| 	struct net_device napi_dev; | 	struct net_device napi_dev; | ||||||
| 
 | 
 | ||||||
|  | @ -1131,7 +1138,7 @@ struct ieee802_11_elems { | ||||||
| 	u8 *prep; | 	u8 *prep; | ||||||
| 	u8 *perr; | 	u8 *perr; | ||||||
| 	struct ieee80211_rann_ie *rann; | 	struct ieee80211_rann_ie *rann; | ||||||
| 	u8 *ch_switch_elem; | 	struct ieee80211_channel_sw_ie *ch_switch_ie; | ||||||
| 	u8 *country_elem; | 	u8 *country_elem; | ||||||
| 	u8 *pwr_constr_elem; | 	u8 *pwr_constr_elem; | ||||||
| 	u8 *quiet_elem;	/* first quite element */ | 	u8 *quiet_elem;	/* first quite element */ | ||||||
|  | @ -1157,7 +1164,6 @@ struct ieee802_11_elems { | ||||||
| 	u8 preq_len; | 	u8 preq_len; | ||||||
| 	u8 prep_len; | 	u8 prep_len; | ||||||
| 	u8 perr_len; | 	u8 perr_len; | ||||||
| 	u8 ch_switch_elem_len; |  | ||||||
| 	u8 country_elem_len; | 	u8 country_elem_len; | ||||||
| 	u8 pwr_constr_elem_len; | 	u8 pwr_constr_elem_len; | ||||||
| 	u8 quiet_elem_len; | 	u8 quiet_elem_len; | ||||||
|  | @ -1202,6 +1208,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, | ||||||
| void ieee80211_send_pspoll(struct ieee80211_local *local, | void ieee80211_send_pspoll(struct ieee80211_local *local, | ||||||
| 			   struct ieee80211_sub_if_data *sdata); | 			   struct ieee80211_sub_if_data *sdata); | ||||||
| void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency); | void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency); | ||||||
|  | void ieee80211_recalc_ps_vif(struct ieee80211_sub_if_data *sdata); | ||||||
| int ieee80211_max_network_latency(struct notifier_block *nb, | int ieee80211_max_network_latency(struct notifier_block *nb, | ||||||
| 				  unsigned long data, void *dummy); | 				  unsigned long data, void *dummy); | ||||||
| int ieee80211_set_arp_filter(struct ieee80211_sub_if_data *sdata); | int ieee80211_set_arp_filter(struct ieee80211_sub_if_data *sdata); | ||||||
|  | @ -1291,6 +1298,8 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local); | ||||||
| void ieee80211_recalc_idle(struct ieee80211_local *local); | void ieee80211_recalc_idle(struct ieee80211_local *local); | ||||||
| void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata, | void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata, | ||||||
| 				    const int offset); | 				    const int offset); | ||||||
|  | int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up); | ||||||
|  | void ieee80211_sdata_stop(struct ieee80211_sub_if_data *sdata); | ||||||
| 
 | 
 | ||||||
| static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata) | static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata) | ||||||
| { | { | ||||||
|  | @ -1425,7 +1434,6 @@ void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, | ||||||
| 			     struct ieee80211_hdr *hdr); | 			     struct ieee80211_hdr *hdr); | ||||||
| void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, | void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, | ||||||
| 			     struct ieee80211_hdr *hdr, bool ack); | 			     struct ieee80211_hdr *hdr, bool ack); | ||||||
| void ieee80211_beacon_connection_loss_work(struct work_struct *work); |  | ||||||
| 
 | 
 | ||||||
| void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, | void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, | ||||||
| 				     enum queue_stop_reason reason); | 				     enum queue_stop_reason reason); | ||||||
|  | @ -1457,13 +1465,15 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | ||||||
| 			     u8 channel); | 			     u8 channel); | ||||||
| struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | ||||||
| 					  u8 *dst, u32 ratemask, | 					  u8 *dst, u32 ratemask, | ||||||
|  | 					  struct ieee80211_channel *chan, | ||||||
| 					  const u8 *ssid, size_t ssid_len, | 					  const u8 *ssid, size_t ssid_len, | ||||||
| 					  const u8 *ie, size_t ie_len, | 					  const u8 *ie, size_t ie_len, | ||||||
| 					  bool directed); | 					  bool directed); | ||||||
| void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | ||||||
| 			      const u8 *ssid, size_t ssid_len, | 			      const u8 *ssid, size_t ssid_len, | ||||||
| 			      const u8 *ie, size_t ie_len, | 			      const u8 *ie, size_t ie_len, | ||||||
| 			      u32 ratemask, bool directed, bool no_cck); | 			      u32 ratemask, bool directed, bool no_cck, | ||||||
|  | 			      struct ieee80211_channel *channel); | ||||||
| 
 | 
 | ||||||
| void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, | void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, | ||||||
| 				  const size_t supp_rates_len, | 				  const size_t supp_rates_len, | ||||||
|  | @ -1487,9 +1497,11 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, | ||||||
| u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, | u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, | ||||||
| 			       u32 cap); | 			       u32 cap); | ||||||
| int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata, | int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata, | ||||||
| 			    struct sk_buff *skb, bool need_basic); | 			    struct sk_buff *skb, bool need_basic, | ||||||
|  | 			    enum ieee80211_band band); | ||||||
| int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata, | int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata, | ||||||
| 				struct sk_buff *skb, bool need_basic); | 				struct sk_buff *skb, bool need_basic, | ||||||
|  | 				enum ieee80211_band band); | ||||||
| 
 | 
 | ||||||
| /* channel management */ | /* channel management */ | ||||||
| enum ieee80211_chan_mode { | enum ieee80211_chan_mode { | ||||||
|  |  | ||||||
|  | @ -100,6 +100,10 @@ static u32 __ieee80211_recalc_idle(struct ieee80211_local *local) | ||||||
| 			sdata->vif.bss_conf.idle = true; | 			sdata->vif.bss_conf.idle = true; | ||||||
| 			continue; | 			continue; | ||||||
| 		} | 		} | ||||||
|  | 
 | ||||||
|  | 		if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) | ||||||
|  | 			continue; | ||||||
|  | 
 | ||||||
| 		/* count everything else */ | 		/* count everything else */ | ||||||
| 		sdata->vif.bss_conf.idle = false; | 		sdata->vif.bss_conf.idle = false; | ||||||
| 		count++; | 		count++; | ||||||
|  | @ -121,7 +125,8 @@ static u32 __ieee80211_recalc_idle(struct ieee80211_local *local) | ||||||
| 
 | 
 | ||||||
| 	list_for_each_entry(sdata, &local->interfaces, list) { | 	list_for_each_entry(sdata, &local->interfaces, list) { | ||||||
| 		if (sdata->vif.type == NL80211_IFTYPE_MONITOR || | 		if (sdata->vif.type == NL80211_IFTYPE_MONITOR || | ||||||
| 		    sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 		    sdata->vif.type == NL80211_IFTYPE_AP_VLAN || | ||||||
|  | 		    sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) | ||||||
| 			continue; | 			continue; | ||||||
| 		if (sdata->old_idle == sdata->vif.bss_conf.idle) | 		if (sdata->old_idle == sdata->vif.bss_conf.idle) | ||||||
| 			continue; | 			continue; | ||||||
|  | @ -204,6 +209,8 @@ static inline int identical_mac_addr_allowed(int type1, int type2) | ||||||
| { | { | ||||||
| 	return type1 == NL80211_IFTYPE_MONITOR || | 	return type1 == NL80211_IFTYPE_MONITOR || | ||||||
| 		type2 == NL80211_IFTYPE_MONITOR || | 		type2 == NL80211_IFTYPE_MONITOR || | ||||||
|  | 		type1 == NL80211_IFTYPE_P2P_DEVICE || | ||||||
|  | 		type2 == NL80211_IFTYPE_P2P_DEVICE || | ||||||
| 		(type1 == NL80211_IFTYPE_AP && type2 == NL80211_IFTYPE_WDS) || | 		(type1 == NL80211_IFTYPE_AP && type2 == NL80211_IFTYPE_WDS) || | ||||||
| 		(type1 == NL80211_IFTYPE_WDS && | 		(type1 == NL80211_IFTYPE_WDS && | ||||||
| 			(type2 == NL80211_IFTYPE_WDS || | 			(type2 == NL80211_IFTYPE_WDS || | ||||||
|  | @ -406,9 +413,10 @@ static void ieee80211_del_virtual_monitor(struct ieee80211_local *local) | ||||||
|  * an error on interface type changes that have been pre-checked, so most |  * an error on interface type changes that have been pre-checked, so most | ||||||
|  * checks should be in ieee80211_check_concurrent_iface. |  * checks should be in ieee80211_check_concurrent_iface. | ||||||
|  */ |  */ | ||||||
| static int ieee80211_do_open(struct net_device *dev, bool coming_up) | int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) | ||||||
| { | { | ||||||
| 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 	struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); | ||||||
|  | 	struct net_device *dev = wdev->netdev; | ||||||
| 	struct ieee80211_local *local = sdata->local; | 	struct ieee80211_local *local = sdata->local; | ||||||
| 	struct sta_info *sta; | 	struct sta_info *sta; | ||||||
| 	u32 changed = 0; | 	u32 changed = 0; | ||||||
|  | @ -443,6 +451,7 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) | ||||||
| 	case NL80211_IFTYPE_STATION: | 	case NL80211_IFTYPE_STATION: | ||||||
| 	case NL80211_IFTYPE_MONITOR: | 	case NL80211_IFTYPE_MONITOR: | ||||||
| 	case NL80211_IFTYPE_ADHOC: | 	case NL80211_IFTYPE_ADHOC: | ||||||
|  | 	case NL80211_IFTYPE_P2P_DEVICE: | ||||||
| 		/* no special treatment */ | 		/* no special treatment */ | ||||||
| 		break; | 		break; | ||||||
| 	case NL80211_IFTYPE_UNSPECIFIED: | 	case NL80211_IFTYPE_UNSPECIFIED: | ||||||
|  | @ -471,7 +480,7 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) | ||||||
| 	 * Copy the hopefully now-present MAC address to | 	 * Copy the hopefully now-present MAC address to | ||||||
| 	 * this interface, if it has the special null one. | 	 * this interface, if it has the special null one. | ||||||
| 	 */ | 	 */ | ||||||
| 	if (is_zero_ether_addr(dev->dev_addr)) { | 	if (dev && is_zero_ether_addr(dev->dev_addr)) { | ||||||
| 		memcpy(dev->dev_addr, | 		memcpy(dev->dev_addr, | ||||||
| 		       local->hw.wiphy->perm_addr, | 		       local->hw.wiphy->perm_addr, | ||||||
| 		       ETH_ALEN); | 		       ETH_ALEN); | ||||||
|  | @ -536,15 +545,23 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) | ||||||
| 			local->fif_probe_req++; | 			local->fif_probe_req++; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | 		if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE) | ||||||
| 			changed |= ieee80211_reset_erp_info(sdata); | 			changed |= ieee80211_reset_erp_info(sdata); | ||||||
| 		ieee80211_bss_info_change_notify(sdata, changed); | 		ieee80211_bss_info_change_notify(sdata, changed); | ||||||
| 
 | 
 | ||||||
| 		if (sdata->vif.type == NL80211_IFTYPE_STATION || | 		switch (sdata->vif.type) { | ||||||
| 		    sdata->vif.type == NL80211_IFTYPE_ADHOC || | 		case NL80211_IFTYPE_STATION: | ||||||
| 		    sdata->vif.type == NL80211_IFTYPE_AP) | 		case NL80211_IFTYPE_ADHOC: | ||||||
|  | 		case NL80211_IFTYPE_AP: | ||||||
|  | 		case NL80211_IFTYPE_MESH_POINT: | ||||||
| 			netif_carrier_off(dev); | 			netif_carrier_off(dev); | ||||||
| 		else | 			break; | ||||||
|  | 		case NL80211_IFTYPE_WDS: | ||||||
|  | 		case NL80211_IFTYPE_P2P_DEVICE: | ||||||
|  | 			break; | ||||||
|  | 		default: | ||||||
| 			netif_carrier_on(dev); | 			netif_carrier_on(dev); | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 		/*
 | 		/*
 | ||||||
| 		 * set default queue parameters so drivers don't | 		 * set default queue parameters so drivers don't | ||||||
|  | @ -576,6 +593,9 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		rate_control_rate_init(sta); | 		rate_control_rate_init(sta); | ||||||
|  | 		netif_carrier_on(dev); | ||||||
|  | 	} else if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) { | ||||||
|  | 		rcu_assign_pointer(local->p2p_sdata, sdata); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
|  | @ -601,6 +621,7 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) | ||||||
| 
 | 
 | ||||||
| 	ieee80211_recalc_ps(local, -1); | 	ieee80211_recalc_ps(local, -1); | ||||||
| 
 | 
 | ||||||
|  | 	if (dev) | ||||||
| 		netif_tx_start_all_queues(dev); | 		netif_tx_start_all_queues(dev); | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
|  | @ -631,7 +652,7 @@ static int ieee80211_open(struct net_device *dev) | ||||||
| 	if (err) | 	if (err) | ||||||
| 		return err; | 		return err; | ||||||
| 
 | 
 | ||||||
| 	return ieee80211_do_open(dev, true); | 	return ieee80211_do_open(&sdata->wdev, true); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | ||||||
|  | @ -652,6 +673,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Stop TX on this interface first. | 	 * Stop TX on this interface first. | ||||||
| 	 */ | 	 */ | ||||||
|  | 	if (sdata->dev) | ||||||
| 		netif_tx_stop_all_queues(sdata->dev); | 		netif_tx_stop_all_queues(sdata->dev); | ||||||
| 
 | 
 | ||||||
| 	ieee80211_roc_purge(sdata); | 	ieee80211_roc_purge(sdata); | ||||||
|  | @ -691,6 +713,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | ||||||
| 		local->fif_probe_req--; | 		local->fif_probe_req--; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if (sdata->dev) { | ||||||
| 		netif_addr_lock_bh(sdata->dev); | 		netif_addr_lock_bh(sdata->dev); | ||||||
| 		spin_lock_bh(&local->filter_lock); | 		spin_lock_bh(&local->filter_lock); | ||||||
| 		__hw_addr_unsync(&local->mc_list, &sdata->dev->mc, | 		__hw_addr_unsync(&local->mc_list, &sdata->dev->mc, | ||||||
|  | @ -699,6 +722,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | ||||||
| 		netif_addr_unlock_bh(sdata->dev); | 		netif_addr_unlock_bh(sdata->dev); | ||||||
| 
 | 
 | ||||||
| 		ieee80211_configure_filter(local); | 		ieee80211_configure_filter(local); | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	del_timer_sync(&local->dynamic_ps_timer); | 	del_timer_sync(&local->dynamic_ps_timer); | ||||||
| 	cancel_work_sync(&local->dynamic_ps_enable_work); | 	cancel_work_sync(&local->dynamic_ps_enable_work); | ||||||
|  | @ -708,7 +732,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | ||||||
| 		struct ieee80211_sub_if_data *vlan, *tmpsdata; | 		struct ieee80211_sub_if_data *vlan, *tmpsdata; | ||||||
| 		struct beacon_data *old_beacon = | 		struct beacon_data *old_beacon = | ||||||
| 			rtnl_dereference(sdata->u.ap.beacon); | 			rtnl_dereference(sdata->u.ap.beacon); | ||||||
| 		struct sk_buff *old_probe_resp = | 		struct probe_resp *old_probe_resp = | ||||||
| 			rtnl_dereference(sdata->u.ap.probe_resp); | 			rtnl_dereference(sdata->u.ap.probe_resp); | ||||||
| 
 | 
 | ||||||
| 		/* sdata_running will return false, so this will disable */ | 		/* sdata_running will return false, so this will disable */ | ||||||
|  | @ -720,7 +744,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | ||||||
| 		RCU_INIT_POINTER(sdata->u.ap.probe_resp, NULL); | 		RCU_INIT_POINTER(sdata->u.ap.probe_resp, NULL); | ||||||
| 		synchronize_rcu(); | 		synchronize_rcu(); | ||||||
| 		kfree(old_beacon); | 		kfree(old_beacon); | ||||||
| 		kfree_skb(old_probe_resp); | 		kfree(old_probe_resp); | ||||||
| 
 | 
 | ||||||
| 		/* down all dependent devices, that is VLANs */ | 		/* down all dependent devices, that is VLANs */ | ||||||
| 		list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans, | 		list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans, | ||||||
|  | @ -759,6 +783,10 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | ||||||
| 		ieee80211_adjust_monitor_flags(sdata, -1); | 		ieee80211_adjust_monitor_flags(sdata, -1); | ||||||
| 		ieee80211_configure_filter(local); | 		ieee80211_configure_filter(local); | ||||||
| 		break; | 		break; | ||||||
|  | 	case NL80211_IFTYPE_P2P_DEVICE: | ||||||
|  | 		/* relies on synchronize_rcu() below */ | ||||||
|  | 		rcu_assign_pointer(local->p2p_sdata, NULL); | ||||||
|  | 		/* fall through */ | ||||||
| 	default: | 	default: | ||||||
| 		flush_work(&sdata->work); | 		flush_work(&sdata->work); | ||||||
| 		/*
 | 		/*
 | ||||||
|  | @ -770,14 +798,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | ||||||
| 		synchronize_rcu(); | 		synchronize_rcu(); | ||||||
| 		skb_queue_purge(&sdata->skb_queue); | 		skb_queue_purge(&sdata->skb_queue); | ||||||
| 
 | 
 | ||||||
| 		/*
 |  | ||||||
| 		 * Disable beaconing here for mesh only, AP and IBSS |  | ||||||
| 		 * are already taken care of. |  | ||||||
| 		 */ |  | ||||||
| 		if (sdata->vif.type == NL80211_IFTYPE_MESH_POINT) |  | ||||||
| 			ieee80211_bss_info_change_notify(sdata, |  | ||||||
| 				BSS_CHANGED_BEACON_ENABLED); |  | ||||||
| 
 |  | ||||||
| 		/*
 | 		/*
 | ||||||
| 		 * Free all remaining keys, there shouldn't be any, | 		 * Free all remaining keys, there shouldn't be any, | ||||||
| 		 * except maybe group keys in AP more or WDS? | 		 * except maybe group keys in AP more or WDS? | ||||||
|  | @ -877,9 +897,8 @@ static void ieee80211_set_multicast_list(struct net_device *dev) | ||||||
|  * Called when the netdev is removed or, by the code below, before |  * Called when the netdev is removed or, by the code below, before | ||||||
|  * the interface type changes. |  * the interface type changes. | ||||||
|  */ |  */ | ||||||
| static void ieee80211_teardown_sdata(struct net_device *dev) | static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata) | ||||||
| { | { | ||||||
| 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |  | ||||||
| 	struct ieee80211_local *local = sdata->local; | 	struct ieee80211_local *local = sdata->local; | ||||||
| 	int flushed; | 	int flushed; | ||||||
| 	int i; | 	int i; | ||||||
|  | @ -900,6 +919,11 @@ static void ieee80211_teardown_sdata(struct net_device *dev) | ||||||
| 	WARN_ON(flushed); | 	WARN_ON(flushed); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void ieee80211_uninit(struct net_device *dev) | ||||||
|  | { | ||||||
|  | 	ieee80211_teardown_sdata(IEEE80211_DEV_TO_SUB_IF(dev)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static u16 ieee80211_netdev_select_queue(struct net_device *dev, | static u16 ieee80211_netdev_select_queue(struct net_device *dev, | ||||||
| 					 struct sk_buff *skb) | 					 struct sk_buff *skb) | ||||||
| { | { | ||||||
|  | @ -909,7 +933,7 @@ static u16 ieee80211_netdev_select_queue(struct net_device *dev, | ||||||
| static const struct net_device_ops ieee80211_dataif_ops = { | static const struct net_device_ops ieee80211_dataif_ops = { | ||||||
| 	.ndo_open		= ieee80211_open, | 	.ndo_open		= ieee80211_open, | ||||||
| 	.ndo_stop		= ieee80211_stop, | 	.ndo_stop		= ieee80211_stop, | ||||||
| 	.ndo_uninit		= ieee80211_teardown_sdata, | 	.ndo_uninit		= ieee80211_uninit, | ||||||
| 	.ndo_start_xmit		= ieee80211_subif_start_xmit, | 	.ndo_start_xmit		= ieee80211_subif_start_xmit, | ||||||
| 	.ndo_set_rx_mode	= ieee80211_set_multicast_list, | 	.ndo_set_rx_mode	= ieee80211_set_multicast_list, | ||||||
| 	.ndo_change_mtu 	= ieee80211_change_mtu, | 	.ndo_change_mtu 	= ieee80211_change_mtu, | ||||||
|  | @ -940,7 +964,7 @@ static u16 ieee80211_monitor_select_queue(struct net_device *dev, | ||||||
| static const struct net_device_ops ieee80211_monitorif_ops = { | static const struct net_device_ops ieee80211_monitorif_ops = { | ||||||
| 	.ndo_open		= ieee80211_open, | 	.ndo_open		= ieee80211_open, | ||||||
| 	.ndo_stop		= ieee80211_stop, | 	.ndo_stop		= ieee80211_stop, | ||||||
| 	.ndo_uninit		= ieee80211_teardown_sdata, | 	.ndo_uninit		= ieee80211_uninit, | ||||||
| 	.ndo_start_xmit		= ieee80211_monitor_start_xmit, | 	.ndo_start_xmit		= ieee80211_monitor_start_xmit, | ||||||
| 	.ndo_set_rx_mode	= ieee80211_set_multicast_list, | 	.ndo_set_rx_mode	= ieee80211_set_multicast_list, | ||||||
| 	.ndo_change_mtu 	= ieee80211_change_mtu, | 	.ndo_change_mtu 	= ieee80211_change_mtu, | ||||||
|  | @ -1099,7 +1123,6 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | ||||||
| 	/* and set some type-dependent values */ | 	/* and set some type-dependent values */ | ||||||
| 	sdata->vif.type = type; | 	sdata->vif.type = type; | ||||||
| 	sdata->vif.p2p = false; | 	sdata->vif.p2p = false; | ||||||
| 	sdata->dev->netdev_ops = &ieee80211_dataif_ops; |  | ||||||
| 	sdata->wdev.iftype = type; | 	sdata->wdev.iftype = type; | ||||||
| 
 | 
 | ||||||
| 	sdata->control_port_protocol = cpu_to_be16(ETH_P_PAE); | 	sdata->control_port_protocol = cpu_to_be16(ETH_P_PAE); | ||||||
|  | @ -1107,8 +1130,11 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | ||||||
| 
 | 
 | ||||||
| 	sdata->noack_map = 0; | 	sdata->noack_map = 0; | ||||||
| 
 | 
 | ||||||
| 	/* only monitor differs */ | 	/* only monitor/p2p-device differ */ | ||||||
|  | 	if (sdata->dev) { | ||||||
|  | 		sdata->dev->netdev_ops = &ieee80211_dataif_ops; | ||||||
| 		sdata->dev->type = ARPHRD_ETHER; | 		sdata->dev->type = ARPHRD_ETHER; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	skb_queue_head_init(&sdata->skb_queue); | 	skb_queue_head_init(&sdata->skb_queue); | ||||||
| 	INIT_WORK(&sdata->work, ieee80211_iface_work); | 	INIT_WORK(&sdata->work, ieee80211_iface_work); | ||||||
|  | @ -1146,6 +1172,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | ||||||
| 		break; | 		break; | ||||||
| 	case NL80211_IFTYPE_WDS: | 	case NL80211_IFTYPE_WDS: | ||||||
| 	case NL80211_IFTYPE_AP_VLAN: | 	case NL80211_IFTYPE_AP_VLAN: | ||||||
|  | 	case NL80211_IFTYPE_P2P_DEVICE: | ||||||
| 		break; | 		break; | ||||||
| 	case NL80211_IFTYPE_UNSPECIFIED: | 	case NL80211_IFTYPE_UNSPECIFIED: | ||||||
| 	case NUM_NL80211_IFTYPES: | 	case NUM_NL80211_IFTYPES: | ||||||
|  | @ -1156,18 +1183,6 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | ||||||
| 	ieee80211_debugfs_add_netdev(sdata); | 	ieee80211_debugfs_add_netdev(sdata); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void ieee80211_clean_sdata(struct ieee80211_sub_if_data *sdata) |  | ||||||
| { |  | ||||||
| 	switch (sdata->vif.type) { |  | ||||||
| 	case NL80211_IFTYPE_MESH_POINT: |  | ||||||
| 		mesh_path_flush_by_iface(sdata); |  | ||||||
| 		break; |  | ||||||
| 
 |  | ||||||
| 	default: |  | ||||||
| 		break; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata, | static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata, | ||||||
| 					   enum nl80211_iftype type) | 					   enum nl80211_iftype type) | ||||||
| { | { | ||||||
|  | @ -1225,7 +1240,7 @@ static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata, | ||||||
| 
 | 
 | ||||||
| 	ieee80211_do_stop(sdata, false); | 	ieee80211_do_stop(sdata, false); | ||||||
| 
 | 
 | ||||||
| 	ieee80211_teardown_sdata(sdata->dev); | 	ieee80211_teardown_sdata(sdata); | ||||||
| 
 | 
 | ||||||
| 	ret = drv_change_interface(local, sdata, internal_type, p2p); | 	ret = drv_change_interface(local, sdata, internal_type, p2p); | ||||||
| 	if (ret) | 	if (ret) | ||||||
|  | @ -1240,7 +1255,7 @@ static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata, | ||||||
| 
 | 
 | ||||||
| 	ieee80211_setup_sdata(sdata, type); | 	ieee80211_setup_sdata(sdata, type); | ||||||
| 
 | 
 | ||||||
| 	err = ieee80211_do_open(sdata->dev, false); | 	err = ieee80211_do_open(&sdata->wdev, false); | ||||||
| 	WARN(err, "type change: do_open returned %d", err); | 	WARN(err, "type change: do_open returned %d", err); | ||||||
| 
 | 
 | ||||||
| 	return ret; | 	return ret; | ||||||
|  | @ -1267,14 +1282,14 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, | ||||||
| 			return ret; | 			return ret; | ||||||
| 	} else { | 	} else { | ||||||
| 		/* Purge and reset type-dependent state. */ | 		/* Purge and reset type-dependent state. */ | ||||||
| 		ieee80211_teardown_sdata(sdata->dev); | 		ieee80211_teardown_sdata(sdata); | ||||||
| 		ieee80211_setup_sdata(sdata, type); | 		ieee80211_setup_sdata(sdata, type); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* reset some values that shouldn't be kept across type changes */ | 	/* reset some values that shouldn't be kept across type changes */ | ||||||
| 	sdata->vif.bss_conf.basic_rates = | 	sdata->vif.bss_conf.basic_rates = | ||||||
| 		ieee80211_mandatory_rates(sdata->local, | 		ieee80211_mandatory_rates(sdata->local, | ||||||
| 			sdata->local->hw.conf.channel->band); | 			sdata->local->oper_channel->band); | ||||||
| 	sdata->drop_unencrypted = 0; | 	sdata->drop_unencrypted = 0; | ||||||
| 	if (type == NL80211_IFTYPE_STATION) | 	if (type == NL80211_IFTYPE_STATION) | ||||||
| 		sdata->u.mgd.use_4addr = false; | 		sdata->u.mgd.use_4addr = false; | ||||||
|  | @ -1283,8 +1298,7 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void ieee80211_assign_perm_addr(struct ieee80211_local *local, | static void ieee80211_assign_perm_addr(struct ieee80211_local *local, | ||||||
| 				       struct net_device *dev, | 				       u8 *perm_addr, enum nl80211_iftype type) | ||||||
| 				       enum nl80211_iftype type) |  | ||||||
| { | { | ||||||
| 	struct ieee80211_sub_if_data *sdata; | 	struct ieee80211_sub_if_data *sdata; | ||||||
| 	u64 mask, start, addr, val, inc; | 	u64 mask, start, addr, val, inc; | ||||||
|  | @ -1293,13 +1307,12 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local, | ||||||
| 	int i; | 	int i; | ||||||
| 
 | 
 | ||||||
| 	/* default ... something at least */ | 	/* default ... something at least */ | ||||||
| 	memcpy(dev->perm_addr, local->hw.wiphy->perm_addr, ETH_ALEN); | 	memcpy(perm_addr, local->hw.wiphy->perm_addr, ETH_ALEN); | ||||||
| 
 | 
 | ||||||
| 	if (is_zero_ether_addr(local->hw.wiphy->addr_mask) && | 	if (is_zero_ether_addr(local->hw.wiphy->addr_mask) && | ||||||
| 	    local->hw.wiphy->n_addresses <= 1) | 	    local->hw.wiphy->n_addresses <= 1) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| 	mutex_lock(&local->iflist_mtx); | 	mutex_lock(&local->iflist_mtx); | ||||||
| 
 | 
 | ||||||
| 	switch (type) { | 	switch (type) { | ||||||
|  | @ -1312,11 +1325,24 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local, | ||||||
| 		list_for_each_entry(sdata, &local->interfaces, list) { | 		list_for_each_entry(sdata, &local->interfaces, list) { | ||||||
| 			if (sdata->vif.type != NL80211_IFTYPE_AP) | 			if (sdata->vif.type != NL80211_IFTYPE_AP) | ||||||
| 				continue; | 				continue; | ||||||
| 			memcpy(dev->perm_addr, sdata->vif.addr, ETH_ALEN); | 			memcpy(perm_addr, sdata->vif.addr, ETH_ALEN); | ||||||
| 			break; | 			break; | ||||||
| 		} | 		} | ||||||
| 		/* keep default if no AP interface present */ | 		/* keep default if no AP interface present */ | ||||||
| 		break; | 		break; | ||||||
|  | 	case NL80211_IFTYPE_P2P_CLIENT: | ||||||
|  | 	case NL80211_IFTYPE_P2P_GO: | ||||||
|  | 		if (local->hw.flags & IEEE80211_HW_P2P_DEV_ADDR_FOR_INTF) { | ||||||
|  | 			list_for_each_entry(sdata, &local->interfaces, list) { | ||||||
|  | 				if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE) | ||||||
|  | 					continue; | ||||||
|  | 				if (!ieee80211_sdata_running(sdata)) | ||||||
|  | 					continue; | ||||||
|  | 				memcpy(perm_addr, sdata->vif.addr, ETH_ALEN); | ||||||
|  | 				goto out_unlock; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		/* otherwise fall through */ | ||||||
| 	default: | 	default: | ||||||
| 		/* assign a new address if possible -- try n_addresses first */ | 		/* assign a new address if possible -- try n_addresses first */ | ||||||
| 		for (i = 0; i < local->hw.wiphy->n_addresses; i++) { | 		for (i = 0; i < local->hw.wiphy->n_addresses; i++) { | ||||||
|  | @ -1331,7 +1357,7 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local, | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			if (!used) { | 			if (!used) { | ||||||
| 				memcpy(dev->perm_addr, | 				memcpy(perm_addr, | ||||||
| 				       local->hw.wiphy->addresses[i].addr, | 				       local->hw.wiphy->addresses[i].addr, | ||||||
| 				       ETH_ALEN); | 				       ETH_ALEN); | ||||||
| 				break; | 				break; | ||||||
|  | @ -1382,7 +1408,7 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local, | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			if (!used) { | 			if (!used) { | ||||||
| 				memcpy(dev->perm_addr, tmp_addr, ETH_ALEN); | 				memcpy(perm_addr, tmp_addr, ETH_ALEN); | ||||||
| 				break; | 				break; | ||||||
| 			} | 			} | ||||||
| 			addr = (start & ~mask) | (val & mask); | 			addr = (start & ~mask) | (val & mask); | ||||||
|  | @ -1391,6 +1417,7 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local, | ||||||
| 		break; | 		break; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  out_unlock: | ||||||
| 	mutex_unlock(&local->iflist_mtx); | 	mutex_unlock(&local->iflist_mtx); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -1398,17 +1425,32 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | ||||||
| 		     struct wireless_dev **new_wdev, enum nl80211_iftype type, | 		     struct wireless_dev **new_wdev, enum nl80211_iftype type, | ||||||
| 		     struct vif_params *params) | 		     struct vif_params *params) | ||||||
| { | { | ||||||
| 	struct net_device *ndev; | 	struct net_device *ndev = NULL; | ||||||
| 	struct ieee80211_sub_if_data *sdata = NULL; | 	struct ieee80211_sub_if_data *sdata = NULL; | ||||||
| 	int ret, i; | 	int ret, i; | ||||||
| 	int txqs = 1; | 	int txqs = 1; | ||||||
| 
 | 
 | ||||||
| 	ASSERT_RTNL(); | 	ASSERT_RTNL(); | ||||||
| 
 | 
 | ||||||
|  | 	if (type == NL80211_IFTYPE_P2P_DEVICE) { | ||||||
|  | 		struct wireless_dev *wdev; | ||||||
|  | 
 | ||||||
|  | 		sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size, | ||||||
|  | 				GFP_KERNEL); | ||||||
|  | 		if (!sdata) | ||||||
|  | 			return -ENOMEM; | ||||||
|  | 		wdev = &sdata->wdev; | ||||||
|  | 
 | ||||||
|  | 		sdata->dev = NULL; | ||||||
|  | 		strlcpy(sdata->name, name, IFNAMSIZ); | ||||||
|  | 		ieee80211_assign_perm_addr(local, wdev->address, type); | ||||||
|  | 		memcpy(sdata->vif.addr, wdev->address, ETH_ALEN); | ||||||
|  | 	} else { | ||||||
| 		if (local->hw.queues >= IEEE80211_NUM_ACS) | 		if (local->hw.queues >= IEEE80211_NUM_ACS) | ||||||
| 			txqs = IEEE80211_NUM_ACS; | 			txqs = IEEE80211_NUM_ACS; | ||||||
| 
 | 
 | ||||||
| 	ndev = alloc_netdev_mqs(sizeof(*sdata) + local->hw.vif_data_size, | 		ndev = alloc_netdev_mqs(sizeof(*sdata) + | ||||||
|  | 					local->hw.vif_data_size, | ||||||
| 					name, ieee80211_if_setup, txqs, 1); | 					name, ieee80211_if_setup, txqs, 1); | ||||||
| 		if (!ndev) | 		if (!ndev) | ||||||
| 			return -ENOMEM; | 			return -ENOMEM; | ||||||
|  | @ -1424,23 +1466,27 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | ||||||
| 		ndev->needed_tailroom = IEEE80211_ENCRYPT_TAILROOM; | 		ndev->needed_tailroom = IEEE80211_ENCRYPT_TAILROOM; | ||||||
| 
 | 
 | ||||||
| 		ret = dev_alloc_name(ndev, ndev->name); | 		ret = dev_alloc_name(ndev, ndev->name); | ||||||
| 	if (ret < 0) | 		if (ret < 0) { | ||||||
| 		goto fail; | 			free_netdev(ndev); | ||||||
|  | 			return ret; | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 	ieee80211_assign_perm_addr(local, ndev, type); | 		ieee80211_assign_perm_addr(local, ndev->perm_addr, type); | ||||||
| 		memcpy(ndev->dev_addr, ndev->perm_addr, ETH_ALEN); | 		memcpy(ndev->dev_addr, ndev->perm_addr, ETH_ALEN); | ||||||
| 		SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); | 		SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); | ||||||
| 
 | 
 | ||||||
| 	/* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */ | 		/* don't use IEEE80211_DEV_TO_SUB_IF -- it checks too much */ | ||||||
| 		sdata = netdev_priv(ndev); | 		sdata = netdev_priv(ndev); | ||||||
| 		ndev->ieee80211_ptr = &sdata->wdev; | 		ndev->ieee80211_ptr = &sdata->wdev; | ||||||
| 		memcpy(sdata->vif.addr, ndev->dev_addr, ETH_ALEN); | 		memcpy(sdata->vif.addr, ndev->dev_addr, ETH_ALEN); | ||||||
| 		memcpy(sdata->name, ndev->name, IFNAMSIZ); | 		memcpy(sdata->name, ndev->name, IFNAMSIZ); | ||||||
| 
 | 
 | ||||||
|  | 		sdata->dev = ndev; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	/* initialise type-independent data */ | 	/* initialise type-independent data */ | ||||||
| 	sdata->wdev.wiphy = local->hw.wiphy; | 	sdata->wdev.wiphy = local->hw.wiphy; | ||||||
| 	sdata->local = local; | 	sdata->local = local; | ||||||
| 	sdata->dev = ndev; |  | ||||||
| #ifdef CONFIG_INET | #ifdef CONFIG_INET | ||||||
| 	sdata->arp_filter_state = true; | 	sdata->arp_filter_state = true; | ||||||
| #endif | #endif | ||||||
|  | @ -1469,6 +1515,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | ||||||
| 	/* setup type-dependent data */ | 	/* setup type-dependent data */ | ||||||
| 	ieee80211_setup_sdata(sdata, type); | 	ieee80211_setup_sdata(sdata, type); | ||||||
| 
 | 
 | ||||||
|  | 	if (ndev) { | ||||||
| 		if (params) { | 		if (params) { | ||||||
| 			ndev->ieee80211_ptr->use_4addr = params->use_4addr; | 			ndev->ieee80211_ptr->use_4addr = params->use_4addr; | ||||||
| 			if (type == NL80211_IFTYPE_STATION) | 			if (type == NL80211_IFTYPE_STATION) | ||||||
|  | @ -1478,8 +1525,11 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | ||||||
| 		ndev->features |= local->hw.netdev_features; | 		ndev->features |= local->hw.netdev_features; | ||||||
| 
 | 
 | ||||||
| 		ret = register_netdevice(ndev); | 		ret = register_netdevice(ndev); | ||||||
| 	if (ret) | 		if (ret) { | ||||||
| 		goto fail; | 			free_netdev(ndev); | ||||||
|  | 			return ret; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	mutex_lock(&local->iflist_mtx); | 	mutex_lock(&local->iflist_mtx); | ||||||
| 	list_add_tail_rcu(&sdata->list, &local->interfaces); | 	list_add_tail_rcu(&sdata->list, &local->interfaces); | ||||||
|  | @ -1489,10 +1539,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | ||||||
| 		*new_wdev = &sdata->wdev; | 		*new_wdev = &sdata->wdev; | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| 
 |  | ||||||
|  fail: |  | ||||||
| 	free_netdev(ndev); |  | ||||||
| 	return ret; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata) | void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata) | ||||||
|  | @ -1503,11 +1549,22 @@ void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata) | ||||||
| 	list_del_rcu(&sdata->list); | 	list_del_rcu(&sdata->list); | ||||||
| 	mutex_unlock(&sdata->local->iflist_mtx); | 	mutex_unlock(&sdata->local->iflist_mtx); | ||||||
| 
 | 
 | ||||||
| 	/* clean up type-dependent data */ |  | ||||||
| 	ieee80211_clean_sdata(sdata); |  | ||||||
| 
 |  | ||||||
| 	synchronize_rcu(); | 	synchronize_rcu(); | ||||||
|  | 
 | ||||||
|  | 	if (sdata->dev) { | ||||||
| 		unregister_netdevice(sdata->dev); | 		unregister_netdevice(sdata->dev); | ||||||
|  | 	} else { | ||||||
|  | 		cfg80211_unregister_wdev(&sdata->wdev); | ||||||
|  | 		kfree(sdata); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ieee80211_sdata_stop(struct ieee80211_sub_if_data *sdata) | ||||||
|  | { | ||||||
|  | 	if (WARN_ON_ONCE(!test_bit(SDATA_STATE_RUNNING, &sdata->state))) | ||||||
|  | 		return; | ||||||
|  | 	ieee80211_do_stop(sdata, true); | ||||||
|  | 	ieee80211_teardown_sdata(sdata); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  | @ -1518,6 +1575,7 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local) | ||||||
| { | { | ||||||
| 	struct ieee80211_sub_if_data *sdata, *tmp; | 	struct ieee80211_sub_if_data *sdata, *tmp; | ||||||
| 	LIST_HEAD(unreg_list); | 	LIST_HEAD(unreg_list); | ||||||
|  | 	LIST_HEAD(wdev_list); | ||||||
| 
 | 
 | ||||||
| 	ASSERT_RTNL(); | 	ASSERT_RTNL(); | ||||||
| 
 | 
 | ||||||
|  | @ -1525,13 +1583,20 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local) | ||||||
| 	list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) { | 	list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) { | ||||||
| 		list_del(&sdata->list); | 		list_del(&sdata->list); | ||||||
| 
 | 
 | ||||||
| 		ieee80211_clean_sdata(sdata); | 		if (sdata->dev) | ||||||
| 
 |  | ||||||
| 			unregister_netdevice_queue(sdata->dev, &unreg_list); | 			unregister_netdevice_queue(sdata->dev, &unreg_list); | ||||||
|  | 		else | ||||||
|  | 			list_add(&sdata->list, &wdev_list); | ||||||
| 	} | 	} | ||||||
| 	mutex_unlock(&local->iflist_mtx); | 	mutex_unlock(&local->iflist_mtx); | ||||||
| 	unregister_netdevice_many(&unreg_list); | 	unregister_netdevice_many(&unreg_list); | ||||||
| 	list_del(&unreg_list); | 	list_del(&unreg_list); | ||||||
|  | 
 | ||||||
|  | 	list_for_each_entry_safe(sdata, tmp, &wdev_list, list) { | ||||||
|  | 		list_del(&sdata->list); | ||||||
|  | 		cfg80211_unregister_wdev(&sdata->wdev); | ||||||
|  | 		kfree(sdata); | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int netdev_notify(struct notifier_block *nb, | static int netdev_notify(struct notifier_block *nb, | ||||||
|  |  | ||||||
|  | @ -207,6 +207,10 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, | ||||||
| 		sdata->vif.bss_conf.bssid = NULL; | 		sdata->vif.bss_conf.bssid = NULL; | ||||||
| 	else if (ieee80211_vif_is_mesh(&sdata->vif)) { | 	else if (ieee80211_vif_is_mesh(&sdata->vif)) { | ||||||
| 		sdata->vif.bss_conf.bssid = zero; | 		sdata->vif.bss_conf.bssid = zero; | ||||||
|  | 	} else if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) { | ||||||
|  | 		sdata->vif.bss_conf.bssid = sdata->vif.addr; | ||||||
|  | 		WARN_ONCE(changed & ~(BSS_CHANGED_IDLE), | ||||||
|  | 			  "P2P Device BSS changed %#x", changed); | ||||||
| 	} else { | 	} else { | ||||||
| 		WARN_ON(1); | 		WARN_ON(1); | ||||||
| 		return; | 		return; | ||||||
|  | @ -514,6 +518,11 @@ ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { | ||||||
| 			BIT(IEEE80211_STYPE_AUTH >> 4) | | 			BIT(IEEE80211_STYPE_AUTH >> 4) | | ||||||
| 			BIT(IEEE80211_STYPE_DEAUTH >> 4), | 			BIT(IEEE80211_STYPE_DEAUTH >> 4), | ||||||
| 	}, | 	}, | ||||||
|  | 	[NL80211_IFTYPE_P2P_DEVICE] = { | ||||||
|  | 		.tx = 0xffff, | ||||||
|  | 		.rx = BIT(IEEE80211_STYPE_ACTION >> 4) | | ||||||
|  | 			BIT(IEEE80211_STYPE_PROBE_REQ >> 4), | ||||||
|  | 	}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct ieee80211_ht_cap mac80211_ht_capa_mod_mask = { | static const struct ieee80211_ht_cap mac80211_ht_capa_mod_mask = { | ||||||
|  | @ -536,6 +545,11 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | ||||||
| 	int priv_size, i; | 	int priv_size, i; | ||||||
| 	struct wiphy *wiphy; | 	struct wiphy *wiphy; | ||||||
| 
 | 
 | ||||||
|  | 	if (WARN_ON(!ops->tx || !ops->start || !ops->stop || !ops->config || | ||||||
|  | 		    !ops->add_interface || !ops->remove_interface || | ||||||
|  | 		    !ops->configure_filter)) | ||||||
|  | 		return NULL; | ||||||
|  | 
 | ||||||
| 	if (WARN_ON(ops->sta_state && (ops->sta_add || ops->sta_remove))) | 	if (WARN_ON(ops->sta_state && (ops->sta_add || ops->sta_remove))) | ||||||
| 		return NULL; | 		return NULL; | ||||||
| 
 | 
 | ||||||
|  | @ -588,13 +602,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | ||||||
| 
 | 
 | ||||||
| 	local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN); | 	local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN); | ||||||
| 
 | 
 | ||||||
| 	BUG_ON(!ops->tx); |  | ||||||
| 	BUG_ON(!ops->start); |  | ||||||
| 	BUG_ON(!ops->stop); |  | ||||||
| 	BUG_ON(!ops->config); |  | ||||||
| 	BUG_ON(!ops->add_interface); |  | ||||||
| 	BUG_ON(!ops->remove_interface); |  | ||||||
| 	BUG_ON(!ops->configure_filter); |  | ||||||
| 	local->ops = ops; | 	local->ops = ops; | ||||||
| 
 | 
 | ||||||
| 	/* set up some defaults */ | 	/* set up some defaults */ | ||||||
|  |  | ||||||
|  | @ -109,11 +109,11 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata, | ||||||
| 
 | 
 | ||||||
| 	/* Disallow HT40+/- mismatch */ | 	/* Disallow HT40+/- mismatch */ | ||||||
| 	if (ie->ht_operation && | 	if (ie->ht_operation && | ||||||
| 	    (local->_oper_channel_type == NL80211_CHAN_HT40MINUS || | 	    (sdata->vif.bss_conf.channel_type == NL80211_CHAN_HT40MINUS || | ||||||
| 	    local->_oper_channel_type == NL80211_CHAN_HT40PLUS) && | 	     sdata->vif.bss_conf.channel_type == NL80211_CHAN_HT40PLUS) && | ||||||
| 	    (sta_channel_type == NL80211_CHAN_HT40MINUS || | 	    (sta_channel_type == NL80211_CHAN_HT40MINUS || | ||||||
| 	     sta_channel_type == NL80211_CHAN_HT40PLUS) && | 	     sta_channel_type == NL80211_CHAN_HT40PLUS) && | ||||||
| 	    local->_oper_channel_type != sta_channel_type) | 	    sdata->vif.bss_conf.channel_type != sta_channel_type) | ||||||
| 		goto mismatch; | 		goto mismatch; | ||||||
| 
 | 
 | ||||||
| 	return true; | 	return true; | ||||||
|  | @ -355,17 +355,18 @@ int mesh_add_ds_params_ie(struct sk_buff *skb, | ||||||
| { | { | ||||||
| 	struct ieee80211_local *local = sdata->local; | 	struct ieee80211_local *local = sdata->local; | ||||||
| 	struct ieee80211_supported_band *sband; | 	struct ieee80211_supported_band *sband; | ||||||
|  | 	struct ieee80211_channel *chan = local->oper_channel; | ||||||
| 	u8 *pos; | 	u8 *pos; | ||||||
| 
 | 
 | ||||||
| 	if (skb_tailroom(skb) < 3) | 	if (skb_tailroom(skb) < 3) | ||||||
| 		return -ENOMEM; | 		return -ENOMEM; | ||||||
| 
 | 
 | ||||||
| 	sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 	sband = local->hw.wiphy->bands[chan->band]; | ||||||
| 	if (sband->band == IEEE80211_BAND_2GHZ) { | 	if (sband->band == IEEE80211_BAND_2GHZ) { | ||||||
| 		pos = skb_put(skb, 2 + 1); | 		pos = skb_put(skb, 2 + 1); | ||||||
| 		*pos++ = WLAN_EID_DS_PARAMS; | 		*pos++ = WLAN_EID_DS_PARAMS; | ||||||
| 		*pos++ = 1; | 		*pos++ = 1; | ||||||
| 		*pos++ = ieee80211_frequency_to_channel(local->hw.conf.channel->center_freq); | 		*pos++ = ieee80211_frequency_to_channel(chan->center_freq); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
|  | @ -380,7 +381,7 @@ int mesh_add_ht_cap_ie(struct sk_buff *skb, | ||||||
| 
 | 
 | ||||||
| 	sband = local->hw.wiphy->bands[local->oper_channel->band]; | 	sband = local->hw.wiphy->bands[local->oper_channel->band]; | ||||||
| 	if (!sband->ht_cap.ht_supported || | 	if (!sband->ht_cap.ht_supported || | ||||||
| 	    local->_oper_channel_type == NL80211_CHAN_NO_HT) | 	    sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) | ||||||
| 		return 0; | 		return 0; | ||||||
| 
 | 
 | ||||||
| 	if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_cap)) | 	if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_cap)) | ||||||
|  | @ -397,7 +398,8 @@ int mesh_add_ht_oper_ie(struct sk_buff *skb, | ||||||
| { | { | ||||||
| 	struct ieee80211_local *local = sdata->local; | 	struct ieee80211_local *local = sdata->local; | ||||||
| 	struct ieee80211_channel *channel = local->oper_channel; | 	struct ieee80211_channel *channel = local->oper_channel; | ||||||
| 	enum nl80211_channel_type channel_type = local->_oper_channel_type; | 	enum nl80211_channel_type channel_type = | ||||||
|  | 				sdata->vif.bss_conf.channel_type; | ||||||
| 	struct ieee80211_supported_band *sband = | 	struct ieee80211_supported_band *sband = | ||||||
| 				local->hw.wiphy->bands[channel->band]; | 				local->hw.wiphy->bands[channel->band]; | ||||||
| 	struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap; | 	struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap; | ||||||
|  | @ -608,12 +610,14 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) | ||||||
| 	sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL; | 	sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL; | ||||||
| 	sdata->vif.bss_conf.basic_rates = | 	sdata->vif.bss_conf.basic_rates = | ||||||
| 		ieee80211_mandatory_rates(sdata->local, | 		ieee80211_mandatory_rates(sdata->local, | ||||||
| 					  sdata->local->hw.conf.channel->band); | 					  sdata->local->oper_channel->band); | ||||||
| 	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON | | 	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON | | ||||||
| 						BSS_CHANGED_BEACON_ENABLED | | 						BSS_CHANGED_BEACON_ENABLED | | ||||||
| 						BSS_CHANGED_HT | | 						BSS_CHANGED_HT | | ||||||
| 						BSS_CHANGED_BASIC_RATES | | 						BSS_CHANGED_BASIC_RATES | | ||||||
| 						BSS_CHANGED_BEACON_INT); | 						BSS_CHANGED_BEACON_INT); | ||||||
|  | 
 | ||||||
|  | 	netif_carrier_on(sdata->dev); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) | ||||||
|  | @ -621,9 +625,15 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) | ||||||
| 	struct ieee80211_local *local = sdata->local; | 	struct ieee80211_local *local = sdata->local; | ||||||
| 	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||||||
| 
 | 
 | ||||||
|  | 	netif_carrier_off(sdata->dev); | ||||||
|  | 
 | ||||||
|  | 	/* stop the beacon */ | ||||||
| 	ifmsh->mesh_id_len = 0; | 	ifmsh->mesh_id_len = 0; | ||||||
| 	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); | 	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); | ||||||
| 	sta_info_flush(local, NULL); | 
 | ||||||
|  | 	/* flush STAs and mpaths on this iface */ | ||||||
|  | 	sta_info_flush(sdata->local, sdata); | ||||||
|  | 	mesh_path_flush_by_iface(sdata); | ||||||
| 
 | 
 | ||||||
| 	del_timer_sync(&sdata->u.mesh.housekeeping_timer); | 	del_timer_sync(&sdata->u.mesh.housekeeping_timer); | ||||||
| 	del_timer_sync(&sdata->u.mesh.mesh_path_root_timer); | 	del_timer_sync(&sdata->u.mesh.mesh_path_root_timer); | ||||||
|  |  | ||||||
|  | @ -215,6 +215,9 @@ struct mesh_rmc { | ||||||
| /* Maximum number of paths per interface */ | /* Maximum number of paths per interface */ | ||||||
| #define MESH_MAX_MPATHS		1024 | #define MESH_MAX_MPATHS		1024 | ||||||
| 
 | 
 | ||||||
|  | /* Number of frames buffered per destination for unresolved destinations */ | ||||||
|  | #define MESH_FRAME_QUEUE_LEN	10 | ||||||
|  | 
 | ||||||
| /* Public interfaces */ | /* Public interfaces */ | ||||||
| /* Various */ | /* Various */ | ||||||
| int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, | int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, | ||||||
|  |  | ||||||
|  | @ -17,8 +17,6 @@ | ||||||
| #define MAX_METRIC	0xffffffff | #define MAX_METRIC	0xffffffff | ||||||
| #define ARITH_SHIFT	8 | #define ARITH_SHIFT	8 | ||||||
| 
 | 
 | ||||||
| /* Number of frames buffered per destination for unresolved destinations */ |  | ||||||
| #define MESH_FRAME_QUEUE_LEN	10 |  | ||||||
| #define MAX_PREQ_QUEUE_LEN	64 | #define MAX_PREQ_QUEUE_LEN	64 | ||||||
| 
 | 
 | ||||||
| /* Destination only */ | /* Destination only */ | ||||||
|  |  | ||||||
|  | @ -203,23 +203,17 @@ void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta) | ||||||
| { | { | ||||||
| 	struct sk_buff *skb; | 	struct sk_buff *skb; | ||||||
| 	struct ieee80211_hdr *hdr; | 	struct ieee80211_hdr *hdr; | ||||||
| 	struct sk_buff_head tmpq; |  | ||||||
| 	unsigned long flags; | 	unsigned long flags; | ||||||
| 
 | 
 | ||||||
| 	rcu_assign_pointer(mpath->next_hop, sta); | 	rcu_assign_pointer(mpath->next_hop, sta); | ||||||
| 
 | 
 | ||||||
| 	__skb_queue_head_init(&tmpq); |  | ||||||
| 
 |  | ||||||
| 	spin_lock_irqsave(&mpath->frame_queue.lock, flags); | 	spin_lock_irqsave(&mpath->frame_queue.lock, flags); | ||||||
| 
 | 	skb_queue_walk(&mpath->frame_queue, skb) { | ||||||
| 	while ((skb = __skb_dequeue(&mpath->frame_queue)) != NULL) { |  | ||||||
| 		hdr = (struct ieee80211_hdr *) skb->data; | 		hdr = (struct ieee80211_hdr *) skb->data; | ||||||
| 		memcpy(hdr->addr1, sta->sta.addr, ETH_ALEN); | 		memcpy(hdr->addr1, sta->sta.addr, ETH_ALEN); | ||||||
| 		memcpy(hdr->addr2, mpath->sdata->vif.addr, ETH_ALEN); | 		memcpy(hdr->addr2, mpath->sdata->vif.addr, ETH_ALEN); | ||||||
| 		__skb_queue_tail(&tmpq, skb); |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	skb_queue_splice(&tmpq, &mpath->frame_queue); |  | ||||||
| 	spin_unlock_irqrestore(&mpath->frame_queue.lock, flags); | 	spin_unlock_irqrestore(&mpath->frame_queue.lock, flags); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -285,40 +279,42 @@ static void mesh_path_move_to_queue(struct mesh_path *gate_mpath, | ||||||
| 				    struct mesh_path *from_mpath, | 				    struct mesh_path *from_mpath, | ||||||
| 				    bool copy) | 				    bool copy) | ||||||
| { | { | ||||||
| 	struct sk_buff *skb, *cp_skb = NULL; | 	struct sk_buff *skb, *fskb, *tmp; | ||||||
| 	struct sk_buff_head gateq, failq; | 	struct sk_buff_head failq; | ||||||
| 	unsigned long flags; | 	unsigned long flags; | ||||||
| 	int num_skbs; |  | ||||||
| 
 | 
 | ||||||
| 	BUG_ON(gate_mpath == from_mpath); | 	BUG_ON(gate_mpath == from_mpath); | ||||||
| 	BUG_ON(!gate_mpath->next_hop); | 	BUG_ON(!gate_mpath->next_hop); | ||||||
| 
 | 
 | ||||||
| 	__skb_queue_head_init(&gateq); |  | ||||||
| 	__skb_queue_head_init(&failq); | 	__skb_queue_head_init(&failq); | ||||||
| 
 | 
 | ||||||
| 	spin_lock_irqsave(&from_mpath->frame_queue.lock, flags); | 	spin_lock_irqsave(&from_mpath->frame_queue.lock, flags); | ||||||
| 	skb_queue_splice_init(&from_mpath->frame_queue, &failq); | 	skb_queue_splice_init(&from_mpath->frame_queue, &failq); | ||||||
| 	spin_unlock_irqrestore(&from_mpath->frame_queue.lock, flags); | 	spin_unlock_irqrestore(&from_mpath->frame_queue.lock, flags); | ||||||
| 
 | 
 | ||||||
| 	num_skbs = skb_queue_len(&failq); | 	skb_queue_walk_safe(&failq, fskb, tmp) { | ||||||
| 
 | 		if (skb_queue_len(&gate_mpath->frame_queue) >= | ||||||
| 	while (num_skbs--) { | 				  MESH_FRAME_QUEUE_LEN) { | ||||||
| 		skb = __skb_dequeue(&failq); | 			mpath_dbg(gate_mpath->sdata, "mpath queue full!\n"); | ||||||
| 		if (copy) { | 			break; | ||||||
| 			cp_skb = skb_copy(skb, GFP_ATOMIC); |  | ||||||
| 			if (cp_skb) |  | ||||||
| 				__skb_queue_tail(&failq, cp_skb); |  | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | 		skb = skb_copy(fskb, GFP_ATOMIC); | ||||||
|  | 		if (WARN_ON(!skb)) | ||||||
|  | 			break; | ||||||
|  | 
 | ||||||
| 		prepare_for_gate(skb, gate_mpath->dst, gate_mpath); | 		prepare_for_gate(skb, gate_mpath->dst, gate_mpath); | ||||||
| 		__skb_queue_tail(&gateq, skb); | 		skb_queue_tail(&gate_mpath->frame_queue, skb); | ||||||
|  | 
 | ||||||
|  | 		if (copy) | ||||||
|  | 			continue; | ||||||
|  | 
 | ||||||
|  | 		__skb_unlink(fskb, &failq); | ||||||
|  | 		kfree_skb(fskb); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	spin_lock_irqsave(&gate_mpath->frame_queue.lock, flags); |  | ||||||
| 	skb_queue_splice(&gateq, &gate_mpath->frame_queue); |  | ||||||
| 	mpath_dbg(gate_mpath->sdata, "Mpath queue for gate %pM has %d frames\n", | 	mpath_dbg(gate_mpath->sdata, "Mpath queue for gate %pM has %d frames\n", | ||||||
| 		  gate_mpath->dst, skb_queue_len(&gate_mpath->frame_queue)); | 		  gate_mpath->dst, skb_queue_len(&gate_mpath->frame_queue)); | ||||||
| 	spin_unlock_irqrestore(&gate_mpath->frame_queue.lock, flags); |  | ||||||
| 
 | 
 | ||||||
| 	if (!copy) | 	if (!copy) | ||||||
| 		return; | 		return; | ||||||
|  | @ -531,7 +527,7 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) | ||||||
| 
 | 
 | ||||||
| 	read_lock_bh(&pathtbl_resize_lock); | 	read_lock_bh(&pathtbl_resize_lock); | ||||||
| 	memcpy(new_mpath->dst, dst, ETH_ALEN); | 	memcpy(new_mpath->dst, dst, ETH_ALEN); | ||||||
| 	memset(new_mpath->rann_snd_addr, 0xff, ETH_ALEN); | 	eth_broadcast_addr(new_mpath->rann_snd_addr); | ||||||
| 	new_mpath->is_root = false; | 	new_mpath->is_root = false; | ||||||
| 	new_mpath->sdata = sdata; | 	new_mpath->sdata = sdata; | ||||||
| 	new_mpath->flags = 0; | 	new_mpath->flags = 0; | ||||||
|  |  | ||||||
|  | @ -117,7 +117,7 @@ static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata) | ||||||
| 	u16 ht_opmode; | 	u16 ht_opmode; | ||||||
| 	bool non_ht_sta = false, ht20_sta = false; | 	bool non_ht_sta = false, ht20_sta = false; | ||||||
| 
 | 
 | ||||||
| 	if (local->_oper_channel_type == NL80211_CHAN_NO_HT) | 	if (sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) | ||||||
| 		return 0; | 		return 0; | ||||||
| 
 | 
 | ||||||
| 	rcu_read_lock(); | 	rcu_read_lock(); | ||||||
|  | @ -147,7 +147,8 @@ out: | ||||||
| 
 | 
 | ||||||
| 	if (non_ht_sta) | 	if (non_ht_sta) | ||||||
| 		ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED; | 		ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED; | ||||||
| 	else if (ht20_sta && local->_oper_channel_type > NL80211_CHAN_HT20) | 	else if (ht20_sta && | ||||||
|  | 		 sdata->vif.bss_conf.channel_type > NL80211_CHAN_HT20) | ||||||
| 		ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_20MHZ; | 		ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_20MHZ; | ||||||
| 	else | 	else | ||||||
| 		ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONE; | 		ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONE; | ||||||
|  | @ -215,12 +216,14 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | ||||||
| 		u8 *da, __le16 llid, __le16 plid, __le16 reason) { | 		u8 *da, __le16 llid, __le16 plid, __le16 reason) { | ||||||
| 	struct ieee80211_local *local = sdata->local; | 	struct ieee80211_local *local = sdata->local; | ||||||
| 	struct sk_buff *skb; | 	struct sk_buff *skb; | ||||||
|  | 	struct ieee80211_tx_info *info; | ||||||
| 	struct ieee80211_mgmt *mgmt; | 	struct ieee80211_mgmt *mgmt; | ||||||
| 	bool include_plid = false; | 	bool include_plid = false; | ||||||
| 	u16 peering_proto = 0; | 	u16 peering_proto = 0; | ||||||
| 	u8 *pos, ie_len = 4; | 	u8 *pos, ie_len = 4; | ||||||
| 	int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.self_prot) + | 	int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.self_prot) + | ||||||
| 		      sizeof(mgmt->u.action.u.self_prot); | 		      sizeof(mgmt->u.action.u.self_prot); | ||||||
|  | 	int err = -ENOMEM; | ||||||
| 
 | 
 | ||||||
| 	skb = dev_alloc_skb(local->tx_headroom + | 	skb = dev_alloc_skb(local->tx_headroom + | ||||||
| 			    hdr_len + | 			    hdr_len + | ||||||
|  | @ -236,6 +239,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | ||||||
| 			    sdata->u.mesh.ie_len); | 			    sdata->u.mesh.ie_len); | ||||||
| 	if (!skb) | 	if (!skb) | ||||||
| 		return -1; | 		return -1; | ||||||
|  | 	info = IEEE80211_SKB_CB(skb); | ||||||
| 	skb_reserve(skb, local->tx_headroom); | 	skb_reserve(skb, local->tx_headroom); | ||||||
| 	mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len); | 	mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len); | ||||||
| 	memset(mgmt, 0, hdr_len); | 	memset(mgmt, 0, hdr_len); | ||||||
|  | @ -256,15 +260,18 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | ||||||
| 			pos = skb_put(skb, 2); | 			pos = skb_put(skb, 2); | ||||||
| 			memcpy(pos + 2, &plid, 2); | 			memcpy(pos + 2, &plid, 2); | ||||||
| 		} | 		} | ||||||
| 		if (ieee80211_add_srates_ie(sdata, skb, true) || | 		if (ieee80211_add_srates_ie(sdata, skb, true, | ||||||
| 		    ieee80211_add_ext_srates_ie(sdata, skb, true) || | 					    local->oper_channel->band) || | ||||||
|  | 		    ieee80211_add_ext_srates_ie(sdata, skb, true, | ||||||
|  | 						local->oper_channel->band) || | ||||||
| 		    mesh_add_rsn_ie(skb, sdata) || | 		    mesh_add_rsn_ie(skb, sdata) || | ||||||
| 		    mesh_add_meshid_ie(skb, sdata) || | 		    mesh_add_meshid_ie(skb, sdata) || | ||||||
| 		    mesh_add_meshconf_ie(skb, sdata)) | 		    mesh_add_meshconf_ie(skb, sdata)) | ||||||
| 			return -1; | 			goto free; | ||||||
| 	} else {	/* WLAN_SP_MESH_PEERING_CLOSE */ | 	} else {	/* WLAN_SP_MESH_PEERING_CLOSE */ | ||||||
|  | 		info->flags |= IEEE80211_TX_CTL_NO_ACK; | ||||||
| 		if (mesh_add_meshid_ie(skb, sdata)) | 		if (mesh_add_meshid_ie(skb, sdata)) | ||||||
| 			return -1; | 			goto free; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* Add Mesh Peering Management element */ | 	/* Add Mesh Peering Management element */ | ||||||
|  | @ -283,11 +290,12 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | ||||||
| 		ie_len += 2;	/* reason code */ | 		ie_len += 2;	/* reason code */ | ||||||
| 		break; | 		break; | ||||||
| 	default: | 	default: | ||||||
| 		return -EINVAL; | 		err = -EINVAL; | ||||||
|  | 		goto free; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (WARN_ON(skb_tailroom(skb) < 2 + ie_len)) | 	if (WARN_ON(skb_tailroom(skb) < 2 + ie_len)) | ||||||
| 		return -ENOMEM; | 		goto free; | ||||||
| 
 | 
 | ||||||
| 	pos = skb_put(skb, 2 + ie_len); | 	pos = skb_put(skb, 2 + ie_len); | ||||||
| 	*pos++ = WLAN_EID_PEER_MGMT; | 	*pos++ = WLAN_EID_PEER_MGMT; | ||||||
|  | @ -308,14 +316,17 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | ||||||
| 	if (action != WLAN_SP_MESH_PEERING_CLOSE) { | 	if (action != WLAN_SP_MESH_PEERING_CLOSE) { | ||||||
| 		if (mesh_add_ht_cap_ie(skb, sdata) || | 		if (mesh_add_ht_cap_ie(skb, sdata) || | ||||||
| 		    mesh_add_ht_oper_ie(skb, sdata)) | 		    mesh_add_ht_oper_ie(skb, sdata)) | ||||||
| 			return -1; | 			goto free; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (mesh_add_vendor_ies(skb, sdata)) | 	if (mesh_add_vendor_ies(skb, sdata)) | ||||||
| 		return -1; | 		goto free; | ||||||
| 
 | 
 | ||||||
| 	ieee80211_tx_skb(sdata, skb); | 	ieee80211_tx_skb(sdata, skb); | ||||||
| 	return 0; | 	return 0; | ||||||
|  | free: | ||||||
|  | 	kfree_skb(skb); | ||||||
|  | 	return err; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  | @ -360,9 +371,14 @@ static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata, | ||||||
| 
 | 
 | ||||||
| 	spin_lock_bh(&sta->lock); | 	spin_lock_bh(&sta->lock); | ||||||
| 	sta->last_rx = jiffies; | 	sta->last_rx = jiffies; | ||||||
|  | 	if (sta->plink_state == NL80211_PLINK_ESTAB) { | ||||||
|  | 		spin_unlock_bh(&sta->lock); | ||||||
|  | 		return sta; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	sta->sta.supp_rates[band] = rates; | 	sta->sta.supp_rates[band] = rates; | ||||||
| 	if (elems->ht_cap_elem && | 	if (elems->ht_cap_elem && | ||||||
| 	    sdata->local->_oper_channel_type != NL80211_CHAN_NO_HT) | 	    sdata->vif.bss_conf.channel_type != NL80211_CHAN_NO_HT) | ||||||
| 		ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, | 		ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, | ||||||
| 						  elems->ht_cap_elem, | 						  elems->ht_cap_elem, | ||||||
| 						  &sta->sta.ht_cap); | 						  &sta->sta.ht_cap); | ||||||
|  |  | ||||||
|  | @ -146,6 +146,9 @@ void ieee80211_sta_reset_beacon_monitor(struct ieee80211_sub_if_data *sdata) | ||||||
| 	if (sdata->vif.driver_flags & IEEE80211_VIF_BEACON_FILTER) | 	if (sdata->vif.driver_flags & IEEE80211_VIF_BEACON_FILTER) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
|  | 	if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
| 	mod_timer(&sdata->u.mgd.bcn_mon_timer, | 	mod_timer(&sdata->u.mgd.bcn_mon_timer, | ||||||
| 		  round_jiffies_up(jiffies + sdata->u.mgd.beacon_timeout)); | 		  round_jiffies_up(jiffies + sdata->u.mgd.beacon_timeout)); | ||||||
| } | } | ||||||
|  | @ -182,15 +185,15 @@ static u32 ieee80211_config_ht_tx(struct ieee80211_sub_if_data *sdata, | ||||||
| 	u16 ht_opmode; | 	u16 ht_opmode; | ||||||
| 	bool disable_40 = false; | 	bool disable_40 = false; | ||||||
| 
 | 
 | ||||||
| 	sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 	sband = local->hw.wiphy->bands[local->oper_channel->band]; | ||||||
| 
 | 
 | ||||||
| 	switch (sdata->vif.bss_conf.channel_type) { | 	switch (sdata->vif.bss_conf.channel_type) { | ||||||
| 	case NL80211_CHAN_HT40PLUS: | 	case NL80211_CHAN_HT40PLUS: | ||||||
| 		if (local->hw.conf.channel->flags & IEEE80211_CHAN_NO_HT40PLUS) | 		if (local->oper_channel->flags & IEEE80211_CHAN_NO_HT40PLUS) | ||||||
| 			disable_40 = true; | 			disable_40 = true; | ||||||
| 		break; | 		break; | ||||||
| 	case NL80211_CHAN_HT40MINUS: | 	case NL80211_CHAN_HT40MINUS: | ||||||
| 		if (local->hw.conf.channel->flags & IEEE80211_CHAN_NO_HT40MINUS) | 		if (local->oper_channel->flags & IEEE80211_CHAN_NO_HT40MINUS) | ||||||
| 			disable_40 = true; | 			disable_40 = true; | ||||||
| 		break; | 		break; | ||||||
| 	default: | 	default: | ||||||
|  | @ -326,6 +329,26 @@ static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata, | ||||||
| 	ieee80211_ie_build_ht_cap(pos, &ht_cap, cap); | 	ieee80211_ie_build_ht_cap(pos, &ht_cap, cap); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata, | ||||||
|  | 				 struct sk_buff *skb, | ||||||
|  | 				 struct ieee80211_supported_band *sband) | ||||||
|  | { | ||||||
|  | 	u8 *pos; | ||||||
|  | 	u32 cap; | ||||||
|  | 	struct ieee80211_sta_vht_cap vht_cap; | ||||||
|  | 
 | ||||||
|  | 	BUILD_BUG_ON(sizeof(vht_cap) != sizeof(sband->vht_cap)); | ||||||
|  | 
 | ||||||
|  | 	memcpy(&vht_cap, &sband->vht_cap, sizeof(vht_cap)); | ||||||
|  | 
 | ||||||
|  | 	/* determine capability flags */ | ||||||
|  | 	cap = vht_cap.cap; | ||||||
|  | 
 | ||||||
|  | 	/* reserve and fill IE */ | ||||||
|  | 	pos = skb_put(skb, sizeof(struct ieee80211_vht_capabilities) + 2); | ||||||
|  | 	ieee80211_ie_build_vht_cap(pos, &vht_cap, cap); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | ||||||
| { | { | ||||||
| 	struct ieee80211_local *local = sdata->local; | 	struct ieee80211_local *local = sdata->local; | ||||||
|  | @ -371,6 +394,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | ||||||
| 			4 + /* power capability */ | 			4 + /* power capability */ | ||||||
| 			2 + 2 * sband->n_channels + /* supported channels */ | 			2 + 2 * sband->n_channels + /* supported channels */ | ||||||
| 			2 + sizeof(struct ieee80211_ht_cap) + /* HT */ | 			2 + sizeof(struct ieee80211_ht_cap) + /* HT */ | ||||||
|  | 			2 + sizeof(struct ieee80211_vht_capabilities) + /* VHT */ | ||||||
| 			assoc_data->ie_len + /* extra IEs */ | 			assoc_data->ie_len + /* extra IEs */ | ||||||
| 			9, /* WMM */ | 			9, /* WMM */ | ||||||
| 			GFP_KERNEL); | 			GFP_KERNEL); | ||||||
|  | @ -503,6 +527,9 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | ||||||
| 		ieee80211_add_ht_ie(sdata, skb, assoc_data->ap_ht_param, | 		ieee80211_add_ht_ie(sdata, skb, assoc_data->ap_ht_param, | ||||||
| 				    sband, local->oper_channel, ifmgd->ap_smps); | 				    sband, local->oper_channel, ifmgd->ap_smps); | ||||||
| 
 | 
 | ||||||
|  | 	if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) | ||||||
|  | 		ieee80211_add_vht_ie(sdata, skb, sband); | ||||||
|  | 
 | ||||||
| 	/* if present, add any custom non-vendor IEs that go after HT */ | 	/* if present, add any custom non-vendor IEs that go after HT */ | ||||||
| 	if (assoc_data->ie_len && assoc_data->ie) { | 	if (assoc_data->ie_len && assoc_data->ie) { | ||||||
| 		noffset = ieee80211_ie_split_vendor(assoc_data->ie, | 		noffset = ieee80211_ie_split_vendor(assoc_data->ie, | ||||||
|  | @ -583,8 +610,6 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | ||||||
| 			IEEE80211_SKB_CB(skb)->flags |= | 			IEEE80211_SKB_CB(skb)->flags |= | ||||||
| 				IEEE80211_TX_INTFL_DONT_ENCRYPT; | 				IEEE80211_TX_INTFL_DONT_ENCRYPT; | ||||||
| 
 | 
 | ||||||
| 		drv_mgd_prepare_tx(local, sdata); |  | ||||||
| 
 |  | ||||||
| 		ieee80211_tx_skb(sdata, skb); | 		ieee80211_tx_skb(sdata, skb); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | @ -687,6 +712,7 @@ static void ieee80211_chswitch_work(struct work_struct *work) | ||||||
| 	/* XXX: shouldn't really modify cfg80211-owned data! */ | 	/* XXX: shouldn't really modify cfg80211-owned data! */ | ||||||
| 	ifmgd->associated->channel = sdata->local->oper_channel; | 	ifmgd->associated->channel = sdata->local->oper_channel; | ||||||
| 
 | 
 | ||||||
|  | 	/* XXX: wait for a beacon first? */ | ||||||
| 	ieee80211_wake_queues_by_reason(&sdata->local->hw, | 	ieee80211_wake_queues_by_reason(&sdata->local->hw, | ||||||
| 					IEEE80211_QUEUE_STOP_REASON_CSA); | 					IEEE80211_QUEUE_STOP_REASON_CSA); | ||||||
|  out: |  out: | ||||||
|  | @ -763,36 +789,32 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | ||||||
| 
 | 
 | ||||||
| 	sdata->local->csa_channel = new_ch; | 	sdata->local->csa_channel = new_ch; | ||||||
| 
 | 
 | ||||||
| 	if (sdata->local->ops->channel_switch) { | 	ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; | ||||||
| 		/* use driver's channel switch callback */ | 
 | ||||||
| 		struct ieee80211_channel_switch ch_switch; | 	if (sw_elem->mode) | ||||||
| 		memset(&ch_switch, 0, sizeof(ch_switch)); |  | ||||||
| 		ch_switch.timestamp = timestamp; |  | ||||||
| 		if (sw_elem->mode) { |  | ||||||
| 			ch_switch.block_tx = true; |  | ||||||
| 		ieee80211_stop_queues_by_reason(&sdata->local->hw, | 		ieee80211_stop_queues_by_reason(&sdata->local->hw, | ||||||
| 				IEEE80211_QUEUE_STOP_REASON_CSA); | 				IEEE80211_QUEUE_STOP_REASON_CSA); | ||||||
| 		} | 
 | ||||||
| 		ch_switch.channel = new_ch; | 	if (sdata->local->ops->channel_switch) { | ||||||
| 		ch_switch.count = sw_elem->count; | 		/* use driver's channel switch callback */ | ||||||
| 		ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; | 		struct ieee80211_channel_switch ch_switch = { | ||||||
|  | 			.timestamp = timestamp, | ||||||
|  | 			.block_tx = sw_elem->mode, | ||||||
|  | 			.channel = new_ch, | ||||||
|  | 			.count = sw_elem->count, | ||||||
|  | 		}; | ||||||
|  | 
 | ||||||
| 		drv_channel_switch(sdata->local, &ch_switch); | 		drv_channel_switch(sdata->local, &ch_switch); | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* channel switch handled in software */ | 	/* channel switch handled in software */ | ||||||
| 	if (sw_elem->count <= 1) { | 	if (sw_elem->count <= 1) | ||||||
| 		ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work); | 		ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work); | ||||||
| 	} else { | 	else | ||||||
| 		if (sw_elem->mode) |  | ||||||
| 			ieee80211_stop_queues_by_reason(&sdata->local->hw, |  | ||||||
| 					IEEE80211_QUEUE_STOP_REASON_CSA); |  | ||||||
| 		ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; |  | ||||||
| 		mod_timer(&ifmgd->chswitch_timer, | 		mod_timer(&ifmgd->chswitch_timer, | ||||||
| 			  jiffies + | 			  TU_TO_EXP_TIME(sw_elem->count * | ||||||
| 			  msecs_to_jiffies(sw_elem->count * |  | ||||||
| 					 cbss->beacon_interval)); | 					 cbss->beacon_interval)); | ||||||
| 	} |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, | static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, | ||||||
|  | @ -1007,6 +1029,16 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) | ||||||
| 	ieee80211_change_ps(local); | 	ieee80211_change_ps(local); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void ieee80211_recalc_ps_vif(struct ieee80211_sub_if_data *sdata) | ||||||
|  | { | ||||||
|  | 	bool ps_allowed = ieee80211_powersave_allowed(sdata); | ||||||
|  | 
 | ||||||
|  | 	if (sdata->vif.bss_conf.ps != ps_allowed) { | ||||||
|  | 		sdata->vif.bss_conf.ps = ps_allowed; | ||||||
|  | 		ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_PS); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void ieee80211_dynamic_ps_disable_work(struct work_struct *work) | void ieee80211_dynamic_ps_disable_work(struct work_struct *work) | ||||||
| { | { | ||||||
| 	struct ieee80211_local *local = | 	struct ieee80211_local *local = | ||||||
|  | @ -1239,7 +1271,7 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	use_short_slot = !!(capab & WLAN_CAPABILITY_SHORT_SLOT_TIME); | 	use_short_slot = !!(capab & WLAN_CAPABILITY_SHORT_SLOT_TIME); | ||||||
| 	if (sdata->local->hw.conf.channel->band == IEEE80211_BAND_5GHZ) | 	if (sdata->local->oper_channel->band == IEEE80211_BAND_5GHZ) | ||||||
| 		use_short_slot = true; | 		use_short_slot = true; | ||||||
| 
 | 
 | ||||||
| 	if (use_protection != bss_conf->use_cts_prot) { | 	if (use_protection != bss_conf->use_cts_prot) { | ||||||
|  | @ -1310,6 +1342,8 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | ||||||
| 	ieee80211_recalc_smps(local); | 	ieee80211_recalc_smps(local); | ||||||
| 	mutex_unlock(&local->iflist_mtx); | 	mutex_unlock(&local->iflist_mtx); | ||||||
| 
 | 
 | ||||||
|  | 	ieee80211_recalc_ps_vif(sdata); | ||||||
|  | 
 | ||||||
| 	netif_tx_start_all_queues(sdata->dev); | 	netif_tx_start_all_queues(sdata->dev); | ||||||
| 	netif_carrier_on(sdata->dev); | 	netif_carrier_on(sdata->dev); | ||||||
| } | } | ||||||
|  | @ -1371,6 +1405,9 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | ||||||
| 	} | 	} | ||||||
| 	local->ps_sdata = NULL; | 	local->ps_sdata = NULL; | ||||||
| 
 | 
 | ||||||
|  | 	/* disable per-vif ps */ | ||||||
|  | 	ieee80211_recalc_ps_vif(sdata); | ||||||
|  | 
 | ||||||
| 	/* flush out any pending frame (e.g. DELBA) before deauth/disassoc */ | 	/* flush out any pending frame (e.g. DELBA) before deauth/disassoc */ | ||||||
| 	if (tx) | 	if (tx) | ||||||
| 		drv_flush(local, false); | 		drv_flush(local, false); | ||||||
|  | @ -1542,7 +1579,8 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) | ||||||
| 			ssid_len = ssid[1]; | 			ssid_len = ssid[1]; | ||||||
| 
 | 
 | ||||||
| 		ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid_len, NULL, | 		ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid_len, NULL, | ||||||
| 					 0, (u32) -1, true, false); | 					 0, (u32) -1, true, false, | ||||||
|  | 					 ifmgd->associated->channel); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms); | 	ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms); | ||||||
|  | @ -1645,7 +1683,9 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, | ||||||
| 		ssid_len = ssid[1]; | 		ssid_len = ssid[1]; | ||||||
| 
 | 
 | ||||||
| 	skb = ieee80211_build_probe_req(sdata, cbss->bssid, | 	skb = ieee80211_build_probe_req(sdata, cbss->bssid, | ||||||
| 					(u32) -1, ssid + 2, ssid_len, | 					(u32) -1, | ||||||
|  | 					sdata->local->oper_channel, | ||||||
|  | 					ssid + 2, ssid_len, | ||||||
| 					NULL, 0, true); | 					NULL, 0, true); | ||||||
| 
 | 
 | ||||||
| 	return skb; | 	return skb; | ||||||
|  | @ -1656,7 +1696,6 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) | ||||||
| { | { | ||||||
| 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||||||
| 	struct ieee80211_local *local = sdata->local; | 	struct ieee80211_local *local = sdata->local; | ||||||
| 	u8 bssid[ETH_ALEN]; |  | ||||||
| 	u8 frame_buf[DEAUTH_DISASSOC_LEN]; | 	u8 frame_buf[DEAUTH_DISASSOC_LEN]; | ||||||
| 
 | 
 | ||||||
| 	mutex_lock(&ifmgd->mtx); | 	mutex_lock(&ifmgd->mtx); | ||||||
|  | @ -1665,9 +1704,8 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN); | 	sdata_info(sdata, "Connection to AP %pM lost\n", | ||||||
| 
 | 		   ifmgd->associated->bssid); | ||||||
| 	sdata_info(sdata, "Connection to AP %pM lost\n", bssid); |  | ||||||
| 
 | 
 | ||||||
| 	ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, | 	ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, | ||||||
| 			       WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, | 			       WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, | ||||||
|  | @ -1685,7 +1723,7 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) | ||||||
| 	mutex_unlock(&local->mtx); | 	mutex_unlock(&local->mtx); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ieee80211_beacon_connection_loss_work(struct work_struct *work) | static void ieee80211_beacon_connection_loss_work(struct work_struct *work) | ||||||
| { | { | ||||||
| 	struct ieee80211_sub_if_data *sdata = | 	struct ieee80211_sub_if_data *sdata = | ||||||
| 		container_of(work, struct ieee80211_sub_if_data, | 		container_of(work, struct ieee80211_sub_if_data, | ||||||
|  | @ -2232,14 +2270,10 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | ||||||
| 		mutex_unlock(&local->iflist_mtx); | 		mutex_unlock(&local->iflist_mtx); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (elems->ch_switch_elem && (elems->ch_switch_elem_len == 3) && | 	if (elems->ch_switch_ie && | ||||||
| 	    (memcmp(mgmt->bssid, sdata->u.mgd.associated->bssid, | 	    memcmp(mgmt->bssid, sdata->u.mgd.associated->bssid, ETH_ALEN) == 0) | ||||||
| 							ETH_ALEN) == 0)) { | 		ieee80211_sta_process_chanswitch(sdata, elems->ch_switch_ie, | ||||||
| 		struct ieee80211_channel_sw_ie *sw_elem = |  | ||||||
| 			(struct ieee80211_channel_sw_ie *)elems->ch_switch_elem; |  | ||||||
| 		ieee80211_sta_process_chanswitch(sdata, sw_elem, |  | ||||||
| 						 bss, rx_status->mactime); | 						 bss, rx_status->mactime); | ||||||
| 	} |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -2326,7 +2360,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | ||||||
| 	if (baselen > len) | 	if (baselen > len) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
| 	if (rx_status->freq != local->hw.conf.channel->center_freq) | 	if (rx_status->freq != local->oper_channel->center_freq) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
| 	if (ifmgd->assoc_data && !ifmgd->assoc_data->have_beacon && | 	if (ifmgd->assoc_data && !ifmgd->assoc_data->have_beacon && | ||||||
|  | @ -2490,7 +2524,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | ||||||
| 	    !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) { | 	    !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) { | ||||||
| 		struct ieee80211_supported_band *sband; | 		struct ieee80211_supported_band *sband; | ||||||
| 
 | 
 | ||||||
| 		sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 		sband = local->hw.wiphy->bands[local->oper_channel->band]; | ||||||
| 
 | 
 | ||||||
| 		changed |= ieee80211_config_ht_tx(sdata, elems.ht_operation, | 		changed |= ieee80211_config_ht_tx(sdata, elems.ht_operation, | ||||||
| 						  bssid, true); | 						  bssid, true); | ||||||
|  | @ -2673,7 +2707,8 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) | ||||||
| 		 * will not answer to direct packet in unassociated state. | 		 * will not answer to direct packet in unassociated state. | ||||||
| 		 */ | 		 */ | ||||||
| 		ieee80211_send_probe_req(sdata, NULL, ssidie + 2, ssidie[1], | 		ieee80211_send_probe_req(sdata, NULL, ssidie + 2, ssidie[1], | ||||||
| 					 NULL, 0, (u32) -1, true, false); | 					 NULL, 0, (u32) -1, true, false, | ||||||
|  | 					 auth_data->bss->channel); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; | 	auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; | ||||||
|  | @ -3000,41 +3035,17 @@ int ieee80211_max_network_latency(struct notifier_block *nb, | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, | static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, | ||||||
| 				     struct cfg80211_bss *cbss, bool assoc) | 				  struct cfg80211_bss *cbss) | ||||||
| { | { | ||||||
| 	struct ieee80211_local *local = sdata->local; | 	struct ieee80211_local *local = sdata->local; | ||||||
| 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||||||
| 	struct ieee80211_bss *bss = (void *)cbss->priv; |  | ||||||
| 	struct sta_info *sta = NULL; |  | ||||||
| 	bool have_sta = false; |  | ||||||
| 	int err; |  | ||||||
| 	int ht_cfreq; | 	int ht_cfreq; | ||||||
| 	enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | 	enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | ||||||
| 	const u8 *ht_oper_ie; | 	const u8 *ht_oper_ie; | ||||||
| 	const struct ieee80211_ht_operation *ht_oper = NULL; | 	const struct ieee80211_ht_operation *ht_oper = NULL; | ||||||
| 	struct ieee80211_supported_band *sband; | 	struct ieee80211_supported_band *sband; | ||||||
| 
 | 
 | ||||||
| 	if (WARN_ON(!ifmgd->auth_data && !ifmgd->assoc_data)) |  | ||||||
| 		return -EINVAL; |  | ||||||
| 
 |  | ||||||
| 	if (assoc) { |  | ||||||
| 		rcu_read_lock(); |  | ||||||
| 		have_sta = sta_info_get(sdata, cbss->bssid); |  | ||||||
| 		rcu_read_unlock(); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if (!have_sta) { |  | ||||||
| 		sta = sta_info_alloc(sdata, cbss->bssid, GFP_KERNEL); |  | ||||||
| 		if (!sta) |  | ||||||
| 			return -ENOMEM; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	mutex_lock(&local->mtx); |  | ||||||
| 	ieee80211_recalc_idle(sdata->local); |  | ||||||
| 	mutex_unlock(&local->mtx); |  | ||||||
| 
 |  | ||||||
| 	/* switch to the right channel */ |  | ||||||
| 	sband = local->hw.wiphy->bands[cbss->channel->band]; | 	sband = local->hw.wiphy->bands[cbss->channel->band]; | ||||||
| 
 | 
 | ||||||
| 	ifmgd->flags &= ~IEEE80211_STA_DISABLE_40MHZ; | 	ifmgd->flags &= ~IEEE80211_STA_DISABLE_40MHZ; | ||||||
|  | @ -3097,10 +3108,51 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, | ||||||
| 	local->oper_channel = cbss->channel; | 	local->oper_channel = cbss->channel; | ||||||
| 	ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | 	ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | ||||||
| 
 | 
 | ||||||
| 	if (sta) { | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, | ||||||
|  | 				     struct cfg80211_bss *cbss, bool assoc) | ||||||
|  | { | ||||||
|  | 	struct ieee80211_local *local = sdata->local; | ||||||
|  | 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||||||
|  | 	struct ieee80211_bss *bss = (void *)cbss->priv; | ||||||
|  | 	struct sta_info *new_sta = NULL; | ||||||
|  | 	bool have_sta = false; | ||||||
|  | 	int err; | ||||||
|  | 
 | ||||||
|  | 	if (WARN_ON(!ifmgd->auth_data && !ifmgd->assoc_data)) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 	if (assoc) { | ||||||
|  | 		rcu_read_lock(); | ||||||
|  | 		have_sta = sta_info_get(sdata, cbss->bssid); | ||||||
|  | 		rcu_read_unlock(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (!have_sta) { | ||||||
|  | 		new_sta = sta_info_alloc(sdata, cbss->bssid, GFP_KERNEL); | ||||||
|  | 		if (!new_sta) | ||||||
|  | 			return -ENOMEM; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	mutex_lock(&local->mtx); | ||||||
|  | 	ieee80211_recalc_idle(sdata->local); | ||||||
|  | 	mutex_unlock(&local->mtx); | ||||||
|  | 
 | ||||||
|  | 	if (new_sta) { | ||||||
| 		u32 rates = 0, basic_rates = 0; | 		u32 rates = 0, basic_rates = 0; | ||||||
| 		bool have_higher_than_11mbit; | 		bool have_higher_than_11mbit; | ||||||
| 		int min_rate = INT_MAX, min_rate_index = -1; | 		int min_rate = INT_MAX, min_rate_index = -1; | ||||||
|  | 		struct ieee80211_supported_band *sband; | ||||||
|  | 
 | ||||||
|  | 		sband = local->hw.wiphy->bands[cbss->channel->band]; | ||||||
|  | 
 | ||||||
|  | 		err = ieee80211_prep_channel(sdata, cbss); | ||||||
|  | 		if (err) { | ||||||
|  | 			sta_info_free(local, new_sta); | ||||||
|  | 			return err; | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 		ieee80211_get_rates(sband, bss->supp_rates, | 		ieee80211_get_rates(sband, bss->supp_rates, | ||||||
| 				    bss->supp_rates_len, | 				    bss->supp_rates_len, | ||||||
|  | @ -3122,7 +3174,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, | ||||||
| 			basic_rates = BIT(min_rate_index); | 			basic_rates = BIT(min_rate_index); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		sta->sta.supp_rates[cbss->channel->band] = rates; | 		new_sta->sta.supp_rates[cbss->channel->band] = rates; | ||||||
| 		sdata->vif.bss_conf.basic_rates = basic_rates; | 		sdata->vif.bss_conf.basic_rates = basic_rates; | ||||||
| 
 | 
 | ||||||
| 		/* cf. IEEE 802.11 9.2.12 */ | 		/* cf. IEEE 802.11 9.2.12 */ | ||||||
|  | @ -3145,10 +3197,10 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, | ||||||
| 			BSS_CHANGED_BEACON_INT); | 			BSS_CHANGED_BEACON_INT); | ||||||
| 
 | 
 | ||||||
| 		if (assoc) | 		if (assoc) | ||||||
| 			sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); | 			sta_info_pre_move_state(new_sta, IEEE80211_STA_AUTH); | ||||||
| 
 | 
 | ||||||
| 		err = sta_info_insert(sta); | 		err = sta_info_insert(new_sta); | ||||||
| 		sta = NULL; | 		new_sta = NULL; | ||||||
| 		if (err) { | 		if (err) { | ||||||
| 			sdata_info(sdata, | 			sdata_info(sdata, | ||||||
| 				   "failed to insert STA entry for the AP (error %d)\n", | 				   "failed to insert STA entry for the AP (error %d)\n", | ||||||
|  | @ -3301,8 +3353,12 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | ||||||
| 
 | 
 | ||||||
| 	/* prepare assoc data */ | 	/* prepare assoc data */ | ||||||
| 	 | 	 | ||||||
| 	ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N; | 	/*
 | ||||||
| 	ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED; | 	 * keep only the 40 MHz disable bit set as it might have | ||||||
|  | 	 * been set during authentication already, all other bits | ||||||
|  | 	 * should be reset for a new connection | ||||||
|  | 	 */ | ||||||
|  | 	ifmgd->flags &= IEEE80211_STA_DISABLE_40MHZ; | ||||||
| 
 | 
 | ||||||
| 	ifmgd->beacon_crc_valid = false; | 	ifmgd->beacon_crc_valid = false; | ||||||
| 
 | 
 | ||||||
|  | @ -3318,21 +3374,34 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | ||||||
| 		    req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP || | 		    req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP || | ||||||
| 		    req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) { | 		    req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) { | ||||||
| 			ifmgd->flags |= IEEE80211_STA_DISABLE_11N; | 			ifmgd->flags |= IEEE80211_STA_DISABLE_11N; | ||||||
|  | 			ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; | ||||||
| 			netdev_info(sdata->dev, | 			netdev_info(sdata->dev, | ||||||
| 				    "disabling HT due to WEP/TKIP use\n"); | 				    "disabling HT/VHT due to WEP/TKIP use\n"); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (req->flags & ASSOC_REQ_DISABLE_HT) | 	if (req->flags & ASSOC_REQ_DISABLE_HT) { | ||||||
| 		ifmgd->flags |= IEEE80211_STA_DISABLE_11N; | 		ifmgd->flags |= IEEE80211_STA_DISABLE_11N; | ||||||
|  | 		ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	/* Also disable HT if we don't support it or the AP doesn't use WMM */ | 	/* Also disable HT if we don't support it or the AP doesn't use WMM */ | ||||||
| 	sband = local->hw.wiphy->bands[req->bss->channel->band]; | 	sband = local->hw.wiphy->bands[req->bss->channel->band]; | ||||||
| 	if (!sband->ht_cap.ht_supported || | 	if (!sband->ht_cap.ht_supported || | ||||||
| 	    local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used) { | 	    local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used) { | ||||||
| 		ifmgd->flags |= IEEE80211_STA_DISABLE_11N; | 		ifmgd->flags |= IEEE80211_STA_DISABLE_11N; | ||||||
|  | 		if (!bss->wmm_used) | ||||||
| 			netdev_info(sdata->dev, | 			netdev_info(sdata->dev, | ||||||
| 			    "disabling HT as WMM/QoS is not supported\n"); | 				    "disabling HT as WMM/QoS is not supported by the AP\n"); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* disable VHT if we don't support it or the AP doesn't use WMM */ | ||||||
|  | 	if (!sband->vht_cap.vht_supported || | ||||||
|  | 	    local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used) { | ||||||
|  | 		ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; | ||||||
|  | 		if (!bss->wmm_used) | ||||||
|  | 			netdev_info(sdata->dev, | ||||||
|  | 				    "disabling VHT as WMM/QoS is not supported by the AP\n"); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	memcpy(&ifmgd->ht_capa, &req->ht_capa, sizeof(ifmgd->ht_capa)); | 	memcpy(&ifmgd->ht_capa, &req->ht_capa, sizeof(ifmgd->ht_capa)); | ||||||
|  | @ -3467,14 +3536,17 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | ||||||
| 		   req->bssid, req->reason_code); | 		   req->bssid, req->reason_code); | ||||||
| 
 | 
 | ||||||
| 	if (ifmgd->associated && | 	if (ifmgd->associated && | ||||||
| 	    ether_addr_equal(ifmgd->associated->bssid, req->bssid)) | 	    ether_addr_equal(ifmgd->associated->bssid, req->bssid)) { | ||||||
| 		ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, | 		ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, | ||||||
| 				       req->reason_code, true, frame_buf); | 				       req->reason_code, true, frame_buf); | ||||||
| 	else | 	} else { | ||||||
|  | 		drv_mgd_prepare_tx(sdata->local, sdata); | ||||||
| 		ieee80211_send_deauth_disassoc(sdata, req->bssid, | 		ieee80211_send_deauth_disassoc(sdata, req->bssid, | ||||||
| 					       IEEE80211_STYPE_DEAUTH, | 					       IEEE80211_STYPE_DEAUTH, | ||||||
| 					       req->reason_code, true, | 					       req->reason_code, true, | ||||||
| 					       frame_buf); | 					       frame_buf); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	mutex_unlock(&ifmgd->mtx); | 	mutex_unlock(&ifmgd->mtx); | ||||||
| 
 | 
 | ||||||
| 	__cfg80211_send_deauth(sdata->dev, frame_buf, DEAUTH_DISASSOC_LEN); | 	__cfg80211_send_deauth(sdata->dev, frame_buf, DEAUTH_DISASSOC_LEN); | ||||||
|  |  | ||||||
|  | @ -116,6 +116,9 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local, | ||||||
| 		if (!ieee80211_sdata_running(sdata)) | 		if (!ieee80211_sdata_running(sdata)) | ||||||
| 			continue; | 			continue; | ||||||
| 
 | 
 | ||||||
|  | 		if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) | ||||||
|  | 			continue; | ||||||
|  | 
 | ||||||
| 		if (sdata->vif.type != NL80211_IFTYPE_MONITOR) | 		if (sdata->vif.type != NL80211_IFTYPE_MONITOR) | ||||||
| 			set_bit(SDATA_STATE_OFFCHANNEL, &sdata->state); | 			set_bit(SDATA_STATE_OFFCHANNEL, &sdata->state); | ||||||
| 
 | 
 | ||||||
|  | @ -144,6 +147,9 @@ void ieee80211_offchannel_return(struct ieee80211_local *local, | ||||||
| 
 | 
 | ||||||
| 	mutex_lock(&local->iflist_mtx); | 	mutex_lock(&local->iflist_mtx); | ||||||
| 	list_for_each_entry(sdata, &local->interfaces, list) { | 	list_for_each_entry(sdata, &local->interfaces, list) { | ||||||
|  | 		if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) | ||||||
|  | 			continue; | ||||||
|  | 
 | ||||||
| 		if (sdata->vif.type != NL80211_IFTYPE_MONITOR) | 		if (sdata->vif.type != NL80211_IFTYPE_MONITOR) | ||||||
| 			clear_bit(SDATA_STATE_OFFCHANNEL, &sdata->state); | 			clear_bit(SDATA_STATE_OFFCHANNEL, &sdata->state); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -56,7 +56,7 @@ static inline void rate_control_rate_init(struct sta_info *sta) | ||||||
| 	if (!ref) | 	if (!ref) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
| 	sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 	sband = local->hw.wiphy->bands[local->oper_channel->band]; | ||||||
| 
 | 
 | ||||||
| 	ref->ops->rate_init(ref->priv, sband, ista, priv_sta); | 	ref->ops->rate_init(ref->priv, sband, ista, priv_sta); | ||||||
| 	set_sta_flag(sta, WLAN_STA_RATE_CONTROL); | 	set_sta_flag(sta, WLAN_STA_RATE_CONTROL); | ||||||
|  |  | ||||||
|  | @ -60,7 +60,9 @@ static inline int should_drop_frame(struct sk_buff *skb, | ||||||
| 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | ||||||
| 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||||||
| 
 | 
 | ||||||
| 	if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC)) | 	if (status->flag & (RX_FLAG_FAILED_FCS_CRC | | ||||||
|  | 			    RX_FLAG_FAILED_PLCP_CRC | | ||||||
|  | 			    RX_FLAG_AMPDU_IS_ZEROLEN)) | ||||||
| 		return 1; | 		return 1; | ||||||
| 	if (unlikely(skb->len < 16 + present_fcs_len)) | 	if (unlikely(skb->len < 16 + present_fcs_len)) | ||||||
| 		return 1; | 		return 1; | ||||||
|  | @ -91,6 +93,13 @@ ieee80211_rx_radiotap_len(struct ieee80211_local *local, | ||||||
| 	if (status->flag & RX_FLAG_HT) /* HT info */ | 	if (status->flag & RX_FLAG_HT) /* HT info */ | ||||||
| 		len += 3; | 		len += 3; | ||||||
| 
 | 
 | ||||||
|  | 	if (status->flag & RX_FLAG_AMPDU_DETAILS) { | ||||||
|  | 		/* padding */ | ||||||
|  | 		while (len & 3) | ||||||
|  | 			len++; | ||||||
|  | 		len += 8; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	return len; | 	return len; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -215,6 +224,37 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | ||||||
| 		pos++; | 		pos++; | ||||||
| 		*pos++ = status->rate_idx; | 		*pos++ = status->rate_idx; | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	if (status->flag & RX_FLAG_AMPDU_DETAILS) { | ||||||
|  | 		u16 flags = 0; | ||||||
|  | 
 | ||||||
|  | 		/* ensure 4 byte alignment */ | ||||||
|  | 		while ((pos - (u8 *)rthdr) & 3) | ||||||
|  | 			pos++; | ||||||
|  | 		rthdr->it_present |= | ||||||
|  | 			cpu_to_le32(1 << IEEE80211_RADIOTAP_AMPDU_STATUS); | ||||||
|  | 		put_unaligned_le32(status->ampdu_reference, pos); | ||||||
|  | 		pos += 4; | ||||||
|  | 		if (status->flag & RX_FLAG_AMPDU_REPORT_ZEROLEN) | ||||||
|  | 			flags |= IEEE80211_RADIOTAP_AMPDU_REPORT_ZEROLEN; | ||||||
|  | 		if (status->flag & RX_FLAG_AMPDU_IS_ZEROLEN) | ||||||
|  | 			flags |= IEEE80211_RADIOTAP_AMPDU_IS_ZEROLEN; | ||||||
|  | 		if (status->flag & RX_FLAG_AMPDU_LAST_KNOWN) | ||||||
|  | 			flags |= IEEE80211_RADIOTAP_AMPDU_LAST_KNOWN; | ||||||
|  | 		if (status->flag & RX_FLAG_AMPDU_IS_LAST) | ||||||
|  | 			flags |= IEEE80211_RADIOTAP_AMPDU_IS_LAST; | ||||||
|  | 		if (status->flag & RX_FLAG_AMPDU_DELIM_CRC_ERROR) | ||||||
|  | 			flags |= IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_ERR; | ||||||
|  | 		if (status->flag & RX_FLAG_AMPDU_DELIM_CRC_KNOWN) | ||||||
|  | 			flags |= IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN; | ||||||
|  | 		put_unaligned_le16(flags, pos); | ||||||
|  | 		pos += 2; | ||||||
|  | 		if (status->flag & RX_FLAG_AMPDU_DELIM_CRC_KNOWN) | ||||||
|  | 			*pos++ = status->ampdu_delimiter_crc; | ||||||
|  | 		else | ||||||
|  | 			*pos++ = 0; | ||||||
|  | 		*pos++ = 0; | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  | @ -2268,7 +2308,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | ||||||
| 
 | 
 | ||||||
| 		goto queue; | 		goto queue; | ||||||
| 	case WLAN_CATEGORY_SPECTRUM_MGMT: | 	case WLAN_CATEGORY_SPECTRUM_MGMT: | ||||||
| 		if (local->hw.conf.channel->band != IEEE80211_BAND_5GHZ) | 		if (status->band != IEEE80211_BAND_5GHZ) | ||||||
| 			break; | 			break; | ||||||
| 
 | 
 | ||||||
| 		if (sdata->vif.type != NL80211_IFTYPE_STATION) | 		if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||||||
|  | @ -2772,8 +2812,7 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx, | ||||||
| 		if (!bssid) { | 		if (!bssid) { | ||||||
| 			if (!ether_addr_equal(sdata->vif.addr, hdr->addr1)) | 			if (!ether_addr_equal(sdata->vif.addr, hdr->addr1)) | ||||||
| 				return 0; | 				return 0; | ||||||
| 		} else if (!ieee80211_bssid_match(bssid, | 		} else if (!ieee80211_bssid_match(bssid, sdata->vif.addr)) { | ||||||
| 					sdata->vif.addr)) { |  | ||||||
| 			/*
 | 			/*
 | ||||||
| 			 * Accept public action frames even when the | 			 * Accept public action frames even when the | ||||||
| 			 * BSSID doesn't match, this is used for P2P | 			 * BSSID doesn't match, this is used for P2P | ||||||
|  | @ -2793,9 +2832,18 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx, | ||||||
| 		if (!ether_addr_equal(sdata->u.wds.remote_addr, hdr->addr2)) | 		if (!ether_addr_equal(sdata->u.wds.remote_addr, hdr->addr2)) | ||||||
| 			return 0; | 			return 0; | ||||||
| 		break; | 		break; | ||||||
|  | 	case NL80211_IFTYPE_P2P_DEVICE: | ||||||
|  | 		if (!ieee80211_is_public_action(hdr, skb->len) && | ||||||
|  | 		    !ieee80211_is_probe_req(hdr->frame_control) && | ||||||
|  | 		    !ieee80211_is_probe_resp(hdr->frame_control) && | ||||||
|  | 		    !ieee80211_is_beacon(hdr->frame_control)) | ||||||
|  | 			return 0; | ||||||
|  | 		if (!ether_addr_equal(sdata->vif.addr, hdr->addr1)) | ||||||
|  | 			status->rx_flags &= ~IEEE80211_RX_RA_MATCH; | ||||||
|  | 		break; | ||||||
| 	default: | 	default: | ||||||
| 		/* should never get here */ | 		/* should never get here */ | ||||||
| 		WARN_ON(1); | 		WARN_ON_ONCE(1); | ||||||
| 		break; | 		break; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -416,7 +416,8 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local, | ||||||
| 			local->scan_req->ssids[i].ssid_len, | 			local->scan_req->ssids[i].ssid_len, | ||||||
| 			local->scan_req->ie, local->scan_req->ie_len, | 			local->scan_req->ie, local->scan_req->ie_len, | ||||||
| 			local->scan_req->rates[band], false, | 			local->scan_req->rates[band], false, | ||||||
| 			local->scan_req->no_cck); | 			local->scan_req->no_cck, | ||||||
|  | 			local->hw.conf.channel); | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * After sending probe requests, wait for probe responses | 	 * After sending probe requests, wait for probe responses | ||||||
|  | @ -479,11 +480,10 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | ||||||
| 	if (local->ops->hw_scan) { | 	if (local->ops->hw_scan) { | ||||||
| 		__set_bit(SCAN_HW_SCANNING, &local->scanning); | 		__set_bit(SCAN_HW_SCANNING, &local->scanning); | ||||||
| 	} else if ((req->n_channels == 1) && | 	} else if ((req->n_channels == 1) && | ||||||
| 		   (req->channels[0]->center_freq == | 		   (req->channels[0] == local->oper_channel)) { | ||||||
| 		    local->hw.conf.channel->center_freq)) { | 		/*
 | ||||||
| 
 | 		 * If we are scanning only on the operating channel | ||||||
| 		/* If we are scanning only on the current channel, then
 | 		 * then we do not need to stop normal activities | ||||||
| 		 * we do not need to stop normal activities |  | ||||||
| 		 */ | 		 */ | ||||||
| 		unsigned long next_delay; | 		unsigned long next_delay; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -519,19 +519,27 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | ||||||
| 		u64 cookie = (unsigned long)skb; | 		u64 cookie = (unsigned long)skb; | ||||||
| 		acked = info->flags & IEEE80211_TX_STAT_ACK; | 		acked = info->flags & IEEE80211_TX_STAT_ACK; | ||||||
| 
 | 
 | ||||||
| 		/*
 |  | ||||||
| 		 * TODO: When we have non-netdev frame TX, |  | ||||||
| 		 * we cannot use skb->dev->ieee80211_ptr |  | ||||||
| 		 */ |  | ||||||
| 
 |  | ||||||
| 		if (ieee80211_is_nullfunc(hdr->frame_control) || | 		if (ieee80211_is_nullfunc(hdr->frame_control) || | ||||||
| 		    ieee80211_is_qos_nullfunc(hdr->frame_control)) | 		    ieee80211_is_qos_nullfunc(hdr->frame_control)) { | ||||||
| 			cfg80211_probe_status(skb->dev, hdr->addr1, | 			cfg80211_probe_status(skb->dev, hdr->addr1, | ||||||
| 					      cookie, acked, GFP_ATOMIC); | 					      cookie, acked, GFP_ATOMIC); | ||||||
| 		else | 		} else if (skb->dev) { | ||||||
| 			cfg80211_mgmt_tx_status( | 			cfg80211_mgmt_tx_status( | ||||||
| 				skb->dev->ieee80211_ptr, cookie, skb->data, | 				skb->dev->ieee80211_ptr, cookie, skb->data, | ||||||
| 				skb->len, acked, GFP_ATOMIC); | 				skb->len, acked, GFP_ATOMIC); | ||||||
|  | 		} else { | ||||||
|  | 			struct ieee80211_sub_if_data *p2p_sdata; | ||||||
|  | 
 | ||||||
|  | 			rcu_read_lock(); | ||||||
|  | 
 | ||||||
|  | 			p2p_sdata = rcu_dereference(local->p2p_sdata); | ||||||
|  | 			if (p2p_sdata) { | ||||||
|  | 				cfg80211_mgmt_tx_status( | ||||||
|  | 					&p2p_sdata->wdev, cookie, skb->data, | ||||||
|  | 					skb->len, acked, GFP_ATOMIC); | ||||||
|  | 			} | ||||||
|  | 			rcu_read_unlock(); | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (unlikely(info->ack_frame_id)) { | 	if (unlikely(info->ack_frame_id)) { | ||||||
|  |  | ||||||
|  | @ -24,7 +24,7 @@ | ||||||
| 			__string(vif_name, sdata->dev ? sdata->dev->name : "<nodev>") | 			__string(vif_name, sdata->dev ? sdata->dev->name : "<nodev>") | ||||||
| #define VIF_ASSIGN	__entry->vif_type = sdata->vif.type; __entry->sdata = sdata;	\ | #define VIF_ASSIGN	__entry->vif_type = sdata->vif.type; __entry->sdata = sdata;	\ | ||||||
| 			__entry->p2p = sdata->vif.p2p;					\ | 			__entry->p2p = sdata->vif.p2p;					\ | ||||||
| 			__assign_str(vif_name, sdata->dev ? sdata->dev->name : "<nodev>") | 			__assign_str(vif_name, sdata->dev ? sdata->dev->name : sdata->name) | ||||||
| #define VIF_PR_FMT	" vif:%s(%d%s)" | #define VIF_PR_FMT	" vif:%s(%d%s)" | ||||||
| #define VIF_PR_ARG	__get_str(vif_name), __entry->vif_type, __entry->p2p ? "/p2p" : "" | #define VIF_PR_ARG	__get_str(vif_name), __entry->vif_type, __entry->p2p ? "/p2p" : "" | ||||||
| 
 | 
 | ||||||
|  | @ -274,9 +274,12 @@ TRACE_EVENT(drv_config, | ||||||
| 		__entry->dynamic_ps_timeout = local->hw.conf.dynamic_ps_timeout; | 		__entry->dynamic_ps_timeout = local->hw.conf.dynamic_ps_timeout; | ||||||
| 		__entry->max_sleep_period = local->hw.conf.max_sleep_period; | 		__entry->max_sleep_period = local->hw.conf.max_sleep_period; | ||||||
| 		__entry->listen_interval = local->hw.conf.listen_interval; | 		__entry->listen_interval = local->hw.conf.listen_interval; | ||||||
| 		__entry->long_frame_max_tx_count = local->hw.conf.long_frame_max_tx_count; | 		__entry->long_frame_max_tx_count = | ||||||
| 		__entry->short_frame_max_tx_count = local->hw.conf.short_frame_max_tx_count; | 			local->hw.conf.long_frame_max_tx_count; | ||||||
| 		__entry->center_freq = local->hw.conf.channel->center_freq; | 		__entry->short_frame_max_tx_count = | ||||||
|  | 			local->hw.conf.short_frame_max_tx_count; | ||||||
|  | 		__entry->center_freq = local->hw.conf.channel ? | ||||||
|  | 					local->hw.conf.channel->center_freq : 0; | ||||||
| 		__entry->channel_type = local->hw.conf.channel_type; | 		__entry->channel_type = local->hw.conf.channel_type; | ||||||
| 		__entry->smps = local->hw.conf.smps_mode; | 		__entry->smps = local->hw.conf.smps_mode; | ||||||
| 	), | 	), | ||||||
|  |  | ||||||
|  | @ -55,7 +55,7 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, | ||||||
| 	if (WARN_ON_ONCE(info->control.rates[0].idx < 0)) | 	if (WARN_ON_ONCE(info->control.rates[0].idx < 0)) | ||||||
| 		return 0; | 		return 0; | ||||||
| 
 | 
 | ||||||
| 	sband = local->hw.wiphy->bands[tx->channel->band]; | 	sband = local->hw.wiphy->bands[info->band]; | ||||||
| 	txrate = &sband->bitrates[info->control.rates[0].idx]; | 	txrate = &sband->bitrates[info->control.rates[0].idx]; | ||||||
| 
 | 
 | ||||||
| 	erp = txrate->flags & IEEE80211_RATE_ERP_G; | 	erp = txrate->flags & IEEE80211_RATE_ERP_G; | ||||||
|  | @ -615,7 +615,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) | ||||||
| 
 | 
 | ||||||
| 	memset(&txrc, 0, sizeof(txrc)); | 	memset(&txrc, 0, sizeof(txrc)); | ||||||
| 
 | 
 | ||||||
| 	sband = tx->local->hw.wiphy->bands[tx->channel->band]; | 	sband = tx->local->hw.wiphy->bands[info->band]; | ||||||
| 
 | 
 | ||||||
| 	len = min_t(u32, tx->skb->len + FCS_LEN, | 	len = min_t(u32, tx->skb->len + FCS_LEN, | ||||||
| 			 tx->local->hw.wiphy->frag_threshold); | 			 tx->local->hw.wiphy->frag_threshold); | ||||||
|  | @ -626,13 +626,13 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) | ||||||
| 	txrc.bss_conf = &tx->sdata->vif.bss_conf; | 	txrc.bss_conf = &tx->sdata->vif.bss_conf; | ||||||
| 	txrc.skb = tx->skb; | 	txrc.skb = tx->skb; | ||||||
| 	txrc.reported_rate.idx = -1; | 	txrc.reported_rate.idx = -1; | ||||||
| 	txrc.rate_idx_mask = tx->sdata->rc_rateidx_mask[tx->channel->band]; | 	txrc.rate_idx_mask = tx->sdata->rc_rateidx_mask[info->band]; | ||||||
| 	if (txrc.rate_idx_mask == (1 << sband->n_bitrates) - 1) | 	if (txrc.rate_idx_mask == (1 << sband->n_bitrates) - 1) | ||||||
| 		txrc.max_rate_idx = -1; | 		txrc.max_rate_idx = -1; | ||||||
| 	else | 	else | ||||||
| 		txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1; | 		txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1; | ||||||
| 	memcpy(txrc.rate_idx_mcs_mask, | 	memcpy(txrc.rate_idx_mcs_mask, | ||||||
| 	       tx->sdata->rc_rateidx_mcs_mask[tx->channel->band], | 	       tx->sdata->rc_rateidx_mcs_mask[info->band], | ||||||
| 	       sizeof(txrc.rate_idx_mcs_mask)); | 	       sizeof(txrc.rate_idx_mcs_mask)); | ||||||
| 	txrc.bss = (tx->sdata->vif.type == NL80211_IFTYPE_AP || | 	txrc.bss = (tx->sdata->vif.type == NL80211_IFTYPE_AP || | ||||||
| 		    tx->sdata->vif.type == NL80211_IFTYPE_MESH_POINT || | 		    tx->sdata->vif.type == NL80211_IFTYPE_MESH_POINT || | ||||||
|  | @ -667,7 +667,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) | ||||||
| 		 "scanning and associated. Target station: " | 		 "scanning and associated. Target station: " | ||||||
| 		 "%pM on %d GHz band\n", | 		 "%pM on %d GHz band\n", | ||||||
| 		 tx->sdata->name, hdr->addr1, | 		 tx->sdata->name, hdr->addr1, | ||||||
| 		 tx->channel->band ? 5 : 2)) | 		 info->band ? 5 : 2)) | ||||||
| 		return TX_DROP; | 		return TX_DROP; | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
|  | @ -1131,7 +1131,6 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, | ||||||
| 	tx->skb = skb; | 	tx->skb = skb; | ||||||
| 	tx->local = local; | 	tx->local = local; | ||||||
| 	tx->sdata = sdata; | 	tx->sdata = sdata; | ||||||
| 	tx->channel = local->hw.conf.channel; |  | ||||||
| 	__skb_queue_head_init(&tx->skbs); | 	__skb_queue_head_init(&tx->skbs); | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
|  | @ -1204,6 +1203,7 @@ static bool ieee80211_tx_frags(struct ieee80211_local *local, | ||||||
| 			       struct sk_buff_head *skbs, | 			       struct sk_buff_head *skbs, | ||||||
| 			       bool txpending) | 			       bool txpending) | ||||||
| { | { | ||||||
|  | 	struct ieee80211_tx_control control; | ||||||
| 	struct sk_buff *skb, *tmp; | 	struct sk_buff *skb, *tmp; | ||||||
| 	unsigned long flags; | 	unsigned long flags; | ||||||
| 
 | 
 | ||||||
|  | @ -1240,10 +1240,10 @@ static bool ieee80211_tx_frags(struct ieee80211_local *local, | ||||||
| 		spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 		spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | ||||||
| 
 | 
 | ||||||
| 		info->control.vif = vif; | 		info->control.vif = vif; | ||||||
| 		info->control.sta = sta; | 		control.sta = sta; | ||||||
| 
 | 
 | ||||||
| 		__skb_unlink(skb, skbs); | 		__skb_unlink(skb, skbs); | ||||||
| 		drv_tx(local, skb); | 		drv_tx(local, &control, skb); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return true; | 	return true; | ||||||
|  | @ -1399,8 +1399,7 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata, | ||||||
| 		goto out; | 		goto out; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	tx.channel = local->hw.conf.channel; | 	info->band = local->hw.conf.channel->band; | ||||||
| 	info->band = tx.channel->band; |  | ||||||
| 
 | 
 | ||||||
| 	/* set up hw_queue value early */ | 	/* set up hw_queue value early */ | ||||||
| 	if (!(info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) || | 	if (!(info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) || | ||||||
|  | @ -1720,7 +1719,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | ||||||
| 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||||||
| 	struct ieee80211_local *local = sdata->local; | 	struct ieee80211_local *local = sdata->local; | ||||||
| 	struct ieee80211_tx_info *info; | 	struct ieee80211_tx_info *info; | ||||||
| 	int ret = NETDEV_TX_BUSY, head_need; | 	int head_need; | ||||||
| 	u16 ethertype, hdrlen,  meshhdrlen = 0; | 	u16 ethertype, hdrlen,  meshhdrlen = 0; | ||||||
| 	__le16 fc; | 	__le16 fc; | ||||||
| 	struct ieee80211_hdr hdr; | 	struct ieee80211_hdr hdr; | ||||||
|  | @ -1736,10 +1735,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | ||||||
| 	u32 info_flags = 0; | 	u32 info_flags = 0; | ||||||
| 	u16 info_id = 0; | 	u16 info_id = 0; | ||||||
| 
 | 
 | ||||||
| 	if (unlikely(skb->len < ETH_HLEN)) { | 	if (unlikely(skb->len < ETH_HLEN)) | ||||||
| 		ret = NETDEV_TX_OK; |  | ||||||
| 		goto fail; | 		goto fail; | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	/* convert Ethernet header to proper 802.11 header (based on
 | 	/* convert Ethernet header to proper 802.11 header (based on
 | ||||||
| 	 * operation mode) */ | 	 * operation mode) */ | ||||||
|  | @ -1787,7 +1784,6 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | ||||||
| 		if (!sdata->u.mesh.mshcfg.dot11MeshTTL) { | 		if (!sdata->u.mesh.mshcfg.dot11MeshTTL) { | ||||||
| 			/* Do not send frames with mesh_ttl == 0 */ | 			/* Do not send frames with mesh_ttl == 0 */ | ||||||
| 			sdata->u.mesh.mshstats.dropped_frames_ttl++; | 			sdata->u.mesh.mshstats.dropped_frames_ttl++; | ||||||
| 			ret = NETDEV_TX_OK; |  | ||||||
| 			goto fail; | 			goto fail; | ||||||
| 		} | 		} | ||||||
| 		rcu_read_lock(); | 		rcu_read_lock(); | ||||||
|  | @ -1880,10 +1876,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | ||||||
| 
 | 
 | ||||||
| 		if (tdls_direct) { | 		if (tdls_direct) { | ||||||
| 			/* link during setup - throw out frames to peer */ | 			/* link during setup - throw out frames to peer */ | ||||||
| 			if (!tdls_auth) { | 			if (!tdls_auth) | ||||||
| 				ret = NETDEV_TX_OK; |  | ||||||
| 				goto fail; | 				goto fail; | ||||||
| 			} |  | ||||||
| 
 | 
 | ||||||
| 			/* DA SA BSSID */ | 			/* DA SA BSSID */ | ||||||
| 			memcpy(hdr.addr1, skb->data, ETH_ALEN); | 			memcpy(hdr.addr1, skb->data, ETH_ALEN); | ||||||
|  | @ -1917,7 +1911,6 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | ||||||
| 		hdrlen = 24; | 		hdrlen = 24; | ||||||
| 		break; | 		break; | ||||||
| 	default: | 	default: | ||||||
| 		ret = NETDEV_TX_OK; |  | ||||||
| 		goto fail; | 		goto fail; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -1962,7 +1955,6 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | ||||||
| 
 | 
 | ||||||
| 		I802_DEBUG_INC(local->tx_handlers_drop_unauth_port); | 		I802_DEBUG_INC(local->tx_handlers_drop_unauth_port); | ||||||
| 
 | 
 | ||||||
| 		ret = NETDEV_TX_OK; |  | ||||||
| 		goto fail; | 		goto fail; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -2017,11 +2009,9 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | ||||||
| 		skb = skb_clone(skb, GFP_ATOMIC); | 		skb = skb_clone(skb, GFP_ATOMIC); | ||||||
| 		kfree_skb(tmp_skb); | 		kfree_skb(tmp_skb); | ||||||
| 
 | 
 | ||||||
| 		if (!skb) { | 		if (!skb) | ||||||
| 			ret = NETDEV_TX_OK; |  | ||||||
| 			goto fail; | 			goto fail; | ||||||
| 	} | 	} | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	hdr.frame_control = fc; | 	hdr.frame_control = fc; | ||||||
| 	hdr.duration_id = 0; | 	hdr.duration_id = 0; | ||||||
|  | @ -2123,10 +2113,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | ||||||
| 	return NETDEV_TX_OK; | 	return NETDEV_TX_OK; | ||||||
| 
 | 
 | ||||||
|  fail: |  fail: | ||||||
| 	if (ret == NETDEV_TX_OK) |  | ||||||
| 	dev_kfree_skb(skb); | 	dev_kfree_skb(skb); | ||||||
| 
 | 	return NETDEV_TX_OK; | ||||||
| 	return ret; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -2301,12 +2289,9 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | ||||||
| 	struct ieee80211_sub_if_data *sdata = NULL; | 	struct ieee80211_sub_if_data *sdata = NULL; | ||||||
| 	struct ieee80211_if_ap *ap = NULL; | 	struct ieee80211_if_ap *ap = NULL; | ||||||
| 	struct beacon_data *beacon; | 	struct beacon_data *beacon; | ||||||
| 	struct ieee80211_supported_band *sband; | 	enum ieee80211_band band = local->oper_channel->band; | ||||||
| 	enum ieee80211_band band = local->hw.conf.channel->band; |  | ||||||
| 	struct ieee80211_tx_rate_control txrc; | 	struct ieee80211_tx_rate_control txrc; | ||||||
| 
 | 
 | ||||||
| 	sband = local->hw.wiphy->bands[band]; |  | ||||||
| 
 |  | ||||||
| 	rcu_read_lock(); | 	rcu_read_lock(); | ||||||
| 
 | 
 | ||||||
| 	sdata = vif_to_sdata(vif); | 	sdata = vif_to_sdata(vif); | ||||||
|  | @ -2416,7 +2401,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | ||||||
| 		memset(mgmt, 0, hdr_len); | 		memset(mgmt, 0, hdr_len); | ||||||
| 		mgmt->frame_control = | 		mgmt->frame_control = | ||||||
| 		    cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON); | 		    cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON); | ||||||
| 		memset(mgmt->da, 0xff, ETH_ALEN); | 		eth_broadcast_addr(mgmt->da); | ||||||
| 		memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); | 		memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); | ||||||
| 		memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); | 		memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); | ||||||
| 		mgmt->u.beacon.beacon_int = | 		mgmt->u.beacon.beacon_int = | ||||||
|  | @ -2428,9 +2413,9 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | ||||||
| 		*pos++ = WLAN_EID_SSID; | 		*pos++ = WLAN_EID_SSID; | ||||||
| 		*pos++ = 0x0; | 		*pos++ = 0x0; | ||||||
| 
 | 
 | ||||||
| 		if (ieee80211_add_srates_ie(sdata, skb, true) || | 		if (ieee80211_add_srates_ie(sdata, skb, true, band) || | ||||||
| 		    mesh_add_ds_params_ie(skb, sdata) || | 		    mesh_add_ds_params_ie(skb, sdata) || | ||||||
| 		    ieee80211_add_ext_srates_ie(sdata, skb, true) || | 		    ieee80211_add_ext_srates_ie(sdata, skb, true, band) || | ||||||
| 		    mesh_add_rsn_ie(skb, sdata) || | 		    mesh_add_rsn_ie(skb, sdata) || | ||||||
| 		    mesh_add_ht_cap_ie(skb, sdata) || | 		    mesh_add_ht_cap_ie(skb, sdata) || | ||||||
| 		    mesh_add_ht_oper_ie(skb, sdata) || | 		    mesh_add_ht_oper_ie(skb, sdata) || | ||||||
|  | @ -2453,12 +2438,12 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | ||||||
| 
 | 
 | ||||||
| 	memset(&txrc, 0, sizeof(txrc)); | 	memset(&txrc, 0, sizeof(txrc)); | ||||||
| 	txrc.hw = hw; | 	txrc.hw = hw; | ||||||
| 	txrc.sband = sband; | 	txrc.sband = local->hw.wiphy->bands[band]; | ||||||
| 	txrc.bss_conf = &sdata->vif.bss_conf; | 	txrc.bss_conf = &sdata->vif.bss_conf; | ||||||
| 	txrc.skb = skb; | 	txrc.skb = skb; | ||||||
| 	txrc.reported_rate.idx = -1; | 	txrc.reported_rate.idx = -1; | ||||||
| 	txrc.rate_idx_mask = sdata->rc_rateidx_mask[band]; | 	txrc.rate_idx_mask = sdata->rc_rateidx_mask[band]; | ||||||
| 	if (txrc.rate_idx_mask == (1 << sband->n_bitrates) - 1) | 	if (txrc.rate_idx_mask == (1 << txrc.sband->n_bitrates) - 1) | ||||||
| 		txrc.max_rate_idx = -1; | 		txrc.max_rate_idx = -1; | ||||||
| 	else | 	else | ||||||
| 		txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1; | 		txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1; | ||||||
|  | @ -2482,7 +2467,8 @@ struct sk_buff *ieee80211_proberesp_get(struct ieee80211_hw *hw, | ||||||
| 					struct ieee80211_vif *vif) | 					struct ieee80211_vif *vif) | ||||||
| { | { | ||||||
| 	struct ieee80211_if_ap *ap = NULL; | 	struct ieee80211_if_ap *ap = NULL; | ||||||
| 	struct sk_buff *presp = NULL, *skb = NULL; | 	struct sk_buff *skb = NULL; | ||||||
|  | 	struct probe_resp *presp = NULL; | ||||||
| 	struct ieee80211_hdr *hdr; | 	struct ieee80211_hdr *hdr; | ||||||
| 	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | 	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||||||
| 
 | 
 | ||||||
|  | @ -2496,10 +2482,12 @@ struct sk_buff *ieee80211_proberesp_get(struct ieee80211_hw *hw, | ||||||
| 	if (!presp) | 	if (!presp) | ||||||
| 		goto out; | 		goto out; | ||||||
| 
 | 
 | ||||||
| 	skb = skb_copy(presp, GFP_ATOMIC); | 	skb = dev_alloc_skb(presp->len); | ||||||
| 	if (!skb) | 	if (!skb) | ||||||
| 		goto out; | 		goto out; | ||||||
| 
 | 
 | ||||||
|  | 	memcpy(skb_put(skb, presp->len), presp->data, presp->len); | ||||||
|  | 
 | ||||||
| 	hdr = (struct ieee80211_hdr *) skb->data; | 	hdr = (struct ieee80211_hdr *) skb->data; | ||||||
| 	memset(hdr->addr1, 0, sizeof(hdr->addr1)); | 	memset(hdr->addr1, 0, sizeof(hdr->addr1)); | ||||||
| 
 | 
 | ||||||
|  | @ -2610,9 +2598,9 @@ struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw, | ||||||
| 	memset(hdr, 0, sizeof(*hdr)); | 	memset(hdr, 0, sizeof(*hdr)); | ||||||
| 	hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 	hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||||||
| 					 IEEE80211_STYPE_PROBE_REQ); | 					 IEEE80211_STYPE_PROBE_REQ); | ||||||
| 	memset(hdr->addr1, 0xff, ETH_ALEN); | 	eth_broadcast_addr(hdr->addr1); | ||||||
| 	memcpy(hdr->addr2, vif->addr, ETH_ALEN); | 	memcpy(hdr->addr2, vif->addr, ETH_ALEN); | ||||||
| 	memset(hdr->addr3, 0xff, ETH_ALEN); | 	eth_broadcast_addr(hdr->addr3); | ||||||
| 
 | 
 | ||||||
| 	pos = skb_put(skb, ie_ssid_len); | 	pos = skb_put(skb, ie_ssid_len); | ||||||
| 	*pos++ = WLAN_EID_SSID; | 	*pos++ = WLAN_EID_SSID; | ||||||
|  | @ -2709,8 +2697,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, | ||||||
| 	info = IEEE80211_SKB_CB(skb); | 	info = IEEE80211_SKB_CB(skb); | ||||||
| 
 | 
 | ||||||
| 	tx.flags |= IEEE80211_TX_PS_BUFFERED; | 	tx.flags |= IEEE80211_TX_PS_BUFFERED; | ||||||
| 	tx.channel = local->hw.conf.channel; | 	info->band = local->oper_channel->band; | ||||||
| 	info->band = tx.channel->band; |  | ||||||
| 
 | 
 | ||||||
| 	if (invoke_tx_handlers(&tx)) | 	if (invoke_tx_handlers(&tx)) | ||||||
| 		skb = NULL; | 		skb = NULL; | ||||||
|  |  | ||||||
|  | @ -276,6 +276,9 @@ void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue) | ||||||
| 	list_for_each_entry_rcu(sdata, &local->interfaces, list) { | 	list_for_each_entry_rcu(sdata, &local->interfaces, list) { | ||||||
| 		int ac; | 		int ac; | ||||||
| 
 | 
 | ||||||
|  | 		if (!sdata->dev) | ||||||
|  | 			continue; | ||||||
|  | 
 | ||||||
| 		if (test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state)) | 		if (test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state)) | ||||||
| 			continue; | 			continue; | ||||||
| 
 | 
 | ||||||
|  | @ -364,6 +367,9 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, | ||||||
| 	list_for_each_entry_rcu(sdata, &local->interfaces, list) { | 	list_for_each_entry_rcu(sdata, &local->interfaces, list) { | ||||||
| 		int ac; | 		int ac; | ||||||
| 
 | 
 | ||||||
|  | 		if (!sdata->dev) | ||||||
|  | 			continue; | ||||||
|  | 
 | ||||||
| 		for (ac = 0; ac < n_acs; ac++) { | 		for (ac = 0; ac < n_acs; ac++) { | ||||||
| 			if (sdata->vif.hw_queue[ac] == queue || | 			if (sdata->vif.hw_queue[ac] == queue || | ||||||
| 			    sdata->vif.cab_queue == queue) | 			    sdata->vif.cab_queue == queue) | ||||||
|  | @ -768,8 +774,11 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, | ||||||
| 				elem_parse_failed = true; | 				elem_parse_failed = true; | ||||||
| 			break; | 			break; | ||||||
| 		case WLAN_EID_CHANNEL_SWITCH: | 		case WLAN_EID_CHANNEL_SWITCH: | ||||||
| 			elems->ch_switch_elem = pos; | 			if (elen != sizeof(struct ieee80211_channel_sw_ie)) { | ||||||
| 			elems->ch_switch_elem_len = elen; | 				elem_parse_failed = true; | ||||||
|  | 				break; | ||||||
|  | 			} | ||||||
|  | 			elems->ch_switch_ie = (void *)pos; | ||||||
| 			break; | 			break; | ||||||
| 		case WLAN_EID_QUIET: | 		case WLAN_EID_QUIET: | ||||||
| 			if (!elems->quiet_elem) { | 			if (!elems->quiet_elem) { | ||||||
|  | @ -832,7 +841,7 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, | ||||||
| 
 | 
 | ||||||
| 	memset(&qparam, 0, sizeof(qparam)); | 	memset(&qparam, 0, sizeof(qparam)); | ||||||
| 
 | 
 | ||||||
| 	use_11b = (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) && | 	use_11b = (local->oper_channel->band == IEEE80211_BAND_2GHZ) && | ||||||
| 		 !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE); | 		 !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE); | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
|  | @ -899,7 +908,8 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, | ||||||
| 		drv_conf_tx(local, sdata, ac, &qparam); | 		drv_conf_tx(local, sdata, ac, &qparam); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (sdata->vif.type != NL80211_IFTYPE_MONITOR) { | 	if (sdata->vif.type != NL80211_IFTYPE_MONITOR && | ||||||
|  | 	    sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE) { | ||||||
| 		sdata->vif.bss_conf.qos = enable_qos; | 		sdata->vif.bss_conf.qos = enable_qos; | ||||||
| 		if (bss_notify) | 		if (bss_notify) | ||||||
| 			ieee80211_bss_info_change_notify(sdata, | 			ieee80211_bss_info_change_notify(sdata, | ||||||
|  | @ -919,7 +929,7 @@ void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, | ||||||
| 		if ((supp_rates[i] & 0x7f) * 5 > 110) | 		if ((supp_rates[i] & 0x7f) * 5 > 110) | ||||||
| 			have_higher_than_11mbit = 1; | 			have_higher_than_11mbit = 1; | ||||||
| 
 | 
 | ||||||
| 	if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && | 	if (local->oper_channel->band == IEEE80211_BAND_2GHZ && | ||||||
| 	    have_higher_than_11mbit) | 	    have_higher_than_11mbit) | ||||||
| 		sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; | 		sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; | ||||||
| 	else | 	else | ||||||
|  | @ -1100,6 +1110,7 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | ||||||
| 
 | 
 | ||||||
| struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | ||||||
| 					  u8 *dst, u32 ratemask, | 					  u8 *dst, u32 ratemask, | ||||||
|  | 					  struct ieee80211_channel *chan, | ||||||
| 					  const u8 *ssid, size_t ssid_len, | 					  const u8 *ssid, size_t ssid_len, | ||||||
| 					  const u8 *ie, size_t ie_len, | 					  const u8 *ie, size_t ie_len, | ||||||
| 					  bool directed) | 					  bool directed) | ||||||
|  | @ -1109,7 +1120,7 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | ||||||
| 	struct ieee80211_mgmt *mgmt; | 	struct ieee80211_mgmt *mgmt; | ||||||
| 	size_t buf_len; | 	size_t buf_len; | ||||||
| 	u8 *buf; | 	u8 *buf; | ||||||
| 	u8 chan; | 	u8 chan_no; | ||||||
| 
 | 
 | ||||||
| 	/* FIXME: come up with a proper value */ | 	/* FIXME: come up with a proper value */ | ||||||
| 	buf = kmalloc(200 + ie_len, GFP_KERNEL); | 	buf = kmalloc(200 + ie_len, GFP_KERNEL); | ||||||
|  | @ -1122,14 +1133,12 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | ||||||
| 	 * badly-behaved APs don't respond when this parameter is included. | 	 * badly-behaved APs don't respond when this parameter is included. | ||||||
| 	 */ | 	 */ | ||||||
| 	if (directed) | 	if (directed) | ||||||
| 		chan = 0; | 		chan_no = 0; | ||||||
| 	else | 	else | ||||||
| 		chan = ieee80211_frequency_to_channel( | 		chan_no = ieee80211_frequency_to_channel(chan->center_freq); | ||||||
| 			local->hw.conf.channel->center_freq); |  | ||||||
| 
 | 
 | ||||||
| 	buf_len = ieee80211_build_preq_ies(local, buf, ie, ie_len, | 	buf_len = ieee80211_build_preq_ies(local, buf, ie, ie_len, chan->band, | ||||||
| 					   local->hw.conf.channel->band, | 					   ratemask, chan_no); | ||||||
| 					   ratemask, chan); |  | ||||||
| 
 | 
 | ||||||
| 	skb = ieee80211_probereq_get(&local->hw, &sdata->vif, | 	skb = ieee80211_probereq_get(&local->hw, &sdata->vif, | ||||||
| 				     ssid, ssid_len, | 				     ssid, ssid_len, | ||||||
|  | @ -1154,11 +1163,13 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | ||||||
| void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | ||||||
| 			      const u8 *ssid, size_t ssid_len, | 			      const u8 *ssid, size_t ssid_len, | ||||||
| 			      const u8 *ie, size_t ie_len, | 			      const u8 *ie, size_t ie_len, | ||||||
| 			      u32 ratemask, bool directed, bool no_cck) | 			      u32 ratemask, bool directed, bool no_cck, | ||||||
|  | 			      struct ieee80211_channel *channel) | ||||||
| { | { | ||||||
| 	struct sk_buff *skb; | 	struct sk_buff *skb; | ||||||
| 
 | 
 | ||||||
| 	skb = ieee80211_build_probe_req(sdata, dst, ratemask, ssid, ssid_len, | 	skb = ieee80211_build_probe_req(sdata, dst, ratemask, channel, | ||||||
|  | 					ssid, ssid_len, | ||||||
| 					ie, ie_len, directed); | 					ie, ie_len, directed); | ||||||
| 	if (skb) { | 	if (skb) { | ||||||
| 		if (no_cck) | 		if (no_cck) | ||||||
|  | @ -1359,7 +1370,8 @@ int ieee80211_reconfig(struct ieee80211_local *local) | ||||||
| 		switch (sdata->vif.type) { | 		switch (sdata->vif.type) { | ||||||
| 		case NL80211_IFTYPE_STATION: | 		case NL80211_IFTYPE_STATION: | ||||||
| 			changed |= BSS_CHANGED_ASSOC | | 			changed |= BSS_CHANGED_ASSOC | | ||||||
| 				   BSS_CHANGED_ARP_FILTER; | 				   BSS_CHANGED_ARP_FILTER | | ||||||
|  | 				   BSS_CHANGED_PS; | ||||||
| 			mutex_lock(&sdata->u.mgd.mtx); | 			mutex_lock(&sdata->u.mgd.mtx); | ||||||
| 			ieee80211_bss_info_change_notify(sdata, changed); | 			ieee80211_bss_info_change_notify(sdata, changed); | ||||||
| 			mutex_unlock(&sdata->u.mgd.mtx); | 			mutex_unlock(&sdata->u.mgd.mtx); | ||||||
|  | @ -1385,6 +1397,9 @@ int ieee80211_reconfig(struct ieee80211_local *local) | ||||||
| 		case NL80211_IFTYPE_MONITOR: | 		case NL80211_IFTYPE_MONITOR: | ||||||
| 			/* ignore virtual */ | 			/* ignore virtual */ | ||||||
| 			break; | 			break; | ||||||
|  | 		case NL80211_IFTYPE_P2P_DEVICE: | ||||||
|  | 			changed = BSS_CHANGED_IDLE; | ||||||
|  | 			break; | ||||||
| 		case NL80211_IFTYPE_UNSPECIFIED: | 		case NL80211_IFTYPE_UNSPECIFIED: | ||||||
| 		case NUM_NL80211_IFTYPES: | 		case NUM_NL80211_IFTYPES: | ||||||
| 		case NL80211_IFTYPE_P2P_CLIENT: | 		case NL80211_IFTYPE_P2P_CLIENT: | ||||||
|  | @ -1571,6 +1586,8 @@ void ieee80211_recalc_smps(struct ieee80211_local *local) | ||||||
| 	list_for_each_entry(sdata, &local->interfaces, list) { | 	list_for_each_entry(sdata, &local->interfaces, list) { | ||||||
| 		if (!ieee80211_sdata_running(sdata)) | 		if (!ieee80211_sdata_running(sdata)) | ||||||
| 			continue; | 			continue; | ||||||
|  | 		if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) | ||||||
|  | 			continue; | ||||||
| 		if (sdata->vif.type != NL80211_IFTYPE_STATION) | 		if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||||||
| 			goto set; | 			goto set; | ||||||
| 
 | 
 | ||||||
|  | @ -1809,7 +1826,8 @@ ieee80211_ht_oper_to_channel_type(struct ieee80211_ht_operation *ht_oper) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata, | int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata, | ||||||
| 			    struct sk_buff *skb, bool need_basic) | 			    struct sk_buff *skb, bool need_basic, | ||||||
|  | 			    enum ieee80211_band band) | ||||||
| { | { | ||||||
| 	struct ieee80211_local *local = sdata->local; | 	struct ieee80211_local *local = sdata->local; | ||||||
| 	struct ieee80211_supported_band *sband; | 	struct ieee80211_supported_band *sband; | ||||||
|  | @ -1817,7 +1835,7 @@ int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata, | ||||||
| 	u8 i, rates, *pos; | 	u8 i, rates, *pos; | ||||||
| 	u32 basic_rates = sdata->vif.bss_conf.basic_rates; | 	u32 basic_rates = sdata->vif.bss_conf.basic_rates; | ||||||
| 
 | 
 | ||||||
| 	sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 	sband = local->hw.wiphy->bands[band]; | ||||||
| 	rates = sband->n_bitrates; | 	rates = sband->n_bitrates; | ||||||
| 	if (rates > 8) | 	if (rates > 8) | ||||||
| 		rates = 8; | 		rates = 8; | ||||||
|  | @ -1840,7 +1858,8 @@ int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata, | int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata, | ||||||
| 				struct sk_buff *skb, bool need_basic) | 				struct sk_buff *skb, bool need_basic, | ||||||
|  | 				enum ieee80211_band band) | ||||||
| { | { | ||||||
| 	struct ieee80211_local *local = sdata->local; | 	struct ieee80211_local *local = sdata->local; | ||||||
| 	struct ieee80211_supported_band *sband; | 	struct ieee80211_supported_band *sband; | ||||||
|  | @ -1848,7 +1867,7 @@ int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata, | ||||||
| 	u8 i, exrates, *pos; | 	u8 i, exrates, *pos; | ||||||
| 	u32 basic_rates = sdata->vif.bss_conf.basic_rates; | 	u32 basic_rates = sdata->vif.bss_conf.basic_rates; | ||||||
| 
 | 
 | ||||||
| 	sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 	sband = local->hw.wiphy->bands[band]; | ||||||
| 	exrates = sband->n_bitrates; | 	exrates = sband->n_bitrates; | ||||||
| 	if (exrates > 8) | 	if (exrates > 8) | ||||||
| 		exrates -= 8; | 		exrates -= 8; | ||||||
|  |  | ||||||
|  | @ -150,6 +150,20 @@ static void rfkill_led_trigger_activate(struct led_classdev *led) | ||||||
| 	rfkill_led_trigger_event(rfkill); | 	rfkill_led_trigger_event(rfkill); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | const char *rfkill_get_led_trigger_name(struct rfkill *rfkill) | ||||||
|  | { | ||||||
|  | 	return rfkill->led_trigger.name; | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL(rfkill_get_led_trigger_name); | ||||||
|  | 
 | ||||||
|  | void rfkill_set_led_trigger_name(struct rfkill *rfkill, const char *name) | ||||||
|  | { | ||||||
|  | 	BUG_ON(!rfkill); | ||||||
|  | 
 | ||||||
|  | 	rfkill->ledtrigname = name; | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL(rfkill_set_led_trigger_name); | ||||||
|  | 
 | ||||||
| static int rfkill_led_trigger_register(struct rfkill *rfkill) | static int rfkill_led_trigger_register(struct rfkill *rfkill) | ||||||
| { | { | ||||||
| 	rfkill->led_trigger.name = rfkill->ledtrigname | 	rfkill->led_trigger.name = rfkill->ledtrigname | ||||||
|  |  | ||||||
Some files were not shown because too many files have changed in this diff Show more
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 John W. Linville
				John W. Linville