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 | ||||
| 	bool | ||||
| 	depends on BCMA_DRIVER_MIPS && BROKEN | ||||
| 	depends on BCMA_DRIVER_MIPS | ||||
| 	default y | ||||
| 
 | ||||
| config BCMA_NFLASH | ||||
| 	bool | ||||
| 	depends on BCMA_DRIVER_MIPS && BROKEN | ||||
| 	depends on BCMA_DRIVER_MIPS | ||||
| 	default y | ||||
| 
 | ||||
| config BCMA_DRIVER_GMAC_CMN | ||||
|  |  | |||
|  | @ -54,6 +54,7 @@ u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc); | |||
| #ifdef CONFIG_BCMA_SFLASH | ||||
| /* driver_chipcommon_sflash.c */ | ||||
| int bcma_sflash_init(struct bcma_drv_cc *cc); | ||||
| extern struct platform_device bcma_sflash_dev; | ||||
| #else | ||||
| 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 | ||||
| /* driver_chipcommon_nflash.c */ | ||||
| int bcma_nflash_init(struct bcma_drv_cc *cc); | ||||
| extern struct platform_device bcma_nflash_dev; | ||||
| #else | ||||
| static inline int bcma_nflash_init(struct bcma_drv_cc *cc) | ||||
| { | ||||
|  |  | |||
|  | @ -5,15 +5,37 @@ | |||
|  * Licensed under the GNU/GPL. See COPYING for details. | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/platform_device.h> | ||||
| #include <linux/bcma/bcma.h> | ||||
| #include <linux/bcma/bcma_driver_chipcommon.h> | ||||
| #include <linux/delay.h> | ||||
| 
 | ||||
| #include "bcma_private.h" | ||||
| 
 | ||||
| struct platform_device bcma_nflash_dev = { | ||||
| 	.name		= "bcma_nflash", | ||||
| 	.num_resources	= 0, | ||||
| }; | ||||
| 
 | ||||
| /* Initialize NAND flash access */ | ||||
| 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; | ||||
| } | ||||
|  |  | |||
|  | @ -5,15 +5,132 @@ | |||
|  * Licensed under the GNU/GPL. See COPYING for details. | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/platform_device.h> | ||||
| #include <linux/bcma/bcma.h> | ||||
| #include <linux/bcma/bcma_driver_chipcommon.h> | ||||
| #include <linux/delay.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 */ | ||||
| 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; | ||||
| } | ||||
|  |  | |||
|  | @ -7,6 +7,7 @@ | |||
| 
 | ||||
| #include "bcma_private.h" | ||||
| #include <linux/module.h> | ||||
| #include <linux/platform_device.h> | ||||
| #include <linux/bcma/bcma.h> | ||||
| #include <linux/slab.h> | ||||
| 
 | ||||
|  | @ -136,6 +137,22 @@ static int bcma_register_cores(struct bcma_bus *bus) | |||
| 		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; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -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 */ | ||||
| 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; | ||||
| 	size_t payload_len, hdrlen; | ||||
|  |  | |||
|  | @ -1726,7 +1726,9 @@ static void at76_mac80211_tx_callback(struct urb *urb) | |||
| 	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_tx_buffer *tx_buffer = priv->bulk_out_buffer; | ||||
|  |  | |||
|  | @ -55,7 +55,8 @@ | |||
| \********************/ | ||||
| 
 | ||||
| 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; | ||||
| 	u16 qnum = skb_get_queue_mapping(skb); | ||||
|  |  | |||
|  | @ -280,6 +280,7 @@ struct ath_tx_control { | |||
| 	struct ath_txq *txq; | ||||
| 	struct ath_node *an; | ||||
| 	u8 paprd; | ||||
| 	struct ieee80211_sta *sta; | ||||
| }; | ||||
| 
 | ||||
| #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_htc_tx_start(struct ath9k_htc_priv *priv, | ||||
| 		       struct ieee80211_sta *sta, | ||||
| 		       struct sk_buff *skb, u8 slot, bool is_cab); | ||||
| void ath9k_tx_cleanup(struct ath9k_htc_priv *priv); | ||||
| 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; | ||||
| 		} | ||||
| 
 | ||||
| 		ret = ath9k_htc_tx_start(priv, skb, tx_slot, true); | ||||
| 		ret = ath9k_htc_tx_start(priv, NULL, skb, tx_slot, true); | ||||
| 		if (ret != 0) { | ||||
| 			ath9k_htc_tx_clear_slot(priv, tx_slot); | ||||
| 			dev_kfree_skb_any(skb); | ||||
|  |  | |||
|  | @ -856,7 +856,9 @@ set_timer: | |||
| /* 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 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; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = ath9k_htc_tx_start(priv, skb, slot, false); | ||||
| 	ret = ath9k_htc_tx_start(priv, control->sta, skb, slot, false); | ||||
| 	if (ret != 0) { | ||||
| 		ath_dbg(common, XMIT, "Tx failed\n"); | ||||
| 		goto clear_slot; | ||||
|  | @ -1331,6 +1333,34 @@ static int ath9k_htc_sta_remove(struct ieee80211_hw *hw, | |||
| 	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, | ||||
| 			     struct ieee80211_vif *vif, u16 queue, | ||||
| 			     const struct ieee80211_tx_queue_params *params) | ||||
|  | @ -1758,6 +1788,7 @@ struct ieee80211_ops ath9k_htc_ops = { | |||
| 	.sta_add            = ath9k_htc_sta_add, | ||||
| 	.sta_remove         = ath9k_htc_sta_remove, | ||||
| 	.conf_tx            = ath9k_htc_conf_tx, | ||||
| 	.sta_rc_update      = ath9k_htc_sta_rc_update, | ||||
| 	.bss_info_changed   = ath9k_htc_bss_info_changed, | ||||
| 	.set_key            = ath9k_htc_set_key, | ||||
| 	.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, | ||||
| 		       struct ieee80211_sta *sta, | ||||
| 		       struct sk_buff *skb, | ||||
| 		       u8 slot, bool is_cab) | ||||
| { | ||||
| 	struct ieee80211_hdr *hdr; | ||||
| 	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 ath9k_htc_sta *ista; | ||||
| 	struct ath9k_htc_vif *avp = NULL; | ||||
|  |  | |||
|  | @ -696,7 +696,9 @@ mutex_unlock: | |||
| 	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_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)); | ||||
| 	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); | ||||
| 
 | ||||
|  |  | |||
|  | @ -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); | ||||
| } | ||||
| 
 | ||||
| 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) | ||||
| { | ||||
| 	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_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||||
| 	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_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 ath_softc *sc = hw->priv; | ||||
| 	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)) | ||||
| 		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 | ||||
|  |  | |||
|  | @ -425,6 +425,7 @@ struct ar9170 { | |||
| 	bool rx_has_plcp; | ||||
| 	struct sk_buff *rx_failover; | ||||
| 	int rx_failover_missing; | ||||
| 	u32 ampdu_ref; | ||||
| 
 | ||||
| 	/* FIFO for collecting outstanding BlockAckRequest */ | ||||
| 	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); | ||||
| 
 | ||||
| /* 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_process_status(struct ar9170 *ar, | ||||
| 				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 | ||||
| } | ||||
| 
 | ||||
| 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; | ||||
| 
 | ||||
|  | @ -637,6 +638,9 @@ static bool carl9170_ampdu_check(struct ar9170 *ar, u8 *buf, u8 ms) | |||
| 		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 | ||||
| 	 * 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))) | ||||
| 		goto drop; | ||||
| 
 | ||||
| 	memset(&status, 0, sizeof(status)); | ||||
| 
 | ||||
| 	mpdu_len = len - sizeof(*mac); | ||||
| 
 | ||||
| 	mac = (void *)(buf + mpdu_len); | ||||
| 	mac_status = mac->status; | ||||
| 	switch (mac_status & AR9170_RX_STATUS_MPDU) { | ||||
| 	case AR9170_RX_STATUS_MPDU_FIRST: | ||||
| 		ar->ampdu_ref++; | ||||
| 		/* Aggregated MPDUs start with an PLCP header */ | ||||
| 		if (likely(mpdu_len >= sizeof(struct ar9170_rx_head))) { | ||||
| 			head = (void *) buf; | ||||
|  | @ -721,12 +728,13 @@ static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) | |||
| 		break; | ||||
| 
 | ||||
| 	case AR9170_RX_STATUS_MPDU_LAST: | ||||
| 		status.flag |= RX_FLAG_AMPDU_IS_LAST; | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * The last frame of an A-MPDU has an extra tail | ||||
| 		 * which does contain the phy status of the whole | ||||
| 		 * aggregate. | ||||
| 		 */ | ||||
| 
 | ||||
| 		if (likely(mpdu_len >= sizeof(struct ar9170_rx_phystatus))) { | ||||
| 			mpdu_len -= sizeof(struct ar9170_rx_phystatus); | ||||
| 			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))) | ||||
| 		goto drop; | ||||
| 
 | ||||
| 	memset(&status, 0, sizeof(status)); | ||||
| 	if (unlikely(carl9170_rx_mac_status(ar, head, mac, &status))) | ||||
| 		goto drop; | ||||
| 
 | ||||
| 	if (!carl9170_ampdu_check(ar, buf, mac_status)) | ||||
| 	if (!carl9170_ampdu_check(ar, buf, mac_status, &status)) | ||||
| 		goto drop; | ||||
| 
 | ||||
| 	if (phy) | ||||
|  |  | |||
|  | @ -867,14 +867,15 @@ static bool carl9170_tx_cts_check(struct ar9170 *ar, | |||
| 	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 _carl9170_tx_superframe *txc; | ||||
| 	struct carl9170_vif_info *cvif; | ||||
| 	struct ieee80211_tx_info *info; | ||||
| 	struct ieee80211_tx_rate *txrate; | ||||
| 	struct ieee80211_sta *sta; | ||||
| 	struct carl9170_tx_info *arinfo; | ||||
| 	unsigned int hw_queue; | ||||
| 	int i; | ||||
|  | @ -910,8 +911,6 @@ static int carl9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb) | |||
| 	else | ||||
| 		cvif = NULL; | ||||
| 
 | ||||
| 	sta = info->control.sta; | ||||
| 
 | ||||
| 	txc = (void *)skb_push(skb, sizeof(*txc)); | ||||
| 	memset(txc, 0, sizeof(*txc)); | ||||
| 
 | ||||
|  | @ -1457,20 +1456,21 @@ err_unlock_rcu: | |||
| 	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 ieee80211_tx_info *info; | ||||
| 	struct ieee80211_sta *sta; | ||||
| 	struct ieee80211_sta *sta = control->sta; | ||||
| 	bool run; | ||||
| 
 | ||||
| 	if (unlikely(!IS_STARTED(ar))) | ||||
| 		goto err_free; | ||||
| 
 | ||||
| 	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; | ||||
| 
 | ||||
| 	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, | ||||
| 		      struct ieee80211_tx_control *control, | ||||
| 		      struct sk_buff *skb) | ||||
| { | ||||
| 	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, | ||||
| 			    struct ieee80211_tx_control *control, | ||||
| 			    struct sk_buff *skb) | ||||
| { | ||||
| 	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 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; | ||||
| 	} | ||||
| 	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: | ||||
| 	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 | ||||
|  */ | ||||
| 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_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); | ||||
| 
 | ||||
| 	/* 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) { | ||||
| 		D_DROP("Dropping - INVALID STATION: %pM\n", hdr->addr1); | ||||
| 		goto drop; | ||||
|  | @ -2859,7 +2861,9 @@ il3945_mac_stop(struct ieee80211_hw *hw) | |||
| } | ||||
| 
 | ||||
| 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; | ||||
| 
 | ||||
|  | @ -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, | ||||
| 	     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); | ||||
| 
 | ||||
| 	D_MAC80211("leave\n"); | ||||
|  |  | |||
|  | @ -1526,8 +1526,11 @@ il4965_tx_cmd_build_basic(struct il_priv *il, struct sk_buff *skb, | |||
| } | ||||
| 
 | ||||
| static void | ||||
| il4965_tx_cmd_build_rate(struct il_priv *il, struct il_tx_cmd *tx_cmd, | ||||
| 			 struct ieee80211_tx_info *info, __le16 fc) | ||||
| il4965_tx_cmd_build_rate(struct il_priv *il, | ||||
| 			 struct il_tx_cmd *tx_cmd, | ||||
| 			 struct ieee80211_tx_info *info, | ||||
| 			 struct ieee80211_sta *sta, | ||||
| 			 __le16 fc) | ||||
| { | ||||
| 	const u8 rts_retry_limit = 60; | ||||
| 	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; | ||||
| 	if ((info->control.rates[0].flags & IEEE80211_TX_RC_MCS) || rate_idx < 0 | ||||
| 	    || rate_idx > RATE_COUNT_LEGACY) | ||||
| 		rate_idx = | ||||
| 		    rate_lowest_index(&il->bands[info->band], | ||||
| 				      info->control.sta); | ||||
| 		rate_idx = rate_lowest_index(&il->bands[info->band], sta); | ||||
| 	/* For 5 GHZ band, remap mac80211 rate indices into driver indices */ | ||||
| 	if (info->band == IEEE80211_BAND_5GHZ) | ||||
| 		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 | ||||
|  */ | ||||
| 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_tx_info *info = IEEE80211_SKB_CB(skb); | ||||
| 	struct ieee80211_sta *sta = info->control.sta; | ||||
| 	struct il_station_priv *sta_priv = NULL; | ||||
| 	struct il_tx_queue *txq; | ||||
| 	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; | ||||
| 	else { | ||||
| 		/* 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) { | ||||
| 			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 */ | ||||
| 	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); | ||||
| 	/*
 | ||||
|  | @ -5828,7 +5830,9 @@ il4965_mac_stop(struct ieee80211_hw *hw) | |||
| } | ||||
| 
 | ||||
| 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; | ||||
| 
 | ||||
|  | @ -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, | ||||
| 	     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); | ||||
| 
 | ||||
| 	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); | ||||
| void il4965_hwrate_to_tx_control(struct il_priv *il, u32 rate_n_flags, | ||||
| 				 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, | ||||
| 			struct ieee80211_sta *sta, u16 tid, u16 * ssn); | ||||
| 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); | ||||
| 
 | ||||
| /* 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); | ||||
| void il4965_mac_stop(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 */ | ||||
| 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, | ||||
| 			struct ieee80211_sta *sta, u16 tid, u16 *ssn); | ||||
| 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 | ||||
| int iwl_dbgfs_register(struct iwl_priv *priv, const char *name); | ||||
| void iwl_dbgfs_unregister(struct iwl_priv *priv); | ||||
| int iwl_dbgfs_register(struct iwl_priv *priv, struct dentry *dbgfs_dir); | ||||
| #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; | ||||
| } | ||||
| static inline void iwl_dbgfs_unregister(struct iwl_priv *priv) | ||||
| { | ||||
| } | ||||
| #endif /* CONFIG_IWLWIFI_DEBUGFS */ | ||||
| 
 | ||||
| #ifdef CONFIG_IWLWIFI_DEBUG | ||||
|  |  | |||
|  | @ -2349,24 +2349,19 @@ DEBUGFS_READ_WRITE_FILE_OPS(calib_disabled); | |||
|  * 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_drv, *dir_data, *dir_rf, *dir_debug; | ||||
| 	struct dentry *dir_data, *dir_rf, *dir_debug; | ||||
| 
 | ||||
| 	dir_drv = debugfs_create_dir(name, phyd); | ||||
| 	if (!dir_drv) | ||||
| 		return -ENOMEM; | ||||
| 	priv->debugfs_dir = dbgfs_dir; | ||||
| 
 | ||||
| 	priv->debugfs_dir = dir_drv; | ||||
| 
 | ||||
| 	dir_data = debugfs_create_dir("data", dir_drv); | ||||
| 	dir_data = debugfs_create_dir("data", dbgfs_dir); | ||||
| 	if (!dir_data) | ||||
| 		goto err; | ||||
| 	dir_rf = debugfs_create_dir("rf", dir_drv); | ||||
| 	dir_rf = debugfs_create_dir("rf", dbgfs_dir); | ||||
| 	if (!dir_rf) | ||||
| 		goto err; | ||||
| 	dir_debug = debugfs_create_dir("debug", dir_drv); | ||||
| 	dir_debug = debugfs_create_dir("debug", dbgfs_dir); | ||||
| 	if (!dir_debug) | ||||
| 		goto err; | ||||
| 
 | ||||
|  | @ -2412,25 +2407,30 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) | |||
| 	/* Calibrations disabled/enabled status*/ | ||||
| 	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; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| err: | ||||
| 	IWL_ERR(priv, "Can't create the debugfs directory\n"); | ||||
| 	iwl_dbgfs_unregister(priv); | ||||
| 	IWL_ERR(priv, "failed to create the dvm debugfs entries\n"); | ||||
| 	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); | ||||
| 	} | ||||
| 
 | ||||
| 	hw->wiphy->max_remain_on_channel_duration = 1000; | ||||
| 	hw->wiphy->max_remain_on_channel_duration = 500; | ||||
| 
 | ||||
| 	hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY | | ||||
| 			    WIPHY_FLAG_DISABLE_BEACON_HINTS | | ||||
|  | @ -511,14 +511,16 @@ static void iwlagn_mac_set_wakeup(struct ieee80211_hw *hw, bool enabled) | |||
| } | ||||
| #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); | ||||
| 
 | ||||
| 	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); | ||||
| 
 | ||||
| 	if (iwlagn_tx_skb(priv, skb)) | ||||
| 	if (iwlagn_tx_skb(priv, control->sta, 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 | ||||
| 	 * can't come in at this time. | ||||
| 	 */ | ||||
| 	if (priv->ucode_loaded && priv->cur_ucode != IWL_UCODE_INIT) | ||||
| 		ieee80211_remain_on_channel_expired(priv->hw); | ||||
| 
 | ||||
| 	exit_pending = | ||||
|  | @ -994,7 +995,11 @@ static void iwl_bg_restart(struct work_struct *data) | |||
| 		iwlagn_prepare_restart(priv); | ||||
| 		mutex_unlock(&priv->mutex); | ||||
| 		iwl_cancel_deferred_work(priv); | ||||
| 		if (priv->mac80211_registered) | ||||
| 			ieee80211_restart_hw(priv->hw); | ||||
| 		else | ||||
| 			IWL_ERR(priv, | ||||
| 				"Cannot request restart before registrating with mac80211"); | ||||
| 	} else { | ||||
| 		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, | ||||
| 						 const struct iwl_cfg *cfg, | ||||
| 						 const struct iwl_fw *fw) | ||||
| 						 const struct iwl_fw *fw, | ||||
| 						 struct dentry *dbgfs_dir) | ||||
| { | ||||
| 	struct iwl_priv *priv; | ||||
| 	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)) | ||||
| 		goto out_destroy_workqueue; | ||||
| 
 | ||||
| 	if (iwl_dbgfs_register(priv, DRV_NAME)) | ||||
| 		IWL_ERR(priv, | ||||
| 			"failed to create debugfs files. Ignoring error\n"); | ||||
| 	if (iwl_dbgfs_register(priv, dbgfs_dir)) | ||||
| 		goto out_mac80211_unregister; | ||||
| 
 | ||||
| 	return op_mode; | ||||
| 
 | ||||
| out_mac80211_unregister: | ||||
| 	iwlagn_mac_unregister(priv); | ||||
| out_destroy_workqueue: | ||||
| 	iwl_tt_exit(priv); | ||||
| 	iwl_testmode_free(priv); | ||||
| 	iwl_cancel_deferred_work(priv); | ||||
| 	destroy_workqueue(priv->workqueue); | ||||
| 	priv->workqueue = NULL; | ||||
| 	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_dbgfs_unregister(priv); | ||||
| 
 | ||||
| 	iwl_testmode_free(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" : ""); | ||||
| 
 | ||||
| 	if (!(flags & CMD_ASYNC)) { | ||||
| 		cmd.flags |= CMD_WANT_SKB; | ||||
| 		cmd.flags |= CMD_WANT_SKB | CMD_WANT_HCMD; | ||||
| 		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, | ||||
| 				     struct iwl_tx_cmd *tx_cmd, | ||||
| 				     struct ieee80211_tx_info *info, | ||||
| 				     struct ieee80211_sta *sta, | ||||
| 				     __le16 fc) | ||||
| { | ||||
| 	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 || | ||||
| 			(rate_idx < 0) || (rate_idx > IWL_RATE_COUNT_LEGACY)) | ||||
| 		rate_idx = rate_lowest_index( | ||||
| 				&priv->eeprom_data->bands[info->band], | ||||
| 				info->control.sta); | ||||
| 				&priv->eeprom_data->bands[info->band], sta); | ||||
| 	/* For 5 GHZ band, remap mac80211 rate indices into driver indices */ | ||||
| 	if (info->band == IEEE80211_BAND_5GHZ) | ||||
| 		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 | ||||
|  */ | ||||
| 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_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; | ||||
| 	else { | ||||
| 		/* 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) { | ||||
| 			IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n", | ||||
| 				       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); | ||||
| 
 | ||||
| 	if (info->control.sta) | ||||
| 		sta_priv = (void *)info->control.sta->drv_priv; | ||||
| 	if (sta) | ||||
| 		sta_priv = (void *)sta->drv_priv; | ||||
| 
 | ||||
| 	if (sta_priv && sta_priv->asleep && | ||||
| 	    (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 */ | ||||
| 	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)); | ||||
| 
 | ||||
|  |  | |||
|  | @ -101,6 +101,10 @@ MODULE_VERSION(DRV_VERSION); | |||
| MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); | ||||
| MODULE_LICENSE("GPL"); | ||||
| 
 | ||||
| #ifdef CONFIG_IWLWIFI_DEBUGFS | ||||
| static struct dentry *iwl_dbgfs_root; | ||||
| #endif | ||||
| 
 | ||||
| /**
 | ||||
|  * struct iwl_drv - drv common data | ||||
|  * @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 */ | ||||
| 
 | ||||
| 	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 | ||||
|  | @ -194,7 +204,8 @@ static int iwl_alloc_fw_desc(struct iwl_drv *drv, struct fw_desc *desc, | |||
| 	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_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, | ||||
| 				       drv->trans->dev, | ||||
| 				       GFP_KERNEL, drv, iwl_ucode_callback); | ||||
| 				       GFP_KERNEL, drv, iwl_req_fw_callback); | ||||
| } | ||||
| 
 | ||||
| struct fw_img_parsing { | ||||
|  | @ -759,13 +770,57 @@ static int validate_sec_sizes(struct iwl_drv *drv, | |||
| 	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 | ||||
|  * 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_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); | ||||
| 
 | ||||
| 	if (op->ops) { | ||||
| 		const struct iwl_op_mode_ops *ops = op->ops; | ||||
| 		drv->op_mode = ops->start(drv->trans, drv->cfg, &drv->fw); | ||||
| 		drv->op_mode = _iwl_op_mode_start(drv, op); | ||||
| 
 | ||||
| 		if (!drv->op_mode) { | ||||
| 			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_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); | ||||
| 
 | ||||
| 	if (ret) { | ||||
| 		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); | ||||
| 	drv = NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	return drv; | ||||
| } | ||||
|  | @ -984,9 +1067,7 @@ void iwl_drv_stop(struct iwl_drv *drv) | |||
| { | ||||
| 	wait_for_completion(&drv->request_firmware_complete); | ||||
| 
 | ||||
| 	/* op_mode can be NULL if its start failed */ | ||||
| 	if (drv->op_mode) | ||||
| 		iwl_op_mode_stop(drv->op_mode); | ||||
| 	_iwl_op_mode_stop(drv); | ||||
| 
 | ||||
| 	iwl_dealloc_ucode(drv); | ||||
| 
 | ||||
|  | @ -1000,6 +1081,10 @@ void iwl_drv_stop(struct iwl_drv *drv) | |||
| 		list_del(&drv->list); | ||||
| 	mutex_unlock(&iwlwifi_opmode_table_mtx); | ||||
| 
 | ||||
| #ifdef CONFIG_IWLWIFI_DEBUGFS | ||||
| 	debugfs_remove_recursive(drv->dbgfs_drv); | ||||
| #endif | ||||
| 
 | ||||
| 	kfree(drv); | ||||
| } | ||||
| 
 | ||||
|  | @ -1022,15 +1107,18 @@ int iwl_opmode_register(const char *name, const struct iwl_op_mode_ops *ops) | |||
| { | ||||
| 	int i; | ||||
| 	struct iwl_drv *drv; | ||||
| 	struct iwlwifi_opmode_table *op; | ||||
| 
 | ||||
| 	mutex_lock(&iwlwifi_opmode_table_mtx); | ||||
| 	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; | ||||
| 		iwlwifi_opmode_table[i].ops = ops; | ||||
| 		list_for_each_entry(drv, &iwlwifi_opmode_table[i].drv, list) | ||||
| 			drv->op_mode = ops->start(drv->trans, drv->cfg, | ||||
| 						  &drv->fw); | ||||
| 		op->ops = ops; | ||||
| 		/* TODO: need to handle exceptional case */ | ||||
| 		list_for_each_entry(drv, &op->drv, list) | ||||
| 			drv->op_mode = _iwl_op_mode_start(drv, op); | ||||
| 
 | ||||
| 		mutex_unlock(&iwlwifi_opmode_table_mtx); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | @ -1051,12 +1139,9 @@ void iwl_opmode_deregister(const char *name) | |||
| 		iwlwifi_opmode_table[i].ops = NULL; | ||||
| 
 | ||||
| 		/* call the stop routine for all devices */ | ||||
| 		list_for_each_entry(drv, &iwlwifi_opmode_table[i].drv, list) { | ||||
| 			if (drv->op_mode) { | ||||
| 				iwl_op_mode_stop(drv->op_mode); | ||||
| 				drv->op_mode = NULL; | ||||
| 			} | ||||
| 		} | ||||
| 		list_for_each_entry(drv, &iwlwifi_opmode_table[i].drv, list) | ||||
| 			_iwl_op_mode_stop(drv); | ||||
| 
 | ||||
| 		mutex_unlock(&iwlwifi_opmode_table_mtx); | ||||
| 		return; | ||||
| 	} | ||||
|  | @ -1076,6 +1161,14 @@ static int __init iwl_drv_init(void) | |||
| 	pr_info(DRV_DESCRIPTION ", " DRV_VERSION "\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(); | ||||
| } | ||||
| module_init(iwl_drv_init); | ||||
|  | @ -1083,6 +1176,10 @@ module_init(iwl_drv_init); | |||
| static void __exit iwl_drv_exit(void) | ||||
| { | ||||
| 	iwl_pci_unregister_driver(); | ||||
| 
 | ||||
| #ifdef CONFIG_IWLWIFI_DEBUGFS | ||||
| 	debugfs_remove_recursive(iwl_dbgfs_root); | ||||
| #endif | ||||
| } | ||||
| module_exit(iwl_drv_exit); | ||||
| 
 | ||||
|  |  | |||
|  | @ -90,9 +90,9 @@ | |||
|  * 4) The bus specific component configures the bus | ||||
|  * 5) The bus specific component calls to the drv bus agnostic part | ||||
|  *    (iwl_drv_start) | ||||
|  * 6) iwl_drv_start fetches the fw ASYNC, iwl_ucode_callback | ||||
|  * 7) iwl_ucode_callback parses the fw file | ||||
|  * 8) iwl_ucode_callback starts the wifi implementation to matches the fw | ||||
|  * 6) iwl_drv_start fetches the fw ASYNC, iwl_req_fw_callback | ||||
|  * 7) iwl_req_fw_callback parses the fw file | ||||
|  * 8) iwl_req_fw_callback starts the wifi implementation to matches the fw | ||||
|  */ | ||||
| 
 | ||||
| struct iwl_drv; | ||||
|  |  | |||
|  | @ -134,7 +134,8 @@ struct iwl_cfg; | |||
| struct iwl_op_mode_ops { | ||||
| 	struct iwl_op_mode *(*start)(struct iwl_trans *trans, | ||||
| 				     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); | ||||
| 	int (*rx)(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb, | ||||
| 		  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_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 | ||||
|  *	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. | ||||
|  */ | ||||
| enum CMD_MODE { | ||||
| 	CMD_SYNC = 0, | ||||
| 	CMD_ASYNC = BIT(0), | ||||
| 	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 | ||||
|  | @ -460,6 +466,8 @@ struct iwl_trans { | |||
| 	size_t dev_cmd_headroom; | ||||
| 	char dev_cmd_pool_name[50]; | ||||
| 
 | ||||
| 	struct dentry *dbgfs_dir; | ||||
| 
 | ||||
| 	/* pointer to trans specific struct */ | ||||
| 	/*Ensure that this pointer will always be aligned to sizeof pointer */ | ||||
| 	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) | ||||
| 		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; | ||||
| 
 | ||||
| out_free_drv: | ||||
| 	iwl_drv_stop(trans_pcie->drv); | ||||
| out_free_trans: | ||||
| 	iwl_trans_pcie_free(iwl_trans); | ||||
| 	pci_set_drvdata(pdev, NULL); | ||||
|  |  | |||
|  | @ -184,6 +184,7 @@ struct iwl_queue { | |||
| 
 | ||||
| struct iwl_pcie_tx_queue_entry { | ||||
| 	struct iwl_device_cmd *cmd; | ||||
| 	struct iwl_device_cmd *copy_cmd; | ||||
| 	struct sk_buff *skb; | ||||
| 	struct iwl_cmd_meta meta; | ||||
| }; | ||||
|  |  | |||
|  | @ -421,13 +421,23 @@ static void iwl_rx_handle_rxbuf(struct iwl_trans *trans, | |||
| 		index = SEQ_TO_INDEX(sequence); | ||||
| 		cmd_index = get_cmd_index(&txq->q, index); | ||||
| 
 | ||||
| 		if (reclaim) | ||||
| 			cmd = txq->entries[cmd_index].cmd; | ||||
| 		else | ||||
| 		if (reclaim) { | ||||
| 			struct iwl_pcie_tx_queue_entry *ent; | ||||
| 			ent = &txq->entries[cmd_index]; | ||||
| 			cmd = ent->copy_cmd; | ||||
| 			WARN_ON_ONCE(!cmd && ent->meta.flags & CMD_WANT_HCMD); | ||||
| 		} else { | ||||
| 			cmd = NULL; | ||||
| 		} | ||||
| 
 | ||||
| 		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, | ||||
| 		 * 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); | ||||
| 
 | ||||
| 	/* De-alloc array of command/tx buffers */ | ||||
| 
 | ||||
| 	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].copy_cmd); | ||||
| 		} | ||||
| 
 | ||||
| 	/* De-alloc circular buffer of TFDs */ | ||||
| 	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) | ||||
| { | ||||
| 	int ret; | ||||
| 	int t = 0; | ||||
| 
 | ||||
| 	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, | ||||
| 		    CSR_HW_IF_CONFIG_REG_PREPARE); | ||||
| 
 | ||||
| 	ret = iwl_poll_bit(trans, CSR_HW_IF_CONFIG_REG, | ||||
| 			   ~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. */ | ||||
| 	do { | ||||
| 		ret = iwl_set_hw_ready(trans); | ||||
| 		if (ret >= 0) | ||||
| 			return 0; | ||||
| 
 | ||||
| 		usleep_range(200, 1000); | ||||
| 		t += 200; | ||||
| 	} while (t < 150000); | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
|  | @ -1769,7 +1769,7 @@ void iwl_dump_csr(struct iwl_trans *trans) | |||
| #define DEBUGFS_ADD_FILE(name, parent, mode) do {			\ | ||||
| 	if (!debugfs_create_file(#name, mode, parent, trans,		\ | ||||
| 				 &iwl_dbgfs_##name##_ops))		\ | ||||
| 		return -ENOMEM;						\ | ||||
| 		goto err;						\ | ||||
| } while (0) | ||||
| 
 | ||||
| /* 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(fw_restart, dir, S_IWUSR); | ||||
| 	return 0; | ||||
| 
 | ||||
| err: | ||||
| 	IWL_ERR(trans, "failed to create the trans debugfs entry\n"); | ||||
| 	return -ENOMEM; | ||||
| } | ||||
| #else | ||||
| 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; | ||||
| 	bool had_nocopy = false; | ||||
| 	int i; | ||||
| 	u8 *cmd_dest; | ||||
| 	u32 cmd_pos; | ||||
| #ifdef CONFIG_IWLWIFI_DEVICE_TRACING | ||||
| 	const void *trace_bufs[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)); | ||||
| 
 | ||||
| 	/* and copy the data that needs to be copied */ | ||||
| 
 | ||||
| 	cmd_dest = out_cmd->payload; | ||||
| 	cmd_pos = offsetof(struct iwl_device_cmd, payload); | ||||
| 	for (i = 0; i < IWL_MAX_CMD_TFDS; i++) { | ||||
| 		if (!cmd->len[i]) | ||||
| 			continue; | ||||
| 		if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY) | ||||
| 			break; | ||||
| 		memcpy(cmd_dest, cmd->data[i], cmd->len[i]); | ||||
| 		cmd_dest += cmd->len[i]; | ||||
| 		memcpy((u8 *)out_cmd + cmd_pos, cmd->data[i], 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, | ||||
|  |  | |||
|  | @ -227,7 +227,9 @@ static void lbtf_free_adapter(struct lbtf_private *priv) | |||
| 	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; | ||||
| 
 | ||||
|  |  | |||
|  | @ -709,7 +709,9 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, | |||
| 	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; | ||||
| 	struct ieee80211_tx_info *txi; | ||||
|  | @ -1727,6 +1729,7 @@ static const struct ieee80211_iface_limit hwsim_if_limits[] = { | |||
| #endif | ||||
| 				 BIT(NL80211_IFTYPE_AP) | | ||||
| 				 BIT(NL80211_IFTYPE_P2P_GO) }, | ||||
| 	{ .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) }, | ||||
| }; | ||||
| 
 | ||||
| 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_GO) | | ||||
| 			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 | | ||||
| 			    IEEE80211_HW_SIGNAL_DBM | | ||||
|  |  | |||
|  | @ -1830,12 +1830,14 @@ static inline void mwl8k_tx_count_packet(struct ieee80211_sta *sta, u8 tid) | |||
| } | ||||
| 
 | ||||
| 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 ieee80211_tx_info *tx_info; | ||||
| 	struct mwl8k_vif *mwl8k_vif; | ||||
| 	struct ieee80211_sta *sta; | ||||
| 	struct ieee80211_hdr *wh; | ||||
| 	struct mwl8k_tx_queue *txq; | ||||
| 	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; | ||||
| 
 | ||||
| 	tx_info = IEEE80211_SKB_CB(skb); | ||||
| 	sta = tx_info->control.sta; | ||||
| 	mwl8k_vif = MWL8K_VIF(tx_info->control.vif); | ||||
| 
 | ||||
| 	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_len = cpu_to_le16(skb->len); | ||||
| 	tx->rate_info = 0; | ||||
| 	if (!priv->ap_fw && tx_info->control.sta != NULL) | ||||
| 		tx->peer_id = MWL8K_STA(tx_info->control.sta)->peer_id; | ||||
| 	if (!priv->ap_fw && sta != NULL) | ||||
| 		tx->peer_id = MWL8K_STA(sta)->peer_id; | ||||
| 	else | ||||
| 		tx->peer_id = 0; | ||||
| 
 | ||||
|  | @ -4364,7 +4365,9 @@ static void mwl8k_rx_poll(unsigned long data) | |||
| /*
 | ||||
|  * 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; | ||||
| 	int index = skb_get_queue_mapping(skb); | ||||
|  | @ -4376,7 +4379,7 @@ static void mwl8k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	mwl8k_txq_xmit(hw, index, skb); | ||||
| 	mwl8k_txq_xmit(hw, index, control->sta, skb); | ||||
| } | ||||
| 
 | ||||
| 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); | ||||
| 
 | ||||
| /* 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); | ||||
| 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 | ||||
| 	 * 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_low32 = 0; | ||||
| 
 | ||||
|  |  | |||
|  | @ -676,8 +676,9 @@ int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb) | |||
| EXPORT_SYMBOL_GPL(p54_rx); | ||||
| 
 | ||||
| static void p54_tx_80211_header(struct p54_common *priv, struct sk_buff *skb, | ||||
| 				struct ieee80211_tx_info *info, u8 *queue, | ||||
| 				u32 *extra_len, u16 *flags, u16 *aid, | ||||
| 				struct ieee80211_tx_info *info, | ||||
| 				struct ieee80211_sta *sta, | ||||
| 				u8 *queue, u32 *extra_len, u16 *flags, u16 *aid, | ||||
| 				bool *burst_possible) | ||||
| { | ||||
| 	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) | ||||
| 			*aid = info->control.sta->aid; | ||||
| 		if (sta) | ||||
| 			*aid = sta->aid; | ||||
| 		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 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; | ||||
| 	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); | ||||
| 
 | ||||
| 	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. | ||||
|  */ | ||||
| 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); | ||||
| void rt2x00mac_stop(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); | ||||
| 	while (skb) { | ||||
| 		rt2x00mac_tx(rt2x00dev->hw, skb); | ||||
| 		rt2x00mac_tx(rt2x00dev->hw, NULL, skb); | ||||
| 		skb = ieee80211_get_buffered_bc(rt2x00dev->hw, vif); | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -99,7 +99,9 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, | |||
| 	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 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, | ||||
| 						struct sk_buff *skb, | ||||
| 						struct txentry_desc *txdesc, | ||||
| 						struct ieee80211_sta *sta, | ||||
| 						const struct rt2x00_rate *hwrate) | ||||
| { | ||||
| 	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 rt2x00_sta *sta_priv = NULL; | ||||
| 
 | ||||
| 	if (tx_info->control.sta) { | ||||
| 	if (sta) { | ||||
| 		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; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -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 | ||||
| 		 * when using more then one tx stream (>MCS7). | ||||
| 		 */ | ||||
| 		if (tx_info->control.sta && txdesc->u.ht.mcs > 7 && | ||||
| 		    ((tx_info->control.sta->ht_cap.cap & | ||||
| 		if (sta && txdesc->u.ht.mcs > 7 && | ||||
| 		    ((sta->ht_cap.cap & | ||||
| 		      IEEE80211_HT_CAP_SM_PS) >> | ||||
| 		     IEEE80211_HT_CAP_SM_PS_SHIFT) == | ||||
| 		    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, | ||||
| 					     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_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)) | ||||
| 		rt2x00queue_create_tx_descriptor_ht(rt2x00dev, skb, txdesc, | ||||
| 						    hwrate); | ||||
| 						   sta, hwrate); | ||||
| 	else | ||||
| 		rt2x00queue_create_tx_descriptor_plcp(rt2x00dev, skb, txdesc, | ||||
| 						      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 | ||||
| 	 * 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, | ||||
|  | @ -740,7 +742,7 @@ int rt2x00queue_update_beacon_locked(struct rt2x00_dev *rt2x00dev, | |||
| 	 * after that we are free to use the skb->cb array | ||||
| 	 * 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 | ||||
|  |  | |||
|  | @ -244,7 +244,9 @@ static irqreturn_t rtl8180_interrupt(int irq, void *dev_id) | |||
| 	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_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 */ | ||||
| 	skb_set_queue_mapping(skb, 0); | ||||
| 
 | ||||
| 	rtl8180_tx(dev, skb); | ||||
| 	rtl8180_tx(dev, NULL, skb); | ||||
| 
 | ||||
| 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 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 */ | ||||
| 	skb_set_queue_mapping(skb, 0); | ||||
| 
 | ||||
| 	rtl8187_tx(dev, skb); | ||||
| 	rtl8187_tx(dev, NULL, skb); | ||||
| 
 | ||||
| resched: | ||||
| 	/*
 | ||||
|  |  | |||
|  | @ -1341,9 +1341,8 @@ int rtl_send_smps_action(struct ieee80211_hw *hw, | |||
| 		rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0); | ||||
| 
 | ||||
| 		info->control.rates[0].idx = 0; | ||||
| 		info->control.sta = sta; | ||||
| 		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: | ||||
| 	return 0; | ||||
|  |  | |||
|  | @ -124,7 +124,9 @@ static void rtl_op_stop(struct ieee80211_hw *hw) | |||
| 	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_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)) | ||||
| 		goto err_free; | ||||
| 
 | ||||
| 	if (!rtlpriv->intf_ops->waitq_insert(hw, skb)) | ||||
| 		rtlpriv->intf_ops->adapter_tx(hw, skb, &tcb_desc); | ||||
| 	if (!rtlpriv->intf_ops->waitq_insert(hw, control->sta, skb)) | ||||
| 		rtlpriv->intf_ops->adapter_tx(hw, control->sta, skb, &tcb_desc); | ||||
| 
 | ||||
| 	return; | ||||
| 
 | ||||
|  |  | |||
|  | @ -504,7 +504,7 @@ static void _rtl_pci_tx_chk_waitq(struct ieee80211_hw *hw) | |||
| 				_rtl_update_earlymode_info(hw, skb, | ||||
| 							   &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); | ||||
| 	pdesc = &ring->desc[0]; | ||||
| 	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); | ||||
| 
 | ||||
|  | @ -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, | ||||
| 					struct ieee80211_sta *sta, | ||||
| 					struct sk_buff *skb) | ||||
| { | ||||
| 	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; | ||||
| 	u8 tid = rtl_get_tid(skb); | ||||
| 
 | ||||
|  | @ -1337,13 +1336,14 @@ static bool rtl_pci_tx_chk_waitq_insert(struct ieee80211_hw *hw, | |||
| 	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_priv *rtlpriv = rtl_priv(hw); | ||||
| 	struct rtl_sta_info *sta_entry = NULL; | ||||
| 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||||
| 	struct ieee80211_sta *sta = info->control.sta; | ||||
| 	struct rtl8192_tx_ring *ring; | ||||
| 	struct rtl_tx_desc *pdesc; | ||||
| 	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->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); | ||||
| 
 | ||||
|  |  | |||
|  | @ -596,7 +596,9 @@ bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw, | |||
| 
 | ||||
| void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, | ||||
| 			  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) | ||||
| { | ||||
| 	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_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); | ||||
| 	bool defaultadapter = true; | ||||
| 	struct ieee80211_sta *sta; | ||||
| 	u8 *pdesc = pdesc_tx; | ||||
| 	u16 seq_number; | ||||
| 	__le16 fc = hdr->frame_control; | ||||
|  |  | |||
|  | @ -713,6 +713,7 @@ struct rx_desc_92c { | |||
| void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, | ||||
| 			  struct ieee80211_hdr *hdr, | ||||
| 			  u8 *pdesc, struct ieee80211_tx_info *info, | ||||
| 			  struct ieee80211_sta *sta, | ||||
| 			  struct sk_buff *skb, u8 hw_queue, | ||||
| 			  struct rtl_tcb_desc *ptcb_desc); | ||||
| 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, | ||||
| 			  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, | ||||
| 			  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_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); | ||||
| 	bool defaultadapter = true; | ||||
| 	struct ieee80211_sta *sta = info->control.sta = info->control.sta; | ||||
| 	u8 *qc = ieee80211_get_qos_ctl(hdr); | ||||
| 	u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; | ||||
| 	u16 seq_number; | ||||
|  |  | |||
|  | @ -420,7 +420,9 @@ struct sk_buff *rtl8192c_tx_aggregate_hdl(struct ieee80211_hw *, | |||
| 					   struct sk_buff_head *); | ||||
| void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, | ||||
| 			  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, | ||||
| 			  struct rtl_tcb_desc *tcb_desc); | ||||
| 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, | ||||
| 			  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) | ||||
| { | ||||
| 	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_hal *rtlhal = rtl_hal(rtlpriv); | ||||
| 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); | ||||
| 	struct ieee80211_sta *sta = info->control.sta; | ||||
| 	u8 *pdesc = pdesc_tx; | ||||
| 	u16 seq_number; | ||||
| 	__le16 fc = hdr->frame_control; | ||||
|  |  | |||
|  | @ -730,6 +730,7 @@ struct rx_desc_92d { | |||
| void rtl92de_tx_fill_desc(struct ieee80211_hw *hw, | ||||
| 			  struct ieee80211_hdr *hdr, | ||||
| 			  u8 *pdesc, struct ieee80211_tx_info *info, | ||||
| 			  struct ieee80211_sta *sta, | ||||
| 			  struct sk_buff *skb, u8 hw_queue, | ||||
| 			  struct rtl_tcb_desc *ptcb_desc); | ||||
| 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, | ||||
| 		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) | ||||
| { | ||||
| 	struct rtl_priv *rtlpriv = rtl_priv(hw); | ||||
| 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); | ||||
| 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); | ||||
| 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); | ||||
| 	struct ieee80211_sta *sta = info->control.sta; | ||||
| 	u8 *pdesc = pdesc_tx; | ||||
| 	u16 seq_number; | ||||
| 	__le16 fc = hdr->frame_control; | ||||
|  |  | |||
|  | @ -31,6 +31,7 @@ | |||
| 
 | ||||
| void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, | ||||
| 			  u8 *pdesc, struct ieee80211_tx_info *info, | ||||
| 			  struct ieee80211_sta *sta, | ||||
| 			  struct sk_buff *skb, u8 hw_queue, | ||||
| 			  struct rtl_tcb_desc *ptcb_desc); | ||||
| 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); | ||||
| } | ||||
| 
 | ||||
| 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) | ||||
| { | ||||
| 	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 <<= 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); | ||||
| 	if (!ieee80211_has_morefrags(hdr->frame_control)) { | ||||
| 		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); | ||||
| } | ||||
| 
 | ||||
| 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_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))) | ||||
| 		goto err_free; | ||||
| 	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); | ||||
| 	return NETDEV_TX_OK; | ||||
| 
 | ||||
|  | @ -923,6 +927,7 @@ err_free: | |||
| } | ||||
| 
 | ||||
| static bool rtl_usb_tx_chk_waitq_insert(struct ieee80211_hw *hw, | ||||
| 					struct ieee80211_sta *sta, | ||||
| 					struct sk_buff *skb) | ||||
| { | ||||
| 	return false; | ||||
|  |  | |||
|  | @ -122,7 +122,7 @@ enum rt_eeprom_type { | |||
| 	EEPROM_BOOT_EFUSE, | ||||
| }; | ||||
| 
 | ||||
| enum rtl_status { | ||||
| enum ttl_status { | ||||
| 	RTL_STATUS_INTERFACE_START = 0, | ||||
| }; | ||||
| 
 | ||||
|  | @ -1418,6 +1418,7 @@ struct rtl_hal_ops { | |||
| 	void (*fill_tx_desc) (struct ieee80211_hw *hw, | ||||
| 			      struct ieee80211_hdr *hdr, u8 *pdesc_tx, | ||||
| 			      struct ieee80211_tx_info *info, | ||||
| 			      struct ieee80211_sta *sta, | ||||
| 			      struct sk_buff *skb, u8 hw_queue, | ||||
| 			      struct rtl_tcb_desc *ptcb_desc); | ||||
| 	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); | ||||
| 	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); | ||||
| 	void (*flush)(struct ieee80211_hw *hw, bool drop); | ||||
| 	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 */ | ||||
| 	void (*disable_aspm) (struct ieee80211_hw *hw); | ||||
|  |  | |||
|  | @ -354,7 +354,9 @@ out: | |||
| 	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; | ||||
| 	unsigned long flags; | ||||
|  |  | |||
|  | @ -1181,7 +1181,9 @@ out: | |||
| 	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 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); | ||||
| 	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); | ||||
| 
 | ||||
|  |  | |||
|  | @ -130,16 +130,13 @@ bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb) | |||
| } | ||||
| EXPORT_SYMBOL(wl12xx_is_dummy_packet); | ||||
| 
 | ||||
| u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||||
| 			 struct sk_buff *skb) | ||||
| static u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||||
| 				struct sk_buff *skb, struct ieee80211_sta *sta) | ||||
| { | ||||
| 	struct ieee80211_tx_info *control = IEEE80211_SKB_CB(skb); | ||||
| 
 | ||||
| 	if (control->control.sta) { | ||||
| 	if (sta) { | ||||
| 		struct wl1271_station *wl_sta; | ||||
| 
 | ||||
| 		wl_sta = (struct wl1271_station *) | ||||
| 				control->control.sta->drv_priv; | ||||
| 		wl_sta = (struct wl1271_station *)sta->drv_priv; | ||||
| 		return wl_sta->hlid; | ||||
| 	} else { | ||||
| 		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, | ||||
| 		      struct sk_buff *skb) | ||||
| 		      struct sk_buff *skb, struct ieee80211_sta *sta) | ||||
| { | ||||
| 	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; | ||||
| 
 | ||||
| 	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) || | ||||
| 	     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 */ | ||||
| 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; | ||||
| 	u32 extra = 0; | ||||
| 	int ret = 0; | ||||
| 	u32 total_len; | ||||
| 	u8 hlid; | ||||
| 	bool is_dummy; | ||||
| 	bool is_gem = false; | ||||
| 
 | ||||
|  | @ -359,9 +355,13 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif, | |||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	if (hlid == WL12XX_INVALID_LINK_ID) { | ||||
| 		wl1271_error("invalid hlid. dropping skb 0x%p", skb); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	info = IEEE80211_SKB_CB(skb); | ||||
| 
 | ||||
| 	/* TODO: handle dummy packets on multi-vifs */ | ||||
| 	is_dummy = wl12xx_is_dummy_packet(wl, skb); | ||||
| 
 | ||||
| 	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); | ||||
| 	} | ||||
| 	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, | ||||
| 				 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, | ||||
| 					      struct wl12xx_vif *wlvif) | ||||
| 					      struct wl12xx_vif *wlvif, | ||||
| 					      u8 *hlid) | ||||
| { | ||||
| 	struct sk_buff *skb = NULL; | ||||
| 	int i, h, start_hlid; | ||||
|  | @ -544,10 +540,11 @@ static struct sk_buff *wl12xx_vif_skb_dequeue(struct wl1271 *wl, | |||
| 	if (!skb) | ||||
| 		wlvif->last_tx_hlid = 0; | ||||
| 
 | ||||
| 	*hlid = wlvif->last_tx_hlid; | ||||
| 	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; | ||||
| 	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) */ | ||||
| 	if (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) { | ||||
| 				wl->last_wlvif = wlvif; | ||||
| 				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 */ | ||||
| 	if (!skb) | ||||
| 	if (!skb) { | ||||
| 		skb = wl12xx_lnk_skb_dequeue(wl, &wl->links[wl->system_hlid]); | ||||
| 		*hlid = wl->system_hlid; | ||||
| 	} | ||||
| 
 | ||||
| 	/* do a new pass over the wlvif list */ | ||||
| 	if (!skb) { | ||||
| 		wl12xx_for_each_wlvif(wl, wlvif) { | ||||
| 			skb = wl12xx_vif_skb_dequeue(wl, wlvif); | ||||
| 			skb = wl12xx_vif_skb_dequeue(wl, wlvif, hlid); | ||||
| 			if (skb) { | ||||
| 				wl->last_wlvif = wlvif; | ||||
| 				break; | ||||
|  | @ -591,6 +590,7 @@ static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl) | |||
| 		int q; | ||||
| 
 | ||||
| 		skb = wl->dummy_packet; | ||||
| 		*hlid = wl->system_hlid; | ||||
| 		q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); | ||||
| 		spin_lock_irqsave(&wl->wl_lock, flags); | ||||
| 		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, | ||||
| 				  struct sk_buff *skb) | ||||
| 				  struct sk_buff *skb, u8 hlid) | ||||
| { | ||||
| 	unsigned long flags; | ||||
| 	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)) { | ||||
| 		set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags); | ||||
| 	} else { | ||||
| 		u8 hlid = wl12xx_tx_get_hlid(wl, wlvif, skb); | ||||
| 		skb_queue_head(&wl->links[hlid].tx_queue[q], skb); | ||||
| 
 | ||||
| 		/* 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}; | ||||
| 	int ret = 0; | ||||
| 	int bus_ret = 0; | ||||
| 	u8 hlid; | ||||
| 
 | ||||
| 	if (unlikely(wl->state == WL1271_STATE_OFF)) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	while ((skb = wl1271_skb_dequeue(wl))) { | ||||
| 	while ((skb = wl1271_skb_dequeue(wl, &hlid))) { | ||||
| 		struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||||
| 		bool has_data = false; | ||||
| 
 | ||||
| 		wlvif = NULL; | ||||
| 		if (!wl12xx_is_dummy_packet(wl, skb) && 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); | ||||
| 		ret = wl1271_prepare_tx_frame(wl, wlvif, skb, buf_offset); | ||||
| 		ret = wl1271_prepare_tx_frame(wl, wlvif, skb, buf_offset, | ||||
| 					      hlid); | ||||
| 		if (ret == -EAGAIN) { | ||||
| 			/*
 | ||||
| 			 * Aggregation buffer is full. | ||||
| 			 * 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, | ||||
| 							    last_len); | ||||
|  | @ -722,7 +725,7 @@ int wlcore_tx_work_locked(struct wl1271 *wl) | |||
| 			 * Firmware buffer is full. | ||||
| 			 * 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 */ | ||||
| 			set_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); | ||||
| 			goto out_ack; | ||||
|  | @ -732,7 +735,7 @@ int wlcore_tx_work_locked(struct wl1271 *wl) | |||
| 				 * fw still expects dummy packet, | ||||
| 				 * so re-enqueue it | ||||
| 				 */ | ||||
| 				wl1271_skb_queue_head(wl, wlvif, skb); | ||||
| 				wl1271_skb_queue_head(wl, wlvif, skb, hlid); | ||||
| 			else | ||||
| 				ieee80211_free_txskb(wl->hw, skb); | ||||
| 			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, | ||||
| 				enum ieee80211_band rate_band); | ||||
| 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, | ||||
| 		      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_handle_tx_low_watermark(struct wl1271 *wl); | ||||
| 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 | ||||
|  * 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 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); | ||||
| 		if (!skb) | ||||
| 			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; | ||||
| } | ||||
| 
 | ||||
| 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; | ||||
| 
 | ||||
|  |  | |||
|  | @ -515,6 +515,26 @@ struct bcma_pflash { | |||
| 	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 { | ||||
| 	void *regs; | ||||
| 	unsigned long clockspeed; | ||||
|  | @ -535,6 +555,12 @@ struct bcma_drv_cc { | |||
| 	struct bcma_chipcommon_pmu pmu; | ||||
| #ifdef CONFIG_BCMA_DRIVER_MIPS | ||||
| 	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; | ||||
| 	struct bcma_serial_port serial_ports[4]; | ||||
|  |  | |||
|  | @ -85,4 +85,6 @@ | |||
| 							 * (2 ZettaBytes), high 32 bits | ||||
| 							 */ | ||||
| 
 | ||||
| #define BCMA_SFLASH			0x1c000000 | ||||
| 
 | ||||
| #endif /* LINUX_BCMA_REGS_H_ */ | ||||
|  |  | |||
|  | @ -565,6 +565,14 @@ | |||
|  *	%NL80211_ATTR_IFINDEX is now on %NL80211_ATTR_WIPHY_FREQ with | ||||
|  *	%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_AFTER_LAST: internal use | ||||
|  */ | ||||
|  | @ -708,6 +716,9 @@ enum nl80211_commands { | |||
| 
 | ||||
| 	NL80211_CMD_CH_SWITCH_NOTIFY, | ||||
| 
 | ||||
| 	NL80211_CMD_START_P2P_DEVICE, | ||||
| 	NL80211_CMD_STOP_P2P_DEVICE, | ||||
| 
 | ||||
| 	/* add new commands above here */ | ||||
| 
 | ||||
| 	/* used to define NL80211_CMD_MAX below */ | ||||
|  | @ -1575,6 +1586,10 @@ enum nl80211_attrs { | |||
|  * @NL80211_IFTYPE_MESH_POINT: mesh point | ||||
|  * @NL80211_IFTYPE_P2P_CLIENT: P2P client | ||||
|  * @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 | ||||
|  * @NUM_NL80211_IFTYPES: number of defined interface types | ||||
|  * | ||||
|  | @ -1593,6 +1608,7 @@ enum nl80211_iftype { | |||
| 	NL80211_IFTYPE_MESH_POINT, | ||||
| 	NL80211_IFTYPE_P2P_CLIENT, | ||||
| 	NL80211_IFTYPE_P2P_GO, | ||||
| 	NL80211_IFTYPE_P2P_DEVICE, | ||||
| 
 | ||||
| 	/* keep last */ | ||||
| 	NUM_NL80211_IFTYPES, | ||||
|  | @ -2994,12 +3010,18 @@ enum nl80211_ap_sme_features { | |||
|  * @NL80211_FEATURE_CELL_BASE_REG_HINTS: This driver has been tested | ||||
|  *	to work properly to suppport receiving regulatory hints from | ||||
|  *	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 { | ||||
| 	NL80211_FEATURE_SK_TX_STATUS			= 1 << 0, | ||||
| 	NL80211_FEATURE_HT_IBSS				= 1 << 1, | ||||
| 	NL80211_FEATURE_INACTIVITY_TIMER		= 1 << 2, | ||||
| 	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 */ | ||||
| 
 | ||||
| 
 | ||||
| #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 /* RFKILL_H */ | ||||
|  |  | |||
|  | @ -1439,7 +1439,8 @@ struct cfg80211_gtk_rekey_data { | |||
|  * @add_virtual_intf: create a new virtual interface with the given name, | ||||
|  *	must set the struct wireless_dev's iftype. Beware: You must create | ||||
|  *	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 | ||||
|  * | ||||
|  | @ -1618,6 +1619,9 @@ struct cfg80211_gtk_rekey_data { | |||
|  * @get_channel: Get the current operating channel for the virtual interface. | ||||
|  *	For monitor interfaces, it should return %NULL unless there's a single | ||||
|  *	current monitoring channel. | ||||
|  * | ||||
|  * @start_p2p_device: Start the given P2P device. | ||||
|  * @stop_p2p_device: Stop the given P2P device. | ||||
|  */ | ||||
| struct cfg80211_ops { | ||||
| 	int	(*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); | ||||
|  | @ -1834,6 +1838,11 @@ struct cfg80211_ops { | |||
| 		(*get_channel)(struct wiphy *wiphy, | ||||
| 			       struct wireless_dev *wdev, | ||||
| 			       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 | ||||
|  * @beacon_interval: beacon interval used on this device for transmitting | ||||
|  *	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 wiphy *wiphy; | ||||
|  | @ -2415,7 +2426,9 @@ struct wireless_dev { | |||
| 
 | ||||
| 	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 */ | ||||
| 	u8 ssid[IEEE80211_MAX_SSID_LEN]; | ||||
|  | @ -2463,6 +2476,13 @@ struct wireless_dev { | |||
| #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 | ||||
|  * | ||||
|  | @ -3530,6 +3550,22 @@ void cfg80211_ch_switch_notify(struct net_device *dev, int freq, | |||
|  */ | ||||
| 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. */ | ||||
| 
 | ||||
| /* 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 | ||||
|  *     the MCS index. | ||||
|  * | ||||
|  * IEEE80211_RADIOTAP_AMPDU_STATUS	u32, u16, u8, u8	unitless | ||||
|  * | ||||
|  *	Contains the AMPDU information for the subframe. | ||||
|  */ | ||||
| enum ieee80211_radiotap_type { | ||||
| 	IEEE80211_RADIOTAP_TSFT = 0, | ||||
|  | @ -205,6 +208,7 @@ enum ieee80211_radiotap_type { | |||
| 	IEEE80211_RADIOTAP_DATA_RETRIES = 17, | ||||
| 
 | ||||
| 	IEEE80211_RADIOTAP_MCS = 19, | ||||
| 	IEEE80211_RADIOTAP_AMPDU_STATUS = 20, | ||||
| 
 | ||||
| 	/* valid in every it_present bitmap, even vendor namespaces */ | ||||
| 	IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE = 29, | ||||
|  | @ -270,6 +274,13 @@ enum ieee80211_radiotap_type { | |||
| #define IEEE80211_RADIOTAP_MCS_FMT_GF		0x08 | ||||
| #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 */ | ||||
| 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_SSID: SSID 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 { | ||||
| 	BSS_CHANGED_ASSOC		= 1<<0, | ||||
|  | @ -190,6 +191,7 @@ enum ieee80211_bss_change { | |||
| 	BSS_CHANGED_IDLE		= 1<<14, | ||||
| 	BSS_CHANGED_SSID		= 1<<15, | ||||
| 	BSS_CHANGED_AP_PROBE_RESP	= 1<<16, | ||||
| 	BSS_CHANGED_PS			= 1<<17, | ||||
| 
 | ||||
| 	/* 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 | ||||
|  *	hardware config which may be more appropriate depending on what | ||||
|  *	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_len: Length of SSID given in @ssid. | ||||
|  * @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 qos; | ||||
| 	bool idle; | ||||
| 	bool ps; | ||||
| 	u8 ssid[IEEE80211_MAX_SSID_LEN]; | ||||
| 	size_t ssid_len; | ||||
| 	bool hidden_ssid; | ||||
|  | @ -522,9 +527,6 @@ struct ieee80211_tx_rate { | |||
|  *  (2) driver internal use (if applicable) | ||||
|  *  (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 | ||||
|  * @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 | ||||
|  | @ -555,6 +557,7 @@ struct ieee80211_tx_info { | |||
| 					struct ieee80211_tx_rate rates[ | ||||
| 						IEEE80211_TX_MAX_RATES]; | ||||
| 					s8 rts_cts_rate_idx; | ||||
| 					/* 3 bytes free */ | ||||
| 				}; | ||||
| 				/* only needed before rate control */ | ||||
| 				unsigned long jiffies; | ||||
|  | @ -562,7 +565,7 @@ struct ieee80211_tx_info { | |||
| 			/* NB: vif can be NULL for injected frames */ | ||||
| 			struct ieee80211_vif *vif; | ||||
| 			struct ieee80211_key_conf *hw_key; | ||||
| 			struct ieee80211_sta *sta; | ||||
| 			/* 8 bytes free */ | ||||
| 		} control; | ||||
| 		struct { | ||||
| 			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 | ||||
|  *	the driver fills this value it should add %IEEE80211_RADIOTAP_MCS_HAVE_FMT | ||||
|  *	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 { | ||||
| 	RX_FLAG_MMIC_ERROR	= 1<<0, | ||||
| 	RX_FLAG_DECRYPTED	= 1<<1, | ||||
| 	RX_FLAG_MMIC_STRIPPED	= 1<<3, | ||||
| 	RX_FLAG_IV_STRIPPED	= 1<<4, | ||||
| 	RX_FLAG_FAILED_FCS_CRC	= 1<<5, | ||||
| 	RX_FLAG_FAILED_PLCP_CRC = 1<<6, | ||||
| 	RX_FLAG_MACTIME_MPDU	= 1<<7, | ||||
| 	RX_FLAG_SHORTPRE	= 1<<8, | ||||
| 	RX_FLAG_HT		= 1<<9, | ||||
| 	RX_FLAG_40MHZ		= 1<<10, | ||||
| 	RX_FLAG_SHORT_GI	= 1<<11, | ||||
| 	RX_FLAG_NO_SIGNAL_VAL	= 1<<12, | ||||
| 	RX_FLAG_HT_GF		= 1<<13, | ||||
| 	RX_FLAG_MMIC_ERROR		= BIT(0), | ||||
| 	RX_FLAG_DECRYPTED		= BIT(1), | ||||
| 	RX_FLAG_MMIC_STRIPPED		= BIT(3), | ||||
| 	RX_FLAG_IV_STRIPPED		= BIT(4), | ||||
| 	RX_FLAG_FAILED_FCS_CRC		= BIT(5), | ||||
| 	RX_FLAG_FAILED_PLCP_CRC 	= BIT(6), | ||||
| 	RX_FLAG_MACTIME_MPDU		= BIT(7), | ||||
| 	RX_FLAG_SHORTPRE		= BIT(8), | ||||
| 	RX_FLAG_HT			= BIT(9), | ||||
| 	RX_FLAG_40MHZ			= BIT(10), | ||||
| 	RX_FLAG_SHORT_GI		= BIT(11), | ||||
| 	RX_FLAG_NO_SIGNAL_VAL		= BIT(12), | ||||
| 	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) | ||||
|  * @flag: %RX_FLAG_* | ||||
|  * @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 { | ||||
| 	u64 mactime; | ||||
| 	u32 device_timestamp; | ||||
| 	u16 flag; | ||||
| 	u32 ampdu_reference; | ||||
| 	u32 flag; | ||||
| 	u16 freq; | ||||
| 	u8 rate_idx; | ||||
| 	u8 rx_flags; | ||||
| 	u8 band; | ||||
| 	u8 antenna; | ||||
| 	s8 signal; | ||||
| 	u8 ampdu_delimiter_crc; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  | @ -1073,6 +1101,16 @@ enum sta_notify_cmd { | |||
| 	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 | ||||
|  * | ||||
|  | @ -1203,6 +1241,10 @@ enum sta_notify_cmd { | |||
|  *	queue mapping in order to use different queues (not just one per AC) | ||||
|  *	for different virtual interfaces. See the doc section on HW queue | ||||
|  *	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 { | ||||
| 	IEEE80211_HW_HAS_RATE_CONTROL			= 1<<0, | ||||
|  | @ -1230,6 +1272,7 @@ enum ieee80211_hw_flags { | |||
| 	IEEE80211_HW_AP_LINK_PS				= 1<<22, | ||||
| 	IEEE80211_HW_TX_AMPDU_SETUP_IN_HW		= 1<<23, | ||||
| 	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 | ||||
|  *	to this 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 { | ||||
| 	IEEE80211_RC_BW_CHANGED		= BIT(0), | ||||
| 	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. | ||||
|  */ | ||||
| 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); | ||||
| 	void (*stop)(struct ieee80211_hw *hw); | ||||
| #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, | ||||
| 				const u8 *addr[], const size_t *len, u8 *mac) | ||||
| { | ||||
| 	u8 scratch[2 * AES_BLOCK_SIZE]; | ||||
| 	u8 *cbc, *pad; | ||||
| 	u8 cbc[AES_BLOCK_SIZE], pad[AES_BLOCK_SIZE]; | ||||
| 	const u8 *pos, *end; | ||||
| 	size_t i, e, left, total_len; | ||||
| 
 | ||||
| 	cbc = scratch; | ||||
| 	pad = scratch + AES_BLOCK_SIZE; | ||||
| 
 | ||||
| 	memset(cbc, 0, AES_BLOCK_SIZE); | ||||
| 
 | ||||
| 	total_len = 0; | ||||
|  |  | |||
|  | @ -102,6 +102,18 @@ static int ieee80211_change_iface(struct wiphy *wiphy, | |||
| 	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, | ||||
| 				  struct net_device *dev, | ||||
| 				  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)) { | ||||
| 		struct ieee80211_supported_band *sband; | ||||
| 		sband = sta->local->hw.wiphy->bands[ | ||||
| 				sta->local->hw.conf.channel->band]; | ||||
| 				sta->local->oper_channel->band]; | ||||
| 		rate->legacy = sband->bitrates[idx].bitrate; | ||||
| 	} else | ||||
| 		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, | ||||
| 				    const u8 *resp, size_t resp_len) | ||||
| { | ||||
| 	struct sk_buff *new, *old; | ||||
| 	struct probe_resp *new, *old; | ||||
| 
 | ||||
| 	if (!resp || !resp_len) | ||||
| 		return 1; | ||||
| 
 | ||||
| 	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) | ||||
| 		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); | ||||
| 	if (old) { | ||||
| 		/* TODO: use call_rcu() */ | ||||
| 		synchronize_rcu(); | ||||
| 		dev_kfree_skb(old); | ||||
| 	} | ||||
| 	if (old) | ||||
| 		kfree_rcu(old, rcu_head); | ||||
| 
 | ||||
| 	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)
 | ||||
| 	 * 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); | ||||
| 	msg->len = htons(6); | ||||
| 	msg->dsap = 0; | ||||
|  | @ -1285,9 +1295,10 @@ static int ieee80211_change_station(struct wiphy *wiphy, | |||
| 	mutex_unlock(&local->sta_mtx); | ||||
| 
 | ||||
| 	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_vif(sdata); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
|  | @ -1661,7 +1672,7 @@ static int ieee80211_change_bss(struct wiphy *wiphy, | |||
| 	} | ||||
| 
 | ||||
| 	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; | ||||
| 		changed |= BSS_CHANGED_ERP_SLOT; | ||||
| 	} | ||||
|  | @ -1775,6 +1786,7 @@ static int ieee80211_scan(struct wiphy *wiphy, | |||
| 	case NL80211_IFTYPE_ADHOC: | ||||
| 	case NL80211_IFTYPE_MESH_POINT: | ||||
| 	case NL80211_IFTYPE_P2P_CLIENT: | ||||
| 	case NL80211_IFTYPE_P2P_DEVICE: | ||||
| 		break; | ||||
| 	case NL80211_IFTYPE_P2P_GO: | ||||
| 		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) | ||||
| { | ||||
| 	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; | ||||
| 
 | ||||
| 	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_recalc_ps(local, -1); | ||||
| 	ieee80211_recalc_ps_vif(sdata); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
|  | @ -2461,6 +2474,9 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, | |||
| 		if (!sdata->u.mgd.associated) | ||||
| 			need_offchan = true; | ||||
| 		break; | ||||
| 	case NL80211_IFTYPE_P2P_DEVICE: | ||||
| 		need_offchan = true; | ||||
| 		break; | ||||
| 	default: | ||||
| 		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) | ||||
| { | ||||
| 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||||
| 	struct ieee80211_local *local = sdata->local; | ||||
| 	struct ieee80211_tdls_data *tf; | ||||
| 
 | ||||
| 	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 = | ||||
| 			cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); | ||||
| 
 | ||||
| 		ieee80211_add_srates_ie(sdata, skb, false); | ||||
| 		ieee80211_add_ext_srates_ie(sdata, skb, false); | ||||
| 		ieee80211_add_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); | ||||
| 		break; | ||||
| 	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 = | ||||
| 			cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); | ||||
| 
 | ||||
| 		ieee80211_add_srates_ie(sdata, skb, false); | ||||
| 		ieee80211_add_ext_srates_ie(sdata, skb, false); | ||||
| 		ieee80211_add_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); | ||||
| 		break; | ||||
| 	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) | ||||
| { | ||||
| 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||||
| 	struct ieee80211_local *local = sdata->local; | ||||
| 	struct ieee80211_mgmt *mgmt; | ||||
| 
 | ||||
| 	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 = | ||||
| 			cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); | ||||
| 
 | ||||
| 		ieee80211_add_srates_ie(sdata, skb, false); | ||||
| 		ieee80211_add_ext_srates_ie(sdata, skb, false); | ||||
| 		ieee80211_add_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); | ||||
| 		break; | ||||
| 	default: | ||||
|  | @ -3005,6 +3029,8 @@ struct cfg80211_ops mac80211_config_ops = { | |||
| 	.add_virtual_intf = ieee80211_add_iface, | ||||
| 	.del_virtual_intf = ieee80211_del_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, | ||||
| 	.del_key = ieee80211_del_key, | ||||
| 	.get_key = ieee80211_get_key, | ||||
|  |  | |||
|  | @ -63,8 +63,6 @@ DEBUGFS_READONLY_FILE(user_power, "%d", | |||
| 		      local->user_power_level); | ||||
| DEBUGFS_READONLY_FILE(power, "%d", | ||||
| 		      local->hw.conf.power_level); | ||||
| DEBUGFS_READONLY_FILE(frequency, "%d", | ||||
| 		      local->hw.conf.channel->center_freq); | ||||
| DEBUGFS_READONLY_FILE(total_ps_buffered, "%d", | ||||
| 		      local->total_ps_buffered); | ||||
| DEBUGFS_READONLY_FILE(wep_iv, "%#08x", | ||||
|  | @ -91,33 +89,6 @@ static const struct file_operations reset_ops = { | |||
| 	.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, | ||||
| 			    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(channel_type); | ||||
| DEBUGFS_READONLY_FILE_OPS(queues); | ||||
| 
 | ||||
| /* statistics stuff */ | ||||
|  | @ -272,12 +242,10 @@ void debugfs_hw_add(struct ieee80211_local *local) | |||
| 
 | ||||
| 	local->debugfs.keys = debugfs_create_dir("keys", phyd); | ||||
| 
 | ||||
| 	DEBUGFS_ADD(frequency); | ||||
| 	DEBUGFS_ADD(total_ps_buffered); | ||||
| 	DEBUGFS_ADD(wep_iv); | ||||
| 	DEBUGFS_ADD(queues); | ||||
| 	DEBUGFS_ADD_MODE(reset, 0200); | ||||
| 	DEBUGFS_ADD(channel_type); | ||||
| 	DEBUGFS_ADD(hwflags); | ||||
| 	DEBUGFS_ADD(user_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), | ||||
| 	     "%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 * | ||||
|  | @ -22,9 +22,11 @@ get_bss_sdata(struct ieee80211_sub_if_data *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, | ||||
|  | @ -526,6 +528,9 @@ static inline void drv_sta_rc_update(struct ieee80211_local *local, | |||
| 	sdata = get_bss_sdata(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); | ||||
| 	if (local->ops->sta_rc_update) | ||||
| 		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)); | ||||
| 	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||||
| 					  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->bssid, ifibss->bssid, ETH_ALEN); | ||||
| 	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, | ||||
| 		  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); | ||||
| 	cfg80211_put_bss(bss); | ||||
| 	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_local *local = sdata->local; | ||||
| 	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 | ||||
|  | @ -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); | ||||
| 		} | ||||
| 
 | ||||
| 		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_local *local = sdata->local; | ||||
| 	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 | ||||
|  | @ -759,7 +762,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) | |||
| 				return; | ||||
| 			} | ||||
| 			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
 | ||||
| 			 * scanning. */ | ||||
|  |  | |||
|  | @ -193,8 +193,6 @@ struct ieee80211_tx_data { | |||
| 	struct sta_info *sta; | ||||
| 	struct ieee80211_key *key; | ||||
| 
 | ||||
| 	struct ieee80211_channel *channel; | ||||
| 
 | ||||
| 	unsigned int flags; | ||||
| }; | ||||
| 
 | ||||
|  | @ -274,9 +272,15 @@ struct beacon_data { | |||
| 	struct rcu_head rcu_head; | ||||
| }; | ||||
| 
 | ||||
| struct probe_resp { | ||||
| 	struct rcu_head rcu_head; | ||||
| 	int len; | ||||
| 	u8 data[0]; | ||||
| }; | ||||
| 
 | ||||
| struct ieee80211_if_ap { | ||||
| 	struct beacon_data __rcu *beacon; | ||||
| 	struct sk_buff __rcu *probe_resp; | ||||
| 	struct probe_resp __rcu *probe_resp; | ||||
| 
 | ||||
| 	struct list_head vlans; | ||||
| 
 | ||||
|  | @ -359,6 +363,7 @@ enum ieee80211_sta_flags { | |||
| 	IEEE80211_STA_NULLFUNC_ACKED	= BIT(8), | ||||
| 	IEEE80211_STA_RESET_SIGNAL_AVE	= BIT(9), | ||||
| 	IEEE80211_STA_DISABLE_40MHZ	= BIT(10), | ||||
| 	IEEE80211_STA_DISABLE_VHT	= BIT(11), | ||||
| }; | ||||
| 
 | ||||
| struct ieee80211_mgd_auth_data { | ||||
|  | @ -1075,6 +1080,8 @@ struct ieee80211_local { | |||
| 	struct idr ack_status_frames; | ||||
| 	spinlock_t ack_status_lock; | ||||
| 
 | ||||
| 	struct ieee80211_sub_if_data __rcu *p2p_sdata; | ||||
| 
 | ||||
| 	/* dummy netdev for use w/ NAPI */ | ||||
| 	struct net_device napi_dev; | ||||
| 
 | ||||
|  | @ -1131,7 +1138,7 @@ struct ieee802_11_elems { | |||
| 	u8 *prep; | ||||
| 	u8 *perr; | ||||
| 	struct ieee80211_rann_ie *rann; | ||||
| 	u8 *ch_switch_elem; | ||||
| 	struct ieee80211_channel_sw_ie *ch_switch_ie; | ||||
| 	u8 *country_elem; | ||||
| 	u8 *pwr_constr_elem; | ||||
| 	u8 *quiet_elem;	/* first quite element */ | ||||
|  | @ -1157,7 +1164,6 @@ struct ieee802_11_elems { | |||
| 	u8 preq_len; | ||||
| 	u8 prep_len; | ||||
| 	u8 perr_len; | ||||
| 	u8 ch_switch_elem_len; | ||||
| 	u8 country_elem_len; | ||||
| 	u8 pwr_constr_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, | ||||
| 			   struct ieee80211_sub_if_data *sdata); | ||||
| 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, | ||||
| 				  unsigned long data, void *dummy); | ||||
| 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_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata, | ||||
| 				    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) | ||||
| { | ||||
|  | @ -1425,7 +1434,6 @@ void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, | |||
| 			     struct ieee80211_hdr *hdr); | ||||
| void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, | ||||
| 			     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, | ||||
| 				     enum queue_stop_reason reason); | ||||
|  | @ -1457,13 +1465,15 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
| 			     u8 channel); | ||||
| struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | ||||
| 					  u8 *dst, u32 ratemask, | ||||
| 					  struct ieee80211_channel *chan, | ||||
| 					  const u8 *ssid, size_t ssid_len, | ||||
| 					  const u8 *ie, size_t ie_len, | ||||
| 					  bool directed); | ||||
| void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | ||||
| 			      const u8 *ssid, size_t ssid_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, | ||||
| 				  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, | ||||
| 			       u32 cap); | ||||
| 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, | ||||
| 				struct sk_buff *skb, bool need_basic); | ||||
| 				struct sk_buff *skb, bool need_basic, | ||||
| 				enum ieee80211_band band); | ||||
| 
 | ||||
| /* channel management */ | ||||
| enum ieee80211_chan_mode { | ||||
|  |  | |||
|  | @ -100,6 +100,10 @@ static u32 __ieee80211_recalc_idle(struct ieee80211_local *local) | |||
| 			sdata->vif.bss_conf.idle = true; | ||||
| 			continue; | ||||
| 		} | ||||
| 
 | ||||
| 		if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) | ||||
| 			continue; | ||||
| 
 | ||||
| 		/* count everything else */ | ||||
| 		sdata->vif.bss_conf.idle = false; | ||||
| 		count++; | ||||
|  | @ -121,7 +125,8 @@ static u32 __ieee80211_recalc_idle(struct ieee80211_local *local) | |||
| 
 | ||||
| 	list_for_each_entry(sdata, &local->interfaces, list) { | ||||
| 		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; | ||||
| 		if (sdata->old_idle == sdata->vif.bss_conf.idle) | ||||
| 			continue; | ||||
|  | @ -204,6 +209,8 @@ static inline int identical_mac_addr_allowed(int type1, int type2) | |||
| { | ||||
| 	return type1 == 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_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 | ||||
|  * 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 sta_info *sta; | ||||
| 	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_MONITOR: | ||||
| 	case NL80211_IFTYPE_ADHOC: | ||||
| 	case NL80211_IFTYPE_P2P_DEVICE: | ||||
| 		/* no special treatment */ | ||||
| 		break; | ||||
| 	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 | ||||
| 	 * 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, | ||||
| 		       local->hw.wiphy->perm_addr, | ||||
| 		       ETH_ALEN); | ||||
|  | @ -536,15 +545,23 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) | |||
| 			local->fif_probe_req++; | ||||
| 		} | ||||
| 
 | ||||
| 		if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE) | ||||
| 			changed |= ieee80211_reset_erp_info(sdata); | ||||
| 		ieee80211_bss_info_change_notify(sdata, changed); | ||||
| 
 | ||||
| 		if (sdata->vif.type == NL80211_IFTYPE_STATION || | ||||
| 		    sdata->vif.type == NL80211_IFTYPE_ADHOC || | ||||
| 		    sdata->vif.type == NL80211_IFTYPE_AP) | ||||
| 		switch (sdata->vif.type) { | ||||
| 		case NL80211_IFTYPE_STATION: | ||||
| 		case NL80211_IFTYPE_ADHOC: | ||||
| 		case NL80211_IFTYPE_AP: | ||||
| 		case NL80211_IFTYPE_MESH_POINT: | ||||
| 			netif_carrier_off(dev); | ||||
| 		else | ||||
| 			break; | ||||
| 		case NL80211_IFTYPE_WDS: | ||||
| 		case NL80211_IFTYPE_P2P_DEVICE: | ||||
| 			break; | ||||
| 		default: | ||||
| 			netif_carrier_on(dev); | ||||
| 		} | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * 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); | ||||
| 		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); | ||||
| 
 | ||||
| 	if (dev) | ||||
| 		netif_tx_start_all_queues(dev); | ||||
| 
 | ||||
| 	return 0; | ||||
|  | @ -631,7 +652,7 @@ static int ieee80211_open(struct net_device *dev) | |||
| 	if (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, | ||||
|  | @ -652,6 +673,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
| 	/*
 | ||||
| 	 * Stop TX on this interface first. | ||||
| 	 */ | ||||
| 	if (sdata->dev) | ||||
| 		netif_tx_stop_all_queues(sdata->dev); | ||||
| 
 | ||||
| 	ieee80211_roc_purge(sdata); | ||||
|  | @ -691,6 +713,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
| 		local->fif_probe_req--; | ||||
| 	} | ||||
| 
 | ||||
| 	if (sdata->dev) { | ||||
| 		netif_addr_lock_bh(sdata->dev); | ||||
| 		spin_lock_bh(&local->filter_lock); | ||||
| 		__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); | ||||
| 
 | ||||
| 		ieee80211_configure_filter(local); | ||||
| 	} | ||||
| 
 | ||||
| 	del_timer_sync(&local->dynamic_ps_timer); | ||||
| 	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 beacon_data *old_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); | ||||
| 
 | ||||
| 		/* 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); | ||||
| 		synchronize_rcu(); | ||||
| 		kfree(old_beacon); | ||||
| 		kfree_skb(old_probe_resp); | ||||
| 		kfree(old_probe_resp); | ||||
| 
 | ||||
| 		/* down all dependent devices, that is 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_configure_filter(local); | ||||
| 		break; | ||||
| 	case NL80211_IFTYPE_P2P_DEVICE: | ||||
| 		/* relies on synchronize_rcu() below */ | ||||
| 		rcu_assign_pointer(local->p2p_sdata, NULL); | ||||
| 		/* fall through */ | ||||
| 	default: | ||||
| 		flush_work(&sdata->work); | ||||
| 		/*
 | ||||
|  | @ -770,14 +798,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
| 		synchronize_rcu(); | ||||
| 		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, | ||||
| 		 * 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 | ||||
|  * 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; | ||||
| 	int flushed; | ||||
| 	int i; | ||||
|  | @ -900,6 +919,11 @@ static void ieee80211_teardown_sdata(struct net_device *dev) | |||
| 	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, | ||||
| 					 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 = { | ||||
| 	.ndo_open		= ieee80211_open, | ||||
| 	.ndo_stop		= ieee80211_stop, | ||||
| 	.ndo_uninit		= ieee80211_teardown_sdata, | ||||
| 	.ndo_uninit		= ieee80211_uninit, | ||||
| 	.ndo_start_xmit		= ieee80211_subif_start_xmit, | ||||
| 	.ndo_set_rx_mode	= ieee80211_set_multicast_list, | ||||
| 	.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 = { | ||||
| 	.ndo_open		= ieee80211_open, | ||||
| 	.ndo_stop		= ieee80211_stop, | ||||
| 	.ndo_uninit		= ieee80211_teardown_sdata, | ||||
| 	.ndo_uninit		= ieee80211_uninit, | ||||
| 	.ndo_start_xmit		= ieee80211_monitor_start_xmit, | ||||
| 	.ndo_set_rx_mode	= ieee80211_set_multicast_list, | ||||
| 	.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 */ | ||||
| 	sdata->vif.type = type; | ||||
| 	sdata->vif.p2p = false; | ||||
| 	sdata->dev->netdev_ops = &ieee80211_dataif_ops; | ||||
| 	sdata->wdev.iftype = type; | ||||
| 
 | ||||
| 	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; | ||||
| 
 | ||||
| 	/* only monitor differs */ | ||||
| 	/* only monitor/p2p-device differ */ | ||||
| 	if (sdata->dev) { | ||||
| 		sdata->dev->netdev_ops = &ieee80211_dataif_ops; | ||||
| 		sdata->dev->type = ARPHRD_ETHER; | ||||
| 	} | ||||
| 
 | ||||
| 	skb_queue_head_init(&sdata->skb_queue); | ||||
| 	INIT_WORK(&sdata->work, ieee80211_iface_work); | ||||
|  | @ -1146,6 +1172,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | |||
| 		break; | ||||
| 	case NL80211_IFTYPE_WDS: | ||||
| 	case NL80211_IFTYPE_AP_VLAN: | ||||
| 	case NL80211_IFTYPE_P2P_DEVICE: | ||||
| 		break; | ||||
| 	case NL80211_IFTYPE_UNSPECIFIED: | ||||
| 	case NUM_NL80211_IFTYPES: | ||||
|  | @ -1156,18 +1183,6 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *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, | ||||
| 					   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_teardown_sdata(sdata->dev); | ||||
| 	ieee80211_teardown_sdata(sdata); | ||||
| 
 | ||||
| 	ret = drv_change_interface(local, sdata, internal_type, p2p); | ||||
| 	if (ret) | ||||
|  | @ -1240,7 +1255,7 @@ static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata, | |||
| 
 | ||||
| 	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); | ||||
| 
 | ||||
| 	return ret; | ||||
|  | @ -1267,14 +1282,14 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, | |||
| 			return ret; | ||||
| 	} else { | ||||
| 		/* Purge and reset type-dependent state. */ | ||||
| 		ieee80211_teardown_sdata(sdata->dev); | ||||
| 		ieee80211_teardown_sdata(sdata); | ||||
| 		ieee80211_setup_sdata(sdata, type); | ||||
| 	} | ||||
| 
 | ||||
| 	/* reset some values that shouldn't be kept across type changes */ | ||||
| 	sdata->vif.bss_conf.basic_rates = | ||||
| 		ieee80211_mandatory_rates(sdata->local, | ||||
| 			sdata->local->hw.conf.channel->band); | ||||
| 			sdata->local->oper_channel->band); | ||||
| 	sdata->drop_unencrypted = 0; | ||||
| 	if (type == NL80211_IFTYPE_STATION) | ||||
| 		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, | ||||
| 				       struct net_device *dev, | ||||
| 				       enum nl80211_iftype type) | ||||
| 				       u8 *perm_addr, enum nl80211_iftype type) | ||||
| { | ||||
| 	struct ieee80211_sub_if_data *sdata; | ||||
| 	u64 mask, start, addr, val, inc; | ||||
|  | @ -1293,13 +1307,12 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local, | |||
| 	int i; | ||||
| 
 | ||||
| 	/* 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) && | ||||
| 	    local->hw.wiphy->n_addresses <= 1) | ||||
| 		return; | ||||
| 
 | ||||
| 
 | ||||
| 	mutex_lock(&local->iflist_mtx); | ||||
| 
 | ||||
| 	switch (type) { | ||||
|  | @ -1312,11 +1325,24 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local, | |||
| 		list_for_each_entry(sdata, &local->interfaces, list) { | ||||
| 			if (sdata->vif.type != NL80211_IFTYPE_AP) | ||||
| 				continue; | ||||
| 			memcpy(dev->perm_addr, sdata->vif.addr, ETH_ALEN); | ||||
| 			memcpy(perm_addr, sdata->vif.addr, ETH_ALEN); | ||||
| 			break; | ||||
| 		} | ||||
| 		/* keep default if no AP interface present */ | ||||
| 		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: | ||||
| 		/* assign a new address if possible -- try n_addresses first */ | ||||
| 		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) { | ||||
| 				memcpy(dev->perm_addr, | ||||
| 				memcpy(perm_addr, | ||||
| 				       local->hw.wiphy->addresses[i].addr, | ||||
| 				       ETH_ALEN); | ||||
| 				break; | ||||
|  | @ -1382,7 +1408,7 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local, | |||
| 			} | ||||
| 
 | ||||
| 			if (!used) { | ||||
| 				memcpy(dev->perm_addr, tmp_addr, ETH_ALEN); | ||||
| 				memcpy(perm_addr, tmp_addr, ETH_ALEN); | ||||
| 				break; | ||||
| 			} | ||||
| 			addr = (start & ~mask) | (val & mask); | ||||
|  | @ -1391,6 +1417,7 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local, | |||
| 		break; | ||||
| 	} | ||||
| 
 | ||||
|  out_unlock: | ||||
| 	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 vif_params *params) | ||||
| { | ||||
| 	struct net_device *ndev; | ||||
| 	struct net_device *ndev = NULL; | ||||
| 	struct ieee80211_sub_if_data *sdata = NULL; | ||||
| 	int ret, i; | ||||
| 	int txqs = 1; | ||||
| 
 | ||||
| 	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) | ||||
| 			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); | ||||
| 		if (!ndev) | ||||
| 			return -ENOMEM; | ||||
|  | @ -1424,23 +1466,27 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
| 		ndev->needed_tailroom = IEEE80211_ENCRYPT_TAILROOM; | ||||
| 
 | ||||
| 		ret = dev_alloc_name(ndev, ndev->name); | ||||
| 	if (ret < 0) | ||||
| 		goto fail; | ||||
| 		if (ret < 0) { | ||||
| 			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); | ||||
| 		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); | ||||
| 		ndev->ieee80211_ptr = &sdata->wdev; | ||||
| 		memcpy(sdata->vif.addr, ndev->dev_addr, ETH_ALEN); | ||||
| 		memcpy(sdata->name, ndev->name, IFNAMSIZ); | ||||
| 
 | ||||
| 		sdata->dev = ndev; | ||||
| 	} | ||||
| 
 | ||||
| 	/* initialise type-independent data */ | ||||
| 	sdata->wdev.wiphy = local->hw.wiphy; | ||||
| 	sdata->local = local; | ||||
| 	sdata->dev = ndev; | ||||
| #ifdef CONFIG_INET | ||||
| 	sdata->arp_filter_state = true; | ||||
| #endif | ||||
|  | @ -1469,6 +1515,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
| 	/* setup type-dependent data */ | ||||
| 	ieee80211_setup_sdata(sdata, type); | ||||
| 
 | ||||
| 	if (ndev) { | ||||
| 		if (params) { | ||||
| 			ndev->ieee80211_ptr->use_4addr = params->use_4addr; | ||||
| 			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; | ||||
| 
 | ||||
| 		ret = register_netdevice(ndev); | ||||
| 	if (ret) | ||||
| 		goto fail; | ||||
| 		if (ret) { | ||||
| 			free_netdev(ndev); | ||||
| 			return ret; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	mutex_lock(&local->iflist_mtx); | ||||
| 	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; | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
|  fail: | ||||
| 	free_netdev(ndev); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| 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); | ||||
| 	mutex_unlock(&sdata->local->iflist_mtx); | ||||
| 
 | ||||
| 	/* clean up type-dependent data */ | ||||
| 	ieee80211_clean_sdata(sdata); | ||||
| 
 | ||||
| 	synchronize_rcu(); | ||||
| 
 | ||||
| 	if (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; | ||||
| 	LIST_HEAD(unreg_list); | ||||
| 	LIST_HEAD(wdev_list); | ||||
| 
 | ||||
| 	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_del(&sdata->list); | ||||
| 
 | ||||
| 		ieee80211_clean_sdata(sdata); | ||||
| 
 | ||||
| 		if (sdata->dev) | ||||
| 			unregister_netdevice_queue(sdata->dev, &unreg_list); | ||||
| 		else | ||||
| 			list_add(&sdata->list, &wdev_list); | ||||
| 	} | ||||
| 	mutex_unlock(&local->iflist_mtx); | ||||
| 	unregister_netdevice_many(&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, | ||||
|  |  | |||
|  | @ -207,6 +207,10 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, | |||
| 		sdata->vif.bss_conf.bssid = NULL; | ||||
| 	else if (ieee80211_vif_is_mesh(&sdata->vif)) { | ||||
| 		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 { | ||||
| 		WARN_ON(1); | ||||
| 		return; | ||||
|  | @ -514,6 +518,11 @@ ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { | |||
| 			BIT(IEEE80211_STYPE_AUTH >> 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 = { | ||||
|  | @ -536,6 +545,11 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
| 	int priv_size, i; | ||||
| 	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))) | ||||
| 		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); | ||||
| 
 | ||||
| 	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; | ||||
| 
 | ||||
| 	/* set up some defaults */ | ||||
|  |  | |||
|  | @ -109,11 +109,11 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata, | |||
| 
 | ||||
| 	/* Disallow HT40+/- mismatch */ | ||||
| 	if (ie->ht_operation && | ||||
| 	    (local->_oper_channel_type == NL80211_CHAN_HT40MINUS || | ||||
| 	    local->_oper_channel_type == NL80211_CHAN_HT40PLUS) && | ||||
| 	    (sdata->vif.bss_conf.channel_type == NL80211_CHAN_HT40MINUS || | ||||
| 	     sdata->vif.bss_conf.channel_type == NL80211_CHAN_HT40PLUS) && | ||||
| 	    (sta_channel_type == NL80211_CHAN_HT40MINUS || | ||||
| 	     sta_channel_type == NL80211_CHAN_HT40PLUS) && | ||||
| 	    local->_oper_channel_type != sta_channel_type) | ||||
| 	    sdata->vif.bss_conf.channel_type != sta_channel_type) | ||||
| 		goto mismatch; | ||||
| 
 | ||||
| 	return true; | ||||
|  | @ -355,17 +355,18 @@ int mesh_add_ds_params_ie(struct sk_buff *skb, | |||
| { | ||||
| 	struct ieee80211_local *local = sdata->local; | ||||
| 	struct ieee80211_supported_band *sband; | ||||
| 	struct ieee80211_channel *chan = local->oper_channel; | ||||
| 	u8 *pos; | ||||
| 
 | ||||
| 	if (skb_tailroom(skb) < 3) | ||||
| 		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) { | ||||
| 		pos = skb_put(skb, 2 + 1); | ||||
| 		*pos++ = WLAN_EID_DS_PARAMS; | ||||
| 		*pos++ = 1; | ||||
| 		*pos++ = ieee80211_frequency_to_channel(local->hw.conf.channel->center_freq); | ||||
| 		*pos++ = ieee80211_frequency_to_channel(chan->center_freq); | ||||
| 	} | ||||
| 
 | ||||
| 	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]; | ||||
| 	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; | ||||
| 
 | ||||
| 	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_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 = | ||||
| 				local->hw.wiphy->bands[channel->band]; | ||||
| 	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.basic_rates = | ||||
| 		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 | | ||||
| 						BSS_CHANGED_BEACON_ENABLED | | ||||
| 						BSS_CHANGED_HT | | ||||
| 						BSS_CHANGED_BASIC_RATES | | ||||
| 						BSS_CHANGED_BEACON_INT); | ||||
| 
 | ||||
| 	netif_carrier_on(sdata->dev); | ||||
| } | ||||
| 
 | ||||
| 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_if_mesh *ifmsh = &sdata->u.mesh; | ||||
| 
 | ||||
| 	netif_carrier_off(sdata->dev); | ||||
| 
 | ||||
| 	/* stop the beacon */ | ||||
| 	ifmsh->mesh_id_len = 0; | ||||
| 	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.mesh_path_root_timer); | ||||
|  |  | |||
|  | @ -215,6 +215,9 @@ struct mesh_rmc { | |||
| /* Maximum number of paths per interface */ | ||||
| #define MESH_MAX_MPATHS		1024 | ||||
| 
 | ||||
| /* Number of frames buffered per destination for unresolved destinations */ | ||||
| #define MESH_FRAME_QUEUE_LEN	10 | ||||
| 
 | ||||
| /* Public interfaces */ | ||||
| /* Various */ | ||||
| int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, | ||||
|  |  | |||
|  | @ -17,8 +17,6 @@ | |||
| #define MAX_METRIC	0xffffffff | ||||
| #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 | ||||
| 
 | ||||
| /* Destination only */ | ||||
|  |  | |||
|  | @ -203,23 +203,17 @@ void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta) | |||
| { | ||||
| 	struct sk_buff *skb; | ||||
| 	struct ieee80211_hdr *hdr; | ||||
| 	struct sk_buff_head tmpq; | ||||
| 	unsigned long flags; | ||||
| 
 | ||||
| 	rcu_assign_pointer(mpath->next_hop, sta); | ||||
| 
 | ||||
| 	__skb_queue_head_init(&tmpq); | ||||
| 
 | ||||
| 	spin_lock_irqsave(&mpath->frame_queue.lock, flags); | ||||
| 
 | ||||
| 	while ((skb = __skb_dequeue(&mpath->frame_queue)) != NULL) { | ||||
| 	skb_queue_walk(&mpath->frame_queue, skb) { | ||||
| 		hdr = (struct ieee80211_hdr *) skb->data; | ||||
| 		memcpy(hdr->addr1, sta->sta.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); | ||||
| } | ||||
| 
 | ||||
|  | @ -285,40 +279,42 @@ static void mesh_path_move_to_queue(struct mesh_path *gate_mpath, | |||
| 				    struct mesh_path *from_mpath, | ||||
| 				    bool copy) | ||||
| { | ||||
| 	struct sk_buff *skb, *cp_skb = NULL; | ||||
| 	struct sk_buff_head gateq, failq; | ||||
| 	struct sk_buff *skb, *fskb, *tmp; | ||||
| 	struct sk_buff_head failq; | ||||
| 	unsigned long flags; | ||||
| 	int num_skbs; | ||||
| 
 | ||||
| 	BUG_ON(gate_mpath == from_mpath); | ||||
| 	BUG_ON(!gate_mpath->next_hop); | ||||
| 
 | ||||
| 	__skb_queue_head_init(&gateq); | ||||
| 	__skb_queue_head_init(&failq); | ||||
| 
 | ||||
| 	spin_lock_irqsave(&from_mpath->frame_queue.lock, flags); | ||||
| 	skb_queue_splice_init(&from_mpath->frame_queue, &failq); | ||||
| 	spin_unlock_irqrestore(&from_mpath->frame_queue.lock, flags); | ||||
| 
 | ||||
| 	num_skbs = skb_queue_len(&failq); | ||||
| 
 | ||||
| 	while (num_skbs--) { | ||||
| 		skb = __skb_dequeue(&failq); | ||||
| 		if (copy) { | ||||
| 			cp_skb = skb_copy(skb, GFP_ATOMIC); | ||||
| 			if (cp_skb) | ||||
| 				__skb_queue_tail(&failq, cp_skb); | ||||
| 	skb_queue_walk_safe(&failq, fskb, tmp) { | ||||
| 		if (skb_queue_len(&gate_mpath->frame_queue) >= | ||||
| 				  MESH_FRAME_QUEUE_LEN) { | ||||
| 			mpath_dbg(gate_mpath->sdata, "mpath queue full!\n"); | ||||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
| 		skb = skb_copy(fskb, GFP_ATOMIC); | ||||
| 		if (WARN_ON(!skb)) | ||||
| 			break; | ||||
| 
 | ||||
| 		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", | ||||
| 		  gate_mpath->dst, skb_queue_len(&gate_mpath->frame_queue)); | ||||
| 	spin_unlock_irqrestore(&gate_mpath->frame_queue.lock, flags); | ||||
| 
 | ||||
| 	if (!copy) | ||||
| 		return; | ||||
|  | @ -531,7 +527,7 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) | |||
| 
 | ||||
| 	read_lock_bh(&pathtbl_resize_lock); | ||||
| 	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->sdata = sdata; | ||||
| 	new_mpath->flags = 0; | ||||
|  |  | |||
|  | @ -117,7 +117,7 @@ static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata) | |||
| 	u16 ht_opmode; | ||||
| 	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; | ||||
| 
 | ||||
| 	rcu_read_lock(); | ||||
|  | @ -147,7 +147,8 @@ out: | |||
| 
 | ||||
| 	if (non_ht_sta) | ||||
| 		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; | ||||
| 	else | ||||
| 		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) { | ||||
| 	struct ieee80211_local *local = sdata->local; | ||||
| 	struct sk_buff *skb; | ||||
| 	struct ieee80211_tx_info *info; | ||||
| 	struct ieee80211_mgmt *mgmt; | ||||
| 	bool include_plid = false; | ||||
| 	u16 peering_proto = 0; | ||||
| 	u8 *pos, ie_len = 4; | ||||
| 	int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.self_prot) + | ||||
| 		      sizeof(mgmt->u.action.u.self_prot); | ||||
| 	int err = -ENOMEM; | ||||
| 
 | ||||
| 	skb = dev_alloc_skb(local->tx_headroom + | ||||
| 			    hdr_len + | ||||
|  | @ -236,6 +239,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
| 			    sdata->u.mesh.ie_len); | ||||
| 	if (!skb) | ||||
| 		return -1; | ||||
| 	info = IEEE80211_SKB_CB(skb); | ||||
| 	skb_reserve(skb, local->tx_headroom); | ||||
| 	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 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); | ||||
| 			memcpy(pos + 2, &plid, 2); | ||||
| 		} | ||||
| 		if (ieee80211_add_srates_ie(sdata, skb, true) || | ||||
| 		    ieee80211_add_ext_srates_ie(sdata, skb, true) || | ||||
| 		if (ieee80211_add_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_meshid_ie(skb, sdata) || | ||||
| 		    mesh_add_meshconf_ie(skb, sdata)) | ||||
| 			return -1; | ||||
| 			goto free; | ||||
| 	} else {	/* WLAN_SP_MESH_PEERING_CLOSE */ | ||||
| 		info->flags |= IEEE80211_TX_CTL_NO_ACK; | ||||
| 		if (mesh_add_meshid_ie(skb, sdata)) | ||||
| 			return -1; | ||||
| 			goto free; | ||||
| 	} | ||||
| 
 | ||||
| 	/* 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 */ | ||||
| 		break; | ||||
| 	default: | ||||
| 		return -EINVAL; | ||||
| 		err = -EINVAL; | ||||
| 		goto free; | ||||
| 	} | ||||
| 
 | ||||
| 	if (WARN_ON(skb_tailroom(skb) < 2 + ie_len)) | ||||
| 		return -ENOMEM; | ||||
| 		goto free; | ||||
| 
 | ||||
| 	pos = skb_put(skb, 2 + ie_len); | ||||
| 	*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 (mesh_add_ht_cap_ie(skb, sdata) || | ||||
| 		    mesh_add_ht_oper_ie(skb, sdata)) | ||||
| 			return -1; | ||||
| 			goto free; | ||||
| 	} | ||||
| 
 | ||||
| 	if (mesh_add_vendor_ies(skb, sdata)) | ||||
| 		return -1; | ||||
| 		goto free; | ||||
| 
 | ||||
| 	ieee80211_tx_skb(sdata, skb); | ||||
| 	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); | ||||
| 	sta->last_rx = jiffies; | ||||
| 	if (sta->plink_state == NL80211_PLINK_ESTAB) { | ||||
| 		spin_unlock_bh(&sta->lock); | ||||
| 		return sta; | ||||
| 	} | ||||
| 
 | ||||
| 	sta->sta.supp_rates[band] = rates; | ||||
| 	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, | ||||
| 						  elems->ht_cap_elem, | ||||
| 						  &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) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) | ||||
| 		return; | ||||
| 
 | ||||
| 	mod_timer(&sdata->u.mgd.bcn_mon_timer, | ||||
| 		  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; | ||||
| 	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) { | ||||
| 	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; | ||||
| 		break; | ||||
| 	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; | ||||
| 		break; | ||||
| 	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); | ||||
| } | ||||
| 
 | ||||
| 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) | ||||
| { | ||||
| 	struct ieee80211_local *local = sdata->local; | ||||
|  | @ -371,6 +394,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
| 			4 + /* power capability */ | ||||
| 			2 + 2 * sband->n_channels + /* supported channels */ | ||||
| 			2 + sizeof(struct ieee80211_ht_cap) + /* HT */ | ||||
| 			2 + sizeof(struct ieee80211_vht_capabilities) + /* VHT */ | ||||
| 			assoc_data->ie_len + /* extra IEs */ | ||||
| 			9, /* WMM */ | ||||
| 			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, | ||||
| 				    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 (assoc_data->ie_len && 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_TX_INTFL_DONT_ENCRYPT; | ||||
| 
 | ||||
| 		drv_mgd_prepare_tx(local, sdata); | ||||
| 
 | ||||
| 		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! */ | ||||
| 	ifmgd->associated->channel = sdata->local->oper_channel; | ||||
| 
 | ||||
| 	/* XXX: wait for a beacon first? */ | ||||
| 	ieee80211_wake_queues_by_reason(&sdata->local->hw, | ||||
| 					IEEE80211_QUEUE_STOP_REASON_CSA); | ||||
|  out: | ||||
|  | @ -763,37 +789,33 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
| 
 | ||||
| 	sdata->local->csa_channel = new_ch; | ||||
| 
 | ||||
| 	if (sdata->local->ops->channel_switch) { | ||||
| 		/* use driver's channel switch callback */ | ||||
| 		struct ieee80211_channel_switch ch_switch; | ||||
| 		memset(&ch_switch, 0, sizeof(ch_switch)); | ||||
| 		ch_switch.timestamp = timestamp; | ||||
| 		if (sw_elem->mode) { | ||||
| 			ch_switch.block_tx = true; | ||||
| 	ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; | ||||
| 
 | ||||
| 	if (sw_elem->mode) | ||||
| 		ieee80211_stop_queues_by_reason(&sdata->local->hw, | ||||
| 				IEEE80211_QUEUE_STOP_REASON_CSA); | ||||
| 		} | ||||
| 		ch_switch.channel = new_ch; | ||||
| 		ch_switch.count = sw_elem->count; | ||||
| 		ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; | ||||
| 
 | ||||
| 	if (sdata->local->ops->channel_switch) { | ||||
| 		/* use driver's channel switch callback */ | ||||
| 		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); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	/* channel switch handled in software */ | ||||
| 	if (sw_elem->count <= 1) { | ||||
| 	if (sw_elem->count <= 1) | ||||
| 		ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work); | ||||
| 	} else { | ||||
| 		if (sw_elem->mode) | ||||
| 			ieee80211_stop_queues_by_reason(&sdata->local->hw, | ||||
| 					IEEE80211_QUEUE_STOP_REASON_CSA); | ||||
| 		ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; | ||||
| 	else | ||||
| 		mod_timer(&ifmgd->chswitch_timer, | ||||
| 			  jiffies + | ||||
| 			  msecs_to_jiffies(sw_elem->count * | ||||
| 			  TU_TO_EXP_TIME(sw_elem->count * | ||||
| 					 cbss->beacon_interval)); | ||||
| } | ||||
| } | ||||
| 
 | ||||
| static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, | ||||
| 					u16 capab_info, u8 *pwr_constr_elem, | ||||
|  | @ -1007,6 +1029,16 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) | |||
| 	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) | ||||
| { | ||||
| 	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); | ||||
| 	if (sdata->local->hw.conf.channel->band == IEEE80211_BAND_5GHZ) | ||||
| 	if (sdata->local->oper_channel->band == IEEE80211_BAND_5GHZ) | ||||
| 		use_short_slot = true; | ||||
| 
 | ||||
| 	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); | ||||
| 	mutex_unlock(&local->iflist_mtx); | ||||
| 
 | ||||
| 	ieee80211_recalc_ps_vif(sdata); | ||||
| 
 | ||||
| 	netif_tx_start_all_queues(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; | ||||
| 
 | ||||
| 	/* disable per-vif ps */ | ||||
| 	ieee80211_recalc_ps_vif(sdata); | ||||
| 
 | ||||
| 	/* flush out any pending frame (e.g. DELBA) before deauth/disassoc */ | ||||
| 	if (tx) | ||||
| 		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]; | ||||
| 
 | ||||
| 		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); | ||||
|  | @ -1645,7 +1683,9 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, | |||
| 		ssid_len = ssid[1]; | ||||
| 
 | ||||
| 	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); | ||||
| 
 | ||||
| 	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_local *local = sdata->local; | ||||
| 	u8 bssid[ETH_ALEN]; | ||||
| 	u8 frame_buf[DEAUTH_DISASSOC_LEN]; | ||||
| 
 | ||||
| 	mutex_lock(&ifmgd->mtx); | ||||
|  | @ -1665,9 +1704,8 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) | |||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN); | ||||
| 
 | ||||
| 	sdata_info(sdata, "Connection to AP %pM lost\n", bssid); | ||||
| 	sdata_info(sdata, "Connection to AP %pM lost\n", | ||||
| 		   ifmgd->associated->bssid); | ||||
| 
 | ||||
| 	ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, | ||||
| 			       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); | ||||
| } | ||||
| 
 | ||||
| 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 = | ||||
| 		container_of(work, struct ieee80211_sub_if_data, | ||||
|  | @ -2232,15 +2270,11 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
| 		mutex_unlock(&local->iflist_mtx); | ||||
| 	} | ||||
| 
 | ||||
| 	if (elems->ch_switch_elem && (elems->ch_switch_elem_len == 3) && | ||||
| 	    (memcmp(mgmt->bssid, sdata->u.mgd.associated->bssid, | ||||
| 							ETH_ALEN) == 0)) { | ||||
| 		struct ieee80211_channel_sw_ie *sw_elem = | ||||
| 			(struct ieee80211_channel_sw_ie *)elems->ch_switch_elem; | ||||
| 		ieee80211_sta_process_chanswitch(sdata, sw_elem, | ||||
| 	if (elems->ch_switch_ie && | ||||
| 	    memcmp(mgmt->bssid, sdata->u.mgd.associated->bssid, ETH_ALEN) == 0) | ||||
| 		ieee80211_sta_process_chanswitch(sdata, elems->ch_switch_ie, | ||||
| 						 bss, rx_status->mactime); | ||||
| } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, | ||||
|  | @ -2326,7 +2360,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
| 	if (baselen > len) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (rx_status->freq != local->hw.conf.channel->center_freq) | ||||
| 	if (rx_status->freq != local->oper_channel->center_freq) | ||||
| 		return; | ||||
| 
 | ||||
| 	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)) { | ||||
| 		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, | ||||
| 						  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. | ||||
| 		 */ | ||||
| 		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; | ||||
|  | @ -3000,41 +3035,17 @@ int ieee80211_max_network_latency(struct notifier_block *nb, | |||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, | ||||
| 				     struct cfg80211_bss *cbss, bool assoc) | ||||
| static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, | ||||
| 				  struct cfg80211_bss *cbss) | ||||
| { | ||||
| 	struct ieee80211_local *local = sdata->local; | ||||
| 	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; | ||||
| 	enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | ||||
| 	const u8 *ht_oper_ie; | ||||
| 	const struct ieee80211_ht_operation *ht_oper = NULL; | ||||
| 	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]; | ||||
| 
 | ||||
| 	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; | ||||
| 	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; | ||||
| 		bool have_higher_than_11mbit; | ||||
| 		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, | ||||
| 				    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); | ||||
| 		} | ||||
| 
 | ||||
| 		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; | ||||
| 
 | ||||
| 		/* 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); | ||||
| 
 | ||||
| 		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); | ||||
| 		sta = NULL; | ||||
| 		err = sta_info_insert(new_sta); | ||||
| 		new_sta = NULL; | ||||
| 		if (err) { | ||||
| 			sdata_info(sdata, | ||||
| 				   "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 */ | ||||
| 	 | ||||
| 	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; | ||||
| 
 | ||||
|  | @ -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_WEP104) { | ||||
| 			ifmgd->flags |= IEEE80211_STA_DISABLE_11N; | ||||
| 			ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; | ||||
| 			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_VHT; | ||||
| 	} | ||||
| 
 | ||||
| 	/* 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]; | ||||
| 	if (!sband->ht_cap.ht_supported || | ||||
| 	    local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used) { | ||||
| 		ifmgd->flags |= IEEE80211_STA_DISABLE_11N; | ||||
| 		if (!bss->wmm_used) | ||||
| 			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)); | ||||
|  | @ -3467,14 +3536,17 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | |||
| 		   req->bssid, req->reason_code); | ||||
| 
 | ||||
| 	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, | ||||
| 				       req->reason_code, true, frame_buf); | ||||
| 	else | ||||
| 	} else { | ||||
| 		drv_mgd_prepare_tx(sdata->local, sdata); | ||||
| 		ieee80211_send_deauth_disassoc(sdata, req->bssid, | ||||
| 					       IEEE80211_STYPE_DEAUTH, | ||||
| 					       req->reason_code, true, | ||||
| 					       frame_buf); | ||||
| 	} | ||||
| 
 | ||||
| 	mutex_unlock(&ifmgd->mtx); | ||||
| 
 | ||||
| 	__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)) | ||||
| 			continue; | ||||
| 
 | ||||
| 		if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) | ||||
| 			continue; | ||||
| 
 | ||||
| 		if (sdata->vif.type != NL80211_IFTYPE_MONITOR) | ||||
| 			set_bit(SDATA_STATE_OFFCHANNEL, &sdata->state); | ||||
| 
 | ||||
|  | @ -144,6 +147,9 @@ void ieee80211_offchannel_return(struct ieee80211_local *local, | |||
| 
 | ||||
| 	mutex_lock(&local->iflist_mtx); | ||||
| 	list_for_each_entry(sdata, &local->interfaces, list) { | ||||
| 		if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) | ||||
| 			continue; | ||||
| 
 | ||||
| 		if (sdata->vif.type != NL80211_IFTYPE_MONITOR) | ||||
| 			clear_bit(SDATA_STATE_OFFCHANNEL, &sdata->state); | ||||
| 
 | ||||
|  |  | |||
|  | @ -56,7 +56,7 @@ static inline void rate_control_rate_init(struct sta_info *sta) | |||
| 	if (!ref) | ||||
| 		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); | ||||
| 	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_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; | ||||
| 	if (unlikely(skb->len < 16 + present_fcs_len)) | ||||
| 		return 1; | ||||
|  | @ -91,6 +93,13 @@ ieee80211_rx_radiotap_len(struct ieee80211_local *local, | |||
| 	if (status->flag & RX_FLAG_HT) /* HT info */ | ||||
| 		len += 3; | ||||
| 
 | ||||
| 	if (status->flag & RX_FLAG_AMPDU_DETAILS) { | ||||
| 		/* padding */ | ||||
| 		while (len & 3) | ||||
| 			len++; | ||||
| 		len += 8; | ||||
| 	} | ||||
| 
 | ||||
| 	return len; | ||||
| } | ||||
| 
 | ||||
|  | @ -215,6 +224,37 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
| 		pos++; | ||||
| 		*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; | ||||
| 	case WLAN_CATEGORY_SPECTRUM_MGMT: | ||||
| 		if (local->hw.conf.channel->band != IEEE80211_BAND_5GHZ) | ||||
| 		if (status->band != IEEE80211_BAND_5GHZ) | ||||
| 			break; | ||||
| 
 | ||||
| 		if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||||
|  | @ -2772,8 +2812,7 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx, | |||
| 		if (!bssid) { | ||||
| 			if (!ether_addr_equal(sdata->vif.addr, hdr->addr1)) | ||||
| 				return 0; | ||||
| 		} else if (!ieee80211_bssid_match(bssid, | ||||
| 					sdata->vif.addr)) { | ||||
| 		} else if (!ieee80211_bssid_match(bssid, sdata->vif.addr)) { | ||||
| 			/*
 | ||||
| 			 * Accept public action frames even when the | ||||
| 			 * 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)) | ||||
| 			return 0; | ||||
| 		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: | ||||
| 		/* should never get here */ | ||||
| 		WARN_ON(1); | ||||
| 		WARN_ON_ONCE(1); | ||||
| 		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->ie, local->scan_req->ie_len, | ||||
| 			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 | ||||
|  | @ -479,11 +480,10 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
| 	if (local->ops->hw_scan) { | ||||
| 		__set_bit(SCAN_HW_SCANNING, &local->scanning); | ||||
| 	} else if ((req->n_channels == 1) && | ||||
| 		   (req->channels[0]->center_freq == | ||||
| 		    local->hw.conf.channel->center_freq)) { | ||||
| 
 | ||||
| 		/* If we are scanning only on the current channel, then
 | ||||
| 		 * we do not need to stop normal activities | ||||
| 		   (req->channels[0] == local->oper_channel)) { | ||||
| 		/*
 | ||||
| 		 * If we are scanning only on the operating channel | ||||
| 		 * then we do not need to stop normal activities | ||||
| 		 */ | ||||
| 		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; | ||||
| 		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) || | ||||
| 		    ieee80211_is_qos_nullfunc(hdr->frame_control)) | ||||
| 		    ieee80211_is_qos_nullfunc(hdr->frame_control)) { | ||||
| 			cfg80211_probe_status(skb->dev, hdr->addr1, | ||||
| 					      cookie, acked, GFP_ATOMIC); | ||||
| 		else | ||||
| 		} else if (skb->dev) { | ||||
| 			cfg80211_mgmt_tx_status( | ||||
| 				skb->dev->ieee80211_ptr, cookie, skb->data, | ||||
| 				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)) { | ||||
|  |  | |||
|  | @ -24,7 +24,7 @@ | |||
| 			__string(vif_name, sdata->dev ? sdata->dev->name : "<nodev>") | ||||
| #define VIF_ASSIGN	__entry->vif_type = sdata->vif.type; __entry->sdata = sdata;	\ | ||||
| 			__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_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->max_sleep_period = local->hw.conf.max_sleep_period; | ||||
| 		__entry->listen_interval = local->hw.conf.listen_interval; | ||||
| 		__entry->long_frame_max_tx_count = local->hw.conf.long_frame_max_tx_count; | ||||
| 		__entry->short_frame_max_tx_count = local->hw.conf.short_frame_max_tx_count; | ||||
| 		__entry->center_freq = local->hw.conf.channel->center_freq; | ||||
| 		__entry->long_frame_max_tx_count = | ||||
| 			local->hw.conf.long_frame_max_tx_count; | ||||
| 		__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->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)) | ||||
| 		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]; | ||||
| 
 | ||||
| 	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)); | ||||
| 
 | ||||
| 	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, | ||||
| 			 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.skb = tx->skb; | ||||
| 	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) | ||||
| 		txrc.max_rate_idx = -1; | ||||
| 	else | ||||
| 		txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1; | ||||
| 	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)); | ||||
| 	txrc.bss = (tx->sdata->vif.type == NL80211_IFTYPE_AP || | ||||
| 		    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: " | ||||
| 		 "%pM on %d GHz band\n", | ||||
| 		 tx->sdata->name, hdr->addr1, | ||||
| 		 tx->channel->band ? 5 : 2)) | ||||
| 		 info->band ? 5 : 2)) | ||||
| 		return TX_DROP; | ||||
| 
 | ||||
| 	/*
 | ||||
|  | @ -1131,7 +1131,6 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, | |||
| 	tx->skb = skb; | ||||
| 	tx->local = local; | ||||
| 	tx->sdata = sdata; | ||||
| 	tx->channel = local->hw.conf.channel; | ||||
| 	__skb_queue_head_init(&tx->skbs); | ||||
| 
 | ||||
| 	/*
 | ||||
|  | @ -1204,6 +1203,7 @@ static bool ieee80211_tx_frags(struct ieee80211_local *local, | |||
| 			       struct sk_buff_head *skbs, | ||||
| 			       bool txpending) | ||||
| { | ||||
| 	struct ieee80211_tx_control control; | ||||
| 	struct sk_buff *skb, *tmp; | ||||
| 	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); | ||||
| 
 | ||||
| 		info->control.vif = vif; | ||||
| 		info->control.sta = sta; | ||||
| 		control.sta = sta; | ||||
| 
 | ||||
| 		__skb_unlink(skb, skbs); | ||||
| 		drv_tx(local, skb); | ||||
| 		drv_tx(local, &control, skb); | ||||
| 	} | ||||
| 
 | ||||
| 	return true; | ||||
|  | @ -1399,8 +1399,7 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata, | |||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	tx.channel = local->hw.conf.channel; | ||||
| 	info->band = tx.channel->band; | ||||
| 	info->band = local->hw.conf.channel->band; | ||||
| 
 | ||||
| 	/* set up hw_queue value early */ | ||||
| 	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_local *local = sdata->local; | ||||
| 	struct ieee80211_tx_info *info; | ||||
| 	int ret = NETDEV_TX_BUSY, head_need; | ||||
| 	int head_need; | ||||
| 	u16 ethertype, hdrlen,  meshhdrlen = 0; | ||||
| 	__le16 fc; | ||||
| 	struct ieee80211_hdr hdr; | ||||
|  | @ -1736,10 +1735,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 	u32 info_flags = 0; | ||||
| 	u16 info_id = 0; | ||||
| 
 | ||||
| 	if (unlikely(skb->len < ETH_HLEN)) { | ||||
| 		ret = NETDEV_TX_OK; | ||||
| 	if (unlikely(skb->len < ETH_HLEN)) | ||||
| 		goto fail; | ||||
| 	} | ||||
| 
 | ||||
| 	/* convert Ethernet header to proper 802.11 header (based on
 | ||||
| 	 * operation mode) */ | ||||
|  | @ -1787,7 +1784,6 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 		if (!sdata->u.mesh.mshcfg.dot11MeshTTL) { | ||||
| 			/* Do not send frames with mesh_ttl == 0 */ | ||||
| 			sdata->u.mesh.mshstats.dropped_frames_ttl++; | ||||
| 			ret = NETDEV_TX_OK; | ||||
| 			goto fail; | ||||
| 		} | ||||
| 		rcu_read_lock(); | ||||
|  | @ -1880,10 +1876,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 
 | ||||
| 		if (tdls_direct) { | ||||
| 			/* link during setup - throw out frames to peer */ | ||||
| 			if (!tdls_auth) { | ||||
| 				ret = NETDEV_TX_OK; | ||||
| 			if (!tdls_auth) | ||||
| 				goto fail; | ||||
| 			} | ||||
| 
 | ||||
| 			/* DA SA BSSID */ | ||||
| 			memcpy(hdr.addr1, skb->data, ETH_ALEN); | ||||
|  | @ -1917,7 +1911,6 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 		hdrlen = 24; | ||||
| 		break; | ||||
| 	default: | ||||
| 		ret = NETDEV_TX_OK; | ||||
| 		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); | ||||
| 
 | ||||
| 		ret = NETDEV_TX_OK; | ||||
| 		goto fail; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -2017,11 +2009,9 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 		skb = skb_clone(skb, GFP_ATOMIC); | ||||
| 		kfree_skb(tmp_skb); | ||||
| 
 | ||||
| 		if (!skb) { | ||||
| 			ret = NETDEV_TX_OK; | ||||
| 		if (!skb) | ||||
| 			goto fail; | ||||
| 	} | ||||
| 	} | ||||
| 
 | ||||
| 	hdr.frame_control = fc; | ||||
| 	hdr.duration_id = 0; | ||||
|  | @ -2123,10 +2113,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 	return NETDEV_TX_OK; | ||||
| 
 | ||||
|  fail: | ||||
| 	if (ret == NETDEV_TX_OK) | ||||
| 	dev_kfree_skb(skb); | ||||
| 
 | ||||
| 	return ret; | ||||
| 	return NETDEV_TX_OK; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -2301,12 +2289,9 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
| 	struct ieee80211_sub_if_data *sdata = NULL; | ||||
| 	struct ieee80211_if_ap *ap = NULL; | ||||
| 	struct beacon_data *beacon; | ||||
| 	struct ieee80211_supported_band *sband; | ||||
| 	enum ieee80211_band band = local->hw.conf.channel->band; | ||||
| 	enum ieee80211_band band = local->oper_channel->band; | ||||
| 	struct ieee80211_tx_rate_control txrc; | ||||
| 
 | ||||
| 	sband = local->hw.wiphy->bands[band]; | ||||
| 
 | ||||
| 	rcu_read_lock(); | ||||
| 
 | ||||
| 	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); | ||||
| 		mgmt->frame_control = | ||||
| 		    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->bssid, sdata->vif.addr, ETH_ALEN); | ||||
| 		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++ = 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) || | ||||
| 		    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_ht_cap_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)); | ||||
| 	txrc.hw = hw; | ||||
| 	txrc.sband = sband; | ||||
| 	txrc.sband = local->hw.wiphy->bands[band]; | ||||
| 	txrc.bss_conf = &sdata->vif.bss_conf; | ||||
| 	txrc.skb = skb; | ||||
| 	txrc.reported_rate.idx = -1; | ||||
| 	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; | ||||
| 	else | ||||
| 		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_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_sub_if_data *sdata = vif_to_sdata(vif); | ||||
| 
 | ||||
|  | @ -2496,10 +2482,12 @@ struct sk_buff *ieee80211_proberesp_get(struct ieee80211_hw *hw, | |||
| 	if (!presp) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	skb = skb_copy(presp, GFP_ATOMIC); | ||||
| 	skb = dev_alloc_skb(presp->len); | ||||
| 	if (!skb) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	memcpy(skb_put(skb, presp->len), presp->data, presp->len); | ||||
| 
 | ||||
| 	hdr = (struct ieee80211_hdr *) skb->data; | ||||
| 	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)); | ||||
| 	hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||||
| 					 IEEE80211_STYPE_PROBE_REQ); | ||||
| 	memset(hdr->addr1, 0xff, ETH_ALEN); | ||||
| 	eth_broadcast_addr(hdr->addr1); | ||||
| 	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++ = WLAN_EID_SSID; | ||||
|  | @ -2709,8 +2697,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, | |||
| 	info = IEEE80211_SKB_CB(skb); | ||||
| 
 | ||||
| 	tx.flags |= IEEE80211_TX_PS_BUFFERED; | ||||
| 	tx.channel = local->hw.conf.channel; | ||||
| 	info->band = tx.channel->band; | ||||
| 	info->band = local->oper_channel->band; | ||||
| 
 | ||||
| 	if (invoke_tx_handlers(&tx)) | ||||
| 		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) { | ||||
| 		int ac; | ||||
| 
 | ||||
| 		if (!sdata->dev) | ||||
| 			continue; | ||||
| 
 | ||||
| 		if (test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state)) | ||||
| 			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) { | ||||
| 		int ac; | ||||
| 
 | ||||
| 		if (!sdata->dev) | ||||
| 			continue; | ||||
| 
 | ||||
| 		for (ac = 0; ac < n_acs; ac++) { | ||||
| 			if (sdata->vif.hw_queue[ac] == 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; | ||||
| 			break; | ||||
| 		case WLAN_EID_CHANNEL_SWITCH: | ||||
| 			elems->ch_switch_elem = pos; | ||||
| 			elems->ch_switch_elem_len = elen; | ||||
| 			if (elen != sizeof(struct ieee80211_channel_sw_ie)) { | ||||
| 				elem_parse_failed = true; | ||||
| 				break; | ||||
| 			} | ||||
| 			elems->ch_switch_ie = (void *)pos; | ||||
| 			break; | ||||
| 		case WLAN_EID_QUIET: | ||||
| 			if (!elems->quiet_elem) { | ||||
|  | @ -832,7 +841,7 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, | |||
| 
 | ||||
| 	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); | ||||
| 
 | ||||
| 	/*
 | ||||
|  | @ -899,7 +908,8 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, | |||
| 		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; | ||||
| 		if (bss_notify) | ||||
| 			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) | ||||
| 			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) | ||||
| 		sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; | ||||
| 	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, | ||||
| 					  u8 *dst, u32 ratemask, | ||||
| 					  struct ieee80211_channel *chan, | ||||
| 					  const u8 *ssid, size_t ssid_len, | ||||
| 					  const u8 *ie, size_t ie_len, | ||||
| 					  bool directed) | ||||
|  | @ -1109,7 +1120,7 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | |||
| 	struct ieee80211_mgmt *mgmt; | ||||
| 	size_t buf_len; | ||||
| 	u8 *buf; | ||||
| 	u8 chan; | ||||
| 	u8 chan_no; | ||||
| 
 | ||||
| 	/* FIXME: come up with a proper value */ | ||||
| 	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. | ||||
| 	 */ | ||||
| 	if (directed) | ||||
| 		chan = 0; | ||||
| 		chan_no = 0; | ||||
| 	else | ||||
| 		chan = ieee80211_frequency_to_channel( | ||||
| 			local->hw.conf.channel->center_freq); | ||||
| 		chan_no = ieee80211_frequency_to_channel(chan->center_freq); | ||||
| 
 | ||||
| 	buf_len = ieee80211_build_preq_ies(local, buf, ie, ie_len, | ||||
| 					   local->hw.conf.channel->band, | ||||
| 					   ratemask, chan); | ||||
| 	buf_len = ieee80211_build_preq_ies(local, buf, ie, ie_len, chan->band, | ||||
| 					   ratemask, chan_no); | ||||
| 
 | ||||
| 	skb = ieee80211_probereq_get(&local->hw, &sdata->vif, | ||||
| 				     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, | ||||
| 			      const u8 *ssid, size_t ssid_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; | ||||
| 
 | ||||
| 	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); | ||||
| 	if (skb) { | ||||
| 		if (no_cck) | ||||
|  | @ -1359,7 +1370,8 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
| 		switch (sdata->vif.type) { | ||||
| 		case NL80211_IFTYPE_STATION: | ||||
| 			changed |= BSS_CHANGED_ASSOC | | ||||
| 				   BSS_CHANGED_ARP_FILTER; | ||||
| 				   BSS_CHANGED_ARP_FILTER | | ||||
| 				   BSS_CHANGED_PS; | ||||
| 			mutex_lock(&sdata->u.mgd.mtx); | ||||
| 			ieee80211_bss_info_change_notify(sdata, changed); | ||||
| 			mutex_unlock(&sdata->u.mgd.mtx); | ||||
|  | @ -1385,6 +1397,9 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
| 		case NL80211_IFTYPE_MONITOR: | ||||
| 			/* ignore virtual */ | ||||
| 			break; | ||||
| 		case NL80211_IFTYPE_P2P_DEVICE: | ||||
| 			changed = BSS_CHANGED_IDLE; | ||||
| 			break; | ||||
| 		case NL80211_IFTYPE_UNSPECIFIED: | ||||
| 		case NUM_NL80211_IFTYPES: | ||||
| 		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) { | ||||
| 		if (!ieee80211_sdata_running(sdata)) | ||||
| 			continue; | ||||
| 		if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) | ||||
| 			continue; | ||||
| 		if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||||
| 			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, | ||||
| 			    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_supported_band *sband; | ||||
|  | @ -1817,7 +1835,7 @@ int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata, | |||
| 	u8 i, rates, *pos; | ||||
| 	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; | ||||
| 	if (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, | ||||
| 				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_supported_band *sband; | ||||
|  | @ -1848,7 +1867,7 @@ int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata, | |||
| 	u8 i, exrates, *pos; | ||||
| 	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; | ||||
| 	if (exrates > 8) | ||||
| 		exrates -= 8; | ||||
|  |  | |||
|  | @ -150,6 +150,20 @@ static void rfkill_led_trigger_activate(struct led_classdev *led) | |||
| 	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) | ||||
| { | ||||
| 	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