[linux-next] LinuxNextTracking branch, master, updated. next-20121126

batman at open-mesh.org batman at open-mesh.org
Tue Nov 27 00:21:18 CET 2012


The following commit has been merged in the master branch:
commit 67f4efdce7d85282fbd5832cddc80a07eb89b6d6
Merge: c53aa5058ad5ca8876a47d6639ad4d4f2c5ed584 f4a75d2eb7b1e2206094b901be09adb31ba63681
Author: David S. Miller <davem at davemloft.net>
Date:   Sat Nov 17 22:00:43 2012 -0500

    Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
    
    Minor line offset auto-merges.
    
    Signed-off-by: David S. Miller <davem at davemloft.net>

diff --combined MAINTAINERS
index aedb604,bb0b27d..a9c794c
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@@ -2507,6 -2507,7 +2507,7 @@@ M:	Joonyoung Shim <jy0922.shim at samsung.
  M:	Seung-Woo Kim <sw0312.kim at samsung.com>
  M:	Kyungmin Park <kyungmin.park at samsung.com>
  L:	dri-devel at lists.freedesktop.org
+ T:	git git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos.git
  S:	Supported
  F:	drivers/gpu/drm/exynos
  F:	include/drm/exynos*
@@@ -3597,6 -3598,49 +3598,49 @@@ F:	drivers/hid/hid-hyperv.
  F:	drivers/net/hyperv/
  F:	drivers/staging/hv/
  
+ I2C OVER PARALLEL PORT
+ M:	Jean Delvare <khali at linux-fr.org>
+ L:	linux-i2c at vger.kernel.org
+ S:	Maintained
+ F:	Documentation/i2c/busses/i2c-parport
+ F:	Documentation/i2c/busses/i2c-parport-light
+ F:	drivers/i2c/busses/i2c-parport.c
+ F:	drivers/i2c/busses/i2c-parport-light.c
+ 
+ I2C/SMBUS CONTROLLER DRIVERS FOR PC
+ M:	Jean Delvare <khali at linux-fr.org>
+ L:	linux-i2c at vger.kernel.org
+ S:	Maintained
+ F:	Documentation/i2c/busses/i2c-ali1535
+ F:	Documentation/i2c/busses/i2c-ali1563
+ F:	Documentation/i2c/busses/i2c-ali15x3
+ F:	Documentation/i2c/busses/i2c-amd756
+ F:	Documentation/i2c/busses/i2c-amd8111
+ F:	Documentation/i2c/busses/i2c-i801
+ F:	Documentation/i2c/busses/i2c-nforce2
+ F:	Documentation/i2c/busses/i2c-piix4
+ F:	Documentation/i2c/busses/i2c-sis5595
+ F:	Documentation/i2c/busses/i2c-sis630
+ F:	Documentation/i2c/busses/i2c-sis96x
+ F:	Documentation/i2c/busses/i2c-via
+ F:	Documentation/i2c/busses/i2c-viapro
+ F:	drivers/i2c/busses/i2c-ali1535.c
+ F:	drivers/i2c/busses/i2c-ali1563.c
+ F:	drivers/i2c/busses/i2c-ali15x3.c
+ F:	drivers/i2c/busses/i2c-amd756.c
+ F:	drivers/i2c/busses/i2c-amd756-s4882.c
+ F:	drivers/i2c/busses/i2c-amd8111.c
+ F:	drivers/i2c/busses/i2c-i801.c
+ F:	drivers/i2c/busses/i2c-isch.c
+ F:	drivers/i2c/busses/i2c-nforce2.c
+ F:	drivers/i2c/busses/i2c-nforce2-s4985.c
+ F:	drivers/i2c/busses/i2c-piix4.c
+ F:	drivers/i2c/busses/i2c-sis5595.c
+ F:	drivers/i2c/busses/i2c-sis630.c
+ F:	drivers/i2c/busses/i2c-sis96x.c
+ F:	drivers/i2c/busses/i2c-via.c
+ F:	drivers/i2c/busses/i2c-viapro.c
+ 
  I2C/SMBUS STUB DRIVER
  M:	"Mark M. Hoffman" <mhoffman at lightlink.com>
  L:	linux-i2c at vger.kernel.org
@@@ -3604,9 -3648,8 +3648,8 @@@ S:	Maintaine
  F:	drivers/i2c/busses/i2c-stub.c
  
  I2C SUBSYSTEM
- M:	"Jean Delvare (PC drivers, core)" <khali at linux-fr.org>
+ M:	Wolfram Sang <w.sang at pengutronix.de>
  M:	"Ben Dooks (embedded platforms)" <ben-linux at fluff.org>
- M:	"Wolfram Sang (embedded platforms)" <w.sang at pengutronix.de>
  L:	linux-i2c at vger.kernel.org
  W:	http://i2c.wiki.kernel.org/
  T:	quilt kernel.org/pub/linux/kernel/people/jdelvare/linux-2.6/jdelvare-i2c/
@@@ -3617,6 -3660,13 +3660,13 @@@ F:	drivers/i2c
  F:	include/linux/i2c.h
  F:	include/linux/i2c-*.h
  
+ I2C-TAOS-EVM DRIVER
+ M:	Jean Delvare <khali at linux-fr.org>
+ L:	linux-i2c at vger.kernel.org
+ S:	Maintained
+ F:	Documentation/i2c/busses/i2c-taos-evm
+ F:	drivers/i2c/busses/i2c-taos-evm.c
+ 
  I2C-TINY-USB DRIVER
  M:	Till Harbaum <till at harbaum.org>
  L:	linux-i2c at vger.kernel.org
@@@ -3878,9 -3928,7 +3928,9 @@@ M:	Greg Rose <gregory.v.rose at intel.com
  M:	Peter P Waskiewicz Jr <peter.p.waskiewicz.jr at intel.com>
  M:	Alex Duyck <alexander.h.duyck at intel.com>
  M:	John Ronciak <john.ronciak at intel.com>
 +M:	Tushar Dave <tushar.n.dave at intel.com>
  L:	e1000-devel at lists.sourceforge.net
 +W:	http://www.intel.com/support/feedback.htm
  W:	http://e1000.sourceforge.net/
  T:	git git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/net.git
  T:	git git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/net-next.git
@@@ -6367,7 -6415,6 +6417,7 @@@ F:	drivers/scsi/st
  SCTP PROTOCOL
  M:	Vlad Yasevich <vyasevich at gmail.com>
  M:	Sridhar Samudrala <sri at us.ibm.com>
 +M:	Neil Horman <nhorman at tuxdriver.com>
  L:	linux-sctp at vger.kernel.org
  W:	http://lksctp.sourceforge.net
  S:	Maintained
@@@ -7212,6 -7259,14 +7262,14 @@@ L:	linux-xtensa at linux-xtensa.or
  S:	Maintained
  F:	arch/xtensa/
  
+ THERMAL
+ M:      Zhang Rui <rui.zhang at intel.com>
+ L:      linux-pm at vger.kernel.org
+ T:      git git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux.git
+ S:      Supported
+ F:      drivers/thermal/
+ F:      include/linux/thermal.h
+ 
  THINKPAD ACPI EXTRAS DRIVER
  M:	Henrique de Moraes Holschuh <ibm-acpi at hmh.eng.br>
  L:	ibm-acpi-devel at lists.sourceforge.net
@@@ -7509,12 -7564,6 +7567,12 @@@ S:	Maintaine
  F:	Documentation/usb/acm.txt
  F:	drivers/usb/class/cdc-acm.*
  
 +USB AR5523 WIRELESS DRIVER
 +M:	Pontus Fuchs <pontus.fuchs at gmail.com>
 +L:	linux-wireless at vger.kernel.org
 +S:	Maintained
 +F:	drivers/net/wireless/ath/ar5523/
 +
  USB ATTACHED SCSI
  M:	Matthew Wilcox <willy at linux.intel.com>
  M:	Sarah Sharp <sarah.a.sharp at linux.intel.com>
@@@ -7895,13 -7944,6 +7953,6 @@@ M:	Roger Luethi <rl at hellgate.ch
  S:	Maintained
  F:	drivers/net/ethernet/via/via-rhine.c
  
- VIAPRO SMBUS DRIVER
- M:	Jean Delvare <khali at linux-fr.org>
- L:	linux-i2c at vger.kernel.org
- S:	Maintained
- F:	Documentation/i2c/busses/i2c-viapro
- F:	drivers/i2c/busses/i2c-viapro.c
- 
  VIA SD/MMC CARD CONTROLLER DRIVER
  M:	Bruce Chang <brucechang at via.com.tw>
  M:	Harald Welte <HaraldWelte at viatech.com>
diff --combined drivers/net/ethernet/micrel/ksz884x.c
index e4ba868,69e0197..d16ef24
--- a/drivers/net/ethernet/micrel/ksz884x.c
+++ b/drivers/net/ethernet/micrel/ksz884x.c
@@@ -5459,8 -5459,10 +5459,10 @@@ static int prepare_hardware(struct net_
  	rc = request_irq(dev->irq, netdev_intr, IRQF_SHARED, dev->name, dev);
  	if (rc)
  		return rc;
- 	tasklet_enable(&hw_priv->rx_tasklet);
- 	tasklet_enable(&hw_priv->tx_tasklet);
+ 	tasklet_init(&hw_priv->rx_tasklet, rx_proc_task,
+ 		     (unsigned long) hw_priv);
+ 	tasklet_init(&hw_priv->tx_tasklet, tx_proc_task,
+ 		     (unsigned long) hw_priv);
  
  	hw->promiscuous = 0;
  	hw->all_multi = 0;
@@@ -7033,16 -7035,6 +7035,6 @@@ static int __devinit pcidev_init(struc
  	spin_lock_init(&hw_priv->hwlock);
  	mutex_init(&hw_priv->lock);
  
- 	/* tasklet is enabled. */
- 	tasklet_init(&hw_priv->rx_tasklet, rx_proc_task,
- 		(unsigned long) hw_priv);
- 	tasklet_init(&hw_priv->tx_tasklet, tx_proc_task,
- 		(unsigned long) hw_priv);
- 
- 	/* tasklet_enable will decrement the atomic counter. */
- 	tasklet_disable(&hw_priv->rx_tasklet);
- 	tasklet_disable(&hw_priv->tx_tasklet);
- 
  	for (i = 0; i < TOTAL_PORT_NUM; i++)
  		init_waitqueue_head(&hw_priv->counter[i].counter);
  
@@@ -7251,7 -7243,18 +7243,7 @@@ static struct pci_driver pci_device_dri
  	.remove		= pcidev_exit
  };
  
 -static int __init ksz884x_init_module(void)
 -{
 -	return pci_register_driver(&pci_device_driver);
 -}
 -
 -static void __exit ksz884x_cleanup_module(void)
 -{
 -	pci_unregister_driver(&pci_device_driver);
 -}
 -
 -module_init(ksz884x_init_module);
 -module_exit(ksz884x_cleanup_module);
 +module_pci_driver(pci_device_driver);
  
  MODULE_DESCRIPTION("KSZ8841/2 PCI network driver");
  MODULE_AUTHOR("Tristram Ha <Tristram.Ha at micrel.com>");
diff --combined drivers/net/usb/cdc_ncm.c
index ddc7b88,74fab1a..d38bc20
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@@ -51,10 -51,90 +51,10 @@@
  #include <linux/atomic.h>
  #include <linux/usb/usbnet.h>
  #include <linux/usb/cdc.h>
 +#include <linux/usb/cdc_ncm.h>
  
  #define	DRIVER_VERSION				"14-Mar-2012"
  
 -/* CDC NCM subclass 3.2.1 */
 -#define USB_CDC_NCM_NDP16_LENGTH_MIN		0x10
 -
 -/* Maximum NTB length */
 -#define	CDC_NCM_NTB_MAX_SIZE_TX			32768	/* bytes */
 -#define	CDC_NCM_NTB_MAX_SIZE_RX			32768	/* bytes */
 -
 -/* Minimum value for MaxDatagramSize, ch. 6.2.9 */
 -#define	CDC_NCM_MIN_DATAGRAM_SIZE		1514	/* bytes */
 -
 -#define	CDC_NCM_MIN_TX_PKT			512	/* bytes */
 -
 -/* Default value for MaxDatagramSize */
 -#define	CDC_NCM_MAX_DATAGRAM_SIZE		8192	/* bytes */
 -
 -/*
 - * Maximum amount of datagrams in NCM Datagram Pointer Table, not counting
 - * the last NULL entry.
 - */
 -#define	CDC_NCM_DPT_DATAGRAMS_MAX		40
 -
 -/* Restart the timer, if amount of datagrams is less than given value */
 -#define	CDC_NCM_RESTART_TIMER_DATAGRAM_CNT	3
 -#define	CDC_NCM_TIMER_PENDING_CNT		2
 -#define CDC_NCM_TIMER_INTERVAL			(400UL * NSEC_PER_USEC)
 -
 -/* The following macro defines the minimum header space */
 -#define	CDC_NCM_MIN_HDR_SIZE \
 -	(sizeof(struct usb_cdc_ncm_nth16) + sizeof(struct usb_cdc_ncm_ndp16) + \
 -	(CDC_NCM_DPT_DATAGRAMS_MAX + 1) * sizeof(struct usb_cdc_ncm_dpe16))
 -
 -struct cdc_ncm_data {
 -	struct usb_cdc_ncm_nth16 nth16;
 -	struct usb_cdc_ncm_ndp16 ndp16;
 -	struct usb_cdc_ncm_dpe16 dpe16[CDC_NCM_DPT_DATAGRAMS_MAX + 1];
 -};
 -
 -struct cdc_ncm_ctx {
 -	struct cdc_ncm_data tx_ncm;
 -	struct usb_cdc_ncm_ntb_parameters ncm_parm;
 -	struct hrtimer tx_timer;
 -	struct tasklet_struct bh;
 -
 -	const struct usb_cdc_ncm_desc *func_desc;
 -	const struct usb_cdc_header_desc *header_desc;
 -	const struct usb_cdc_union_desc *union_desc;
 -	const struct usb_cdc_ether_desc *ether_desc;
 -
 -	struct net_device *netdev;
 -	struct usb_device *udev;
 -	struct usb_host_endpoint *in_ep;
 -	struct usb_host_endpoint *out_ep;
 -	struct usb_host_endpoint *status_ep;
 -	struct usb_interface *intf;
 -	struct usb_interface *control;
 -	struct usb_interface *data;
 -
 -	struct sk_buff *tx_curr_skb;
 -	struct sk_buff *tx_rem_skb;
 -
 -	spinlock_t mtx;
 -	atomic_t stop;
 -
 -	u32 tx_timer_pending;
 -	u32 tx_curr_offset;
 -	u32 tx_curr_last_offset;
 -	u32 tx_curr_frame_num;
 -	u32 rx_speed;
 -	u32 tx_speed;
 -	u32 rx_max;
 -	u32 tx_max;
 -	u32 max_datagram_size;
 -	u16 tx_max_datagrams;
 -	u16 tx_remainder;
 -	u16 tx_modulus;
 -	u16 tx_ndp_modulus;
 -	u16 tx_seq;
 -	u16 rx_seq;
 -	u16 connected;
 -};
 -
  static void cdc_ncm_txpath_bh(unsigned long param);
  static void cdc_ncm_tx_timeout_start(struct cdc_ncm_ctx *ctx);
  static enum hrtimer_restart cdc_ncm_tx_timer_cb(struct hrtimer *hr_timer);
@@@ -78,19 -158,17 +78,19 @@@ static u8 cdc_ncm_setup(struct cdc_ncm_
  	u8 flags;
  	u8 iface_no;
  	int err;
 +	int eth_hlen;
  	u16 ntb_fmt_supported;
 +	u32 min_dgram_size;
 +	u32 min_hdr_size;
 +	struct usbnet *dev = netdev_priv(ctx->netdev);
  
  	iface_no = ctx->control->cur_altsetting->desc.bInterfaceNumber;
  
 -	err = usb_control_msg(ctx->udev,
 -				usb_rcvctrlpipe(ctx->udev, 0),
 -				USB_CDC_GET_NTB_PARAMETERS,
 -				USB_TYPE_CLASS | USB_DIR_IN
 -				 | USB_RECIP_INTERFACE,
 -				0, iface_no, &ctx->ncm_parm,
 -				sizeof(ctx->ncm_parm), 10000);
 +	err = usbnet_read_cmd(dev, USB_CDC_GET_NTB_PARAMETERS,
 +			      USB_TYPE_CLASS | USB_DIR_IN
 +			      |USB_RECIP_INTERFACE,
 +			      0, iface_no, &ctx->ncm_parm,
 +			      sizeof(ctx->ncm_parm));
  	if (err < 0) {
  		pr_debug("failed GET_NTB_PARAMETERS\n");
  		return 1;
@@@ -106,19 -184,10 +106,19 @@@
  	ctx->tx_max_datagrams = le16_to_cpu(ctx->ncm_parm.wNtbOutMaxDatagrams);
  	ntb_fmt_supported = le16_to_cpu(ctx->ncm_parm.bmNtbFormatsSupported);
  
 -	if (ctx->func_desc != NULL)
 +	eth_hlen = ETH_HLEN;
 +	min_dgram_size = CDC_NCM_MIN_DATAGRAM_SIZE;
 +	min_hdr_size = CDC_NCM_MIN_HDR_SIZE;
 +	if (ctx->mbim_desc != NULL) {
 +		flags = ctx->mbim_desc->bmNetworkCapabilities;
 +		eth_hlen = 0;
 +		min_dgram_size = CDC_MBIM_MIN_DATAGRAM_SIZE;
 +		min_hdr_size = 0;
 +	} else if (ctx->func_desc != NULL) {
  		flags = ctx->func_desc->bmNetworkCapabilities;
 -	else
 +	} else {
  		flags = 0;
 +	}
  
  	pr_debug("dwNtbInMaxSize=%u dwNtbOutMaxSize=%u "
  		 "wNdpOutPayloadRemainder=%u wNdpOutDivisor=%u "
@@@ -146,19 -215,49 +146,19 @@@
  
  	/* inform device about NTB input size changes */
  	if (ctx->rx_max != le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize)) {
 +		__le32 dwNtbInMaxSize = cpu_to_le32(ctx->rx_max);
  
 -		if (flags & USB_CDC_NCM_NCAP_NTB_INPUT_SIZE) {
 -			struct usb_cdc_ncm_ndp_input_size *ndp_in_sz;
 -
 -			ndp_in_sz = kzalloc(sizeof(*ndp_in_sz), GFP_KERNEL);
 -			if (!ndp_in_sz) {
 -				err = -ENOMEM;
 -				goto size_err;
 -			}
 -
 -			err = usb_control_msg(ctx->udev,
 -					usb_sndctrlpipe(ctx->udev, 0),
 -					USB_CDC_SET_NTB_INPUT_SIZE,
 -					USB_TYPE_CLASS | USB_DIR_OUT
 -					 | USB_RECIP_INTERFACE,
 -					0, iface_no, ndp_in_sz, 8, 1000);
 -			kfree(ndp_in_sz);
 -		} else {
 -			__le32 *dwNtbInMaxSize;
 -			dwNtbInMaxSize = kzalloc(sizeof(*dwNtbInMaxSize),
 -					GFP_KERNEL);
 -			if (!dwNtbInMaxSize) {
 -				err = -ENOMEM;
 -				goto size_err;
 -			}
 -			*dwNtbInMaxSize = cpu_to_le32(ctx->rx_max);
 -
 -			err = usb_control_msg(ctx->udev,
 -					usb_sndctrlpipe(ctx->udev, 0),
 -					USB_CDC_SET_NTB_INPUT_SIZE,
 -					USB_TYPE_CLASS | USB_DIR_OUT
 -					 | USB_RECIP_INTERFACE,
 -					0, iface_no, dwNtbInMaxSize, 4, 1000);
 -			kfree(dwNtbInMaxSize);
 -		}
 -size_err:
 +		err = usbnet_write_cmd(dev, USB_CDC_SET_NTB_INPUT_SIZE,
 +				       USB_TYPE_CLASS | USB_DIR_OUT
 +				       | USB_RECIP_INTERFACE,
 +				       0, iface_no, &dwNtbInMaxSize, 4);
  		if (err < 0)
  			pr_debug("Setting NTB Input Size failed\n");
  	}
  
  	/* verify maximum size of transmitted NTB in bytes */
  	if ((ctx->tx_max <
 -	    (CDC_NCM_MIN_HDR_SIZE + CDC_NCM_MIN_DATAGRAM_SIZE)) ||
 +	    (min_hdr_size + min_dgram_size)) ||
  	    (ctx->tx_max > CDC_NCM_NTB_MAX_SIZE_TX)) {
  		pr_debug("Using default maximum transmit length=%d\n",
  						CDC_NCM_NTB_MAX_SIZE_TX);
@@@ -200,85 -299,93 +200,85 @@@
  	}
  
  	/* adjust TX-remainder according to NCM specification. */
 -	ctx->tx_remainder = ((ctx->tx_remainder - ETH_HLEN) &
 -						(ctx->tx_modulus - 1));
 +	ctx->tx_remainder = ((ctx->tx_remainder - eth_hlen) &
 +			     (ctx->tx_modulus - 1));
  
  	/* additional configuration */
  
  	/* set CRC Mode */
  	if (flags & USB_CDC_NCM_NCAP_CRC_MODE) {
 -		err = usb_control_msg(ctx->udev, usb_sndctrlpipe(ctx->udev, 0),
 -				USB_CDC_SET_CRC_MODE,
 -				USB_TYPE_CLASS | USB_DIR_OUT
 -				 | USB_RECIP_INTERFACE,
 -				USB_CDC_NCM_CRC_NOT_APPENDED,
 -				iface_no, NULL, 0, 1000);
 +		err = usbnet_write_cmd(dev, USB_CDC_SET_CRC_MODE,
 +				       USB_TYPE_CLASS | USB_DIR_OUT
 +				       | USB_RECIP_INTERFACE,
 +				       USB_CDC_NCM_CRC_NOT_APPENDED,
 +				       iface_no, NULL, 0);
  		if (err < 0)
  			pr_debug("Setting CRC mode off failed\n");
  	}
  
  	/* set NTB format, if both formats are supported */
  	if (ntb_fmt_supported & USB_CDC_NCM_NTH32_SIGN) {
 -		err = usb_control_msg(ctx->udev, usb_sndctrlpipe(ctx->udev, 0),
 -				USB_CDC_SET_NTB_FORMAT, USB_TYPE_CLASS
 -				 | USB_DIR_OUT | USB_RECIP_INTERFACE,
 -				USB_CDC_NCM_NTB16_FORMAT,
 -				iface_no, NULL, 0, 1000);
 +		err = usbnet_write_cmd(dev, USB_CDC_SET_NTB_FORMAT,
 +				       USB_TYPE_CLASS | USB_DIR_OUT
 +				       | USB_RECIP_INTERFACE,
 +				       USB_CDC_NCM_NTB16_FORMAT,
 +				       iface_no, NULL, 0);
  		if (err < 0)
  			pr_debug("Setting NTB format to 16-bit failed\n");
  	}
  
 -	ctx->max_datagram_size = CDC_NCM_MIN_DATAGRAM_SIZE;
 +	ctx->max_datagram_size = min_dgram_size;
  
  	/* set Max Datagram Size (MTU) */
  	if (flags & USB_CDC_NCM_NCAP_MAX_DATAGRAM_SIZE) {
 -		__le16 *max_datagram_size;
 -		u16 eth_max_sz = le16_to_cpu(ctx->ether_desc->wMaxSegmentSize);
 -
 -		max_datagram_size = kzalloc(sizeof(*max_datagram_size),
 -				GFP_KERNEL);
 -		if (!max_datagram_size) {
 -			err = -ENOMEM;
 +		__le16 max_datagram_size;
 +		u16 eth_max_sz;
 +		if (ctx->ether_desc != NULL)
 +			eth_max_sz = le16_to_cpu(ctx->ether_desc->wMaxSegmentSize);
 +		else if (ctx->mbim_desc != NULL)
 +			eth_max_sz = le16_to_cpu(ctx->mbim_desc->wMaxSegmentSize);
 +		else
  			goto max_dgram_err;
 -		}
  
 -		err = usb_control_msg(ctx->udev, usb_rcvctrlpipe(ctx->udev, 0),
 -				USB_CDC_GET_MAX_DATAGRAM_SIZE,
 -				USB_TYPE_CLASS | USB_DIR_IN
 -				 | USB_RECIP_INTERFACE,
 -				0, iface_no, max_datagram_size,
 -				2, 1000);
 +		err = usbnet_read_cmd(dev, USB_CDC_GET_MAX_DATAGRAM_SIZE,
 +				      USB_TYPE_CLASS | USB_DIR_IN
 +				      | USB_RECIP_INTERFACE,
 +				      0, iface_no, &max_datagram_size, 2);
  		if (err < 0) {
  			pr_debug("GET_MAX_DATAGRAM_SIZE failed, use size=%u\n",
 -						CDC_NCM_MIN_DATAGRAM_SIZE);
 +				 min_dgram_size);
  		} else {
  			ctx->max_datagram_size =
 -				le16_to_cpu(*max_datagram_size);
 +				le16_to_cpu(max_datagram_size);
  			/* Check Eth descriptor value */
  			if (ctx->max_datagram_size > eth_max_sz)
  					ctx->max_datagram_size = eth_max_sz;
  
  			if (ctx->max_datagram_size > CDC_NCM_MAX_DATAGRAM_SIZE)
 -				ctx->max_datagram_size =
 -						CDC_NCM_MAX_DATAGRAM_SIZE;
 +				ctx->max_datagram_size = CDC_NCM_MAX_DATAGRAM_SIZE;
  
 -			if (ctx->max_datagram_size < CDC_NCM_MIN_DATAGRAM_SIZE)
 -				ctx->max_datagram_size =
 -					CDC_NCM_MIN_DATAGRAM_SIZE;
 +			if (ctx->max_datagram_size < min_dgram_size)
 +				ctx->max_datagram_size = min_dgram_size;
  
  			/* if value changed, update device */
  			if (ctx->max_datagram_size !=
 -					le16_to_cpu(*max_datagram_size)) {
 -				err = usb_control_msg(ctx->udev,
 -						usb_sndctrlpipe(ctx->udev, 0),
 +					le16_to_cpu(max_datagram_size)) {
 +				err = usbnet_write_cmd(dev,
  						USB_CDC_SET_MAX_DATAGRAM_SIZE,
  						USB_TYPE_CLASS | USB_DIR_OUT
  						 | USB_RECIP_INTERFACE,
  						0,
 -						iface_no, max_datagram_size,
 -						2, 1000);
 +						iface_no, &max_datagram_size,
 +						2);
  				if (err < 0)
  					pr_debug("SET_MAX_DGRAM_SIZE failed\n");
  			}
  		}
  	}
  
  max_dgram_err:
 -	if (ctx->netdev->mtu != (ctx->max_datagram_size - ETH_HLEN))
 -		ctx->netdev->mtu = ctx->max_datagram_size - ETH_HLEN;
 +	if (ctx->netdev->mtu != (ctx->max_datagram_size - eth_hlen))
 +		ctx->netdev->mtu = ctx->max_datagram_size - eth_hlen;
  
  	return 0;
  }
@@@ -344,7 -451,7 +344,7 @@@ static const struct ethtool_ops cdc_ncm
  	.nway_reset = usbnet_nway_reset,
  };
  
 -static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf)
 +int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting)
  {
  	struct cdc_ncm_ctx *ctx;
  	struct usb_driver *driver;
@@@ -418,13 -525,6 +418,13 @@@
  			ctx->func_desc = (const struct usb_cdc_ncm_desc *)buf;
  			break;
  
 +		case USB_CDC_MBIM_TYPE:
 +			if (buf[0] < sizeof(*(ctx->mbim_desc)))
 +				break;
 +
 +			ctx->mbim_desc = (const struct usb_cdc_mbim_desc *)buf;
 +			break;
 +
  		default:
  			break;
  		}
@@@ -437,13 -537,15 +437,15 @@@ advance
  
  	/* check if we got everything */
  	if ((ctx->control == NULL) || (ctx->data == NULL) ||
 -	    (ctx->ether_desc == NULL) || (ctx->control != intf))
 +	    ((!ctx->mbim_desc) && ((ctx->ether_desc == NULL) || (ctx->control != intf))))
  		goto error;
  
- 	/* claim interfaces, if any */
- 	temp = usb_driver_claim_interface(driver, ctx->data, dev);
- 	if (temp)
- 		goto error;
+ 	/* claim data interface, if different from control */
+ 	if (ctx->data != ctx->control) {
+ 		temp = usb_driver_claim_interface(driver, ctx->data, dev);
+ 		if (temp)
+ 			goto error;
+ 	}
  
  	iface_no = ctx->data->cur_altsetting->desc.bInterfaceNumber;
  
@@@ -457,7 -559,7 +459,7 @@@
  		goto error2;
  
  	/* configure data interface */
 -	temp = usb_set_interface(dev->udev, iface_no, 1);
 +	temp = usb_set_interface(dev->udev, iface_no, data_altsetting);
  	if (temp)
  		goto error2;
  
@@@ -474,13 -576,11 +476,13 @@@
  	usb_set_intfdata(ctx->control, dev);
  	usb_set_intfdata(ctx->intf, dev);
  
 -	temp = usbnet_get_ethernet_addr(dev, ctx->ether_desc->iMACAddress);
 -	if (temp)
 -		goto error2;
 +	if (ctx->ether_desc) {
 +		temp = usbnet_get_ethernet_addr(dev, ctx->ether_desc->iMACAddress);
 +		if (temp)
 +			goto error2;
 +		dev_info(&dev->udev->dev, "MAC-Address: %pM\n", dev->net->dev_addr);
 +	}
  
 -	dev_info(&dev->udev->dev, "MAC-Address: %pM\n", dev->net->dev_addr);
  
  	dev->in = usb_rcvbulkpipe(dev->udev,
  		ctx->in_ep->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
@@@ -489,6 -589,13 +491,6 @@@
  	dev->status = ctx->status_ep;
  	dev->rx_urb_size = ctx->rx_max;
  
 -	/*
 -	 * We should get an event when network connection is "connected" or
 -	 * "disconnected". Set network connection in "disconnected" state
 -	 * (carrier is OFF) during attach, so the IP network stack does not
 -	 * start IPv6 negotiation and more.
 -	 */
 -	netif_carrier_off(dev->net);
  	ctx->tx_speed = ctx->rx_speed = 0;
  	return 0;
  
@@@ -502,9 -609,8 +504,9 @@@ error
  	dev_info(&dev->udev->dev, "bind() failure\n");
  	return -ENODEV;
  }
 +EXPORT_SYMBOL_GPL(cdc_ncm_bind_common);
  
 -static void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf)
 +void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf)
  {
  	struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
  	struct usb_driver *driver = driver_of(intf);
@@@ -519,6 -625,10 +521,10 @@@
  
  	tasklet_kill(&ctx->bh);
  
+ 	/* handle devices with combined control and data interface */
+ 	if (ctx->control == ctx->data)
+ 		ctx->data = NULL;
+ 
  	/* disconnect master --> disconnect slave */
  	if (intf == ctx->control && ctx->data) {
  		usb_set_intfdata(ctx->data, NULL);
@@@ -534,121 -644,52 +540,121 @@@
  	usb_set_intfdata(ctx->intf, NULL);
  	cdc_ncm_free(ctx);
  }
 +EXPORT_SYMBOL_GPL(cdc_ncm_unbind);
  
 -static void cdc_ncm_zero_fill(u8 *ptr, u32 first, u32 end, u32 max)
 +static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf)
  {
 -	if (first >= max)
 -		return;
 -	if (first >= end)
 -		return;
 -	if (end > max)
 -		end = max;
 -	memset(ptr + first, 0, end - first);
 +	int ret;
 +
 +	/* The MBIM spec defines a NCM compatible default altsetting,
 +	 * which we may have matched:
 +	 *
 +	 *  "Functions that implement both NCM 1.0 and MBIM (an
 +	 *   “NCM/MBIM function”) according to this recommendation
 +	 *   shall provide two alternate settings for the
 +	 *   Communication Interface.  Alternate setting 0, and the
 +	 *   associated class and endpoint descriptors, shall be
 +	 *   constructed according to the rules given for the
 +	 *   Communication Interface in section 5 of [USBNCM10].
 +	 *   Alternate setting 1, and the associated class and
 +	 *   endpoint descriptors, shall be constructed according to
 +	 *   the rules given in section 6 (USB Device Model) of this
 +	 *   specification."
 +	 *
 +	 * Do not bind to such interfaces, allowing cdc_mbim to handle
 +	 * them
 +	 */
 +#if IS_ENABLED(CONFIG_USB_NET_CDC_MBIM)
 +	if ((intf->num_altsetting == 2) &&
 +	    !usb_set_interface(dev->udev,
 +			       intf->cur_altsetting->desc.bInterfaceNumber,
 +			       CDC_NCM_COMM_ALTSETTING_MBIM) &&
 +	    cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting))
 +		return -ENODEV;
 +#endif
 +
 +	/* NCM data altsetting is always 1 */
 +	ret = cdc_ncm_bind_common(dev, intf, 1);
 +
 +	/*
 +	 * We should get an event when network connection is "connected" or
 +	 * "disconnected". Set network connection in "disconnected" state
 +	 * (carrier is OFF) during attach, so the IP network stack does not
 +	 * start IPv6 negotiation and more.
 +	 */
 +	netif_carrier_off(dev->net);
 +	return ret;
  }
  
 -static struct sk_buff *
 -cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb)
 +static void cdc_ncm_align_tail(struct sk_buff *skb, size_t modulus, size_t remainder, size_t max)
  {
 +	size_t align = ALIGN(skb->len, modulus) - skb->len + remainder;
 +
 +	if (skb->len + align > max)
 +		align = max - skb->len;
 +	if (align && skb_tailroom(skb) >= align)
 +		memset(skb_put(skb, align), 0, align);
 +}
 +
 +/* return a pointer to a valid struct usb_cdc_ncm_ndp16 of type sign, possibly
 + * allocating a new one within skb
 + */
 +static struct usb_cdc_ncm_ndp16 *cdc_ncm_ndp(struct cdc_ncm_ctx *ctx, struct sk_buff *skb, __le32 sign, size_t reserve)
 +{
 +	struct usb_cdc_ncm_ndp16 *ndp16 = NULL;
 +	struct usb_cdc_ncm_nth16 *nth16 = (void *)skb->data;
 +	size_t ndpoffset = le16_to_cpu(nth16->wNdpIndex);
 +
 +	/* follow the chain of NDPs, looking for a match */
 +	while (ndpoffset) {
 +		ndp16 = (struct usb_cdc_ncm_ndp16 *)(skb->data + ndpoffset);
 +		if  (ndp16->dwSignature == sign)
 +			return ndp16;
 +		ndpoffset = le16_to_cpu(ndp16->wNextNdpIndex);
 +	}
 +
 +	/* align new NDP */
 +	cdc_ncm_align_tail(skb, ctx->tx_ndp_modulus, 0, ctx->tx_max);
 +
 +	/* verify that there is room for the NDP and the datagram (reserve) */
 +	if ((ctx->tx_max - skb->len - reserve) < CDC_NCM_NDP_SIZE)
 +		return NULL;
 +
 +	/* link to it */
 +	if (ndp16)
 +		ndp16->wNextNdpIndex = cpu_to_le16(skb->len);
 +	else
 +		nth16->wNdpIndex = cpu_to_le16(skb->len);
 +
 +	/* push a new empty NDP */
 +	ndp16 = (struct usb_cdc_ncm_ndp16 *)memset(skb_put(skb, CDC_NCM_NDP_SIZE), 0, CDC_NCM_NDP_SIZE);
 +	ndp16->dwSignature = sign;
 +	ndp16->wLength = cpu_to_le16(sizeof(struct usb_cdc_ncm_ndp16) + sizeof(struct usb_cdc_ncm_dpe16));
 +	return ndp16;
 +}
 +
 +struct sk_buff *
 +cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb, __le32 sign)
 +{
 +	struct usb_cdc_ncm_nth16 *nth16;
 +	struct usb_cdc_ncm_ndp16 *ndp16;
  	struct sk_buff *skb_out;
 -	u32 rem;
 -	u32 offset;
 -	u32 last_offset;
 -	u16 n = 0, index;
 +	u16 n = 0, index, ndplen;
  	u8 ready2send = 0;
  
  	/* if there is a remaining skb, it gets priority */
 -	if (skb != NULL)
 +	if (skb != NULL) {
  		swap(skb, ctx->tx_rem_skb);
 -	else
 +		swap(sign, ctx->tx_rem_sign);
 +	} else {
  		ready2send = 1;
 -
 -	/*
 -	 * +----------------+
 -	 * | skb_out        |
 -	 * +----------------+
 -	 *           ^ offset
 -	 *        ^ last_offset
 -	 */
 +	}
  
  	/* check if we are resuming an OUT skb */
 -	if (ctx->tx_curr_skb != NULL) {
 -		/* pop variables */
 -		skb_out = ctx->tx_curr_skb;
 -		offset = ctx->tx_curr_offset;
 -		last_offset = ctx->tx_curr_last_offset;
 -		n = ctx->tx_curr_frame_num;
 +	skb_out = ctx->tx_curr_skb;
  
 -	} else {
 -		/* reset variables */
 +	/* allocate a new OUT skb */
 +	if (!skb_out) {
  		skb_out = alloc_skb((ctx->tx_max + 1), GFP_ATOMIC);
  		if (skb_out == NULL) {
  			if (skb != NULL) {
@@@ -657,21 -698,35 +663,21 @@@
  			}
  			goto exit_no_skb;
  		}
 +		/* fill out the initial 16-bit NTB header */
 +		nth16 = (struct usb_cdc_ncm_nth16 *)memset(skb_put(skb_out, sizeof(struct usb_cdc_ncm_nth16)), 0, sizeof(struct usb_cdc_ncm_nth16));
 +		nth16->dwSignature = cpu_to_le32(USB_CDC_NCM_NTH16_SIGN);
 +		nth16->wHeaderLength = cpu_to_le16(sizeof(struct usb_cdc_ncm_nth16));
 +		nth16->wSequence = cpu_to_le16(ctx->tx_seq++);
  
 -		/* make room for NTH and NDP */
 -		offset = ALIGN(sizeof(struct usb_cdc_ncm_nth16),
 -					ctx->tx_ndp_modulus) +
 -					sizeof(struct usb_cdc_ncm_ndp16) +
 -					(ctx->tx_max_datagrams + 1) *
 -					sizeof(struct usb_cdc_ncm_dpe16);
 -
 -		/* store last valid offset before alignment */
 -		last_offset = offset;
 -		/* align first Datagram offset correctly */
 -		offset = ALIGN(offset, ctx->tx_modulus) + ctx->tx_remainder;
 -		/* zero buffer till the first IP datagram */
 -		cdc_ncm_zero_fill(skb_out->data, 0, offset, offset);
 -		n = 0;
 +		/* count total number of frames in this NTB */
  		ctx->tx_curr_frame_num = 0;
  	}
  
 -	for (; n < ctx->tx_max_datagrams; n++) {
 -		/* check if end of transmit buffer is reached */
 -		if (offset >= ctx->tx_max) {
 -			ready2send = 1;
 -			break;
 -		}
 -		/* compute maximum buffer size */
 -		rem = ctx->tx_max - offset;
 -
 +	for (n = ctx->tx_curr_frame_num; n < ctx->tx_max_datagrams; n++) {
 +		/* send any remaining skb first */
  		if (skb == NULL) {
  			skb = ctx->tx_rem_skb;
 +			sign = ctx->tx_rem_sign;
  			ctx->tx_rem_skb = NULL;
  
  			/* check for end of skb */
@@@ -679,14 -734,7 +685,14 @@@
  				break;
  		}
  
 -		if (skb->len > rem) {
 +		/* get the appropriate NDP for this skb */
 +		ndp16 = cdc_ncm_ndp(ctx, skb_out, sign, skb->len + ctx->tx_modulus + ctx->tx_remainder);
 +
 +		/* align beginning of next frame */
 +		cdc_ncm_align_tail(skb_out,  ctx->tx_modulus, ctx->tx_remainder, ctx->tx_max);
 +
 +		/* check if we had enough room left for both NDP and frame */
 +		if (!ndp16 || skb_out->len + skb->len > ctx->tx_max) {
  			if (n == 0) {
  				/* won't fit, MTU problem? */
  				dev_kfree_skb_any(skb);
@@@ -699,30 -747,31 +705,30 @@@
  					ctx->netdev->stats.tx_dropped++;
  				}
  				ctx->tx_rem_skb = skb;
 +				ctx->tx_rem_sign = sign;
  				skb = NULL;
  				ready2send = 1;
  			}
  			break;
  		}
  
 -		memcpy(((u8 *)skb_out->data) + offset, skb->data, skb->len);
 -
 -		ctx->tx_ncm.dpe16[n].wDatagramLength = cpu_to_le16(skb->len);
 -		ctx->tx_ncm.dpe16[n].wDatagramIndex = cpu_to_le16(offset);
 -
 -		/* update offset */
 -		offset += skb->len;
 -
 -		/* store last valid offset before alignment */
 -		last_offset = offset;
 -
 -		/* align offset correctly */
 -		offset = ALIGN(offset, ctx->tx_modulus) + ctx->tx_remainder;
 +		/* calculate frame number withing this NDP */
 +		ndplen = le16_to_cpu(ndp16->wLength);
 +		index = (ndplen - sizeof(struct usb_cdc_ncm_ndp16)) / sizeof(struct usb_cdc_ncm_dpe16) - 1;
  
 -		/* zero padding */
 -		cdc_ncm_zero_fill(skb_out->data, last_offset, offset,
 -								ctx->tx_max);
 +		/* OK, add this skb */
 +		ndp16->dpe16[index].wDatagramLength = cpu_to_le16(skb->len);
 +		ndp16->dpe16[index].wDatagramIndex = cpu_to_le16(skb_out->len);
 +		ndp16->wLength = cpu_to_le16(ndplen + sizeof(struct usb_cdc_ncm_dpe16));
 +		memcpy(skb_put(skb_out, skb->len), skb->data, skb->len);
  		dev_kfree_skb_any(skb);
  		skb = NULL;
 +
 +		/* send now if this NDP is full */
 +		if (index >= CDC_NCM_DPT_DATAGRAMS_MAX) {
 +			ready2send = 1;
 +			break;
 +		}
  	}
  
  	/* free up any dangling skb */
@@@ -738,12 -787,16 +744,12 @@@
  		/* wait for more frames */
  		/* push variables */
  		ctx->tx_curr_skb = skb_out;
 -		ctx->tx_curr_offset = offset;
 -		ctx->tx_curr_last_offset = last_offset;
  		goto exit_no_skb;
  
  	} else if ((n < ctx->tx_max_datagrams) && (ready2send == 0)) {
  		/* wait for more frames */
  		/* push variables */
  		ctx->tx_curr_skb = skb_out;
 -		ctx->tx_curr_offset = offset;
 -		ctx->tx_curr_last_offset = last_offset;
  		/* set the pending count */
  		if (n < CDC_NCM_RESTART_TIMER_DATAGRAM_CNT)
  			ctx->tx_timer_pending = CDC_NCM_TIMER_PENDING_CNT;
@@@ -754,24 -807,75 +760,24 @@@
  		/* variables will be reset at next call */
  	}
  
 -	/* check for overflow */
 -	if (last_offset > ctx->tx_max)
 -		last_offset = ctx->tx_max;
 -
 -	/* revert offset */
 -	offset = last_offset;
 -
  	/*
  	 * If collected data size is less or equal CDC_NCM_MIN_TX_PKT bytes,
  	 * we send buffers as it is. If we get more data, it would be more
  	 * efficient for USB HS mobile device with DMA engine to receive a full
  	 * size NTB, than canceling DMA transfer and receiving a short packet.
  	 */
 -	if (offset > CDC_NCM_MIN_TX_PKT)
 -		offset = ctx->tx_max;
 -
 -	/* final zero padding */
 -	cdc_ncm_zero_fill(skb_out->data, last_offset, offset, ctx->tx_max);
 -
 -	/* store last offset */
 -	last_offset = offset;
 -
 -	if (((last_offset < ctx->tx_max) && ((last_offset %
 -			le16_to_cpu(ctx->out_ep->desc.wMaxPacketSize)) == 0)) ||
 -	    (((last_offset == ctx->tx_max) && ((ctx->tx_max %
 -		le16_to_cpu(ctx->out_ep->desc.wMaxPacketSize)) == 0)) &&
 -		(ctx->tx_max < le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize)))) {
 -		/* force short packet */
 -		*(((u8 *)skb_out->data) + last_offset) = 0;
 -		last_offset++;
 -	}
 -
 -	/* zero the rest of the DPEs plus the last NULL entry */
 -	for (; n <= CDC_NCM_DPT_DATAGRAMS_MAX; n++) {
 -		ctx->tx_ncm.dpe16[n].wDatagramLength = 0;
 -		ctx->tx_ncm.dpe16[n].wDatagramIndex = 0;
 -	}
 +	if (skb_out->len > CDC_NCM_MIN_TX_PKT)
 +		/* final zero padding */
 +		memset(skb_put(skb_out, ctx->tx_max - skb_out->len), 0, ctx->tx_max - skb_out->len);
  
 -	/* fill out 16-bit NTB header */
 -	ctx->tx_ncm.nth16.dwSignature = cpu_to_le32(USB_CDC_NCM_NTH16_SIGN);
 -	ctx->tx_ncm.nth16.wHeaderLength =
 -					cpu_to_le16(sizeof(ctx->tx_ncm.nth16));
 -	ctx->tx_ncm.nth16.wSequence = cpu_to_le16(ctx->tx_seq);
 -	ctx->tx_ncm.nth16.wBlockLength = cpu_to_le16(last_offset);
 -	index = ALIGN(sizeof(struct usb_cdc_ncm_nth16), ctx->tx_ndp_modulus);
 -	ctx->tx_ncm.nth16.wNdpIndex = cpu_to_le16(index);
 -
 -	memcpy(skb_out->data, &(ctx->tx_ncm.nth16), sizeof(ctx->tx_ncm.nth16));
 -	ctx->tx_seq++;
 -
 -	/* fill out 16-bit NDP table */
 -	ctx->tx_ncm.ndp16.dwSignature =
 -				cpu_to_le32(USB_CDC_NCM_NDP16_NOCRC_SIGN);
 -	rem = sizeof(ctx->tx_ncm.ndp16) + ((ctx->tx_curr_frame_num + 1) *
 -					sizeof(struct usb_cdc_ncm_dpe16));
 -	ctx->tx_ncm.ndp16.wLength = cpu_to_le16(rem);
 -	ctx->tx_ncm.ndp16.wNextNdpIndex = 0; /* reserved */
 -
 -	memcpy(((u8 *)skb_out->data) + index,
 -						&(ctx->tx_ncm.ndp16),
 -						sizeof(ctx->tx_ncm.ndp16));
 +	/* do we need to prevent a ZLP? */
 +	if (((skb_out->len % le16_to_cpu(ctx->out_ep->desc.wMaxPacketSize)) == 0) &&
 +	    (skb_out->len < le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize)) && skb_tailroom(skb_out))
 +		*skb_put(skb_out, 1) = 0;	/* force short packet */
  
 -	memcpy(((u8 *)skb_out->data) + index + sizeof(ctx->tx_ncm.ndp16),
 -					&(ctx->tx_ncm.dpe16),
 -					(ctx->tx_curr_frame_num + 1) *
 -					sizeof(struct usb_cdc_ncm_dpe16));
 -
 -	/* set frame length */
 -	skb_put(skb_out, last_offset);
 +	/* set final frame length */
 +	nth16 = (struct usb_cdc_ncm_nth16 *)skb_out->data;
 +	nth16->wBlockLength = cpu_to_le16(skb_out->len);
  
  	/* return skb */
  	ctx->tx_curr_skb = NULL;
@@@ -784,7 -888,6 +790,7 @@@ exit_no_skb
  		cdc_ncm_tx_timeout_start(ctx);
  	return NULL;
  }
 +EXPORT_SYMBOL_GPL(cdc_ncm_fill_tx_frame);
  
  static void cdc_ncm_tx_timeout_start(struct cdc_ncm_ctx *ctx)
  {
@@@ -819,8 -922,6 +825,8 @@@ static void cdc_ncm_txpath_bh(unsigned 
  		netif_tx_lock_bh(ctx->netdev);
  		usbnet_start_xmit(NULL, ctx->netdev);
  		netif_tx_unlock_bh(ctx->netdev);
 +	} else {
 +		spin_unlock_bh(&ctx->mtx);
  	}
  }
  
@@@ -841,7 -942,7 +847,7 @@@ cdc_ncm_tx_fixup(struct usbnet *dev, st
  		goto error;
  
  	spin_lock_bh(&ctx->mtx);
 -	skb_out = cdc_ncm_fill_tx_frame(ctx, skb);
 +	skb_out = cdc_ncm_fill_tx_frame(ctx, skb, cpu_to_le32(USB_CDC_NCM_NDP16_NOCRC_SIGN));
  	spin_unlock_bh(&ctx->mtx);
  	return skb_out;
  
@@@ -852,12 -953,17 +858,12 @@@ error
  	return NULL;
  }
  
 -static int cdc_ncm_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in)
 +/* verify NTB header and return offset of first NDP, or negative error */
 +int cdc_ncm_rx_verify_nth16(struct cdc_ncm_ctx *ctx, struct sk_buff *skb_in)
  {
 -	struct sk_buff *skb;
 -	struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
 -	int len;
 -	int nframes;
 -	int x;
 -	int offset;
  	struct usb_cdc_ncm_nth16 *nth16;
 -	struct usb_cdc_ncm_ndp16 *ndp16;
 -	struct usb_cdc_ncm_dpe16 *dpe16;
 +	int len;
 +	int ret = -EINVAL;
  
  	if (ctx == NULL)
  		goto error;
@@@ -891,23 -997,20 +897,23 @@@
  	}
  	ctx->rx_seq = le16_to_cpu(nth16->wSequence);
  
 -	len = le16_to_cpu(nth16->wNdpIndex);
 -	if ((len + sizeof(struct usb_cdc_ncm_ndp16)) > skb_in->len) {
 -		pr_debug("invalid DPT16 index <%u>\n",
 -					le16_to_cpu(nth16->wNdpIndex));
 -		goto error;
 -	}
 +	ret = le16_to_cpu(nth16->wNdpIndex);
 +error:
 +	return ret;
 +}
 +EXPORT_SYMBOL_GPL(cdc_ncm_rx_verify_nth16);
  
 -	ndp16 = (struct usb_cdc_ncm_ndp16 *)(((u8 *)skb_in->data) + len);
 +/* verify NDP header and return number of datagrams, or negative error */
 +int cdc_ncm_rx_verify_ndp16(struct sk_buff *skb_in, int ndpoffset)
 +{
 +	struct usb_cdc_ncm_ndp16 *ndp16;
 +	int ret = -EINVAL;
  
 -	if (le32_to_cpu(ndp16->dwSignature) != USB_CDC_NCM_NDP16_NOCRC_SIGN) {
 -		pr_debug("invalid DPT16 signature <%u>\n",
 -					le32_to_cpu(ndp16->dwSignature));
 +	if ((ndpoffset + sizeof(struct usb_cdc_ncm_ndp16)) > skb_in->len) {
 +		pr_debug("invalid NDP offset  <%u>\n", ndpoffset);
  		goto error;
  	}
 +	ndp16 = (struct usb_cdc_ncm_ndp16 *)(skb_in->data + ndpoffset);
  
  	if (le16_to_cpu(ndp16->wLength) < USB_CDC_NCM_NDP16_LENGTH_MIN) {
  		pr_debug("invalid DPT16 length <%u>\n",
@@@ -915,52 -1018,20 +921,52 @@@
  		goto error;
  	}
  
 -	nframes = ((le16_to_cpu(ndp16->wLength) -
 +	ret = ((le16_to_cpu(ndp16->wLength) -
  					sizeof(struct usb_cdc_ncm_ndp16)) /
  					sizeof(struct usb_cdc_ncm_dpe16));
 -	nframes--; /* we process NDP entries except for the last one */
 -
 -	len += sizeof(struct usb_cdc_ncm_ndp16);
 +	ret--; /* we process NDP entries except for the last one */
  
 -	if ((len + nframes * (sizeof(struct usb_cdc_ncm_dpe16))) >
 +	if ((sizeof(struct usb_cdc_ncm_ndp16) + ret * (sizeof(struct usb_cdc_ncm_dpe16))) >
  								skb_in->len) {
 -		pr_debug("Invalid nframes = %d\n", nframes);
 -		goto error;
 +		pr_debug("Invalid nframes = %d\n", ret);
 +		ret = -EINVAL;
  	}
  
 -	dpe16 = (struct usb_cdc_ncm_dpe16 *)(((u8 *)skb_in->data) + len);
 +error:
 +	return ret;
 +}
 +EXPORT_SYMBOL_GPL(cdc_ncm_rx_verify_ndp16);
 +
 +static int cdc_ncm_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in)
 +{
 +	struct sk_buff *skb;
 +	struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
 +	int len;
 +	int nframes;
 +	int x;
 +	int offset;
 +	struct usb_cdc_ncm_ndp16 *ndp16;
 +	struct usb_cdc_ncm_dpe16 *dpe16;
 +	int ndpoffset;
 +	int loopcount = 50; /* arbitrary max preventing infinite loop */
 +
 +	ndpoffset = cdc_ncm_rx_verify_nth16(ctx, skb_in);
 +	if (ndpoffset < 0)
 +		goto error;
 +
 +next_ndp:
 +	nframes = cdc_ncm_rx_verify_ndp16(skb_in, ndpoffset);
 +	if (nframes < 0)
 +		goto error;
 +
 +	ndp16 = (struct usb_cdc_ncm_ndp16 *)(skb_in->data + ndpoffset);
 +
 +	if (le32_to_cpu(ndp16->dwSignature) != USB_CDC_NCM_NDP16_NOCRC_SIGN) {
 +		pr_debug("invalid DPT16 signature <%u>\n",
 +			 le32_to_cpu(ndp16->dwSignature));
 +		goto err_ndp;
 +	}
 +	dpe16 = ndp16->dpe16;
  
  	for (x = 0; x < nframes; x++, dpe16++) {
  		offset = le16_to_cpu(dpe16->wDatagramIndex);
@@@ -972,7 -1043,7 +978,7 @@@
  		 */
  		if ((offset == 0) || (len == 0)) {
  			if (!x)
 -				goto error; /* empty NTB */
 +				goto err_ndp; /* empty NTB */
  			break;
  		}
  
@@@ -983,7 -1054,7 +989,7 @@@
  					"offset[%u]=%u, length=%u, skb=%p\n",
  					x, offset, len, skb_in);
  			if (!x)
 -				goto error;
 +				goto err_ndp;
  			break;
  
  		} else {
@@@ -996,12 -1067,6 +1002,12 @@@
  			usbnet_skb_return(dev, skb);
  		}
  	}
 +err_ndp:
 +	/* are there more NDPs to process? */
 +	ndpoffset = le16_to_cpu(ndp16->wNextNdpIndex);
 +	if (ndpoffset && loopcount--)
 +		goto next_ndp;
 +
  	return 1;
  error:
  	return 0;
@@@ -1066,7 -1131,7 +1072,7 @@@ static void cdc_ncm_status(struct usbne
  		 * USB_CDC_NOTIFY_NETWORK_CONNECTION notification shall be
  		 * sent by device after USB_CDC_NOTIFY_SPEED_CHANGE.
  		 */
 -		ctx->connected = event->wValue;
 +		ctx->connected = le16_to_cpu(event->wValue);
  
  		printk(KERN_INFO KBUILD_MODNAME ": %s: network connection:"
  			" %sconnected\n",
@@@ -1186,6 -1251,14 +1192,14 @@@ static const struct usb_device_id cdc_d
  	  .driver_info = (unsigned long) &wwan_info,
  	},
  
+ 	/* Huawei NCM devices disguised as vendor specific */
+ 	{ USB_VENDOR_AND_INTERFACE_INFO(0x12d1, 0xff, 0x02, 0x16),
+ 	  .driver_info = (unsigned long)&wwan_info,
+ 	},
+ 	{ USB_VENDOR_AND_INTERFACE_INFO(0x12d1, 0xff, 0x02, 0x46),
+ 	  .driver_info = (unsigned long)&wwan_info,
+ 	},
+ 
  	/* Generic CDC-NCM devices */
  	{ USB_INTERFACE_INFO(USB_CLASS_COMM,
  		USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE),
diff --combined drivers/net/usb/smsc95xx.c
index e07f70b,362cb8c..e083f53
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@@ -26,8 -26,6 +26,8 @@@
  #include <linux/ethtool.h>
  #include <linux/mii.h>
  #include <linux/usb.h>
 +#include <linux/bitrev.h>
 +#include <linux/crc16.h>
  #include <linux/crc32.h>
  #include <linux/usb/usbnet.h>
  #include <linux/slab.h>
@@@ -48,8 -46,7 +48,8 @@@
  #define SMSC95XX_INTERNAL_PHY_ID	(1)
  #define SMSC95XX_TX_OVERHEAD		(8)
  #define SMSC95XX_TX_OVERHEAD_CSUM	(12)
 -#define SUPPORTED_WAKE			(WAKE_MAGIC)
 +#define SUPPORTED_WAKE			(WAKE_UCAST | WAKE_BCAST | \
 +					 WAKE_MCAST | WAKE_ARP | WAKE_MAGIC)
  
  #define check_warn(ret, fmt, args...) \
  	({ if (ret < 0) netdev_warn(dev->net, fmt, ##args); })
@@@ -66,98 -63,80 +66,98 @@@ struct smsc95xx_priv 
  	u32 hash_lo;
  	u32 wolopts;
  	spinlock_t mac_cr_lock;
 -};
 -
 -struct usb_context {
 -	struct usb_ctrlrequest req;
 -	struct usbnet *dev;
 +	int wuff_filter_count;
  };
  
  static bool turbo_mode = true;
  module_param(turbo_mode, bool, 0644);
  MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction");
  
 -static int __must_check smsc95xx_read_reg(struct usbnet *dev, u32 index,
 -					  u32 *data)
 +static int __must_check __smsc95xx_read_reg(struct usbnet *dev, u32 index,
 +					    u32 *data, int in_pm)
  {
 -	u32 *buf = kmalloc(4, GFP_KERNEL);
 +	u32 buf;
  	int ret;
 +	int (*fn)(struct usbnet *, u8, u8, u16, u16, void *, u16);
  
  	BUG_ON(!dev);
  
 -	if (!buf)
 -		return -ENOMEM;
 -
 -	ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
 -		USB_VENDOR_REQUEST_READ_REGISTER,
 -		USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 -		00, index, buf, 4, USB_CTRL_GET_TIMEOUT);
 +	if (!in_pm)
 +		fn = usbnet_read_cmd;
 +	else
 +		fn = usbnet_read_cmd_nopm;
  
 +	ret = fn(dev, USB_VENDOR_REQUEST_READ_REGISTER, USB_DIR_IN
 +		 | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 +		 0, index, &buf, 4);
  	if (unlikely(ret < 0))
 -		netdev_warn(dev->net, "Failed to read register index 0x%08x\n", index);
 +		netdev_warn(dev->net,
 +			"Failed to read reg index 0x%08x: %d", index, ret);
  
 -	le32_to_cpus(buf);
 -	*data = *buf;
 -	kfree(buf);
 +	le32_to_cpus(&buf);
 +	*data = buf;
  
  	return ret;
  }
  
 -static int __must_check smsc95xx_write_reg(struct usbnet *dev, u32 index,
 -					   u32 data)
 +static int __must_check __smsc95xx_write_reg(struct usbnet *dev, u32 index,
 +					     u32 data, int in_pm)
  {
 -	u32 *buf = kmalloc(4, GFP_KERNEL);
 +	u32 buf;
  	int ret;
 +	int (*fn)(struct usbnet *, u8, u8, u16, u16, const void *, u16);
  
  	BUG_ON(!dev);
  
 -	if (!buf)
 -		return -ENOMEM;
 -
 -	*buf = data;
 -	cpu_to_le32s(buf);
 +	if (!in_pm)
 +		fn = usbnet_write_cmd;
 +	else
 +		fn = usbnet_write_cmd_nopm;
  
 -	ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
 -		USB_VENDOR_REQUEST_WRITE_REGISTER,
 -		USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 -		00, index, buf, 4, USB_CTRL_SET_TIMEOUT);
 +	buf = data;
 +	cpu_to_le32s(&buf);
  
 +	ret = fn(dev, USB_VENDOR_REQUEST_WRITE_REGISTER, USB_DIR_OUT
 +		 | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 +		 0, index, &buf, 4);
  	if (unlikely(ret < 0))
 -		netdev_warn(dev->net, "Failed to write register index 0x%08x\n", index);
 -
 -	kfree(buf);
 +		netdev_warn(dev->net,
 +			"Failed to write reg index 0x%08x: %d", index, ret);
  
  	return ret;
  }
  
 +static int __must_check smsc95xx_read_reg_nopm(struct usbnet *dev, u32 index,
 +					       u32 *data)
 +{
 +	return __smsc95xx_read_reg(dev, index, data, 1);
 +}
 +
 +static int __must_check smsc95xx_write_reg_nopm(struct usbnet *dev, u32 index,
 +						u32 data)
 +{
 +	return __smsc95xx_write_reg(dev, index, data, 1);
 +}
 +
 +static int __must_check smsc95xx_read_reg(struct usbnet *dev, u32 index,
 +					  u32 *data)
 +{
 +	return __smsc95xx_read_reg(dev, index, data, 0);
 +}
 +
 +static int __must_check smsc95xx_write_reg(struct usbnet *dev, u32 index,
 +					   u32 data)
 +{
 +	return __smsc95xx_write_reg(dev, index, data, 0);
 +}
  static int smsc95xx_set_feature(struct usbnet *dev, u32 feature)
  {
  	if (WARN_ON_ONCE(!dev))
  		return -EINVAL;
  
 -	cpu_to_le32s(&feature);
 -
 -	return usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
 -		USB_REQ_SET_FEATURE, USB_RECIP_DEVICE, feature, 0, NULL, 0,
 -		USB_CTRL_SET_TIMEOUT);
 +	return usbnet_write_cmd_nopm(dev, USB_REQ_SET_FEATURE,
 +				     USB_RECIP_DEVICE, feature, 0,
 +				     NULL, 0);
  }
  
  static int smsc95xx_clear_feature(struct usbnet *dev, u32 feature)
@@@ -165,9 -144,11 +165,9 @@@
  	if (WARN_ON_ONCE(!dev))
  		return -EINVAL;
  
 -	cpu_to_le32s(&feature);
 -
 -	return usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
 -		USB_REQ_CLEAR_FEATURE, USB_RECIP_DEVICE, feature, 0, NULL, 0,
 -		USB_CTRL_SET_TIMEOUT);
 +	return usbnet_write_cmd_nopm(dev, USB_REQ_CLEAR_FEATURE,
 +				     USB_RECIP_DEVICE, feature,
 +				     0, NULL, 0);
  }
  
  /* Loop until the read is completed with timeout
@@@ -203,7 -184,7 +203,7 @@@ static int smsc95xx_mdio_read(struct ne
  	/* set the address, index & direction (read from PHY) */
  	phy_id &= dev->mii.phy_id_mask;
  	idx &= dev->mii.reg_num_mask;
- 	addr = (phy_id << 11) | (idx << 6) | MII_READ_;
+ 	addr = (phy_id << 11) | (idx << 6) | MII_READ_ | MII_BUSY_;
  	ret = smsc95xx_write_reg(dev, MII_ADDR, addr);
  	check_warn_goto_done(ret, "Error writing MII_ADDR");
  
@@@ -240,7 -221,7 +240,7 @@@ static void smsc95xx_mdio_write(struct 
  	/* set the address, index & direction (write to PHY) */
  	phy_id &= dev->mii.phy_id_mask;
  	idx &= dev->mii.reg_num_mask;
- 	addr = (phy_id << 11) | (idx << 6) | MII_WRITE_;
+ 	addr = (phy_id << 11) | (idx << 6) | MII_WRITE_ | MII_BUSY_;
  	ret = smsc95xx_write_reg(dev, MII_ADDR, addr);
  	check_warn_goto_done(ret, "Error writing MII_ADDR");
  
@@@ -369,20 -350,60 +369,20 @@@ static int smsc95xx_write_eeprom(struc
  	return 0;
  }
  
  static int __must_check smsc95xx_write_reg_async(struct usbnet *dev, u16 index,
  						 u32 *data)
  {
 -	struct usb_context *usb_context;
 -	int status;
 -	struct urb *urb;
  	const u16 size = 4;
 +	int ret;
  
 -	urb = usb_alloc_urb(0, GFP_ATOMIC);
 -	if (!urb) {
 -		netdev_warn(dev->net, "Error allocating URB\n");
 -		return -ENOMEM;
 -	}
 -
 -	usb_context = kmalloc(sizeof(struct usb_context), GFP_ATOMIC);
 -	if (usb_context == NULL) {
 -		netdev_warn(dev->net, "Error allocating control msg\n");
 -		usb_free_urb(urb);
 -		return -ENOMEM;
 -	}
 -
 -	usb_context->req.bRequestType =
 -		USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
 -	usb_context->req.bRequest = USB_VENDOR_REQUEST_WRITE_REGISTER;
 -	usb_context->req.wValue = 00;
 -	usb_context->req.wIndex = cpu_to_le16(index);
 -	usb_context->req.wLength = cpu_to_le16(size);
 -
 -	usb_fill_control_urb(urb, dev->udev, usb_sndctrlpipe(dev->udev, 0),
 -		(void *)&usb_context->req, data, size,
 -		smsc95xx_async_cmd_callback,
 -		(void *)usb_context);
 -
 -	status = usb_submit_urb(urb, GFP_ATOMIC);
 -	if (status < 0) {
 -		netdev_warn(dev->net, "Error submitting control msg, sts=%d\n",
 -			    status);
 -		kfree(usb_context);
 -		usb_free_urb(urb);
 -	}
 -
 -	return status;
 +	ret = usbnet_write_cmd_async(dev, USB_VENDOR_REQUEST_WRITE_REGISTER,
 +				     USB_DIR_OUT | USB_TYPE_VENDOR |
 +				     USB_RECIP_DEVICE,
 +				     0, index, data, size);
 +	if (ret < 0)
 +		netdev_warn(dev->net, "Error write async cmd, sts=%d\n",
 +			    ret);
 +	return ret;
  }
  
  /* returns hash bit number for given MAC address
@@@ -744,7 -765,7 +744,7 @@@ static int smsc95xx_start_tx_path(struc
  }
  
  /* Starts the Receive path */
 -static int smsc95xx_start_rx_path(struct usbnet *dev)
 +static int smsc95xx_start_rx_path(struct usbnet *dev, int in_pm)
  {
  	struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
  	unsigned long flags;
@@@ -754,7 -775,7 +754,7 @@@
  	pdata->mac_cr |= MAC_CR_RXEN_;
  	spin_unlock_irqrestore(&pdata->mac_cr_lock, flags);
  
 -	ret = smsc95xx_write_reg(dev, MAC_CR, pdata->mac_cr);
 +	ret = __smsc95xx_write_reg(dev, MAC_CR, pdata->mac_cr, in_pm);
  	check_warn_return(ret, "Failed to write MAC_CR: %d\n", ret);
  
  	return 0;
@@@ -973,7 -994,7 +973,7 @@@ static int smsc95xx_reset(struct usbne
  	ret = smsc95xx_start_tx_path(dev);
  	check_warn_return(ret, "Failed to start TX path");
  
 -	ret = smsc95xx_start_rx_path(dev);
 +	ret = smsc95xx_start_rx_path(dev, 0);
  	check_warn_return(ret, "Failed to start RX path");
  
  	netif_dbg(dev, ifup, dev->net, "smsc95xx_reset, return 0\n");
@@@ -996,7 -1017,6 +996,7 @@@ static const struct net_device_ops smsc
  static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf)
  {
  	struct smsc95xx_priv *pdata = NULL;
 +	u32 val;
  	int ret;
  
  	printk(KERN_INFO SMSC_CHIPNAME " v" SMSC_DRIVER_VERSION "\n");
@@@ -1027,15 -1047,6 +1027,15 @@@
  	/* Init all registers */
  	ret = smsc95xx_reset(dev);
  
 +	/* detect device revision as different features may be available */
 +	ret = smsc95xx_read_reg(dev, ID_REV, &val);
 +	check_warn_return(ret, "Failed to read ID_REV: %d\n", ret);
 +	val >>= 16;
 +	if ((val == ID_REV_CHIP_ID_9500A_) || (val == ID_REV_CHIP_ID_9512_))
 +		pdata->wuff_filter_count = LAN9500A_WUFF_NUM;
 +	else
 +		pdata->wuff_filter_count = LAN9500_WUFF_NUM;
 +
  	dev->net->netdev_ops = &smsc95xx_netdev_ops;
  	dev->net->ethtool_ops = &smsc95xx_ethtool_ops;
  	dev->net->flags |= IFF_MULTICAST;
@@@ -1055,11 -1066,6 +1055,11 @@@ static void smsc95xx_unbind(struct usbn
  	}
  }
  
 +static u16 smsc_crc(const u8 *buffer, size_t len, int filter)
 +{
 +	return bitrev16(crc16(0xFFFF, buffer, len)) << ((filter % 2) * 16);
 +}
 +
  static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
  {
  	struct usbnet *dev = usb_get_intfdata(intf);
@@@ -1075,153 -1081,50 +1075,153 @@@
  		netdev_info(dev->net, "entering SUSPEND2 mode");
  
  		/* disable energy detect (link up) & wake up events */
 -		ret = smsc95xx_read_reg(dev, WUCSR, &val);
 +		ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val);
  		check_warn_return(ret, "Error reading WUCSR");
  
  		val &= ~(WUCSR_MPEN_ | WUCSR_WAKE_EN_);
  
 -		ret = smsc95xx_write_reg(dev, WUCSR, val);
 +		ret = smsc95xx_write_reg_nopm(dev, WUCSR, val);
  		check_warn_return(ret, "Error writing WUCSR");
  
 -		ret = smsc95xx_read_reg(dev, PM_CTRL, &val);
 +		ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
  		check_warn_return(ret, "Error reading PM_CTRL");
  
  		val &= ~(PM_CTL_ED_EN_ | PM_CTL_WOL_EN_);
  
 -		ret = smsc95xx_write_reg(dev, PM_CTRL, val);
 +		ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
  		check_warn_return(ret, "Error writing PM_CTRL");
  
  		/* enter suspend2 mode */
 -		ret = smsc95xx_read_reg(dev, PM_CTRL, &val);
 +		ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
  		check_warn_return(ret, "Error reading PM_CTRL");
  
  		val &= ~(PM_CTL_SUS_MODE_ | PM_CTL_WUPS_ | PM_CTL_PHY_RST_);
  		val |= PM_CTL_SUS_MODE_2;
  
 -		ret = smsc95xx_write_reg(dev, PM_CTRL, val);
 +		ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
  		check_warn_return(ret, "Error writing PM_CTRL");
  
  		return 0;
  	}
  
 +	if (pdata->wolopts & (WAKE_BCAST | WAKE_MCAST | WAKE_ARP | WAKE_UCAST)) {
 +		u32 *filter_mask = kzalloc(32, GFP_KERNEL);
 +		u32 command[2];
 +		u32 offset[2];
 +		u32 crc[4];
 +		int i, filter = 0;
 +
 +		memset(command, 0, sizeof(command));
 +		memset(offset, 0, sizeof(offset));
 +		memset(crc, 0, sizeof(crc));
 +
 +		if (pdata->wolopts & WAKE_BCAST) {
 +			const u8 bcast[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
 +			netdev_info(dev->net, "enabling broadcast detection");
 +			filter_mask[filter * 4] = 0x003F;
 +			filter_mask[filter * 4 + 1] = 0x00;
 +			filter_mask[filter * 4 + 2] = 0x00;
 +			filter_mask[filter * 4 + 3] = 0x00;
 +			command[filter/4] |= 0x05UL << ((filter % 4) * 8);
 +			offset[filter/4] |= 0x00 << ((filter % 4) * 8);
 +			crc[filter/2] |= smsc_crc(bcast, 6, filter);
 +			filter++;
 +		}
 +
 +		if (pdata->wolopts & WAKE_MCAST) {
 +			const u8 mcast[] = {0x01, 0x00, 0x5E};
 +			netdev_info(dev->net, "enabling multicast detection");
 +			filter_mask[filter * 4] = 0x0007;
 +			filter_mask[filter * 4 + 1] = 0x00;
 +			filter_mask[filter * 4 + 2] = 0x00;
 +			filter_mask[filter * 4 + 3] = 0x00;
 +			command[filter/4] |= 0x09UL << ((filter % 4) * 8);
 +			offset[filter/4] |= 0x00  << ((filter % 4) * 8);
 +			crc[filter/2] |= smsc_crc(mcast, 3, filter);
 +			filter++;
 +		}
 +
 +		if (pdata->wolopts & WAKE_ARP) {
 +			const u8 arp[] = {0x08, 0x06};
 +			netdev_info(dev->net, "enabling ARP detection");
 +			filter_mask[filter * 4] = 0x0003;
 +			filter_mask[filter * 4 + 1] = 0x00;
 +			filter_mask[filter * 4 + 2] = 0x00;
 +			filter_mask[filter * 4 + 3] = 0x00;
 +			command[filter/4] |= 0x05UL << ((filter % 4) * 8);
 +			offset[filter/4] |= 0x0C << ((filter % 4) * 8);
 +			crc[filter/2] |= smsc_crc(arp, 2, filter);
 +			filter++;
 +		}
 +
 +		if (pdata->wolopts & WAKE_UCAST) {
 +			netdev_info(dev->net, "enabling unicast detection");
 +			filter_mask[filter * 4] = 0x003F;
 +			filter_mask[filter * 4 + 1] = 0x00;
 +			filter_mask[filter * 4 + 2] = 0x00;
 +			filter_mask[filter * 4 + 3] = 0x00;
 +			command[filter/4] |= 0x01UL << ((filter % 4) * 8);
 +			offset[filter/4] |= 0x00 << ((filter % 4) * 8);
 +			crc[filter/2] |= smsc_crc(dev->net->dev_addr, ETH_ALEN, filter);
 +			filter++;
 +		}
 +
 +		for (i = 0; i < (pdata->wuff_filter_count * 4); i++) {
 +			ret = smsc95xx_write_reg_nopm(dev, WUFF, filter_mask[i]);
 +			if (ret < 0)
 +				kfree(filter_mask);
 +			check_warn_return(ret, "Error writing WUFF");
 +		}
 +		kfree(filter_mask);
 +
 +		for (i = 0; i < (pdata->wuff_filter_count / 4); i++) {
 +			ret = smsc95xx_write_reg_nopm(dev, WUFF, command[i]);
 +			check_warn_return(ret, "Error writing WUFF");
 +		}
 +
 +		for (i = 0; i < (pdata->wuff_filter_count / 4); i++) {
 +			ret = smsc95xx_write_reg_nopm(dev, WUFF, offset[i]);
 +			check_warn_return(ret, "Error writing WUFF");
 +		}
 +
 +		for (i = 0; i < (pdata->wuff_filter_count / 2); i++) {
 +			ret = smsc95xx_write_reg_nopm(dev, WUFF, crc[i]);
 +			check_warn_return(ret, "Error writing WUFF");
 +		}
 +
 +		/* clear any pending pattern match packet status */
 +		ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val);
 +		check_warn_return(ret, "Error reading WUCSR");
 +
 +		val |= WUCSR_WUFR_;
 +
 +		ret = smsc95xx_write_reg_nopm(dev, WUCSR, val);
 +		check_warn_return(ret, "Error writing WUCSR");
 +	}
 +
  	if (pdata->wolopts & WAKE_MAGIC) {
  		/* clear any pending magic packet status */
 -		ret = smsc95xx_read_reg(dev, WUCSR, &val);
 +		ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val);
  		check_warn_return(ret, "Error reading WUCSR");
  
  		val |= WUCSR_MPR_;
  
 -		ret = smsc95xx_write_reg(dev, WUCSR, val);
 +		ret = smsc95xx_write_reg_nopm(dev, WUCSR, val);
  		check_warn_return(ret, "Error writing WUCSR");
  	}
  
 -	/* enable/disable magic packup wake */
 -	ret = smsc95xx_read_reg(dev, WUCSR, &val);
 +	/* enable/disable wakeup sources */
 +	ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val);
  	check_warn_return(ret, "Error reading WUCSR");
  
 +	if (pdata->wolopts & (WAKE_BCAST | WAKE_MCAST | WAKE_ARP | WAKE_UCAST)) {
 +		netdev_info(dev->net, "enabling pattern match wakeup");
 +		val |= WUCSR_WAKE_EN_;
 +	} else {
 +		netdev_info(dev->net, "disabling pattern match wakeup");
 +		val &= ~WUCSR_WAKE_EN_;
 +	}
 +
  	if (pdata->wolopts & WAKE_MAGIC) {
  		netdev_info(dev->net, "enabling magic packet wakeup");
  		val |= WUCSR_MPEN_;
@@@ -1230,41 -1133,41 +1230,41 @@@
  		val &= ~WUCSR_MPEN_;
  	}
  
 -	ret = smsc95xx_write_reg(dev, WUCSR, val);
 +	ret = smsc95xx_write_reg_nopm(dev, WUCSR, val);
  	check_warn_return(ret, "Error writing WUCSR");
  
  	/* enable wol wakeup source */
 -	ret = smsc95xx_read_reg(dev, PM_CTRL, &val);
 +	ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
  	check_warn_return(ret, "Error reading PM_CTRL");
  
  	val |= PM_CTL_WOL_EN_;
  
 -	ret = smsc95xx_write_reg(dev, PM_CTRL, val);
 +	ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
  	check_warn_return(ret, "Error writing PM_CTRL");
  
 -	/* enable receiver */
 -	smsc95xx_start_rx_path(dev);
 +	/* enable receiver to enable frame reception */
 +	smsc95xx_start_rx_path(dev, 1);
  
  	/* some wol options are enabled, so enter SUSPEND0 */
  	netdev_info(dev->net, "entering SUSPEND0 mode");
  
 -	ret = smsc95xx_read_reg(dev, PM_CTRL, &val);
 +	ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
  	check_warn_return(ret, "Error reading PM_CTRL");
  
  	val &= (~(PM_CTL_SUS_MODE_ | PM_CTL_WUPS_ | PM_CTL_PHY_RST_));
  	val |= PM_CTL_SUS_MODE_0;
  
 -	ret = smsc95xx_write_reg(dev, PM_CTRL, val);
 +	ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
  	check_warn_return(ret, "Error writing PM_CTRL");
  
  	/* clear wol status */
  	val &= ~PM_CTL_WUPS_;
  	val |= PM_CTL_WUPS_WOL_;
 -	ret = smsc95xx_write_reg(dev, PM_CTRL, val);
 +	ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
  	check_warn_return(ret, "Error writing PM_CTRL");
  
  	/* read back PM_CTRL */
 -	ret = smsc95xx_read_reg(dev, PM_CTRL, &val);
 +	ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
  	check_warn_return(ret, "Error reading PM_CTRL");
  
  	smsc95xx_set_feature(dev, USB_DEVICE_REMOTE_WAKEUP);
@@@ -1281,26 -1184,26 +1281,26 @@@ static int smsc95xx_resume(struct usb_i
  
  	BUG_ON(!dev);
  
 -	if (pdata->wolopts & WAKE_MAGIC) {
 +	if (pdata->wolopts) {
  		smsc95xx_clear_feature(dev, USB_DEVICE_REMOTE_WAKEUP);
  
 -		/* Disable magic packup wake */
 -		ret = smsc95xx_read_reg(dev, WUCSR, &val);
 +		/* clear wake-up sources */
 +		ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val);
  		check_warn_return(ret, "Error reading WUCSR");
  
 -		val &= ~WUCSR_MPEN_;
 +		val &= ~(WUCSR_WAKE_EN_ | WUCSR_MPEN_);
  
 -		ret = smsc95xx_write_reg(dev, WUCSR, val);
 +		ret = smsc95xx_write_reg_nopm(dev, WUCSR, val);
  		check_warn_return(ret, "Error writing WUCSR");
  
  		/* clear wake-up status */
 -		ret = smsc95xx_read_reg(dev, PM_CTRL, &val);
 +		ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
  		check_warn_return(ret, "Error reading PM_CTRL");
  
  		val &= ~PM_CTL_WOL_EN_;
  		val |= PM_CTL_WUPS_;
  
 -		ret = smsc95xx_write_reg(dev, PM_CTRL, val);
 +		ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
  		check_warn_return(ret, "Error writing PM_CTRL");
  	}
  
diff --combined drivers/net/vxlan.c
index 9814d67,8b5c619..6898a79
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@@ -1,5 -1,5 +1,5 @@@
  /*
-  * VXLAN: Virtual eXtensiable Local Area Network
+  * VXLAN: Virtual eXtensible Local Area Network
   *
   * Copyright (c) 2012 Vyatta Inc.
   *
@@@ -50,8 -50,8 +50,8 @@@
  
  #define VXLAN_N_VID	(1u << 24)
  #define VXLAN_VID_MASK	(VXLAN_N_VID - 1)
- /* VLAN + IP header + UDP + VXLAN */
- #define VXLAN_HEADROOM (4 + 20 + 8 + 8)
+ /* IP header + UDP + VXLAN + Ethernet header */
+ #define VXLAN_HEADROOM (20 + 8 + 8 + 14)
  
  #define VXLAN_FLAGS 0x08000000	/* struct vxlanhdr.vx_flags required value. */
  
@@@ -769,7 -769,7 +769,7 @@@ static netdev_tx_t vxlan_xmit(struct sk
  
  	vxlan_set_owner(dev, skb);
  
 -	/* See __IPTUNNEL_XMIT */
 +	/* See iptunnel_xmit() */
  	skb->ip_summed = CHECKSUM_NONE;
  	ip_select_ident(iph, &rt->dst, NULL);
  
@@@ -1102,14 -1102,15 +1102,18 @@@ static int vxlan_newlink(struct net *ne
  
  		if (!tb[IFLA_MTU])
  			dev->mtu = lowerdev->mtu - VXLAN_HEADROOM;
+ 
+ 		/* update header length based on lower device */
+ 		dev->hard_header_len = lowerdev->hard_header_len +
+ 				       VXLAN_HEADROOM;
  	}
  
  	if (data[IFLA_VXLAN_TOS])
  		vxlan->tos  = nla_get_u8(data[IFLA_VXLAN_TOS]);
  
 +	if (data[IFLA_VXLAN_TTL])
 +		vxlan->ttl = nla_get_u8(data[IFLA_VXLAN_TTL]);
 +
  	if (!data[IFLA_VXLAN_LEARNING] || nla_get_u8(data[IFLA_VXLAN_LEARNING]))
  		vxlan->learn = true;
  
diff --combined drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
index cb30fea,481345c..6d55424
--- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
@@@ -35,7 -35,6 +35,7 @@@
  #include <brcmu_wifi.h>
  #include "dhd.h"
  #include "wl_cfg80211.h"
 +#include "fwil.h"
  
  #define BRCMF_SCAN_IE_LEN_MAX		2048
  #define BRCMF_PNO_VERSION		2
@@@ -49,8 -48,6 +49,8 @@@
  #define BRCMF_PNO_SCAN_COMPLETE		1
  #define BRCMF_PNO_SCAN_INCOMPLETE	0
  
 +#define BRCMF_IFACE_MAX_CNT		2
 +
  #define TLV_LEN_OFF			1	/* length offset */
  #define TLV_HDR_LEN			2	/* header length */
  #define TLV_BODY_OFF			2	/* body offset */
@@@ -94,13 -91,16 +94,13 @@@
  #define BRCMF_ASSOC_PARAMS_FIXED_SIZE \
  	(sizeof(struct brcmf_assoc_params_le) - sizeof(u16))
  
 -static const u8 ether_bcast[ETH_ALEN] = {255, 255, 255, 255, 255, 255};
 -
  static u32 brcmf_dbg_level = WL_DBG_ERR;
  
 -static bool check_sys_up(struct wiphy *wiphy)
 +static bool check_vif_up(struct brcmf_cfg80211_vif *vif)
  {
 -	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
 -	if (!test_bit(WL_STATUS_READY, &cfg->status)) {
 -		WL_INFO("device is not ready : status (%d)\n",
 -			(int)cfg->status);
 +	if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state)) {
 +		WL_INFO("device is not ready : status (%lu)\n",
 +			vif->sme_state);
  		return false;
  	}
  	return true;
@@@ -391,29 -391,55 +391,29 @@@ static u8 brcmf_mw_to_qdbm(u16 mw
  	return qdbm;
  }
  
 -/* function for reading/writing a single u32 from/to the dongle */
 -static int
 -brcmf_exec_dcmd_u32(struct net_device *ndev, u32 cmd, u32 *par)
 +static u16 channel_to_chanspec(struct ieee80211_channel *ch)
  {
 -	int err;
 -	__le32 par_le = cpu_to_le32(*par);
 -
 -	err = brcmf_exec_dcmd(ndev, cmd, &par_le, sizeof(__le32));
 -	*par = le32_to_cpu(par_le);
 -
 -	return err;
 -}
 -
 -static s32
 -brcmf_dev_iovar_setbuf_bsscfg(struct net_device *ndev, s8 *name,
 -			      void *param, s32 paramlen,
 -			      void *buf, s32 buflen, s32 bssidx)
 -{
 -	s32 err = -ENOMEM;
 -	u32 len;
 -
 -	len = brcmf_c_mkiovar_bsscfg(name, param, paramlen,
 -				     buf, buflen, bssidx);
 -	BUG_ON(!len);
 -	if (len > 0)
 -		err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, buf, len);
 -	if (err)
 -		WL_ERR("error (%d)\n", err);
 +	u16 chanspec;
  
 -	return err;
 -}
 +	chanspec = ieee80211_frequency_to_channel(ch->center_freq);
 +	chanspec &= WL_CHANSPEC_CHAN_MASK;
  
 -static s32
 -brcmf_dev_iovar_getbuf_bsscfg(struct net_device *ndev, s8 *name,
 -			      void *param, s32 paramlen,
 -			      void *buf, s32 buflen, s32 bssidx)
 -{
 -	s32 err = -ENOMEM;
 -	u32 len;
 -
 -	len = brcmf_c_mkiovar_bsscfg(name, param, paramlen,
 -				     buf, buflen, bssidx);
 -	BUG_ON(!len);
 -	if (len > 0)
 -		err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, buf, len);
 -	if (err)
 -		WL_ERR("error (%d)\n", err);
 +	if (ch->band == IEEE80211_BAND_2GHZ)
 +		chanspec |= WL_CHANSPEC_BAND_2G;
 +	else
 +		chanspec |= WL_CHANSPEC_BAND_5G;
  
 -	return err;
 +	if (ch->flags & IEEE80211_CHAN_NO_HT40) {
 +		chanspec |= WL_CHANSPEC_BW_20;
 +		chanspec |= WL_CHANSPEC_CTL_SB_NONE;
 +	} else {
 +		chanspec |= WL_CHANSPEC_BW_40;
 +		if (ch->flags & IEEE80211_CHAN_NO_HT40PLUS)
 +			chanspec |= WL_CHANSPEC_CTL_SB_LOWER;
 +		else
 +			chanspec |= WL_CHANSPEC_CTL_SB_UPPER;
 +	}
 +	return chanspec;
  }
  
  static void convert_key_from_CPU(struct brcmf_wsec_key *key,
@@@ -431,17 -457,18 +431,17 @@@
  }
  
  static int
 -send_key_to_dongle(struct brcmf_cfg80211_info *cfg, s32 bssidx,
 -		   struct net_device *ndev, struct brcmf_wsec_key *key)
 +send_key_to_dongle(struct net_device *ndev, struct brcmf_wsec_key *key)
  {
  	int err;
  	struct brcmf_wsec_key_le key_le;
  
  	convert_key_from_CPU(key, &key_le);
  
 -	err  = brcmf_dev_iovar_setbuf_bsscfg(ndev, "wsec_key", &key_le,
 -					     sizeof(key_le),
 -					     cfg->extra_buf,
 -					     WL_EXTRA_BUF_MAX, bssidx);
 +	brcmf_netdev_wait_pend8021x(ndev);
 +
 +	err = brcmf_fil_bsscfg_data_set(netdev_priv(ndev), "wsec_key", &key_le,
 +					sizeof(key_le));
  
  	if (err)
  		WL_ERR("wsec_key error (%d)\n", err);
@@@ -453,7 -480,6 +453,7 @@@ brcmf_cfg80211_change_iface(struct wiph
  			 enum nl80211_iftype type, u32 *flags,
  			 struct vif_params *params)
  {
 +	struct brcmf_if *ifp = netdev_priv(ndev);
  	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
  	s32 infra = 0;
  	s32 ap = 0;
@@@ -485,7 -511,7 +485,7 @@@
  	}
  
  	if (ap) {
 -		set_bit(WL_STATUS_AP_CREATING, &cfg->status);
 +		set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
  		if (!cfg->ap_info)
  			cfg->ap_info = kzalloc(sizeof(*cfg->ap_info),
  					       GFP_KERNEL);
@@@ -495,8 -521,7 +495,8 @@@
  		}
  		WL_INFO("IF Type = AP\n");
  	} else {
 -		err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_INFRA, &infra);
 +		err = brcmf_fil_cmd_int_set(netdev_priv(ndev),
 +					    BRCMF_C_SET_INFRA, infra);
  		if (err) {
  			WL_ERR("WLC_SET_INFRA error (%d)\n", err);
  			err = -EAGAIN;
@@@ -514,13 -539,99 +514,13 @@@ done
  	return err;
  }
  
 -static s32 brcmf_dev_intvar_set(struct net_device *ndev, s8 *name, s32 val)
 -{
 -	s8 buf[BRCMF_DCMD_SMLEN];
 -	u32 len;
 -	s32 err = 0;
 -	__le32 val_le;
 -
 -	val_le = cpu_to_le32(val);
 -	len = brcmf_c_mkiovar(name, (char *)(&val_le), sizeof(val_le), buf,
 -			    sizeof(buf));
 -	BUG_ON(!len);
 -
 -	err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, buf, len);
 -	if (err)
 -		WL_ERR("error (%d)\n", err);
 -
 -	return err;
 -}
 -
 -static s32
 -brcmf_dev_intvar_get(struct net_device *ndev, s8 *name, s32 *retval)
 -{
 -	union {
 -		s8 buf[BRCMF_DCMD_SMLEN];
 -		__le32 val;
 -	} var;
 -	u32 len;
 -	u32 data_null;
 -	s32 err = 0;
 -
 -	len =
 -	    brcmf_c_mkiovar(name, (char *)(&data_null), 0, (char *)(&var),
 -			sizeof(var.buf));
 -	BUG_ON(!len);
 -	err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, &var, len);
 -	if (err)
 -		WL_ERR("error (%d)\n", err);
 -
 -	*retval = le32_to_cpu(var.val);
 -
 -	return err;
 -}
 -
 -static s32
 -brcmf_dev_intvar_set_bsscfg(struct net_device *ndev, s8 *name, u32 val,
 -			    s32 bssidx)
 -{
 -	s8 buf[BRCMF_DCMD_SMLEN];
 -	__le32 val_le;
 -
 -	val_le = cpu_to_le32(val);
 -
 -	return brcmf_dev_iovar_setbuf_bsscfg(ndev, name, &val_le,
 -					     sizeof(val_le), buf, sizeof(buf),
 -					     bssidx);
 -}
 -
 -static s32
 -brcmf_dev_intvar_get_bsscfg(struct net_device *ndev, s8 *name, s32 *val,
 -			    s32 bssidx)
 -{
 -	s8 buf[BRCMF_DCMD_SMLEN];
 -	s32 err;
 -	__le32 val_le;
 -
 -	memset(buf, 0, sizeof(buf));
 -	err = brcmf_dev_iovar_getbuf_bsscfg(ndev, name, val, sizeof(*val), buf,
 -					    sizeof(buf), bssidx);
 -	if (err == 0) {
 -		memcpy(&val_le, buf, sizeof(val_le));
 -		*val = le32_to_cpu(val_le);
 -	}
 -	return err;
 -}
 -
 -
 -/*
 - * For now brcmf_find_bssidx will return 0. Once p2p gets implemented this
 - * should return the ndev matching bssidx.
 - */
 -static s32
 -brcmf_find_bssidx(struct brcmf_cfg80211_info *cfg, struct net_device *ndev)
 -{
 -	return 0;
 -}
 -
  static void brcmf_set_mpc(struct net_device *ndev, int mpc)
  {
 +	struct brcmf_if *ifp = netdev_priv(ndev);
  	s32 err = 0;
 -	struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
  
 -	if (test_bit(WL_STATUS_READY, &cfg->status)) {
 -		err = brcmf_dev_intvar_set(ndev, "mpc", mpc);
 +	if (check_vif_up(ifp->vif)) {
 +		err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc);
  		if (err) {
  			WL_ERR("fail to set mpc\n");
  			return;
@@@ -532,7 -643,7 +532,7 @@@
  static void brcmf_iscan_prep(struct brcmf_scan_params_le *params_le,
  			     struct brcmf_ssid *ssid)
  {
 -	memcpy(params_le->bssid, ether_bcast, ETH_ALEN);
 +	memset(params_le->bssid, 0xFF, ETH_ALEN);
  	params_le->bss_type = DOT11_BSSTYPE_ANY;
  	params_le->scan_type = 0;
  	params_le->channel_num = 0;
@@@ -547,6 -658,30 +547,6 @@@
  }
  
  static s32
 -brcmf_dev_iovar_setbuf(struct net_device *ndev, s8 * iovar, void *param,
 -		    s32 paramlen, void *bufptr, s32 buflen)
 -{
 -	s32 iolen;
 -
 -	iolen = brcmf_c_mkiovar(iovar, param, paramlen, bufptr, buflen);
 -	BUG_ON(!iolen);
 -
 -	return brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, bufptr, iolen);
 -}
 -
 -static s32
 -brcmf_dev_iovar_getbuf(struct net_device *ndev, s8 * iovar, void *param,
 -		    s32 paramlen, void *bufptr, s32 buflen)
 -{
 -	s32 iolen;
 -
 -	iolen = brcmf_c_mkiovar(iovar, param, paramlen, bufptr, buflen);
 -	BUG_ON(!iolen);
 -
 -	return brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, bufptr, buflen);
 -}
 -
 -static s32
  brcmf_run_iscan(struct brcmf_cfg80211_iscan_ctrl *iscan,
  		struct brcmf_ssid *ssid, u16 action)
  {
@@@ -568,8 -703,8 +568,8 @@@
  	params->action = cpu_to_le16(action);
  	params->scan_duration = cpu_to_le16(0);
  
 -	err = brcmf_dev_iovar_setbuf(iscan->ndev, "iscan", params, params_size,
 -				     iscan->dcmd_buf, BRCMF_DCMD_SMLEN);
 +	err = brcmf_fil_iovar_data_set(netdev_priv(iscan->ndev), "iscan",
 +				       params, params_size);
  	if (err) {
  		if (err == -EBUSY)
  			WL_INFO("system busy : iscan canceled\n");
@@@ -586,7 -721,7 +586,7 @@@ static s32 brcmf_do_iscan(struct brcmf_
  	struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg);
  	struct net_device *ndev = cfg_to_ndev(cfg);
  	struct brcmf_ssid ssid;
 -	__le32 passive_scan;
 +	u32 passive_scan;
  	s32 err = 0;
  
  	/* Broadcast scan by default */
@@@ -594,9 -729,9 +594,9 @@@
  
  	iscan->state = WL_ISCAN_STATE_SCANING;
  
 -	passive_scan = cfg->active_scan ? 0 : cpu_to_le32(1);
 -	err = brcmf_exec_dcmd(cfg_to_ndev(cfg), BRCMF_C_SET_PASSIVE_SCAN,
 -			&passive_scan, sizeof(passive_scan));
 +	passive_scan = cfg->active_scan ? 0 : 1;
 +	err = brcmf_fil_cmd_int_set(netdev_priv(ndev),
 +				    BRCMF_C_SET_PASSIVE_SCAN, passive_scan);
  	if (err) {
  		WL_ERR("error (%d)\n", err);
  		return err;
@@@ -619,27 -754,27 +619,27 @@@ brcmf_cfg80211_iscan(struct wiphy *wiph
  		     struct cfg80211_scan_request *request,
  		     struct cfg80211_ssid *this_ssid)
  {
 +	struct brcmf_if *ifp = netdev_priv(ndev);
  	struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
  	struct cfg80211_ssid *ssids;
  	struct brcmf_cfg80211_scan_req *sr = cfg->scan_req_int;
 -	__le32 passive_scan;
 +	u32 passive_scan;
  	bool iscan_req;
  	bool spec_scan;
  	s32 err = 0;
  	u32 SSID_len;
  
 -	if (test_bit(WL_STATUS_SCANNING, &cfg->status)) {
 -		WL_ERR("Scanning already : status (%lu)\n", cfg->status);
 +	if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
 +		WL_ERR("Scanning already: status (%lu)\n", cfg->scan_status);
  		return -EAGAIN;
  	}
 -	if (test_bit(WL_STATUS_SCAN_ABORTING, &cfg->status)) {
 -		WL_ERR("Scanning being aborted : status (%lu)\n",
 -		       cfg->status);
 +	if (test_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status)) {
 +		WL_ERR("Scanning being aborted: status (%lu)\n",
 +		       cfg->scan_status);
  		return -EAGAIN;
  	}
 -	if (test_bit(WL_STATUS_CONNECTING, &cfg->status)) {
 -		WL_ERR("Connecting : status (%lu)\n",
 -		       cfg->status);
 +	if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) {
 +		WL_ERR("Connecting: status (%lu)\n", ifp->vif->sme_state);
  		return -EAGAIN;
  	}
  
@@@ -657,7 -792,7 +657,7 @@@
  	}
  
  	cfg->scan_request = request;
 -	set_bit(WL_STATUS_SCANNING, &cfg->status);
 +	set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
  	if (iscan_req) {
  		err = brcmf_do_iscan(cfg);
  		if (!err)
@@@ -678,16 -813,16 +678,16 @@@
  			WL_SCAN("Broadcast scan\n");
  		}
  
 -		passive_scan = cfg->active_scan ? 0 : cpu_to_le32(1);
 -		err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_PASSIVE_SCAN,
 -				&passive_scan, sizeof(passive_scan));
 +		passive_scan = cfg->active_scan ? 0 : 1;
 +		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
 +					    passive_scan);
  		if (err) {
  			WL_ERR("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
  			goto scan_out;
  		}
  		brcmf_set_mpc(ndev, 0);
 -		err = brcmf_exec_dcmd(ndev, BRCMF_C_SCAN, &sr->ssid_le,
 -				      sizeof(sr->ssid_le));
 +		err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
 +					     &sr->ssid_le, sizeof(sr->ssid_le));
  		if (err) {
  			if (err == -EBUSY)
  				WL_INFO("system busy : scan for \"%s\" "
@@@ -703,7 -838,7 +703,7 @@@
  	return 0;
  
  scan_out:
 -	clear_bit(WL_STATUS_SCANNING, &cfg->status);
 +	clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
  	cfg->scan_request = NULL;
  	return err;
  }
@@@ -716,10 -851,12 +716,10 @@@ static void brcmf_escan_prep(struct brc
  	s32 i;
  	s32 offset;
  	u16 chanspec;
  	char *ptr;
  	struct brcmf_ssid_le ssid_le;
  
 -	memcpy(params_le->bssid, ether_bcast, ETH_ALEN);
 +	memset(params_le->bssid, 0xFF, ETH_ALEN);
  	params_le->bss_type = DOT11_BSSTYPE_ANY;
  	params_le->scan_type = 0;
  	params_le->channel_num = 0;
@@@ -739,9 -876,30 +739,9 @@@
  	WL_SCAN("### List of channelspecs to scan ### %d\n", n_channels);
  	if (n_channels > 0) {
  		for (i = 0; i < n_channels; i++) {
 -			chanspec = 0;
 -			req_channel = request->channels[i];
 -			channel = ieee80211_frequency_to_channel(
 -					req_channel->center_freq);
 -			if (req_channel->band == IEEE80211_BAND_2GHZ)
 -				chanspec |= WL_CHANSPEC_BAND_2G;
 -			else
 -				chanspec |= WL_CHANSPEC_BAND_5G;
 -
 -			if (req_channel->flags & IEEE80211_CHAN_NO_HT40) {
 -				chanspec |= WL_CHANSPEC_BW_20;
 -				chanspec |= WL_CHANSPEC_CTL_SB_NONE;
 -			} else {
 -				chanspec |= WL_CHANSPEC_BW_40;
 -				if (req_channel->flags &
 -						IEEE80211_CHAN_NO_HT40PLUS)
 -					chanspec |= WL_CHANSPEC_CTL_SB_LOWER;
 -				else
 -					chanspec |= WL_CHANSPEC_CTL_SB_UPPER;
 -			}
 -
 -			chanspec |= (channel & WL_CHANSPEC_CHAN_MASK);
 +			chanspec = channel_to_chanspec(request->channels[i]);
  			WL_SCAN("Chan : %d, Channel spec: %x\n",
 -				channel, chanspec);
 +				request->channels[i]->hw_value, chanspec);
  			params_le->channel_list[i] = cpu_to_le16(chanspec);
  		}
  	} else {
@@@ -808,7 -966,7 +808,7 @@@ brcmf_notify_escan_complete(struct brcm
  		/* Do a scan abort to stop the driver's scan engine */
  		WL_SCAN("ABORT scan in firmware\n");
  		memset(&params_le, 0, sizeof(params_le));
 -		memcpy(params_le.bssid, ether_bcast, ETH_ALEN);
 +		memset(params_le.bssid, 0xFF, ETH_ALEN);
  		params_le.bss_type = DOT11_BSSTYPE_ANY;
  		params_le.scan_type = 0;
  		params_le.channel_num = cpu_to_le32(1);
@@@ -819,8 -977,8 +819,8 @@@
  		/* Scan is aborted by setting channel_list[0] to -1 */
  		params_le.channel_list[0] = cpu_to_le16(-1);
  		/* E-Scan (or anyother type) can be aborted by SCAN */
 -		err = brcmf_exec_dcmd(ndev, BRCMF_C_SCAN, &params_le,
 -			sizeof(params_le));
 +		err = brcmf_fil_cmd_data_set(netdev_priv(ndev), BRCMF_C_SCAN,
 +					     &params_le, sizeof(params_le));
  		if (err)
  			WL_ERR("Scan abort  failed\n");
  	}
@@@ -840,7 -998,7 +840,7 @@@
  		cfg80211_scan_done(scan_request, aborted);
  		brcmf_set_mpc(ndev, 1);
  	}
 -	if (!test_and_clear_bit(WL_STATUS_SCANNING, &cfg->status)) {
 +	if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
  		WL_ERR("Scan complete while device not scanning\n");
  		return -EPERM;
  	}
@@@ -878,8 -1036,8 +878,8 @@@ brcmf_run_escan(struct brcmf_cfg80211_i
  	params->action = cpu_to_le16(action);
  	params->sync_id = cpu_to_le16(0x1234);
  
 -	err = brcmf_dev_iovar_setbuf(ndev, "escan", params, params_size,
 -			cfg->escan_ioctl_buf, BRCMF_DCMD_MEDLEN);
 +	err = brcmf_fil_iovar_data_set(netdev_priv(ndev), "escan",
 +				       params, params_size);
  	if (err) {
  		if (err == -EBUSY)
  			WL_INFO("system busy : escan canceled\n");
@@@ -897,16 -1055,16 +897,16 @@@ brcmf_do_escan(struct brcmf_cfg80211_in
  	       struct net_device *ndev, struct cfg80211_scan_request *request)
  {
  	s32 err;
 -	__le32 passive_scan;
 +	u32 passive_scan;
  	struct brcmf_scan_results *results;
  
  	WL_SCAN("Enter\n");
  	cfg->escan_info.ndev = ndev;
  	cfg->escan_info.wiphy = wiphy;
  	cfg->escan_info.escan_state = WL_ESCAN_STATE_SCANNING;
 -	passive_scan = cfg->active_scan ? 0 : cpu_to_le32(1);
 -	err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_PASSIVE_SCAN,
 -			&passive_scan, sizeof(passive_scan));
 +	passive_scan = cfg->active_scan ? 0 : 1;
 +	err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PASSIVE_SCAN,
 +				    passive_scan);
  	if (err) {
  		WL_ERR("error (%d)\n", err);
  		return err;
@@@ -928,11 -1086,10 +928,11 @@@ brcmf_cfg80211_escan(struct wiphy *wiph
  		     struct cfg80211_scan_request *request,
  		     struct cfg80211_ssid *this_ssid)
  {
 +	struct brcmf_if *ifp = netdev_priv(ndev);
  	struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
  	struct cfg80211_ssid *ssids;
  	struct brcmf_cfg80211_scan_req *sr = cfg->scan_req_int;
 -	__le32 passive_scan;
 +	u32 passive_scan;
  	bool escan_req;
  	bool spec_scan;
  	s32 err;
@@@ -940,17 -1097,18 +940,17 @@@
  
  	WL_SCAN("START ESCAN\n");
  
 -	if (test_bit(WL_STATUS_SCANNING, &cfg->status)) {
 -		WL_ERR("Scanning already : status (%lu)\n", cfg->status);
 +	if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
 +		WL_ERR("Scanning already: status (%lu)\n", cfg->scan_status);
  		return -EAGAIN;
  	}
 -	if (test_bit(WL_STATUS_SCAN_ABORTING, &cfg->status)) {
 -		WL_ERR("Scanning being aborted : status (%lu)\n",
 -		       cfg->status);
 +	if (test_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status)) {
 +		WL_ERR("Scanning being aborted: status (%lu)\n",
 +		       cfg->scan_status);
  		return -EAGAIN;
  	}
 -	if (test_bit(WL_STATUS_CONNECTING, &cfg->status)) {
 -		WL_ERR("Connecting : status (%lu)\n",
 -		       cfg->status);
 +	if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) {
 +		WL_ERR("Connecting: status (%lu)\n", ifp->vif->sme_state);
  		return -EAGAIN;
  	}
  
@@@ -970,7 -1128,7 +970,7 @@@
  	}
  
  	cfg->scan_request = request;
 -	set_bit(WL_STATUS_SCANNING, &cfg->status);
 +	set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
  	if (escan_req) {
  		err = brcmf_do_escan(cfg, wiphy, ndev, request);
  		if (!err)
@@@ -991,16 -1149,16 +991,16 @@@
  		} else
  			WL_SCAN("Broadcast scan\n");
  
 -		passive_scan = cfg->active_scan ? 0 : cpu_to_le32(1);
 -		err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_PASSIVE_SCAN,
 -				&passive_scan, sizeof(passive_scan));
 +		passive_scan = cfg->active_scan ? 0 : 1;
 +		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
 +					    passive_scan);
  		if (err) {
  			WL_ERR("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
  			goto scan_out;
  		}
  		brcmf_set_mpc(ndev, 0);
 -		err = brcmf_exec_dcmd(ndev, BRCMF_C_SCAN, &sr->ssid_le,
 -				      sizeof(sr->ssid_le));
 +		err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
 +					     &sr->ssid_le, sizeof(sr->ssid_le));
  		if (err) {
  			if (err == -EBUSY)
  				WL_INFO("BUSY: scan for \"%s\" canceled\n",
@@@ -1016,7 -1174,7 +1016,7 @@@
  	return 0;
  
  scan_out:
 -	clear_bit(WL_STATUS_SCANNING, &cfg->status);
 +	clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
  	if (timer_pending(&cfg->escan_timeout))
  		del_timer_sync(&cfg->escan_timeout);
  	cfg->scan_request = NULL;
@@@ -1024,7 -1182,8 +1024,7 @@@
  }
  
  static s32
 -brcmf_cfg80211_scan(struct wiphy *wiphy,
 -		 struct cfg80211_scan_request *request)
 +brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
  {
  	struct net_device *ndev = request->wdev->netdev;
  	struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
@@@ -1032,8 -1191,7 +1032,8 @@@
  
  	WL_TRACE("Enter\n");
  
 -	if (!check_sys_up(wiphy))
 +	if (!check_vif_up(container_of(request->wdev,
 +				       struct brcmf_cfg80211_vif, wdev)))
  		return -EIO;
  
  	if (cfg->iscan_on)
@@@ -1052,8 -1210,7 +1052,8 @@@ static s32 brcmf_set_rts(struct net_dev
  {
  	s32 err = 0;
  
 -	err = brcmf_dev_intvar_set(ndev, "rtsthresh", rts_threshold);
 +	err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "rtsthresh",
 +				      rts_threshold);
  	if (err)
  		WL_ERR("Error (%d)\n", err);
  
@@@ -1064,8 -1221,7 +1064,8 @@@ static s32 brcmf_set_frag(struct net_de
  {
  	s32 err = 0;
  
 -	err = brcmf_dev_intvar_set(ndev, "fragthresh", frag_threshold);
 +	err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "fragthresh",
 +				      frag_threshold);
  	if (err)
  		WL_ERR("Error (%d)\n", err);
  
@@@ -1077,7 -1233,7 +1077,7 @@@ static s32 brcmf_set_retry(struct net_d
  	s32 err = 0;
  	u32 cmd = (l ? BRCM_SET_LRL : BRCM_SET_SRL);
  
 -	err = brcmf_exec_dcmd_u32(ndev, cmd, &retry);
 +	err = brcmf_fil_cmd_int_set(netdev_priv(ndev), cmd, retry);
  	if (err) {
  		WL_ERR("cmd (%d) , error (%d)\n", cmd, err);
  		return err;
@@@ -1089,11 -1245,10 +1089,11 @@@ static s32 brcmf_cfg80211_set_wiphy_par
  {
  	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
  	struct net_device *ndev = cfg_to_ndev(cfg);
 +	struct brcmf_if *ifp = netdev_priv(ndev);
  	s32 err = 0;
  
  	WL_TRACE("Enter\n");
 -	if (!check_sys_up(wiphy))
 +	if (!check_vif_up(ifp->vif))
  		return -EIO;
  
  	if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
@@@ -1172,8 -1327,7 +1172,8 @@@ static void brcmf_link_down(struct brcm
  	if (cfg->link_up) {
  		ndev = cfg_to_ndev(cfg);
  		WL_INFO("Call WLC_DISASSOC to stop excess roaming\n ");
 -		err = brcmf_exec_dcmd(ndev, BRCMF_C_DISASSOC, NULL, 0);
 +		err = brcmf_fil_cmd_data_set(netdev_priv(ndev),
 +					     BRCMF_C_DISASSOC, NULL, 0);
  		if (err)
  			WL_ERR("WLC_DISASSOC failed (%d)\n", err);
  		cfg->link_up = false;
@@@ -1186,8 -1340,7 +1186,8 @@@ brcmf_cfg80211_join_ibss(struct wiphy *
  		      struct cfg80211_ibss_params *params)
  {
  	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
 -	struct brcmf_cfg80211_profile *profile = cfg->profile;
 +	struct brcmf_if *ifp = netdev_priv(ndev);
 +	struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
  	struct brcmf_join_params join_params;
  	size_t join_params_size = 0;
  	s32 err = 0;
@@@ -1195,7 -1348,7 +1195,7 @@@
  	s32 bcnprd;
  
  	WL_TRACE("Enter\n");
 -	if (!check_sys_up(wiphy))
 +	if (!check_vif_up(ifp->vif))
  		return -EIO;
  
  	if (params->ssid)
@@@ -1205,7 -1358,7 +1205,7 @@@
  		return -EOPNOTSUPP;
  	}
  
 -	set_bit(WL_STATUS_CONNECTING, &cfg->status);
 +	set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
  
  	if (params->bssid)
  		WL_CONN("BSSID: %pM\n", params->bssid);
@@@ -1246,7 -1399,7 +1246,7 @@@
  	if (params->privacy)
  		wsec |= WEP_ENABLED;
  
 -	err = brcmf_dev_intvar_set(ndev, "wsec", wsec);
 +	err = brcmf_fil_iovar_int_set(ifp, "wsec", wsec);
  	if (err) {
  		WL_ERR("wsec failed (%d)\n", err);
  		goto done;
@@@ -1258,7 -1411,7 +1258,7 @@@
  	else
  		bcnprd = 100;
  
 -	err = brcmf_exec_dcmd_u32(ndev, BRCM_SET_BCNPRD, &bcnprd);
 +	err = brcmf_fil_cmd_int_set(ifp, BRCM_SET_BCNPRD, bcnprd);
  	if (err) {
  		WL_ERR("WLC_SET_BCNPRD failed (%d)\n", err);
  		goto done;
@@@ -1281,7 -1434,7 +1281,7 @@@
  				   BRCMF_ASSOC_PARAMS_FIXED_SIZE;
  		memcpy(profile->bssid, params->bssid, ETH_ALEN);
  	} else {
 -		memcpy(join_params.params_le.bssid, ether_bcast, ETH_ALEN);
 +		memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
  		memset(profile->bssid, 0, ETH_ALEN);
  	}
  
@@@ -1300,8 -1453,8 +1300,8 @@@
  
  		/* set channel for starter */
  		target_channel = cfg->channel;
 -		err = brcmf_exec_dcmd_u32(ndev, BRCM_SET_CHANNEL,
 -					  &target_channel);
 +		err = brcmf_fil_cmd_int_set(ifp, BRCM_SET_CHANNEL,
 +					    target_channel);
  		if (err) {
  			WL_ERR("WLC_SET_CHANNEL failed (%d)\n", err);
  			goto done;
@@@ -1312,8 -1465,8 +1312,8 @@@
  	cfg->ibss_starter = false;
  
  
 -	err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SSID,
 -			   &join_params, join_params_size);
 +	err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
 +				     &join_params, join_params_size);
  	if (err) {
  		WL_ERR("WLC_SET_SSID failed (%d)\n", err);
  		goto done;
@@@ -1321,7 -1474,7 +1321,7 @@@
  
  done:
  	if (err)
 -		clear_bit(WL_STATUS_CONNECTING, &cfg->status);
 +		clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
  	WL_TRACE("Exit\n");
  	return err;
  }
@@@ -1330,11 -1483,10 +1330,11 @@@ static s3
  brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
  {
  	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
 +	struct brcmf_if *ifp = netdev_priv(ndev);
  	s32 err = 0;
  
  	WL_TRACE("Enter\n");
 -	if (!check_sys_up(wiphy))
 +	if (!check_vif_up(ifp->vif))
  		return -EIO;
  
  	brcmf_link_down(cfg);
@@@ -1347,7 -1499,8 +1347,7 @@@
  static s32 brcmf_set_wpa_version(struct net_device *ndev,
  				 struct cfg80211_connect_params *sme)
  {
 -	struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
 -	struct brcmf_cfg80211_profile *profile = cfg->profile;
 +	struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
  	struct brcmf_cfg80211_security *sec;
  	s32 val = 0;
  	s32 err = 0;
@@@ -1359,7 -1512,7 +1359,7 @@@
  	else
  		val = WPA_AUTH_DISABLED;
  	WL_CONN("setting wpa_auth to 0x%0x\n", val);
 -	err = brcmf_dev_intvar_set(ndev, "wpa_auth", val);
 +	err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "wpa_auth", val);
  	if (err) {
  		WL_ERR("set wpa_auth failed (%d)\n", err);
  		return err;
@@@ -1372,7 -1525,8 +1372,7 @@@
  static s32 brcmf_set_auth_type(struct net_device *ndev,
  			       struct cfg80211_connect_params *sme)
  {
 -	struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
 -	struct brcmf_cfg80211_profile *profile = cfg->profile;
 +	struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
  	struct brcmf_cfg80211_security *sec;
  	s32 val = 0;
  	s32 err = 0;
@@@ -1398,7 -1552,7 +1398,7 @@@
  		break;
  	}
  
 -	err = brcmf_dev_intvar_set(ndev, "auth", val);
 +	err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "auth", val);
  	if (err) {
  		WL_ERR("set auth failed (%d)\n", err);
  		return err;
@@@ -1412,7 -1566,8 +1412,7 @@@ static s3
  brcmf_set_set_cipher(struct net_device *ndev,
  		     struct cfg80211_connect_params *sme)
  {
 -	struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
 -	struct brcmf_cfg80211_profile *profile = cfg->profile;
 +	struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
  	struct brcmf_cfg80211_security *sec;
  	s32 pval = 0;
  	s32 gval = 0;
@@@ -1462,7 -1617,7 +1462,7 @@@
  	}
  
  	WL_CONN("pval (%d) gval (%d)\n", pval, gval);
 -	err = brcmf_dev_intvar_set(ndev, "wsec", pval | gval);
 +	err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "wsec", pval | gval);
  	if (err) {
  		WL_ERR("error (%d)\n", err);
  		return err;
@@@ -1478,14 -1633,14 +1478,14 @@@
  static s32
  brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
  {
 -	struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
 -	struct brcmf_cfg80211_profile *profile = cfg->profile;
 +	struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
  	struct brcmf_cfg80211_security *sec;
  	s32 val = 0;
  	s32 err = 0;
  
  	if (sme->crypto.n_akm_suites) {
 -		err = brcmf_dev_intvar_get(ndev, "wpa_auth", &val);
 +		err = brcmf_fil_iovar_int_get(netdev_priv(ndev),
 +					      "wpa_auth", &val);
  		if (err) {
  			WL_ERR("could not get wpa_auth (%d)\n", err);
  			return err;
@@@ -1519,8 -1674,7 +1519,8 @@@
  		}
  
  		WL_CONN("setting wpa_auth to %d\n", val);
 -		err = brcmf_dev_intvar_set(ndev, "wpa_auth", val);
 +		err = brcmf_fil_iovar_int_set(netdev_priv(ndev),
 +					      "wpa_auth", val);
  		if (err) {
  			WL_ERR("could not set wpa_auth (%d)\n", err);
  			return err;
@@@ -1536,11 -1690,13 +1536,11 @@@ static s3
  brcmf_set_sharedkey(struct net_device *ndev,
  		    struct cfg80211_connect_params *sme)
  {
 -	struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
 -	struct brcmf_cfg80211_profile *profile = cfg->profile;
 +	struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
  	struct brcmf_cfg80211_security *sec;
  	struct brcmf_wsec_key key;
  	s32 val;
  	s32 err = 0;
 -	s32 bssidx;
  
  	WL_CONN("key len (%d)\n", sme->key_len);
  
@@@ -1583,14 -1739,15 +1583,14 @@@
  	WL_CONN("key length (%d) key index (%d) algo (%d)\n",
  		key.len, key.index, key.algo);
  	WL_CONN("key \"%s\"\n", key.data);
 -	bssidx = brcmf_find_bssidx(cfg, ndev);
 -	err = send_key_to_dongle(cfg, bssidx, ndev, &key);
 +	err = send_key_to_dongle(ndev, &key);
  	if (err)
  		return err;
  
  	if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
  		WL_CONN("set auth_type to shared key\n");
  		val = WL_AUTH_SHARED_KEY;	/* shared key */
 -		err = brcmf_dev_intvar_set_bsscfg(ndev, "auth", val, bssidx);
 +		err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
  		if (err)
  			WL_ERR("set auth failed (%d)\n", err);
  	}
@@@ -1602,8 -1759,7 +1602,8 @@@ brcmf_cfg80211_connect(struct wiphy *wi
  		    struct cfg80211_connect_params *sme)
  {
  	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
 -	struct brcmf_cfg80211_profile *profile = cfg->profile;
 +	struct brcmf_if *ifp = netdev_priv(ndev);
 +	struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
  	struct ieee80211_channel *chan = sme->channel;
  	struct brcmf_join_params join_params;
  	size_t join_params_size;
@@@ -1612,7 -1768,7 +1612,7 @@@
  	s32 err = 0;
  
  	WL_TRACE("Enter\n");
 -	if (!check_sys_up(wiphy))
 +	if (!check_vif_up(ifp->vif))
  		return -EIO;
  
  	if (!sme->ssid) {
@@@ -1620,7 -1776,7 +1620,7 @@@
  		return -EOPNOTSUPP;
  	}
  
 -	set_bit(WL_STATUS_CONNECTING, &cfg->status);
 +	set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
  
  	if (chan) {
  		cfg->channel =
@@@ -1671,7 -1827,7 +1671,7 @@@
  	memcpy(&profile->ssid.SSID, sme->ssid, profile->ssid.SSID_len);
  	join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
  
 -	memcpy(join_params.params_le.bssid, ether_bcast, ETH_ALEN);
 +	memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
  
  	if (ssid.SSID_len < IEEE80211_MAX_SSID_LEN)
  		WL_CONN("ssid \"%s\", len (%d)\n",
@@@ -1679,14 -1835,14 +1679,14 @@@
  
  	brcmf_ch_to_chanspec(cfg->channel,
  			     &join_params, &join_params_size);
 -	err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SSID,
 -			   &join_params, join_params_size);
 +	err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
 +				     &join_params, join_params_size);
  	if (err)
  		WL_ERR("WLC_SET_SSID failed (%d)\n", err);
  
  done:
  	if (err)
 -		clear_bit(WL_STATUS_CONNECTING, &cfg->status);
 +		clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
  	WL_TRACE("Exit\n");
  	return err;
  }
@@@ -1696,21 -1852,20 +1696,21 @@@ brcmf_cfg80211_disconnect(struct wiphy 
  		       u16 reason_code)
  {
  	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
 -	struct brcmf_cfg80211_profile *profile = cfg->profile;
 +	struct brcmf_if *ifp = netdev_priv(ndev);
 +	struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
  	struct brcmf_scb_val_le scbval;
  	s32 err = 0;
  
  	WL_TRACE("Enter. Reason code = %d\n", reason_code);
 -	if (!check_sys_up(wiphy))
 +	if (!check_vif_up(ifp->vif))
  		return -EIO;
  
 -	clear_bit(WL_STATUS_CONNECTED, &cfg->status);
 +	clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
  
  	memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);
  	scbval.val = cpu_to_le32(reason_code);
 -	err = brcmf_exec_dcmd(ndev, BRCMF_C_DISASSOC, &scbval,
 -			      sizeof(struct brcmf_scb_val_le));
 +	err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_DISASSOC,
 +				     &scbval, sizeof(scbval));
  	if (err)
  		WL_ERR("error (%d)\n", err);
  
@@@ -1727,14 -1882,13 +1727,14 @@@ brcmf_cfg80211_set_tx_power(struct wiph
  
  	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
  	struct net_device *ndev = cfg_to_ndev(cfg);
 +	struct brcmf_if *ifp = netdev_priv(ndev);
  	u16 txpwrmw;
  	s32 err = 0;
  	s32 disable = 0;
  	s32 dbm = MBM_TO_DBM(mbm);
  
  	WL_TRACE("Enter\n");
 -	if (!check_sys_up(wiphy))
 +	if (!check_vif_up(ifp->vif))
  		return -EIO;
  
  	switch (type) {
@@@ -1751,7 -1905,7 +1751,7 @@@
  	}
  	/* Make sure radio is off or on as far as software is concerned */
  	disable = WL_RADIO_SW_DISABLE << 16;
 -	err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_RADIO, &disable);
 +	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_RADIO, disable);
  	if (err)
  		WL_ERR("WLC_SET_RADIO error (%d)\n", err);
  
@@@ -1759,8 -1913,8 +1759,8 @@@
  		txpwrmw = 0xffff;
  	else
  		txpwrmw = (u16) dbm;
 -	err = brcmf_dev_intvar_set(ndev, "qtxpower",
 -			(s32) (brcmf_mw_to_qdbm(txpwrmw)));
 +	err = brcmf_fil_iovar_int_set(ifp, "qtxpower",
 +				      (s32)brcmf_mw_to_qdbm(txpwrmw));
  	if (err)
  		WL_ERR("qtxpower error (%d)\n", err);
  	cfg->conf->tx_power = dbm;
@@@ -1773,16 -1927,16 +1773,16 @@@ done
  static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm)
  {
  	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
 -	struct net_device *ndev = cfg_to_ndev(cfg);
 +	struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
  	s32 txpwrdbm;
  	u8 result;
  	s32 err = 0;
  
  	WL_TRACE("Enter\n");
 -	if (!check_sys_up(wiphy))
 +	if (!check_vif_up(ifp->vif))
  		return -EIO;
  
 -	err = brcmf_dev_intvar_get(ndev, "qtxpower", &txpwrdbm);
 +	err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &txpwrdbm);
  	if (err) {
  		WL_ERR("error (%d)\n", err);
  		goto done;
@@@ -1800,17 -1954,19 +1800,17 @@@ static s3
  brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
  			       u8 key_idx, bool unicast, bool multicast)
  {
 -	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
 +	struct brcmf_if *ifp = netdev_priv(ndev);
  	u32 index;
  	u32 wsec;
  	s32 err = 0;
  
  	WL_TRACE("Enter\n");
  	WL_CONN("key index (%d)\n", key_idx);
 -	if (!check_sys_up(wiphy))
 +	if (!check_vif_up(ifp->vif))
  		return -EIO;
  
 -	bssidx = brcmf_find_bssidx(cfg, ndev);
 -	err = brcmf_dev_intvar_get_bsscfg(ndev, "wsec", &wsec, bssidx);
 +	err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
  	if (err) {
  		WL_ERR("WLC_GET_WSEC error (%d)\n", err);
  		goto done;
@@@ -1819,8 -1975,8 +1819,8 @@@
  	if (wsec & WEP_ENABLED) {
  		/* Just select a new current key */
  		index = key_idx;
 -		err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_KEY_PRIMARY,
 -					  &index);
 +		err = brcmf_fil_cmd_int_set(ifp,
 +					    BRCMF_C_SET_KEY_PRIMARY, index);
  		if (err)
  			WL_ERR("error (%d)\n", err);
  	}
@@@ -1833,8 -1989,11 +1833,8 @@@ static s3
  brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,
  	      u8 key_idx, const u8 *mac_addr, struct key_params *params)
  {
 -	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
  	struct brcmf_wsec_key key;
 -	struct brcmf_wsec_key_le key_le;
  	s32 err = 0;
 -	s32 bssidx;
  
  	memset(&key, 0, sizeof(key));
  	key.index = (u32) key_idx;
@@@ -1843,10 -2002,11 +1843,10 @@@
  	if (!is_multicast_ether_addr(mac_addr))
  		memcpy((char *)&key.ea, (void *)mac_addr, ETH_ALEN);
  	key.len = (u32) params->key_len;
  	/* check for key index change */
  	if (key.len == 0) {
  		/* key delete */
 -		err = send_key_to_dongle(cfg, bssidx, ndev, &key);
 +		err = send_key_to_dongle(ndev, &key);
  		if (err)
  			WL_ERR("key delete error (%d)\n", err);
  	} else {
@@@ -1901,7 -2061,13 +1901,7 @@@
  			WL_ERR("Invalid cipher (0x%x)\n", params->cipher);
  			return -EINVAL;
  		}
 -		convert_key_from_CPU(&key, &key_le);
 -
 -		brcmf_netdev_wait_pend8021x(ndev);
 -		err  = brcmf_dev_iovar_setbuf_bsscfg(ndev, "wsec_key", &key_le,
 -						     sizeof(key_le),
 -						     cfg->extra_buf,
 -						     WL_EXTRA_BUF_MAX, bssidx);
 +		err = send_key_to_dongle(ndev, &key);
  		if (err)
  			WL_ERR("wsec_key error (%d)\n", err);
  	}
@@@ -1914,16 -2080,16 +1914,16 @@@ brcmf_cfg80211_add_key(struct wiphy *wi
  		    struct key_params *params)
  {
  	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
 +	struct brcmf_if *ifp = netdev_priv(ndev);
  	struct brcmf_wsec_key key;
  	s32 val;
  	s32 wsec;
  	s32 err = 0;
  	u8 keybuf[8];
  
  	WL_TRACE("Enter\n");
  	WL_CONN("key index (%d)\n", key_idx);
 -	if (!check_sys_up(wiphy))
 +	if (!check_vif_up(ifp->vif))
  		return -EIO;
  
  	if (mac_addr) {
@@@ -1981,17 -2147,18 +1981,17 @@@
  		goto done;
  	}
  
 -	bssidx = brcmf_find_bssidx(cfg, ndev);
 -	err = send_key_to_dongle(cfg, bssidx, ndev, &key);
 +	err = send_key_to_dongle(ndev, &key);
  	if (err)
  		goto done;
  
 -	err = brcmf_dev_intvar_get_bsscfg(ndev, "wsec", &wsec, bssidx);
 +	err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
  	if (err) {
  		WL_ERR("get wsec error (%d)\n", err);
  		goto done;
  	}
  	wsec |= val;
 -	err = brcmf_dev_intvar_set_bsscfg(ndev, "wsec", wsec, bssidx);
 +	err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
  	if (err) {
  		WL_ERR("set wsec error (%d)\n", err);
  		goto done;
@@@ -2006,12 -2173,13 +2006,12 @@@ static s3
  brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
  		    u8 key_idx, bool pairwise, const u8 *mac_addr)
  {
 -	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
 +	struct brcmf_if *ifp = netdev_priv(ndev);
  	struct brcmf_wsec_key key;
  	s32 err = 0;
 -	s32 bssidx;
  
  	WL_TRACE("Enter\n");
 -	if (!check_sys_up(wiphy))
 +	if (!check_vif_up(ifp->vif))
  		return -EIO;
  
  	memset(&key, 0, sizeof(key));
@@@ -2023,7 -2191,8 +2023,7 @@@
  	WL_CONN("key index (%d)\n", key_idx);
  
  	/* Set the new key/index */
 -	bssidx = brcmf_find_bssidx(cfg, ndev);
 -	err = send_key_to_dongle(cfg, bssidx, ndev, &key);
 +	err = send_key_to_dongle(ndev, &key);
  	if (err) {
  		if (err == -EINVAL) {
  			if (key.index >= DOT11_MAX_DEFAULT_KEYS)
@@@ -2044,20 -2213,22 +2044,20 @@@ brcmf_cfg80211_get_key(struct wiphy *wi
  		    void (*callback) (void *cookie, struct key_params * params))
  {
  	struct key_params params;
 -	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
 -	struct brcmf_cfg80211_profile *profile = cfg->profile;
 +	struct brcmf_if *ifp = netdev_priv(ndev);
 +	struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
  	struct brcmf_cfg80211_security *sec;
  	s32 wsec;
  	s32 err = 0;
  
  	WL_TRACE("Enter\n");
  	WL_CONN("key index (%d)\n", key_idx);
 -	if (!check_sys_up(wiphy))
 +	if (!check_vif_up(ifp->vif))
  		return -EIO;
  
  	memset(&params, 0, sizeof(params));
  
 -	bssidx = brcmf_find_bssidx(cfg, ndev);
 -	err = brcmf_dev_intvar_get_bsscfg(ndev, "wsec", &wsec, bssidx);
 +	err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
  	if (err) {
  		WL_ERR("WLC_GET_WSEC error (%d)\n", err);
  		/* Ignore this error, may happen during DISASSOC */
@@@ -2109,33 -2280,33 +2109,33 @@@ brcmf_cfg80211_get_station(struct wiph
  			   u8 *mac, struct station_info *sinfo)
  {
  	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
 -	struct brcmf_cfg80211_profile *profile = cfg->profile;
 +	struct brcmf_if *ifp = netdev_priv(ndev);
 +	struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
  	struct brcmf_scb_val_le scb_val;
  	int rssi;
  	s32 rate;
  	s32 err = 0;
  	u8 *bssid = profile->bssid;
 -	struct brcmf_sta_info_le *sta_info_le;
 +	struct brcmf_sta_info_le sta_info_le;
  
  	WL_TRACE("Enter, MAC %pM\n", mac);
 -	if (!check_sys_up(wiphy))
 +	if (!check_vif_up(ifp->vif))
  		return -EIO;
  
  	if (cfg->conf->mode == WL_MODE_AP) {
 -		err = brcmf_dev_iovar_getbuf(ndev, "sta_info", mac, ETH_ALEN,
 -					     cfg->dcmd_buf,
 -					     WL_DCMD_LEN_MAX);
 +		memcpy(&sta_info_le, mac, ETH_ALEN);
 +		err = brcmf_fil_iovar_data_get(ifp, "sta_info",
 +					       &sta_info_le,
 +					       sizeof(sta_info_le));
  		if (err < 0) {
  			WL_ERR("GET STA INFO failed, %d\n", err);
  			goto done;
  		}
 -		sta_info_le = (struct brcmf_sta_info_le *)cfg->dcmd_buf;
 -
  		sinfo->filled = STATION_INFO_INACTIVE_TIME;
 -		sinfo->inactive_time = le32_to_cpu(sta_info_le->idle) * 1000;
 -		if (le32_to_cpu(sta_info_le->flags) & BRCMF_STA_ASSOC) {
 +		sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
 +		if (le32_to_cpu(sta_info_le.flags) & BRCMF_STA_ASSOC) {
  			sinfo->filled |= STATION_INFO_CONNECTED_TIME;
 -			sinfo->connected_time = le32_to_cpu(sta_info_le->in);
 +			sinfo->connected_time = le32_to_cpu(sta_info_le.in);
  		}
  		WL_TRACE("STA idle time : %d ms, connected time :%d sec\n",
  			 sinfo->inactive_time, sinfo->connected_time);
@@@ -2147,7 -2318,7 +2147,7 @@@
  			goto done;
  		}
  		/* Report the current tx rate */
 -		err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_GET_RATE, &rate);
 +	err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
  		if (err) {
  			WL_ERR("Could not get rate (%d)\n", err);
  			goto done;
@@@ -2157,11 -2328,10 +2157,11 @@@
  			WL_CONN("Rate %d Mbps\n", rate / 2);
  		}
  
 -		if (test_bit(WL_STATUS_CONNECTED, &cfg->status)) {
 +		if (test_bit(BRCMF_VIF_STATUS_CONNECTED,
 +			     &ifp->vif->sme_state)) {
  			memset(&scb_val, 0, sizeof(scb_val));
 -			err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_RSSI, &scb_val,
 -					      sizeof(scb_val));
 +			err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI,
 +						     &scb_val, sizeof(scb_val));
  			if (err) {
  				WL_ERR("Could not get rssi (%d)\n", err);
  				goto done;
@@@ -2186,7 -2356,6 +2186,7 @@@ brcmf_cfg80211_set_power_mgmt(struct wi
  	s32 pm;
  	s32 err = 0;
  	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
 +	struct brcmf_if *ifp = netdev_priv(ndev);
  
  	WL_TRACE("Enter\n");
  
@@@ -2198,7 -2367,7 +2198,7 @@@
  	 * FW later while initializing the dongle
  	 */
  	cfg->pwr_save = enabled;
 -	if (!test_bit(WL_STATUS_READY, &cfg->status)) {
 +	if (!check_vif_up(ifp->vif)) {
  
  		WL_INFO("Device is not ready, storing the value in cfg_info struct\n");
  		goto done;
@@@ -2207,7 -2376,7 +2207,7 @@@
  	pm = enabled ? PM_FAST : PM_OFF;
  	WL_INFO("power save %s\n", (pm ? "enabled" : "disabled"));
  
 -	err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_PM, &pm);
 +	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);
  	if (err) {
  		if (err == -ENODEV)
  			WL_ERR("net_device is not ready yet\n");
@@@ -2224,7 -2393,6 +2224,7 @@@ brcmf_cfg80211_set_bitrate_mask(struct 
  			     const u8 *addr,
  			     const struct cfg80211_bitrate_mask *mask)
  {
 +	struct brcmf_if *ifp = netdev_priv(ndev);
  	struct brcm_rateset_le rateset_le;
  	s32 rate;
  	s32 val;
@@@ -2234,13 -2402,13 +2234,13 @@@
  	s32 err = 0;
  
  	WL_TRACE("Enter\n");
 -	if (!check_sys_up(wiphy))
 +	if (!check_vif_up(ifp->vif))
  		return -EIO;
  
  	/* addr param is always NULL. ignore it */
  	/* Get current rateset */
 -	err = brcmf_exec_dcmd(ndev, BRCM_GET_CURR_RATESET, &rateset_le,
 -			      sizeof(rateset_le));
 +	err = brcmf_fil_cmd_data_get(ifp, BRCM_GET_CURR_RATESET,
 +				     &rateset_le, sizeof(rateset_le));
  	if (err) {
  		WL_ERR("could not get current rateset (%d)\n", err);
  		goto done;
@@@ -2267,8 -2435,8 +2267,8 @@@
  	 *      Set rate override,
  	 *      Since the is a/b/g-blind, both a/bg_rate are enforced.
  	 */
 -	err_bg = brcmf_dev_intvar_set(ndev, "bg_rate", rate);
 -	err_a = brcmf_dev_intvar_set(ndev, "a_rate", rate);
 +	err_bg = brcmf_fil_iovar_int_set(ifp, "bg_rate", rate);
 +	err_a = brcmf_fil_iovar_int_set(ifp, "a_rate", rate);
  	if (err_bg && err_a) {
  		WL_ERR("could not set fixed rate (%d) (%d)\n", err_bg, err_a);
  		err = err_bg | err_a;
@@@ -2397,8 -2565,7 +2397,8 @@@ static s32 wl_inform_ibss(struct brcmf_
  
  	*(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
  
 -	err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_BSS_INFO, buf, WL_BSS_INFO_MAX);
 +	err = brcmf_fil_cmd_data_get(netdev_priv(ndev), BRCMF_C_GET_BSS_INFO,
 +				     buf, WL_BSS_INFO_MAX);
  	if (err) {
  		WL_ERR("WLC_GET_BSS_INFO failed: %d\n", err);
  		goto CleanUp;
@@@ -2507,12 -2674,12 +2507,12 @@@ brcmf_tlv_has_ie(u8 *ie, u8 **tlvs, u3
  	return false;
  }
  
 -struct brcmf_vs_tlv *
 +static struct brcmf_vs_tlv *
  brcmf_find_wpaie(u8 *parse, u32 len)
  {
  	struct brcmf_tlv *ie;
  
 -	while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_WPA))) {
 +	while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
  		if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
  				     WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE))
  			return (struct brcmf_vs_tlv *)ie;
@@@ -2522,9 -2689,7 +2522,9 @@@
  
  static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg)
  {
 -	struct brcmf_cfg80211_profile *profile = cfg->profile;
 +	struct net_device *ndev = cfg_to_ndev(cfg);
 +	struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
 +	struct brcmf_if *ifp = netdev_priv(ndev);
  	struct brcmf_bss_info_le *bi;
  	struct brcmf_ssid *ssid;
  	struct brcmf_tlv *tim;
@@@ -2541,8 -2706,8 +2541,8 @@@
  	ssid = &profile->ssid;
  
  	*(__le32 *)cfg->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
 -	err = brcmf_exec_dcmd(cfg_to_ndev(cfg), BRCMF_C_GET_BSS_INFO,
 -			cfg->extra_buf, WL_EXTRA_BUF_MAX);
 +	err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
 +				     cfg->extra_buf, WL_EXTRA_BUF_MAX);
  	if (err) {
  		WL_ERR("Could not get bss info %d\n", err);
  		goto update_bss_info_out;
@@@ -2567,7 -2732,8 +2567,7 @@@
  		* so we speficially query dtim information to dongle.
  		*/
  		u32 var;
 -		err = brcmf_dev_intvar_get(cfg_to_ndev(cfg),
 -					   "dtim_assoc", &var);
 +		err = brcmf_fil_iovar_int_get(ifp, "dtim_assoc", &var);
  		if (err) {
  			WL_ERR("wl dtim_assoc failed (%d)\n", err);
  			goto update_bss_info_out;
@@@ -2575,6 -2741,9 +2575,6 @@@
  		dtim_period = (u8)var;
  	}
  
 -	profile->beacon_interval = beacon_interval;
 -	profile->dtim_period = dtim_period;
 -
  update_bss_info_out:
  	WL_TRACE("Exit");
  	return err;
@@@ -2586,7 -2755,7 +2586,7 @@@ static void brcmf_abort_scanning(struc
  	struct escan_info *escan = &cfg->escan_info;
  	struct brcmf_ssid ssid;
  
 -	set_bit(WL_STATUS_SCAN_ABORTING, &cfg->status);
 +	set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
  	if (cfg->iscan_on) {
  		iscan->state = WL_ISCAN_STATE_IDLE;
  
@@@ -2612,8 -2781,8 +2612,8 @@@
  		escan->escan_state = WL_ESCAN_STATE_IDLE;
  		brcmf_notify_escan_complete(cfg, escan->ndev, true, true);
  	}
 -	clear_bit(WL_STATUS_SCANNING, &cfg->status);
 -	clear_bit(WL_STATUS_SCAN_ABORTING, &cfg->status);
 +	clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
 +	clear_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
  }
  
  static void brcmf_notify_iscan_complete(struct brcmf_cfg80211_iscan_ctrl *iscan,
@@@ -2622,7 -2791,7 +2622,7 @@@
  	struct brcmf_cfg80211_info *cfg = iscan_to_cfg(iscan);
  	struct net_device *ndev = cfg_to_ndev(cfg);
  
 -	if (!test_and_clear_bit(WL_STATUS_SCANNING, &cfg->status)) {
 +	if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
  		WL_ERR("Scan complete while device not scanning\n");
  		return;
  	}
@@@ -2651,6 -2820,7 +2651,6 @@@ static s3
  brcmf_get_iscan_results(struct brcmf_cfg80211_iscan_ctrl *iscan, u32 *status,
  		     struct brcmf_scan_results **bss_list)
  {
 -	struct brcmf_iscan_results list;
  	struct brcmf_scan_results *results;
  	struct brcmf_scan_results_le *results_le;
  	struct brcmf_iscan_results *list_buf;
@@@ -2660,13 -2830,15 +2660,13 @@@
  	list_buf = (struct brcmf_iscan_results *)iscan->scan_buf;
  	results = &list_buf->results;
  	results_le = &list_buf->results_le;
 -	results->buflen = BRCMF_ISCAN_RESULTS_FIXED_SIZE;
 -	results->version = 0;
 -	results->count = 0;
 +	results_le->buflen = cpu_to_le32(sizeof(iscan->scan_buf));
 +	results_le->version = 0;
 +	results_le->count = 0;
  
 -	memset(&list, 0, sizeof(list));
 -	list.results_le.buflen = cpu_to_le32(WL_ISCAN_BUF_MAX);
 -	err = brcmf_dev_iovar_getbuf(iscan->ndev, "iscanresults", &list,
 -				     BRCMF_ISCAN_RESULTS_FIXED_SIZE,
 -				     iscan->scan_buf, WL_ISCAN_BUF_MAX);
 +	err = brcmf_fil_iovar_data_get(netdev_priv(iscan->ndev), "iscanresults",
 +				       iscan->scan_buf,
 +				       sizeof(iscan->scan_buf));
  	if (err) {
  		WL_ERR("error (%d)\n", err);
  		return err;
@@@ -2880,10 -3052,10 +2880,10 @@@ brcmf_cfg80211_escan_handler(struct brc
  	status = be32_to_cpu(e->status);
  
  	if (!ndev || !cfg->escan_on ||
 -			!test_bit(WL_STATUS_SCANNING, &cfg->status)) {
 +			!test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
  		WL_ERR("scan not ready ndev %p wl->escan_on %d drv_status %x\n",
  			ndev, cfg->escan_on,
 -			!test_bit(WL_STATUS_SCANNING, &cfg->status));
 +			!test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status));
  		return -EPERM;
  	}
  
@@@ -2987,17 -3159,16 +2987,17 @@@ static __always_inline void brcmf_delay
  static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
  {
  	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
 +	struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
  
  	/*
 -	 * Check for WL_STATUS_READY before any function call which
 +	 * Check for BRCMF_VIF_STATUS_READY before any function call which
  	 * could result is bus access. Don't block the resume for
  	 * any driver error conditions
  	 */
  	WL_TRACE("Enter\n");
  
 -	if (test_bit(WL_STATUS_READY, &cfg->status))
 -		brcmf_invoke_iscan(wiphy_to_cfg(wiphy));
 +	if (check_vif_up(ifp->vif))
 +		brcmf_invoke_iscan(cfg);
  
  	WL_TRACE("Exit\n");
  	return 0;
@@@ -3008,53 -3179,85 +3008,53 @@@ static s32 brcmf_cfg80211_suspend(struc
  {
  	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
  	struct net_device *ndev = cfg_to_ndev(cfg);
 +	struct brcmf_cfg80211_vif *vif;
  
  	WL_TRACE("Enter\n");
  
  	/*
 -	 * Check for WL_STATUS_READY before any function call which
 -	 * could result is bus access. Don't block the suspend for
 -	 * any driver error conditions
 -	 */
 -
 -	/*
 -	 * While going to suspend if associated with AP disassociate
 -	 * from AP to save power while system is in suspended state
 +	 * if the primary net_device is not READY there is nothing
 +	 * we can do but pray resume goes smoothly.
  	 */
 -	if ((test_bit(WL_STATUS_CONNECTED, &cfg->status) ||
 -	     test_bit(WL_STATUS_CONNECTING, &cfg->status)) &&
 -	     test_bit(WL_STATUS_READY, &cfg->status)) {
 -		WL_INFO("Disassociating from AP"
 -			" while entering suspend state\n");
 -		brcmf_link_down(cfg);
 +	vif = ((struct brcmf_if *)netdev_priv(ndev))->vif;
 +	if (!check_vif_up(vif))
 +		goto exit;
  
 +	list_for_each_entry(vif, &cfg->vif_list, list) {
 +		if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
 +			continue;
  		/*
 -		 * Make sure WPA_Supplicant receives all the event
 -		 * generated due to DISASSOC call to the fw to keep
 -		 * the state fw and WPA_Supplicant state consistent
 +		 * While going to suspend if associated with AP disassociate
 +		 * from AP to save power while system is in suspended state
  		 */
 -		brcmf_delay(500);
 +		if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state) ||
 +		    test_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state)) {
 +			WL_INFO("Disassociating from AP before suspend\n");
 +			brcmf_link_down(cfg);
 +
 +			/* Make sure WPA_Supplicant receives all the event
 +			 * generated due to DISASSOC call to the fw to keep
 +			 * the state fw and WPA_Supplicant state consistent
 +			 */
 +			brcmf_delay(500);
 +		}
  	}
  
 -	if (test_bit(WL_STATUS_READY, &cfg->status))
 +	/* end any scanning */
 +	if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
  		brcmf_abort_scanning(cfg);
 -	else
 -		clear_bit(WL_STATUS_SCANNING, &cfg->status);
  
  	/* Turn off watchdog timer */
 -	if (test_bit(WL_STATUS_READY, &cfg->status))
 -		brcmf_set_mpc(ndev, 1);
 +	brcmf_set_mpc(ndev, 1);
  
 +exit:
  	WL_TRACE("Exit\n");
 -
 +	/* clear any scanning activity */
 +	cfg->scan_status = 0;
  	return 0;
  }
  
  static __used s32
 -brcmf_dev_bufvar_set(struct net_device *ndev, s8 *name, s8 *buf, s32 len)
 -{
 -	struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
 -	u32 buflen;
 -
 -	buflen = brcmf_c_mkiovar(name, buf, len, cfg->dcmd_buf,
 -			       WL_DCMD_LEN_MAX);
 -	BUG_ON(!buflen);
 -
 -	return brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, cfg->dcmd_buf,
 -			       buflen);
 -}
 -
 -static s32
 -brcmf_dev_bufvar_get(struct net_device *ndev, s8 *name, s8 *buf,
 -		  s32 buf_len)
 -{
 -	struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
 -	u32 len;
 -	s32 err = 0;
 -
 -	len = brcmf_c_mkiovar(name, NULL, 0, cfg->dcmd_buf,
 -			    WL_DCMD_LEN_MAX);
 -	BUG_ON(!len);
 -	err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, cfg->dcmd_buf,
 -			      WL_DCMD_LEN_MAX);
 -	if (err) {
 -		WL_ERR("error (%d)\n", err);
 -		return err;
 -	}
 -	memcpy(buf, cfg->dcmd_buf, buf_len);
 -
 -	return err;
 -}
 -
 -static __used s32
  brcmf_update_pmklist(struct net_device *ndev,
  		     struct brcmf_cfg80211_pmk_list *pmk_list, s32 err)
  {
@@@ -3072,8 -3275,8 +3072,8 @@@
  	}
  
  	if (!err)
 -		brcmf_dev_bufvar_set(ndev, "pmkid_info", (char *)pmk_list,
 -					sizeof(*pmk_list));
 +		brcmf_fil_iovar_data_set(netdev_priv(ndev), "pmkid_info",
 +					 (char *)pmk_list, sizeof(*pmk_list));
  
  	return err;
  }
@@@ -3083,14 -3286,13 +3083,14 @@@ brcmf_cfg80211_set_pmksa(struct wiphy *
  			 struct cfg80211_pmksa *pmksa)
  {
  	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
 +	struct brcmf_if *ifp = netdev_priv(ndev);
  	struct pmkid_list *pmkids = &cfg->pmk_list->pmkids;
  	s32 err = 0;
  	int i;
  	int pmkid_len;
  
  	WL_TRACE("Enter\n");
 -	if (!check_sys_up(wiphy))
 +	if (!check_vif_up(ifp->vif))
  		return -EIO;
  
  	pmkid_len = le32_to_cpu(pmkids->npmkid);
@@@ -3123,13 -3325,12 +3123,13 @@@ brcmf_cfg80211_del_pmksa(struct wiphy *
  		      struct cfg80211_pmksa *pmksa)
  {
  	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
 +	struct brcmf_if *ifp = netdev_priv(ndev);
  	struct pmkid_list pmkid;
  	s32 err = 0;
  	int i, pmkid_len;
  
  	WL_TRACE("Enter\n");
 -	if (!check_sys_up(wiphy))
 +	if (!check_vif_up(ifp->vif))
  		return -EIO;
  
  	memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETH_ALEN);
@@@ -3174,11 -3375,10 +3174,11 @@@ static s3
  brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
  {
  	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
 +	struct brcmf_if *ifp = netdev_priv(ndev);
  	s32 err = 0;
  
  	WL_TRACE("Enter\n");
 -	if (!check_sys_up(wiphy))
 +	if (!check_vif_up(ifp->vif))
  		return -EIO;
  
  	memset(cfg->pmk_list, 0, sizeof(*cfg->pmk_list));
@@@ -3278,15 -3478,15 +3278,15 @@@ brcmf_notify_sched_scan_results(struct 
  		if (request->n_ssids)
  			request->ssids = &ssid[0];
  
 -		if (test_bit(WL_STATUS_SCANNING, &cfg->status)) {
 +		if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
  			/* Abort any on-going scan */
  			brcmf_abort_scanning(cfg);
  		}
  
 -		set_bit(WL_STATUS_SCANNING, &cfg->status);
 +		set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
  		err = brcmf_do_escan(cfg, wiphy, ndev, request);
  		if (err) {
 -			clear_bit(WL_STATUS_SCANNING, &cfg->status);
 +			clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
  			goto out_err;
  		}
  		cfg->sched_escan = true;
@@@ -3312,14 -3512,15 +3312,14 @@@ out_err
  #ifndef CONFIG_BRCMISCAN
  static int brcmf_dev_pno_clean(struct net_device *ndev)
  {
  	int ret;
  
  	/* Disable pfn */
 -	ret = brcmf_dev_intvar_set(ndev, "pfn", 0);
 +	ret = brcmf_fil_iovar_int_set(netdev_priv(ndev), "pfn", 0);
  	if (ret == 0) {
  		/* clear pfn */
 -		ret = brcmf_dev_iovar_setbuf(ndev, "pfnclear", NULL, 0,
 -					     iovbuf, sizeof(iovbuf));
 +		ret = brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfnclear",
 +					       NULL, 0);
  	}
  	if (ret < 0)
  		WL_ERR("failed code %d\n", ret);
@@@ -3330,6 -3531,7 +3330,6 @@@
  static int brcmf_dev_pno_config(struct net_device *ndev)
  {
  	struct brcmf_pno_param_le pfn_param;
 -	char iovbuf[128];
  
  	memset(&pfn_param, 0, sizeof(pfn_param));
  	pfn_param.version = cpu_to_le32(BRCMF_PNO_VERSION);
@@@ -3342,8 -3544,9 +3342,8 @@@
  	/* set up pno scan fr */
  	pfn_param.scan_freq = cpu_to_le32(BRCMF_PNO_TIME);
  
 -	return brcmf_dev_iovar_setbuf(ndev, "pfn_set",
 -				      &pfn_param, sizeof(pfn_param),
 -				      iovbuf, sizeof(iovbuf));
 +	return brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfn_set",
 +					&pfn_param, sizeof(pfn_param));
  }
  
  static int
@@@ -3351,7 -3554,7 +3351,7 @@@ brcmf_cfg80211_sched_scan_start(struct 
  				struct net_device *ndev,
  				struct cfg80211_sched_scan_request *request)
  {
 -	char iovbuf[128];
 +	struct brcmf_if *ifp = netdev_priv(ndev);
  	struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
  	struct brcmf_pno_net_param_le pfn;
  	int i;
@@@ -3359,8 -3562,8 +3359,8 @@@
  
  	WL_SCAN("Enter n_match_sets:%d   n_ssids:%d\n",
  		request->n_match_sets, request->n_ssids);
 -	if (test_bit(WL_STATUS_SCANNING, &cfg->status)) {
 -		WL_ERR("Scanning already : status (%lu)\n", cfg->status);
 +	if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
 +		WL_ERR("Scanning already: status (%lu)\n", cfg->scan_status);
  		return -EAGAIN;
  	}
  
@@@ -3417,14 -3620,15 +3417,14 @@@
  			pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT);
  			pfn.ssid.SSID_len = cpu_to_le32(ssid_len);
  			memcpy(pfn.ssid.SSID, ssid->ssid, ssid_len);
 -			ret = brcmf_dev_iovar_setbuf(ndev, "pfn_add",
 -						     &pfn, sizeof(pfn),
 -						     iovbuf, sizeof(iovbuf));
 +			ret = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn,
 +						       sizeof(pfn));
  			WL_SCAN(">>> PNO filter %s for ssid (%s)\n",
  				ret == 0 ? "set" : "failed",
  				ssid->ssid);
  		}
  		/* Enable the PNO */
 -		if (brcmf_dev_intvar_set(ndev, "pfn", 1) < 0) {
 +		if (brcmf_fil_iovar_int_set(ifp, "pfn", 1) < 0) {
  			WL_ERR("PNO enable failed!! ret=%d\n", ret);
  			return -EINVAL;
  		}
@@@ -3452,20 -3656,12 +3452,20 @@@ static int brcmf_cfg80211_sched_scan_st
  static int brcmf_cfg80211_testmode(struct wiphy *wiphy, void *data, int len)
  {
  	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
 -	struct net_device *ndev = cfg->wdev->netdev;
 +	struct net_device *ndev = cfg_to_ndev(cfg);
  	struct brcmf_dcmd *dcmd = data;
  	struct sk_buff *reply;
  	int ret;
  
 -	ret = brcmf_netlink_dcmd(ndev, dcmd);
 +	WL_TRACE("cmd %x set %d buf %p len %d\n", dcmd->cmd, dcmd->set,
 +		 dcmd->buf, dcmd->len);
 +
 +	if (dcmd->set)
 +		ret = brcmf_fil_cmd_data_set(netdev_priv(ndev), dcmd->cmd,
 +					     dcmd->buf, dcmd->len);
 +	else
 +		ret = brcmf_fil_cmd_data_get(netdev_priv(ndev), dcmd->cmd,
 +					     dcmd->buf, dcmd->len);
  	if (ret == 0) {
  		reply = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(*dcmd));
  		nla_put(reply, NL80211_ATTR_TESTDATA, sizeof(*dcmd), dcmd);
@@@ -3477,23 -3673,23 +3477,23 @@@
  
  static s32 brcmf_configure_opensecurity(struct net_device *ndev, s32 bssidx)
  {
 +	struct brcmf_if *ifp = netdev_priv(ndev);
  	s32 err;
  
  	/* set auth */
 -	err = brcmf_dev_intvar_set_bsscfg(ndev, "auth", 0, bssidx);
 +	err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0);
  	if (err < 0) {
  		WL_ERR("auth error %d\n", err);
  		return err;
  	}
  	/* set wsec */
 -	err = brcmf_dev_intvar_set_bsscfg(ndev, "wsec", 0, bssidx);
 +	err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0);
  	if (err < 0) {
  		WL_ERR("wsec error %d\n", err);
  		return err;
  	}
  	/* set upper-layer auth */
 -	err = brcmf_dev_intvar_set_bsscfg(ndev, "wpa_auth",
 -					  WPA_AUTH_NONE, bssidx);
 +	err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", WPA_AUTH_NONE);
  	if (err < 0) {
  		WL_ERR("wpa_auth error %d\n", err);
  		return err;
@@@ -3514,7 -3710,6 +3514,7 @@@ static s3
  brcmf_configure_wpaie(struct net_device *ndev, struct brcmf_vs_tlv *wpa_ie,
  		     bool is_rsn_ie, s32 bssidx)
  {
 +	struct brcmf_if *ifp = netdev_priv(ndev);
  	u32 auth = 0; /* d11 open authentication */
  	u16 count;
  	s32 err = 0;
@@@ -3655,8 -3850,8 +3655,8 @@@
  				wme_bss_disable = 0;
  		}
  		/* set wme_bss_disable to sync RSN Capabilities */
 -		err = brcmf_dev_intvar_set_bsscfg(ndev, "wme_bss_disable",
 -						  wme_bss_disable, bssidx);
 +		err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
 +					       wme_bss_disable);
  		if (err < 0) {
  			WL_ERR("wme_bss_disable error %d\n", err);
  			goto exit;
@@@ -3666,19 -3861,19 +3666,19 @@@
  	wsec = (pval | gval | SES_OW_ENABLED);
  
  	/* set auth */
 -	err = brcmf_dev_intvar_set_bsscfg(ndev, "auth", auth, bssidx);
 +	err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);
  	if (err < 0) {
  		WL_ERR("auth error %d\n", err);
  		goto exit;
  	}
  	/* set wsec */
 -	err = brcmf_dev_intvar_set_bsscfg(ndev, "wsec", wsec, bssidx);
 +	err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
  	if (err < 0) {
  		WL_ERR("wsec error %d\n", err);
  		goto exit;
  	}
  	/* set upper-layer auth */
 -	err = brcmf_dev_intvar_set_bsscfg(ndev, "wpa_auth", wpa_auth, bssidx);
 +	err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
  	if (err < 0) {
  		WL_ERR("wpa_auth error %d\n", err);
  		goto exit;
@@@ -3768,19 -3963,17 +3768,19 @@@ brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u
  	return ie_len + VNDR_IE_HDR_SIZE;
  }
  
 -s32
 +static s32
  brcmf_set_management_ie(struct brcmf_cfg80211_info *cfg,
 -			struct net_device *ndev, s32 bssidx, s32 pktflag,
 +			struct net_device *ndev, s32 pktflag,
  			u8 *vndr_ie_buf, u32 vndr_ie_len)
  {
 +	struct brcmf_if *ifp = netdev_priv(ndev);
 +	struct vif_saved_ie *saved_ie = &ifp->vif->saved_ie;
  	s32 err = 0;
  	u8  *iovar_ie_buf;
  	u8  *curr_ie_buf;
  	u8  *mgmt_ie_buf = NULL;
  	int mgmt_ie_buf_len;
 -	u32 *mgmt_ie_len = 0;
 +	u32 *mgmt_ie_len;
  	u32 del_add_ie_buf_len = 0;
  	u32 total_ie_buf_len = 0;
  	u32 parsed_ie_buf_len = 0;
@@@ -3791,29 -3984,31 +3791,29 @@@
  	u8 *ptr;
  	int remained_buf_len;
  
 -	WL_TRACE("bssidx %d, pktflag : 0x%02X\n", bssidx, pktflag);
 +	WL_TRACE("bssidx %d, pktflag : 0x%02X\n",
 +		 brcmf_ndev_bssidx(ndev), pktflag);
  	iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
  	if (!iovar_ie_buf)
  		return -ENOMEM;
  	curr_ie_buf = iovar_ie_buf;
 -	if (test_bit(WL_STATUS_AP_CREATING, &cfg->status) ||
 -	    test_bit(WL_STATUS_AP_CREATED, &cfg->status)) {
 +	if (ifp->vif->mode == WL_MODE_AP) {
  		switch (pktflag) {
  		case VNDR_IE_PRBRSP_FLAG:
 -			mgmt_ie_buf = cfg->ap_info->probe_res_ie;
 -			mgmt_ie_len = &cfg->ap_info->probe_res_ie_len;
 -			mgmt_ie_buf_len =
 -				sizeof(cfg->ap_info->probe_res_ie);
 +			mgmt_ie_buf = saved_ie->probe_res_ie;
 +			mgmt_ie_len = &saved_ie->probe_res_ie_len;
 +			mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
  			break;
  		case VNDR_IE_BEACON_FLAG:
 -			mgmt_ie_buf = cfg->ap_info->beacon_ie;
 -			mgmt_ie_len = &cfg->ap_info->beacon_ie_len;
 -			mgmt_ie_buf_len = sizeof(cfg->ap_info->beacon_ie);
 +			mgmt_ie_buf = saved_ie->beacon_ie;
 +			mgmt_ie_len = &saved_ie->beacon_ie_len;
 +			mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
  			break;
  		default:
  			err = -EPERM;
  			WL_ERR("not suitable type\n");
  			goto exit;
  		}
 -		bssidx = 0;
  	} else {
  		err = -EPERM;
  		WL_ERR("not suitable type\n");
@@@ -3909,8 -4104,11 +3909,8 @@@
  		}
  	}
  	if (total_ie_buf_len) {
 -		err  = brcmf_dev_iovar_setbuf_bsscfg(ndev, "vndr_ie",
 -						     iovar_ie_buf,
 -						     total_ie_buf_len,
 -						     cfg->extra_buf,
 -						     WL_EXTRA_BUF_MAX, bssidx);
 +		err  = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf,
 +						 total_ie_buf_len);
  		if (err)
  			WL_ERR("vndr ie set error : %d\n", err);
  	}
@@@ -3925,9 -4123,9 +3925,9 @@@ brcmf_cfg80211_start_ap(struct wiphy *w
  			struct cfg80211_ap_settings *settings)
  {
  	s32 ie_offset;
 +	struct brcmf_if *ifp = netdev_priv(ndev);
  	struct brcmf_tlv *ssid_ie;
  	struct brcmf_ssid_le ssid_le;
 -	s32 ioctl_value;
  	s32 err = -EPERM;
  	struct brcmf_tlv *rsn_ie;
  	struct brcmf_vs_tlv *wpa_ie;
@@@ -3942,7 -4140,7 +3942,7 @@@
  		 settings->ssid, settings->ssid_len, settings->auth_type,
  		 settings->inactivity_timeout);
  
 -	if (!test_bit(WL_STATUS_AP_CREATING, &cfg->status)) {
 +	if (!test_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state)) {
  		WL_ERR("Not in AP creation mode\n");
  		return -EPERM;
  	}
@@@ -3966,17 -4164,20 +3966,17 @@@
  	}
  
  	brcmf_set_mpc(ndev, 0);
 -	ioctl_value = 1;
 -	err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_DOWN, &ioctl_value);
 +	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
  	if (err < 0) {
  		WL_ERR("BRCMF_C_DOWN error %d\n", err);
  		goto exit;
  	}
 -	ioctl_value = 1;
 -	err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_INFRA, &ioctl_value);
 +	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
  	if (err < 0) {
  		WL_ERR("SET INFRA error %d\n", err);
  		goto exit;
  	}
 -	ioctl_value = 1;
 -	err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_AP, &ioctl_value);
 +	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
  	if (err < 0) {
  		WL_ERR("setting AP mode failed %d\n", err);
  		goto exit;
@@@ -4025,7 -4226,7 +4025,7 @@@
  		cfg->ap_info->security_mode = false;
  	}
  	/* Set Beacon IEs to FW */
 -	err = brcmf_set_management_ie(cfg, ndev, bssidx,
 +	err = brcmf_set_management_ie(cfg, ndev,
  				      VNDR_IE_BEACON_FLAG,
  				      (u8 *)settings->beacon.tail,
  				      settings->beacon.tail_len);
@@@ -4035,7 -4236,7 +4035,7 @@@
  		WL_TRACE("Applied Vndr IEs for Beacon\n");
  
  	/* Set Probe Response IEs to FW */
 -	err = brcmf_set_management_ie(cfg, ndev, bssidx,
 +	err = brcmf_set_management_ie(cfg, ndev,
  				      VNDR_IE_PRBRSP_FLAG,
  				      (u8 *)settings->beacon.proberesp_ies,
  				      settings->beacon.proberesp_ies_len);
@@@ -4045,22 -4246,25 +4045,22 @@@
  		WL_TRACE("Applied Vndr IEs for Probe Resp\n");
  
  	if (settings->beacon_interval) {
 -		ioctl_value = settings->beacon_interval;
 -		err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_BCNPRD,
 -					  &ioctl_value);
 +		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
 +					    settings->beacon_interval);
  		if (err < 0) {
  			WL_ERR("Beacon Interval Set Error, %d\n", err);
  			goto exit;
  		}
  	}
  	if (settings->dtim_period) {
 -		ioctl_value = settings->dtim_period;
 -		err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_DTIMPRD,
 -					  &ioctl_value);
 +		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD,
 +					    settings->dtim_period);
  		if (err < 0) {
  			WL_ERR("DTIM Interval Set Error, %d\n", err);
  			goto exit;
  		}
  	}
 -	ioctl_value = 1;
 -	err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_UP, &ioctl_value);
 +	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
  	if (err < 0) {
  		WL_ERR("BRCMF_C_UP error (%d)\n", err);
  		goto exit;
@@@ -4070,14 -4274,14 +4070,14 @@@
  	/* join parameters starts with ssid */
  	memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
  	/* create softap */
 -	err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SSID, &join_params,
 -			      sizeof(join_params));
 +	err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
 +				     &join_params, sizeof(join_params));
  	if (err < 0) {
  		WL_ERR("SET SSID error (%d)\n", err);
  		goto exit;
  	}
 -	clear_bit(WL_STATUS_AP_CREATING, &cfg->status);
 -	set_bit(WL_STATUS_AP_CREATED, &cfg->status);
 +	clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
 +	set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
  
  exit:
  	if (err)
@@@ -4087,8 -4291,8 +4087,8 @@@
  
  static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
  {
 +	struct brcmf_if *ifp = netdev_priv(ndev);
  	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
 -	s32 ioctl_value;
  	s32 err = -EPERM;
  
  	WL_TRACE("Enter\n");
@@@ -4097,20 -4301,21 +4097,20 @@@
  		/* Due to most likely deauths outstanding we sleep */
  		/* first to make sure they get processed by fw. */
  		msleep(400);
 -		ioctl_value = 0;
 -		err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_AP, &ioctl_value);
 +		err = brcmf_fil_cmd_int_set(netdev_priv(ndev),
 +					    BRCMF_C_SET_AP, 0);
  		if (err < 0) {
  			WL_ERR("setting AP mode failed %d\n", err);
  			goto exit;
  		}
 -		ioctl_value = 0;
 -		err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_UP, &ioctl_value);
 +		err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_UP, 0);
  		if (err < 0) {
  			WL_ERR("BRCMF_C_UP error %d\n", err);
  			goto exit;
  		}
  		brcmf_set_mpc(ndev, 1);
 -		clear_bit(WL_STATUS_AP_CREATING, &cfg->status);
 -		clear_bit(WL_STATUS_AP_CREATED, &cfg->status);
 +		clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
 +		clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
  	}
  exit:
  	return err;
@@@ -4121,7 -4326,6 +4121,7 @@@ brcmf_cfg80211_del_station(struct wiph
  			   u8 *mac)
  {
  	struct brcmf_scb_val_le scbval;
 +	struct brcmf_if *ifp = netdev_priv(ndev);
  	s32 err;
  
  	if (!mac)
@@@ -4129,13 -4333,13 +4129,13 @@@
  
  	WL_TRACE("Enter %pM\n", mac);
  
 -	if (!check_sys_up(wiphy))
 +	if (!check_vif_up(ifp->vif))
  		return -EIO;
  
  	memcpy(&scbval.ea, mac, ETH_ALEN);
  	scbval.val = cpu_to_le32(WLAN_REASON_DEAUTH_LEAVING);
 -	err = brcmf_exec_dcmd(ndev, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
 -			      &scbval, sizeof(scbval));
 +	err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
 +				     &scbval, sizeof(scbval));
  	if (err)
  		WL_ERR("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err);
  
@@@ -4197,7 -4401,7 +4197,7 @@@ static s32 brcmf_mode_to_nl80211_iftype
  
  static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
  {
- #ifndef CONFIG_BRCMFISCAN
+ #ifndef CONFIG_BRCMISCAN
  	/* scheduled scan settings */
  	wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
  	wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
@@@ -4206,97 -4410,72 +4206,97 @@@
  #endif
  }
  
 -static struct wireless_dev *brcmf_alloc_wdev(struct device *ndev)
 +static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
  {
 -	struct wireless_dev *wdev;
 +	struct wiphy *wiphy;
  	s32 err = 0;
  
 -	wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
 -	if (!wdev)
 -		return ERR_PTR(-ENOMEM);
 -
 -	wdev->wiphy = wiphy_new(&wl_cfg80211_ops,
 -				sizeof(struct brcmf_cfg80211_info));
 -	if (!wdev->wiphy) {
 +	wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_info));
 +	if (!wiphy) {
  		WL_ERR("Could not allocate wiphy device\n");
 -		err = -ENOMEM;
 -		goto wiphy_new_out;
 -	}
 -	set_wiphy_dev(wdev->wiphy, ndev);
 -	wdev->wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
 -	wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
 -	wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
 -				       BIT(NL80211_IFTYPE_ADHOC) |
 -				       BIT(NL80211_IFTYPE_AP);
 -	wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
 -	wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a;	/* Set
 +		return ERR_PTR(-ENOMEM);
 +	}
 +	set_wiphy_dev(wiphy, phydev);
 +	wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
 +	wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
 +	wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
 +				 BIT(NL80211_IFTYPE_ADHOC) |
 +				 BIT(NL80211_IFTYPE_AP);
 +	wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
 +	wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a;	/* Set
  						* it as 11a by default.
  						* This will be updated with
  						* 11n phy tables in
  						* "ifconfig up"
  						* if phy has 11n capability
  						*/
 -	wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
 -	wdev->wiphy->cipher_suites = __wl_cipher_suites;
 -	wdev->wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
 -	wdev->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;	/* enable power
 +	wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
 +	wiphy->cipher_suites = __wl_cipher_suites;
 +	wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
 +	wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;	/* enable power
  								 * save mode
  								 * by default
  								 */
 -	brcmf_wiphy_pno_params(wdev->wiphy);
 -	err = wiphy_register(wdev->wiphy);
 +	brcmf_wiphy_pno_params(wiphy);
 +	err = wiphy_register(wiphy);
  	if (err < 0) {
  		WL_ERR("Could not register wiphy device (%d)\n", err);
 -		goto wiphy_register_out;
 +		wiphy_free(wiphy);
 +		return ERR_PTR(err);
 +	}
 +	return wiphy;
 +}
 +
 +static
 +struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
 +					   struct net_device *netdev,
 +					   s32 mode, bool pm_block)
 +{
 +	struct brcmf_cfg80211_vif *vif;
 +
 +	if (cfg->vif_cnt == BRCMF_IFACE_MAX_CNT)
 +		return ERR_PTR(-ENOSPC);
 +
 +	vif = kzalloc(sizeof(*vif), GFP_KERNEL);
 +	if (!vif)
 +		return ERR_PTR(-ENOMEM);
 +
 +	vif->wdev.wiphy = cfg->wiphy;
 +	vif->wdev.netdev = netdev;
 +	vif->wdev.iftype = brcmf_mode_to_nl80211_iftype(mode);
 +
 +	if (netdev) {
 +		vif->ifp = netdev_priv(netdev);
 +		netdev->ieee80211_ptr = &vif->wdev;
 +		SET_NETDEV_DEV(netdev, wiphy_dev(cfg->wiphy));
  	}
 -	return wdev;
  
 -wiphy_register_out:
 -	wiphy_free(wdev->wiphy);
 +	vif->mode = mode;
 +	vif->pm_block = pm_block;
 +	vif->roam_off = -1;
  
 -wiphy_new_out:
 -	kfree(wdev);
 +	brcmf_init_prof(&vif->profile);
  
 -	return ERR_PTR(err);
 +	list_add_tail(&vif->list, &cfg->vif_list);
 +	cfg->vif_cnt++;
 +	return vif;
  }
  
 -static void brcmf_free_wdev(struct brcmf_cfg80211_info *cfg)
 +static void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
  {
 -	struct wireless_dev *wdev = cfg->wdev;
 +	struct brcmf_cfg80211_info *cfg;
 +	struct wiphy *wiphy;
  
 -	if (!wdev) {
 -		WL_ERR("wdev is invalid\n");
 -		return;
 +	wiphy = vif->wdev.wiphy;
 +	cfg = wiphy_priv(wiphy);
 +	list_del(&vif->list);
 +	cfg->vif_cnt--;
 +
 +	kfree(vif);
 +	if (!cfg->vif_cnt) {
 +		wiphy_unregister(wiphy);
 +		wiphy_free(wiphy);
  	}
 -	wiphy_unregister(wdev->wiphy);
 -	wiphy_free(wdev->wiphy);
 -	kfree(wdev);
 -	cfg->wdev = NULL;
  }
  
  static bool brcmf_is_linkup(struct brcmf_cfg80211_info *cfg,
@@@ -4362,7 -4541,7 +4362,7 @@@ static void brcmf_clear_assoc_ies(struc
  
  static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg)
  {
 -	struct net_device *ndev = cfg_to_ndev(cfg);
 +	struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
  	struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
  	struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
  	u32 req_len;
@@@ -4371,8 -4550,8 +4371,8 @@@
  
  	brcmf_clear_assoc_ies(cfg);
  
 -	err = brcmf_dev_bufvar_get(ndev, "assoc_info", cfg->extra_buf,
 -				WL_ASSOC_INFO_MAX);
 +	err = brcmf_fil_iovar_data_get(ifp, "assoc_info",
 +				       cfg->extra_buf, WL_ASSOC_INFO_MAX);
  	if (err) {
  		WL_ERR("could not get assoc info (%d)\n", err);
  		return err;
@@@ -4382,9 -4561,9 +4382,9 @@@
  	req_len = le32_to_cpu(assoc_info->req_len);
  	resp_len = le32_to_cpu(assoc_info->resp_len);
  	if (req_len) {
 -		err = brcmf_dev_bufvar_get(ndev, "assoc_req_ies",
 -					   cfg->extra_buf,
 -					   WL_ASSOC_INFO_MAX);
 +		err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies",
 +					       cfg->extra_buf,
 +					       WL_ASSOC_INFO_MAX);
  		if (err) {
  			WL_ERR("could not get assoc req (%d)\n", err);
  			return err;
@@@ -4398,9 -4577,9 +4398,9 @@@
  		conn_info->req_ie = NULL;
  	}
  	if (resp_len) {
 -		err = brcmf_dev_bufvar_get(ndev, "assoc_resp_ies",
 -					   cfg->extra_buf,
 -					   WL_ASSOC_INFO_MAX);
 +		err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies",
 +					       cfg->extra_buf,
 +					       WL_ASSOC_INFO_MAX);
  		if (err) {
  			WL_ERR("could not get assoc resp (%d)\n", err);
  			return err;
@@@ -4424,8 -4603,7 +4424,8 @@@ brcmf_bss_roaming_done(struct brcmf_cfg
  		       struct net_device *ndev,
  		       const struct brcmf_event_msg *e)
  {
 -	struct brcmf_cfg80211_profile *profile = cfg->profile;
 +	struct brcmf_if *ifp = netdev_priv(ndev);
 +	struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
  	struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
  	struct wiphy *wiphy = cfg_to_wiphy(cfg);
  	struct ieee80211_channel *notify_channel = NULL;
@@@ -4450,8 -4628,7 +4450,8 @@@
  
  	/* data sent to dongle has to be little endian */
  	*(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
 -	err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_BSS_INFO, buf, WL_BSS_INFO_MAX);
 +	err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
 +				     buf, WL_BSS_INFO_MAX);
  
  	if (err)
  		goto done;
@@@ -4475,7 -4652,7 +4475,7 @@@ done
  			conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
  	WL_CONN("Report roaming result\n");
  
 -	set_bit(WL_STATUS_CONNECTED, &cfg->status);
 +	set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
  	WL_TRACE("Exit\n");
  	return err;
  }
@@@ -4485,15 -4662,13 +4485,15 @@@ brcmf_bss_connect_done(struct brcmf_cfg
  		       struct net_device *ndev, const struct brcmf_event_msg *e,
  		       bool completed)
  {
 -	struct brcmf_cfg80211_profile *profile = cfg->profile;
 +	struct brcmf_if *ifp = netdev_priv(ndev);
 +	struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
  	struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
  	s32 err = 0;
  
  	WL_TRACE("Enter\n");
  
 -	if (test_and_clear_bit(WL_STATUS_CONNECTING, &cfg->status)) {
 +	if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
 +			       &ifp->vif->sme_state)) {
  		if (completed) {
  			brcmf_get_assoc_ies(cfg);
  			memcpy(profile->bssid, e->addr, ETH_ALEN);
@@@ -4509,8 -4684,7 +4509,8 @@@
  						    WLAN_STATUS_AUTH_TIMEOUT,
  					GFP_KERNEL);
  		if (completed)
 -			set_bit(WL_STATUS_CONNECTED, &cfg->status);
 +			set_bit(BRCMF_VIF_STATUS_CONNECTED,
 +				&ifp->vif->sme_state);
  		WL_CONN("Report connect result - connection %s\n",
  				completed ? "succeeded" : "failed");
  	}
@@@ -4562,8 -4736,7 +4562,8 @@@ brcmf_notify_connect_status(struct brcm
  			    struct net_device *ndev,
  			    const struct brcmf_event_msg *e, void *data)
  {
 -	struct brcmf_cfg80211_profile *profile = cfg->profile;
 +	struct brcmf_if *ifp = netdev_priv(ndev);
 +	struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
  	s32 err = 0;
  
  	if (cfg->conf->mode == WL_MODE_AP) {
@@@ -4574,34 -4747,30 +4574,34 @@@
  			memcpy(profile->bssid, e->addr, ETH_ALEN);
  			wl_inform_ibss(cfg, ndev, e->addr);
  			cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL);
 -			clear_bit(WL_STATUS_CONNECTING, &cfg->status);
 -			set_bit(WL_STATUS_CONNECTED, &cfg->status);
 +			clear_bit(BRCMF_VIF_STATUS_CONNECTING,
 +				  &ifp->vif->sme_state);
 +			set_bit(BRCMF_VIF_STATUS_CONNECTED,
 +				&ifp->vif->sme_state);
  		} else
  			brcmf_bss_connect_done(cfg, ndev, e, true);
  	} else if (brcmf_is_linkdown(cfg, e)) {
  		WL_CONN("Linkdown\n");
  		if (brcmf_is_ibssmode(cfg)) {
 -			clear_bit(WL_STATUS_CONNECTING, &cfg->status);
 -			if (test_and_clear_bit(WL_STATUS_CONNECTED,
 -				&cfg->status))
 +			clear_bit(BRCMF_VIF_STATUS_CONNECTING,
 +				  &ifp->vif->sme_state);
 +			if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED,
 +					       &ifp->vif->sme_state))
  				brcmf_link_down(cfg);
  		} else {
  			brcmf_bss_connect_done(cfg, ndev, e, false);
 -			if (test_and_clear_bit(WL_STATUS_CONNECTED,
 -				&cfg->status)) {
 +			if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED,
 +					       &ifp->vif->sme_state)) {
  				cfg80211_disconnected(ndev, 0, NULL, 0,
 -					GFP_KERNEL);
 +						      GFP_KERNEL);
  				brcmf_link_down(cfg);
  			}
  		}
 -		brcmf_init_prof(cfg->profile);
 +		brcmf_init_prof(ndev_to_prof(ndev));
  	} else if (brcmf_is_nonetwork(cfg, e)) {
  		if (brcmf_is_ibssmode(cfg))
 -			clear_bit(WL_STATUS_CONNECTING, &cfg->status);
 +			clear_bit(BRCMF_VIF_STATUS_CONNECTING,
 +				  &ifp->vif->sme_state);
  		else
  			brcmf_bss_connect_done(cfg, ndev, e, false);
  	}
@@@ -4614,13 -4783,12 +4614,13 @@@ brcmf_notify_roaming_status(struct brcm
  			    struct net_device *ndev,
  			    const struct brcmf_event_msg *e, void *data)
  {
 +	struct brcmf_if *ifp = netdev_priv(ndev);
  	s32 err = 0;
  	u32 event = be32_to_cpu(e->event_type);
  	u32 status = be32_to_cpu(e->status);
  
  	if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
 -		if (test_bit(WL_STATUS_CONNECTED, &cfg->status))
 +		if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
  			brcmf_bss_roaming_done(cfg, ndev, e);
  		else
  			brcmf_bss_connect_done(cfg, ndev, e, true);
@@@ -4653,7 -4821,6 +4653,7 @@@ brcmf_notify_scan_status(struct brcmf_c
  			 struct net_device *ndev,
  			 const struct brcmf_event_msg *e, void *data)
  {
 +	struct brcmf_if *ifp = netdev_priv(ndev);
  	struct brcmf_channel_info_le channel_inform_le;
  	struct brcmf_scan_results_le *bss_list_le;
  	u32 len = WL_SCAN_BUF_MAX;
@@@ -4668,16 -4835,15 +4668,16 @@@
  		return brcmf_wakeup_iscan(cfg_to_iscan(cfg));
  	}
  
 -	if (!test_and_clear_bit(WL_STATUS_SCANNING, &cfg->status)) {
 +	if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
  		WL_ERR("Scan complete while device not scanning\n");
  		scan_abort = true;
  		err = -EINVAL;
  		goto scan_done_out;
  	}
  
 -	err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_CHANNEL, &channel_inform_le,
 -			      sizeof(channel_inform_le));
 +	err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_CHANNEL,
 +				     &channel_inform_le,
 +				     sizeof(channel_inform_le));
  	if (err) {
  		WL_ERR("scan busy (%d)\n", err);
  		scan_abort = true;
@@@ -4691,8 -4857,8 +4691,8 @@@
  
  	memset(cfg->scan_results, 0, len);
  	bss_list_le->buflen = cpu_to_le32(len);
 -	err = brcmf_exec_dcmd(ndev, BRCMF_C_SCAN_RESULTS,
 -			      cfg->scan_results, len);
 +	err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_SCAN_RESULTS,
 +				     cfg->scan_results, len);
  	if (err) {
  		WL_ERR("%s Scan_results error (%d)\n", ndev->name, err);
  		err = -EINVAL;
@@@ -4754,6 -4920,8 +4754,6 @@@ static void brcmf_deinit_priv_mem(struc
  	cfg->bss_info = NULL;
  	kfree(cfg->conf);
  	cfg->conf = NULL;
 -	kfree(cfg->profile);
 -	cfg->profile = NULL;
  	kfree(cfg->scan_req_int);
  	cfg->scan_req_int = NULL;
  	kfree(cfg->escan_ioctl_buf);
@@@ -4782,6 -4950,9 +4782,6 @@@ static s32 brcmf_init_priv_mem(struct b
  	cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
  	if (!cfg->conf)
  		goto init_priv_mem_out;
 -	cfg->profile = kzalloc(sizeof(*cfg->profile), GFP_KERNEL);
 -	if (!cfg->profile)
 -		goto init_priv_mem_out;
  	cfg->bss_info = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
  	if (!cfg->bss_info)
  		goto init_priv_mem_out;
@@@ -4958,6 -5129,7 +4958,6 @@@ static s32 wl_init_priv(struct brcmf_cf
  		return err;
  	brcmf_init_escan(cfg);
  	brcmf_init_conf(cfg->conf);
 -	brcmf_init_prof(cfg->profile);
  	brcmf_link_down(cfg);
  
  	return err;
@@@ -4973,14 -5145,12 +4973,14 @@@ static void wl_deinit_priv(struct brcmf
  	brcmf_deinit_priv_mem(cfg);
  }
  
 -struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct net_device *ndev,
 -						  struct device *busdev,
 -						  struct brcmf_pub *drvr)
 +struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr)
  {
 -	struct wireless_dev *wdev;
 +	struct net_device *ndev = drvr->iflist[0]->ndev;
 +	struct device *busdev = drvr->dev;
  	struct brcmf_cfg80211_info *cfg;
 +	struct wiphy *wiphy;
 +	struct brcmf_cfg80211_vif *vif;
 +	struct brcmf_if *ifp;
  	s32 err = 0;
  
  	if (!ndev) {
@@@ -4988,45 -5158,35 +4988,45 @@@
  		return NULL;
  	}
  
 -	wdev = brcmf_alloc_wdev(busdev);
 -	if (IS_ERR(wdev)) {
 +	ifp = netdev_priv(ndev);
 +	wiphy = brcmf_setup_wiphy(busdev);
 +	if (IS_ERR(wiphy))
  		return NULL;
 -	}
  
 -	wdev->iftype = brcmf_mode_to_nl80211_iftype(WL_MODE_BSS);
 -	cfg = wdev_to_cfg(wdev);
 -	cfg->wdev = wdev;
 +	cfg = wiphy_priv(wiphy);
 +	cfg->wiphy = wiphy;
  	cfg->pub = drvr;
 -	ndev->ieee80211_ptr = wdev;
 -	SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
 -	wdev->netdev = ndev;
 +	INIT_LIST_HEAD(&cfg->vif_list);
 +
 +	vif = brcmf_alloc_vif(cfg, ndev, WL_MODE_BSS, false);
 +	if (IS_ERR(vif)) {
 +		wiphy_free(wiphy);
 +		return NULL;
 +	}
 +
  	err = wl_init_priv(cfg);
  	if (err) {
  		WL_ERR("Failed to init iwm_priv (%d)\n", err);
  		goto cfg80211_attach_out;
  	}
  
 +	ifp->vif = vif;
  	return cfg;
  
  cfg80211_attach_out:
 -	brcmf_free_wdev(cfg);
 +	brcmf_free_vif(vif);
  	return NULL;
  }
  
  void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
  {
 +	struct brcmf_cfg80211_vif *vif;
 +	struct brcmf_cfg80211_vif *tmp;
 +
  	wl_deinit_priv(cfg);
 -	brcmf_free_wdev(cfg);
 +	list_for_each_entry_safe(vif, tmp, &cfg->vif_list, list) {
 +		brcmf_free_vif(vif);
 +	}
  }
  
  void
@@@ -5042,18 -5202,22 +5042,18 @@@ brcmf_cfg80211_event(struct net_device 
  
  static s32 brcmf_dongle_eventmsg(struct net_device *ndev)
  {
 -	/* Room for "event_msgs" + '\0' + bitvec */
 -	s8 iovbuf[BRCMF_EVENTING_MASK_LEN + 12];
  	s8 eventmask[BRCMF_EVENTING_MASK_LEN];
  	s32 err = 0;
  
  	WL_TRACE("Enter\n");
  
  	/* Setup event_msgs */
 -	brcmf_c_mkiovar("event_msgs", eventmask, BRCMF_EVENTING_MASK_LEN,
 -			iovbuf, sizeof(iovbuf));
 -	err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, iovbuf, sizeof(iovbuf));
 +	err = brcmf_fil_iovar_data_get(netdev_priv(ndev), "event_msgs",
 +				       eventmask, BRCMF_EVENTING_MASK_LEN);
  	if (err) {
  		WL_ERR("Get event_msgs error (%d)\n", err);
  		goto dongle_eventmsg_out;
  	}
 -	memcpy(eventmask, iovbuf, BRCMF_EVENTING_MASK_LEN);
  
  	setbit(eventmask, BRCMF_E_SET_SSID);
  	setbit(eventmask, BRCMF_E_ROAM);
@@@ -5077,8 -5241,9 +5077,8 @@@
  	setbit(eventmask, BRCMF_E_ESCAN_RESULT);
  	setbit(eventmask, BRCMF_E_PFN_NET_FOUND);
  
 -	brcmf_c_mkiovar("event_msgs", eventmask, BRCMF_EVENTING_MASK_LEN,
 -			iovbuf, sizeof(iovbuf));
 -	err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, iovbuf, sizeof(iovbuf));
 +	err = brcmf_fil_iovar_data_set(netdev_priv(ndev), "event_msgs",
 +				       eventmask, BRCMF_EVENTING_MASK_LEN);
  	if (err) {
  		WL_ERR("Set event_msgs error (%d)\n", err);
  		goto dongle_eventmsg_out;
@@@ -5092,17 -5257,23 +5092,17 @@@ dongle_eventmsg_out
  static s32
  brcmf_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
  {
 -	s8 iovbuf[32];
 +	struct brcmf_if *ifp = netdev_priv(ndev);
  	s32 err = 0;
  	__le32 roamtrigger[2];
  	__le32 roam_delta[2];
 -	__le32 bcn_to_le;
 -	__le32 roamvar_le;
  
  	/*
  	 * Setup timeout if Beacons are lost and roam is
  	 * off to report link down
  	 */
  	if (roamvar) {
 -		bcn_to_le = cpu_to_le32(bcn_timeout);
 -		brcmf_c_mkiovar("bcn_timeout", (char *)&bcn_to_le,
 -			sizeof(bcn_to_le), iovbuf, sizeof(iovbuf));
 -		err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR,
 -				   iovbuf, sizeof(iovbuf));
 +		err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
  		if (err) {
  			WL_ERR("bcn_timeout error (%d)\n", err);
  			goto dongle_rom_out;
@@@ -5114,7 -5285,10 +5114,7 @@@
  	 * to take care of roaming
  	 */
  	WL_INFO("Internal Roaming = %s\n", roamvar ? "Off" : "On");
 -	roamvar_le = cpu_to_le32(roamvar);
 -	brcmf_c_mkiovar("roam_off", (char *)&roamvar_le,
 -				sizeof(roamvar_le), iovbuf, sizeof(iovbuf));
 -	err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, iovbuf, sizeof(iovbuf));
 +	err = brcmf_fil_iovar_int_set(ifp, "roam_off", roamvar);
  	if (err) {
  		WL_ERR("roam_off error (%d)\n", err);
  		goto dongle_rom_out;
@@@ -5122,8 -5296,8 +5122,8 @@@
  
  	roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
  	roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
 -	err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_ROAM_TRIGGER,
 -			(void *)roamtrigger, sizeof(roamtrigger));
 +	err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
 +				     (void *)roamtrigger, sizeof(roamtrigger));
  	if (err) {
  		WL_ERR("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
  		goto dongle_rom_out;
@@@ -5131,8 -5305,8 +5131,8 @@@
  
  	roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
  	roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
 -	err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_ROAM_DELTA,
 -				(void *)roam_delta, sizeof(roam_delta));
 +	err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
 +				     (void *)roam_delta, sizeof(roam_delta));
  	if (err) {
  		WL_ERR("WLC_SET_ROAM_DELTA error (%d)\n", err);
  		goto dongle_rom_out;
@@@ -5146,11 -5320,13 +5146,11 @@@ static s3
  brcmf_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
  		      s32 scan_unassoc_time, s32 scan_passive_time)
  {
 +	struct brcmf_if *ifp = netdev_priv(ndev);
  	s32 err = 0;
 -	__le32 scan_assoc_tm_le = cpu_to_le32(scan_assoc_time);
 -	__le32 scan_unassoc_tm_le = cpu_to_le32(scan_unassoc_time);
 -	__le32 scan_passive_tm_le = cpu_to_le32(scan_passive_time);
  
 -	err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SCAN_CHANNEL_TIME,
 -			   &scan_assoc_tm_le, sizeof(scan_assoc_tm_le));
 +	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
 +				    scan_assoc_time);
  	if (err) {
  		if (err == -EOPNOTSUPP)
  			WL_INFO("Scan assoc time is not supported\n");
@@@ -5158,8 -5334,8 +5158,8 @@@
  			WL_ERR("Scan assoc time error (%d)\n", err);
  		goto dongle_scantime_out;
  	}
 -	err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SCAN_UNASSOC_TIME,
 -			   &scan_unassoc_tm_le, sizeof(scan_unassoc_tm_le));
 +	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
 +				    scan_unassoc_time);
  	if (err) {
  		if (err == -EOPNOTSUPP)
  			WL_INFO("Scan unassoc time is not supported\n");
@@@ -5168,8 -5344,8 +5168,8 @@@
  		goto dongle_scantime_out;
  	}
  
 -	err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SCAN_PASSIVE_TIME,
 -			   &scan_passive_tm_le, sizeof(scan_passive_tm_le));
 +	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME,
 +				    scan_passive_time);
  	if (err) {
  		if (err == -EOPNOTSUPP)
  			WL_INFO("Scan passive time is not supported\n");
@@@ -5184,14 -5360,13 +5184,14 @@@ dongle_scantime_out
  
  static s32 wl_update_wiphybands(struct brcmf_cfg80211_info *cfg)
  {
 +	struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
  	struct wiphy *wiphy;
  	s32 phy_list;
  	s8 phy;
  	s32 err = 0;
  
 -	err = brcmf_exec_dcmd(cfg_to_ndev(cfg), BRCM_GET_PHYLIST,
 -			      &phy_list, sizeof(phy_list));
 +	err = brcmf_fil_cmd_data_get(ifp, BRCM_GET_PHYLIST,
 +				     &phy_list, sizeof(phy_list));
  	if (err) {
  		WL_ERR("error (%d)\n", err);
  		return err;
@@@ -5233,8 -5408,7 +5233,8 @@@ static s32 brcmf_config_dongle(struct b
  		goto default_conf_out;
  
  	power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
 -	err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_PM, &power_mode);
 +	err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PM,
 +				    power_mode);
  	if (err)
  		goto default_conf_out;
  	WL_INFO("power save set to %s\n",
@@@ -5262,12 -5436,47 +5262,12 @@@ default_conf_out
  
  }
  
 -static int brcmf_debugfs_add_netdev_params(struct brcmf_cfg80211_info *cfg)
 -{
 -	char buf[10+IFNAMSIZ];
 -	struct dentry *fd;
 -	s32 err = 0;
 -
 -	sprintf(buf, "netdev:%s", cfg_to_ndev(cfg)->name);
 -	cfg->debugfsdir = debugfs_create_dir(buf,
 -					cfg_to_wiphy(cfg)->debugfsdir);
 -
 -	fd = debugfs_create_u16("beacon_int", S_IRUGO, cfg->debugfsdir,
 -		(u16 *)&cfg->profile->beacon_interval);
 -	if (!fd) {
 -		err = -ENOMEM;
 -		goto err_out;
 -	}
 -
 -	fd = debugfs_create_u8("dtim_period", S_IRUGO, cfg->debugfsdir,
 -		(u8 *)&cfg->profile->dtim_period);
 -	if (!fd) {
 -		err = -ENOMEM;
 -		goto err_out;
 -	}
 -
 -err_out:
 -	return err;
 -}
 -
 -static void brcmf_debugfs_remove_netdev(struct brcmf_cfg80211_info *cfg)
 -{
 -	debugfs_remove_recursive(cfg->debugfsdir);
 -	cfg->debugfsdir = NULL;
 -}
 -
  static s32 __brcmf_cfg80211_up(struct brcmf_cfg80211_info *cfg)
  {
 +	struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
  	s32 err = 0;
  
 -	set_bit(WL_STATUS_READY, &cfg->status);
 -
 -	brcmf_debugfs_add_netdev_params(cfg);
 +	set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
  
  	err = brcmf_config_dongle(cfg);
  	if (err)
@@@ -5280,16 -5489,13 +5280,16 @@@
  
  static s32 __brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg)
  {
 +	struct net_device *ndev = cfg_to_ndev(cfg);
 +	struct brcmf_if *ifp = netdev_priv(ndev);
 +
  	/*
  	 * While going down, if associated with AP disassociate
  	 * from AP to save power
  	 */
 -	if ((test_bit(WL_STATUS_CONNECTED, &cfg->status) ||
 -	     test_bit(WL_STATUS_CONNECTING, &cfg->status)) &&
 -	     test_bit(WL_STATUS_READY, &cfg->status)) {
 +	if ((test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state) ||
 +	     test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) &&
 +	     check_vif_up(ifp->vif)) {
  		WL_INFO("Disassociating from AP");
  		brcmf_link_down(cfg);
  
@@@ -5301,7 -5507,9 +5301,7 @@@
  	}
  
  	brcmf_abort_scanning(cfg);
 -	clear_bit(WL_STATUS_READY, &cfg->status);
 -
 -	brcmf_debugfs_remove_netdev(cfg);
 +	clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
  
  	return 0;
  }
diff --combined drivers/net/wireless/iwlwifi/dvm/main.c
index 475df45,408132c..30e761d
--- a/drivers/net/wireless/iwlwifi/dvm/main.c
+++ b/drivers/net/wireless/iwlwifi/dvm/main.c
@@@ -1191,6 -1191,8 +1191,6 @@@ static void iwl_option_config(struct iw
  
  static int iwl_eeprom_init_hw_params(struct iwl_priv *priv)
  {
 -	u16 radio_cfg;
 -
  	priv->eeprom_data->sku = priv->eeprom_data->sku;
  
  	if (priv->eeprom_data->sku & EEPROM_SKU_CAP_11N_ENABLE &&
@@@ -1206,6 -1208,8 +1206,6 @@@
  
  	IWL_INFO(priv, "Device SKU: 0x%X\n", priv->eeprom_data->sku);
  
 -	radio_cfg = priv->eeprom_data->radio_cfg;
 -
  	priv->hw_params.tx_chains_num =
  		num_of_ant(priv->eeprom_data->valid_tx_ant);
  	if (priv->cfg->rx_with_siso_diversity)
@@@ -1330,9 -1334,6 +1330,9 @@@ static struct iwl_op_mode *iwl_op_mode_
  	/* Configure transport layer */
  	iwl_trans_configure(priv->trans, &trans_cfg);
  
 +	trans->rx_mpdu_cmd = REPLY_RX_MPDU_CMD;
 +	trans->rx_mpdu_cmd_hdr_size = sizeof(struct iwl_rx_mpdu_res_start);
 +
  	/* At this point both hw and priv are allocated. */
  
  	SET_IEEE80211_DEV(priv->hw, priv->trans->dev);
@@@ -2113,7 -2114,7 +2113,7 @@@ static void iwl_free_skb(struct iwl_op_
  
  	info = IEEE80211_SKB_CB(skb);
  	iwl_trans_free_tx_cmd(priv->trans, info->driver_data[1]);
- 	dev_kfree_skb_any(skb);
+ 	ieee80211_free_txskb(priv->hw, skb);
  }
  
  static void iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state)
@@@ -2151,6 -2152,8 +2151,6 @@@ static int __init iwl_init(void
  {
  
  	int ret;
 -	pr_info(DRV_DESCRIPTION ", " DRV_VERSION "\n");
 -	pr_info(DRV_COPYRIGHT "\n");
  
  	ret = iwlagn_rate_control_register();
  	if (ret) {
diff --combined drivers/net/wireless/iwlwifi/pcie/rx.c
index 137af4c,bb69f8f..41d821f
--- a/drivers/net/wireless/iwlwifi/pcie/rx.c
+++ b/drivers/net/wireless/iwlwifi/pcie/rx.c
@@@ -321,6 -321,14 +321,14 @@@ static void iwl_rx_allocate(struct iwl_
  			dma_map_page(trans->dev, page, 0,
  				     PAGE_SIZE << trans_pcie->rx_page_order,
  				     DMA_FROM_DEVICE);
+ 		if (dma_mapping_error(trans->dev, rxb->page_dma)) {
+ 			rxb->page = NULL;
+ 			spin_lock_irqsave(&rxq->lock, flags);
+ 			list_add(&rxb->list, &rxq->rx_used);
+ 			spin_unlock_irqrestore(&rxq->lock, flags);
+ 			__free_pages(page, trans_pcie->rx_page_order);
+ 			return;
+ 		}
  		/* dma address must be no more than 36 bits */
  		BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36));
  		/* and also 256 byte aligned! */
@@@ -411,8 -419,7 +419,8 @@@ static void iwl_rx_handle_rxbuf(struct 
  
  		len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
  		len += sizeof(u32); /* account for status word */
 -		trace_iwlwifi_dev_rx(trans->dev, pkt, len);
 +		trace_iwlwifi_dev_rx(trans->dev, trans, pkt, len);
 +		trace_iwlwifi_dev_rx_data(trans->dev, trans, pkt, len);
  
  		/* Reclaim a command buffer only if this packet is a response
  		 *   to a (driver-originated) command.
@@@ -489,8 -496,19 +497,19 @@@
  			dma_map_page(trans->dev, rxb->page, 0,
  				     PAGE_SIZE << trans_pcie->rx_page_order,
  				     DMA_FROM_DEVICE);
- 		list_add_tail(&rxb->list, &rxq->rx_free);
- 		rxq->free_count++;
+ 		if (dma_mapping_error(trans->dev, rxb->page_dma)) {
+ 			/*
+ 			 * free the page(s) as well to not break
+ 			 * the invariant that the items on the used
+ 			 * list have no page(s)
+ 			 */
+ 			__free_pages(rxb->page, trans_pcie->rx_page_order);
+ 			rxb->page = NULL;
+ 			list_add_tail(&rxb->list, &rxq->rx_used);
+ 		} else {
+ 			list_add_tail(&rxb->list, &rxq->rx_free);
+ 			rxq->free_count++;
+ 		}
  	} else
  		list_add_tail(&rxb->list, &rxq->rx_used);
  	spin_unlock_irqrestore(&rxq->lock, flags);
diff --combined net/batman-adv/soft-interface.c
index 2d1f895,ce0684a..54800c7
--- a/net/batman-adv/soft-interface.c
+++ b/net/batman-adv/soft-interface.c
@@@ -20,7 -20,6 +20,7 @@@
  #include "main.h"
  #include "soft-interface.h"
  #include "hard-interface.h"
 +#include "distributed-arp-table.h"
  #include "routing.h"
  #include "send.h"
  #include "debugfs.h"
@@@ -147,16 -146,13 +147,16 @@@ static int batadv_interface_tx(struct s
  	struct batadv_bcast_packet *bcast_packet;
  	struct vlan_ethhdr *vhdr;
  	__be16 ethertype = __constant_htons(BATADV_ETH_P_BATMAN);
 -	static const uint8_t stp_addr[ETH_ALEN] = {0x01, 0x80, 0xC2, 0x00, 0x00,
 -						   0x00};
 +	static const uint8_t stp_addr[ETH_ALEN] = {0x01, 0x80, 0xC2, 0x00,
 +						   0x00, 0x00};
 +	static const uint8_t ectp_addr[ETH_ALEN] = {0xCF, 0x00, 0x00, 0x00,
 +						    0x00, 0x00};
  	unsigned int header_len = 0;
  	int data_len = skb->len, ret;
  	short vid __maybe_unused = -1;
  	bool do_bcast = false;
  	uint32_t seqno;
 +	unsigned long brd_delay = 1;
  
  	if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
  		goto dropped;
@@@ -184,16 -180,10 +184,16 @@@
  
  	/* don't accept stp packets. STP does not help in meshes.
  	 * better use the bridge loop avoidance ...
 +	 *
 +	 * The same goes for ECTP sent at least by some Cisco Switches,
 +	 * it might confuse the mesh when used with bridge loop avoidance.
  	 */
  	if (batadv_compare_eth(ethhdr->h_dest, stp_addr))
  		goto dropped;
  
 +	if (batadv_compare_eth(ethhdr->h_dest, ectp_addr))
 +		goto dropped;
 +
  	if (is_multicast_ether_addr(ethhdr->h_dest)) {
  		do_bcast = true;
  
@@@ -226,13 -216,6 +226,13 @@@
  		if (!primary_if)
  			goto dropped;
  
 +		/* in case of ARP request, we do not immediately broadcasti the
 +		 * packet, instead we first wait for DAT to try to retrieve the
 +		 * correct ARP entry
 +		 */
 +		if (batadv_dat_snoop_outgoing_arp_request(bat_priv, skb))
 +			brd_delay = msecs_to_jiffies(ARP_REQ_DELAY);
 +
  		if (batadv_skb_head_push(skb, sizeof(*bcast_packet)) < 0)
  			goto dropped;
  
@@@ -254,7 -237,7 +254,7 @@@
  		seqno = atomic_inc_return(&bat_priv->bcast_seqno);
  		bcast_packet->seqno = htonl(seqno);
  
 -		batadv_add_bcast_packet_to_list(bat_priv, skb, 1);
 +		batadv_add_bcast_packet_to_list(bat_priv, skb, brd_delay);
  
  		/* a copy is stored in the bcast list, therefore removing
  		 * the original skb.
@@@ -269,12 -252,7 +269,12 @@@
  				goto dropped;
  		}
  
 -		ret = batadv_unicast_send_skb(skb, bat_priv);
 +		if (batadv_dat_snoop_outgoing_arp_request(bat_priv, skb))
 +			goto dropped;
 +
 +		batadv_dat_snoop_outgoing_arp_reply(bat_priv, skb);
 +
 +		ret = batadv_unicast_send_skb(bat_priv, skb);
  		if (ret != 0)
  			goto dropped_freed;
  	}
@@@ -347,6 -325,12 +347,12 @@@ void batadv_interface_rx(struct net_dev
  
  	soft_iface->last_rx = jiffies;
  
+ 	/* Let the bridge loop avoidance check the packet. If will
+ 	 * not handle it, we can safely push it up.
+ 	 */
+ 	if (batadv_bla_rx(bat_priv, skb, vid, is_bcast))
+ 		goto out;
+ 
  	if (orig_node)
  		batadv_tt_add_temporary_global_entry(bat_priv, orig_node,
  						     ethhdr->h_source);
@@@ -354,12 -338,6 +360,6 @@@
  	if (batadv_is_ap_isolated(bat_priv, ethhdr->h_source, ethhdr->h_dest))
  		goto dropped;
  
- 	/* Let the bridge loop avoidance check the packet. If will
- 	 * not handle it, we can safely push it up.
- 	 */
- 	if (batadv_bla_rx(bat_priv, skb, vid, is_bcast))
- 		goto out;
- 
  	netif_rx(skb);
  	goto out;
  
@@@ -369,51 -347,7 +369,51 @@@ out
  	return;
  }
  
 +/* batman-adv network devices have devices nesting below it and are a special
 + * "super class" of normal network devices; split their locks off into a
 + * separate class since they always nest.
 + */
 +static struct lock_class_key batadv_netdev_xmit_lock_key;
 +static struct lock_class_key batadv_netdev_addr_lock_key;
 +
 +/**
 + * batadv_set_lockdep_class_one - Set lockdep class for a single tx queue
 + * @dev: device which owns the tx queue
 + * @txq: tx queue to modify
 + * @_unused: always NULL
 + */
 +static void batadv_set_lockdep_class_one(struct net_device *dev,
 +					 struct netdev_queue *txq,
 +					 void *_unused)
 +{
 +	lockdep_set_class(&txq->_xmit_lock, &batadv_netdev_xmit_lock_key);
 +}
 +
 +/**
 + * batadv_set_lockdep_class - Set txq and addr_list lockdep class
 + * @dev: network device to modify
 + */
 +static void batadv_set_lockdep_class(struct net_device *dev)
 +{
 +	lockdep_set_class(&dev->addr_list_lock, &batadv_netdev_addr_lock_key);
 +	netdev_for_each_tx_queue(dev, batadv_set_lockdep_class_one, NULL);
 +}
 +
 +/**
 + * batadv_softif_init - Late stage initialization of soft interface
 + * @dev: registered network device to modify
 + *
 + * Returns error code on failures
 + */
 +static int batadv_softif_init(struct net_device *dev)
 +{
 +	batadv_set_lockdep_class(dev);
 +
 +	return 0;
 +}
 +
  static const struct net_device_ops batadv_netdev_ops = {
 +	.ndo_init = batadv_softif_init,
  	.ndo_open = batadv_interface_open,
  	.ndo_stop = batadv_interface_release,
  	.ndo_get_stats = batadv_interface_stats,
@@@ -480,9 -414,6 +480,9 @@@ struct net_device *batadv_softif_create
  	atomic_set(&bat_priv->aggregated_ogms, 1);
  	atomic_set(&bat_priv->bonding, 0);
  	atomic_set(&bat_priv->bridge_loop_avoidance, 0);
 +#ifdef CONFIG_BATMAN_ADV_DAT
 +	atomic_set(&bat_priv->distributed_arp_table, 1);
 +#endif
  	atomic_set(&bat_priv->ap_isolation, 0);
  	atomic_set(&bat_priv->vis_mode, BATADV_VIS_TYPE_CLIENT_UPDATE);
  	atomic_set(&bat_priv->gw_mode, BATADV_GW_MODE_OFF);
@@@ -505,6 -436,7 +505,6 @@@
  #endif
  	bat_priv->tt.last_changeset = NULL;
  	bat_priv->tt.last_changeset_len = 0;
 -	bat_priv->tt.poss_change = false;
  
  	bat_priv->primary_if = NULL;
  	bat_priv->num_ifaces = 0;
@@@ -624,13 -556,6 +624,13 @@@ static const struct 
  	{ "tt_response_rx" },
  	{ "tt_roam_adv_tx" },
  	{ "tt_roam_adv_rx" },
 +#ifdef CONFIG_BATMAN_ADV_DAT
 +	{ "dat_get_tx" },
 +	{ "dat_get_rx" },
 +	{ "dat_put_tx" },
 +	{ "dat_put_rx" },
 +	{ "dat_cached_reply_tx" },
 +#endif
  };
  
  static void batadv_get_strings(struct net_device *dev, uint32_t stringset,
diff --combined net/batman-adv/translation-table.c
index 9f5705f,baae715..582f134
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@@ -238,134 -238,92 +238,134 @@@ static int batadv_tt_local_init(struct 
  	return 0;
  }
  
 +static void batadv_tt_global_free(struct batadv_priv *bat_priv,
 +				  struct batadv_tt_global_entry *tt_global,
 +				  const char *message)
 +{
 +	batadv_dbg(BATADV_DBG_TT, bat_priv,
 +		   "Deleting global tt entry %pM: %s\n",
 +		   tt_global->common.addr, message);
 +
 +	batadv_hash_remove(bat_priv->tt.global_hash, batadv_compare_tt,
 +			   batadv_choose_orig, tt_global->common.addr);
 +	batadv_tt_global_entry_free_ref(tt_global);
 +
 +}
 +
  void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
  			 int ifindex)
  {
  	struct batadv_priv *bat_priv = netdev_priv(soft_iface);
 -	struct batadv_tt_local_entry *tt_local_entry = NULL;
 -	struct batadv_tt_global_entry *tt_global_entry = NULL;
 +	struct batadv_tt_local_entry *tt_local;
 +	struct batadv_tt_global_entry *tt_global;
  	struct hlist_head *head;
  	struct hlist_node *node;
  	struct batadv_tt_orig_list_entry *orig_entry;
  	int hash_added;
 +	bool roamed_back = false;
  
 -	tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr);
 +	tt_local = batadv_tt_local_hash_find(bat_priv, addr);
 +	tt_global = batadv_tt_global_hash_find(bat_priv, addr);
  
 -	if (tt_local_entry) {
 -		tt_local_entry->last_seen = jiffies;
 -		/* possibly unset the BATADV_TT_CLIENT_PENDING flag */
 -		tt_local_entry->common.flags &= ~BATADV_TT_CLIENT_PENDING;
 -		goto out;
 +	if (tt_local) {
 +		tt_local->last_seen = jiffies;
 +		if (tt_local->common.flags & BATADV_TT_CLIENT_PENDING) {
 +			batadv_dbg(BATADV_DBG_TT, bat_priv,
 +				   "Re-adding pending client %pM\n", addr);
 +			/* whatever the reason why the PENDING flag was set,
 +			 * this is a client which was enqueued to be removed in
 +			 * this orig_interval. Since it popped up again, the
 +			 * flag can be reset like it was never enqueued
 +			 */
 +			tt_local->common.flags &= ~BATADV_TT_CLIENT_PENDING;
 +			goto add_event;
 +		}
 +
 +		if (tt_local->common.flags & BATADV_TT_CLIENT_ROAM) {
 +			batadv_dbg(BATADV_DBG_TT, bat_priv,
 +				   "Roaming client %pM came back to its original location\n",
 +				   addr);
 +			/* the ROAM flag is set because this client roamed away
 +			 * and the node got a roaming_advertisement message. Now
 +			 * that the client popped up again at its original
 +			 * location such flag can be unset
 +			 */
 +			tt_local->common.flags &= ~BATADV_TT_CLIENT_ROAM;
 +			roamed_back = true;
 +		}
 +		goto check_roaming;
  	}
  
 -	tt_local_entry = kmalloc(sizeof(*tt_local_entry), GFP_ATOMIC);
 -	if (!tt_local_entry)
 +	tt_local = kmalloc(sizeof(*tt_local), GFP_ATOMIC);
 +	if (!tt_local)
  		goto out;
  
  	batadv_dbg(BATADV_DBG_TT, bat_priv,
  		   "Creating new local tt entry: %pM (ttvn: %d)\n", addr,
  		   (uint8_t)atomic_read(&bat_priv->tt.vn));
  
 -	memcpy(tt_local_entry->common.addr, addr, ETH_ALEN);
 -	tt_local_entry->common.flags = BATADV_NO_FLAGS;
 +	memcpy(tt_local->common.addr, addr, ETH_ALEN);
 +	tt_local->common.flags = BATADV_NO_FLAGS;
  	if (batadv_is_wifi_iface(ifindex))
 -		tt_local_entry->common.flags |= BATADV_TT_CLIENT_WIFI;
 -	atomic_set(&tt_local_entry->common.refcount, 2);
 -	tt_local_entry->last_seen = jiffies;
 -	tt_local_entry->common.added_at = tt_local_entry->last_seen;
 +		tt_local->common.flags |= BATADV_TT_CLIENT_WIFI;
 +	atomic_set(&tt_local->common.refcount, 2);
 +	tt_local->last_seen = jiffies;
 +	tt_local->common.added_at = tt_local->last_seen;
  
  	/* the batman interface mac address should never be purged */
  	if (batadv_compare_eth(addr, soft_iface->dev_addr))
 -		tt_local_entry->common.flags |= BATADV_TT_CLIENT_NOPURGE;
 +		tt_local->common.flags |= BATADV_TT_CLIENT_NOPURGE;
  
  	/* The local entry has to be marked as NEW to avoid to send it in
  	 * a full table response going out before the next ttvn increment
  	 * (consistency check)
  	 */
 -	tt_local_entry->common.flags |= BATADV_TT_CLIENT_NEW;
 +	tt_local->common.flags |= BATADV_TT_CLIENT_NEW;
  
  	hash_added = batadv_hash_add(bat_priv->tt.local_hash, batadv_compare_tt,
 -				     batadv_choose_orig,
 -				     &tt_local_entry->common,
 -				     &tt_local_entry->common.hash_entry);
 +				     batadv_choose_orig, &tt_local->common,
 +				     &tt_local->common.hash_entry);
  
  	if (unlikely(hash_added != 0)) {
  		/* remove the reference for the hash */
 -		batadv_tt_local_entry_free_ref(tt_local_entry);
 +		batadv_tt_local_entry_free_ref(tt_local);
  		goto out;
  	}
  
 -	batadv_tt_local_event(bat_priv, addr, tt_local_entry->common.flags);
 +add_event:
 +	batadv_tt_local_event(bat_priv, addr, tt_local->common.flags);
  
 -	/* remove address from global hash if present */
 -	tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr);
 -
 -	/* Check whether it is a roaming! */
 -	if (tt_global_entry) {
 +check_roaming:
 +	/* Check whether it is a roaming, but don't do anything if the roaming
 +	 * process has already been handled
 +	 */
 +	if (tt_global && !(tt_global->common.flags & BATADV_TT_CLIENT_ROAM)) {
  		/* These node are probably going to update their tt table */
 -		head = &tt_global_entry->orig_list;
 +		head = &tt_global->orig_list;
  		rcu_read_lock();
  		hlist_for_each_entry_rcu(orig_entry, node, head, list) {
 -			orig_entry->orig_node->tt_poss_change = true;
 -
 -			batadv_send_roam_adv(bat_priv,
 -					     tt_global_entry->common.addr,
 +			batadv_send_roam_adv(bat_priv, tt_global->common.addr,
  					     orig_entry->orig_node);
  		}
  		rcu_read_unlock();
 -		/* The global entry has to be marked as ROAMING and
 -		 * has to be kept for consistency purpose
 -		 */
 -		tt_global_entry->common.flags |= BATADV_TT_CLIENT_ROAM;
 -		tt_global_entry->roam_at = jiffies;
 +		if (roamed_back) {
 +			batadv_tt_global_free(bat_priv, tt_global,
 +					      "Roaming canceled");
 +			tt_global = NULL;
 +		} else {
 +			/* The global entry has to be marked as ROAMING and
 +			 * has to be kept for consistency purpose
 +			 */
 +			tt_global->common.flags |= BATADV_TT_CLIENT_ROAM;
 +			tt_global->roam_at = jiffies;
 +		}
  	}
 +
  out:
 -	if (tt_local_entry)
 -		batadv_tt_local_entry_free_ref(tt_local_entry);
 -	if (tt_global_entry)
 -		batadv_tt_global_entry_free_ref(tt_global_entry);
 +	if (tt_local)
 +		batadv_tt_local_entry_free_ref(tt_local);
 +	if (tt_global)
 +		batadv_tt_global_entry_free_ref(tt_global);
  }
  
  static void batadv_tt_realloc_packet_buff(unsigned char **packet_buff,
@@@ -476,10 -434,22 +476,10 @@@ int batadv_tt_local_seq_print_text(stru
  	struct hlist_node *node;
  	struct hlist_head *head;
  	uint32_t i;
 -	int ret = 0;
  
 -	primary_if = batadv_primary_if_get_selected(bat_priv);
 -	if (!primary_if) {
 -		ret = seq_printf(seq,
 -				 "BATMAN mesh %s disabled - please specify interfaces to enable it\n",
 -				 net_dev->name);
 -		goto out;
 -	}
 -
 -	if (primary_if->if_status != BATADV_IF_ACTIVE) {
 -		ret = seq_printf(seq,
 -				 "BATMAN mesh %s disabled - primary interface not active\n",
 -				 net_dev->name);
 +	primary_if = batadv_seq_print_text_primary_if_get(seq);
 +	if (!primary_if)
  		goto out;
 -	}
  
  	seq_printf(seq,
  		   "Locally retrieved addresses (from %s) announced via TT (TTVN: %u):\n",
@@@ -509,7 -479,7 +509,7 @@@
  out:
  	if (primary_if)
  		batadv_hardif_free_ref(primary_if);
 -	return ret;
 +	return 0;
  }
  
  static void
@@@ -531,57 -501,24 +531,57 @@@ batadv_tt_local_set_pending(struct bata
  		   tt_local_entry->common.addr, message);
  }
  
 -void batadv_tt_local_remove(struct batadv_priv *bat_priv, const uint8_t *addr,
 -			    const char *message, bool roaming)
 +/**
 + * batadv_tt_local_remove - logically remove an entry from the local table
 + * @bat_priv: the bat priv with all the soft interface information
 + * @addr: the MAC address of the client to remove
 + * @message: message to append to the log on deletion
 + * @roaming: true if the deletion is due to a roaming event
 + *
 + * Returns the flags assigned to the local entry before being deleted
 + */
 +uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv,
 +				const uint8_t *addr, const char *message,
 +				bool roaming)
  {
 -	struct batadv_tt_local_entry *tt_local_entry = NULL;
 -	uint16_t flags;
 +	struct batadv_tt_local_entry *tt_local_entry;
 +	uint16_t flags, curr_flags = BATADV_NO_FLAGS;
  
  	tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr);
  	if (!tt_local_entry)
  		goto out;
  
 +	curr_flags = tt_local_entry->common.flags;
 +
  	flags = BATADV_TT_CLIENT_DEL;
 -	if (roaming)
 +	/* if this global entry addition is due to a roaming, the node has to
 +	 * mark the local entry as "roamed" in order to correctly reroute
 +	 * packets later
 +	 */
 +	if (roaming) {
  		flags |= BATADV_TT_CLIENT_ROAM;
 +		/* mark the local client as ROAMed */
 +		tt_local_entry->common.flags |= BATADV_TT_CLIENT_ROAM;
 +	}
 +
 +	if (!(tt_local_entry->common.flags & BATADV_TT_CLIENT_NEW)) {
 +		batadv_tt_local_set_pending(bat_priv, tt_local_entry, flags,
 +					    message);
 +		goto out;
 +	}
 +	/* if this client has been added right now, it is possible to
 +	 * immediately purge it
 +	 */
 +	batadv_tt_local_event(bat_priv, tt_local_entry->common.addr,
 +			      curr_flags | BATADV_TT_CLIENT_DEL);
 +	hlist_del_rcu(&tt_local_entry->common.hash_entry);
 +	batadv_tt_local_entry_free_ref(tt_local_entry);
  
  out:
  	if (tt_local_entry)
  		batadv_tt_local_entry_free_ref(tt_local_entry);
 +
 +	return curr_flags;
  }
  
  static void batadv_tt_local_purge_list(struct batadv_priv *bat_priv,
@@@ -784,23 -721,12 +784,23 @@@ int batadv_tt_global_add(struct batadv_
  			 const unsigned char *tt_addr, uint8_t flags,
  			 uint8_t ttvn)
  {
 -	struct batadv_tt_global_entry *tt_global_entry = NULL;
 +	struct batadv_tt_global_entry *tt_global_entry;
 +	struct batadv_tt_local_entry *tt_local_entry;
  	int ret = 0;
  	int hash_added;
  	struct batadv_tt_common_entry *common;
 +	uint16_t local_flags;
  
  	tt_global_entry = batadv_tt_global_hash_find(bat_priv, tt_addr);
 +	tt_local_entry = batadv_tt_local_hash_find(bat_priv, tt_addr);
 +
 +	/* if the node already has a local client for this entry, it has to wait
 +	 * for a roaming advertisement instead of manually messing up the global
 +	 * table
 +	 */
 +	if ((flags & BATADV_TT_CLIENT_TEMP) && tt_local_entry &&
 +	    !(tt_local_entry->common.flags & BATADV_TT_CLIENT_NEW))
 +		goto out;
  
  	if (!tt_global_entry) {
  		tt_global_entry = kzalloc(sizeof(*tt_global_entry), GFP_ATOMIC);
@@@ -812,12 -738,6 +812,12 @@@
  
  		common->flags = flags;
  		tt_global_entry->roam_at = 0;
 +		/* node must store current time in case of roaming. This is
 +		 * needed to purge this entry out on timeout (if nobody claims
 +		 * it)
 +		 */
 +		if (flags & BATADV_TT_CLIENT_ROAM)
 +			tt_global_entry->roam_at = jiffies;
  		atomic_set(&common->refcount, 2);
  		common->added_at = jiffies;
  
@@@ -835,32 -755,26 +835,38 @@@
  			goto out_remove;
  		}
  	} else {
 +		common = &tt_global_entry->common;
  		/* If there is already a global entry, we can use this one for
  		 * our processing.
 -		 * But if we are trying to add a temporary client we can exit
 -		 * directly because the temporary information should never
 -		 * override any already known client state (whatever it is)
 +		 * But if we are trying to add a temporary client then here are
 +		 * two options at this point:
 +		 * 1) the global client is not a temporary client: the global
 +		 *    client has to be left as it is, temporary information
 +		 *    should never override any already known client state
 +		 * 2) the global client is a temporary client: purge the
 +		 *    originator list and add the new one orig_entry
  		 */
 -		if (flags & BATADV_TT_CLIENT_TEMP)
 -			goto out;
 +		if (flags & BATADV_TT_CLIENT_TEMP) {
 +			if (!(common->flags & BATADV_TT_CLIENT_TEMP))
 +				goto out;
 +			if (batadv_tt_global_entry_has_orig(tt_global_entry,
 +							    orig_node))
 +				goto out_remove;
 +			batadv_tt_global_del_orig_list(tt_global_entry);
 +			goto add_orig_entry;
 +		}
  
  		/* if the client was temporary added before receiving the first
  		 * OGM announcing it, we have to clear the TEMP flag
  		 */
 -		tt_global_entry->common.flags &= ~BATADV_TT_CLIENT_TEMP;
 +		common->flags &= ~BATADV_TT_CLIENT_TEMP;
  
+ 		/* the change can carry possible "attribute" flags like the
+ 		 * TT_CLIENT_WIFI, therefore they have to be copied in the
+ 		 * client entry
+ 		 */
+ 		tt_global_entry->common.flags |= flags;
+ 
  		/* If there is the BATADV_TT_CLIENT_ROAM flag set, there is only
  		 * one originator left in the list and we previously received a
  		 * delete + roaming change for this originator.
@@@ -868,40 -782,28 +874,40 @@@
  		 * We should first delete the old originator before adding the
  		 * new one.
  		 */
 -		if (tt_global_entry->common.flags & BATADV_TT_CLIENT_ROAM) {
 +		if (common->flags & BATADV_TT_CLIENT_ROAM) {
  			batadv_tt_global_del_orig_list(tt_global_entry);
 -			tt_global_entry->common.flags &= ~BATADV_TT_CLIENT_ROAM;
 +			common->flags &= ~BATADV_TT_CLIENT_ROAM;
  			tt_global_entry->roam_at = 0;
  		}
  	}
 +add_orig_entry:
  	/* add the new orig_entry (if needed) or update it */
  	batadv_tt_global_orig_entry_add(tt_global_entry, orig_node, ttvn);
  
  	batadv_dbg(BATADV_DBG_TT, bat_priv,
  		   "Creating new global tt entry: %pM (via %pM)\n",
 -		   tt_global_entry->common.addr, orig_node->orig);
 +		   common->addr, orig_node->orig);
 +	ret = 1;
  
  out_remove:
 +
  	/* remove address from local hash if present */
 -	batadv_tt_local_remove(bat_priv, tt_global_entry->common.addr,
 -			       "global tt received",
 -			       flags & BATADV_TT_CLIENT_ROAM);
 -	ret = 1;
 +	local_flags = batadv_tt_local_remove(bat_priv, tt_addr,
 +					     "global tt received",
 +					     !!(flags & BATADV_TT_CLIENT_ROAM));
 +	tt_global_entry->common.flags |= local_flags & BATADV_TT_CLIENT_WIFI;
 +
 +	if (!(flags & BATADV_TT_CLIENT_ROAM))
 +		/* this is a normal global add. Therefore the client is not in a
 +		 * roaming state anymore.
 +		 */
 +		tt_global_entry->common.flags &= ~BATADV_TT_CLIENT_ROAM;
 +
  out:
  	if (tt_global_entry)
  		batadv_tt_global_entry_free_ref(tt_global_entry);
 +	if (tt_local_entry)
 +		batadv_tt_local_entry_free_ref(tt_local_entry);
  	return ret;
  }
  
@@@ -946,10 -848,22 +952,10 @@@ int batadv_tt_global_seq_print_text(str
  	struct hlist_node *node;
  	struct hlist_head *head;
  	uint32_t i;
 -	int ret = 0;
  
 -	primary_if = batadv_primary_if_get_selected(bat_priv);
 -	if (!primary_if) {
 -		ret = seq_printf(seq,
 -				 "BATMAN mesh %s disabled - please specify interfaces to enable it\n",
 -				 net_dev->name);
 +	primary_if = batadv_seq_print_text_primary_if_get(seq);
 +	if (!primary_if)
  		goto out;
 -	}
 -
 -	if (primary_if->if_status != BATADV_IF_ACTIVE) {
 -		ret = seq_printf(seq,
 -				 "BATMAN mesh %s disabled - primary interface not active\n",
 -				 net_dev->name);
 -		goto out;
 -	}
  
  	seq_printf(seq,
  		   "Globally announced TT entries received via the mesh %s\n",
@@@ -973,7 -887,7 +979,7 @@@
  out:
  	if (primary_if)
  		batadv_hardif_free_ref(primary_if);
 -	return ret;
 +	return 0;
  }
  
  /* deletes the orig list of a tt_global_entry */
@@@ -1019,6 -933,21 +1025,6 @@@ batadv_tt_global_del_orig_entry(struct 
  	spin_unlock_bh(&tt_global_entry->list_lock);
  }
  
 -static void
 -batadv_tt_global_del_struct(struct batadv_priv *bat_priv,
 -			    struct batadv_tt_global_entry *tt_global_entry,
 -			    const char *message)
 -{
 -	batadv_dbg(BATADV_DBG_TT, bat_priv,
 -		   "Deleting global tt entry %pM: %s\n",
 -		   tt_global_entry->common.addr, message);
 -
 -	batadv_hash_remove(bat_priv->tt.global_hash, batadv_compare_tt,
 -			   batadv_choose_orig, tt_global_entry->common.addr);
 -	batadv_tt_global_entry_free_ref(tt_global_entry);
 -
 -}
 -
  /* If the client is to be deleted, we check if it is the last origantor entry
   * within tt_global entry. If yes, we set the BATADV_TT_CLIENT_ROAM flag and the
   * timer, otherwise we simply remove the originator scheduled for deletion.
@@@ -1067,7 -996,7 +1073,7 @@@ static void batadv_tt_global_del(struc
  				 const unsigned char *addr,
  				 const char *message, bool roaming)
  {
 -	struct batadv_tt_global_entry *tt_global_entry = NULL;
 +	struct batadv_tt_global_entry *tt_global_entry;
  	struct batadv_tt_local_entry *local_entry = NULL;
  
  	tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr);
@@@ -1079,8 -1008,8 +1085,8 @@@
  						orig_node, message);
  
  		if (hlist_empty(&tt_global_entry->orig_list))
 -			batadv_tt_global_del_struct(bat_priv, tt_global_entry,
 -						    message);
 +			batadv_tt_global_free(bat_priv, tt_global_entry,
 +					      message);
  
  		goto out;
  	}
@@@ -1103,7 -1032,7 +1109,7 @@@
  	if (local_entry) {
  		/* local entry exists, case 2: client roamed to us. */
  		batadv_tt_global_del_orig_list(tt_global_entry);
 -		batadv_tt_global_del_struct(bat_priv, tt_global_entry, message);
 +		batadv_tt_global_free(bat_priv, tt_global_entry, message);
  	} else
  		/* no local entry exists, case 1: check for roaming */
  		batadv_tt_global_del_roaming(bat_priv, tt_global_entry,
@@@ -1282,8 -1211,7 +1288,8 @@@ struct batadv_orig_node *batadv_transta
  
  	if (src && atomic_read(&bat_priv->ap_isolation)) {
  		tt_local_entry = batadv_tt_local_hash_find(bat_priv, src);
 -		if (!tt_local_entry)
 +		if (!tt_local_entry ||
 +		    (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING))
  			goto out;
  	}
  
@@@ -1549,11 -1477,11 +1555,11 @@@ batadv_tt_response_fill_table(uint16_t 
  	tt_tot = tt_len / sizeof(struct batadv_tt_change);
  
  	len = tt_query_size + tt_len;
 -	skb = dev_alloc_skb(len + ETH_HLEN);
 +	skb = dev_alloc_skb(len + ETH_HLEN + NET_IP_ALIGN);
  	if (!skb)
  		goto out;
  
 -	skb_reserve(skb, ETH_HLEN);
 +	skb_reserve(skb, ETH_HLEN + NET_IP_ALIGN);
  	tt_response = (struct batadv_tt_query_packet *)skb_put(skb, len);
  	tt_response->ttvn = ttvn;
  
@@@ -1574,7 -1502,7 +1580,7 @@@
  
  			memcpy(tt_change->addr, tt_common_entry->addr,
  			       ETH_ALEN);
- 			tt_change->flags = BATADV_NO_FLAGS;
+ 			tt_change->flags = tt_common_entry->flags;
  
  			tt_count++;
  			tt_change++;
@@@ -1615,11 -1543,11 +1621,11 @@@ static int batadv_send_tt_request(struc
  	if (!tt_req_node)
  		goto out;
  
 -	skb = dev_alloc_skb(sizeof(*tt_request) + ETH_HLEN);
 +	skb = dev_alloc_skb(sizeof(*tt_request) + ETH_HLEN + NET_IP_ALIGN);
  	if (!skb)
  		goto out;
  
 -	skb_reserve(skb, ETH_HLEN);
 +	skb_reserve(skb, ETH_HLEN + NET_IP_ALIGN);
  
  	tt_req_len = sizeof(*tt_request);
  	tt_request = (struct batadv_tt_query_packet *)skb_put(skb, tt_req_len);
@@@ -1670,7 -1598,7 +1676,7 @@@ static boo
  batadv_send_other_tt_response(struct batadv_priv *bat_priv,
  			      struct batadv_tt_query_packet *tt_request)
  {
 -	struct batadv_orig_node *req_dst_orig_node = NULL;
 +	struct batadv_orig_node *req_dst_orig_node;
  	struct batadv_orig_node *res_dst_orig_node = NULL;
  	struct batadv_neigh_node *neigh_node = NULL;
  	struct batadv_hard_iface *primary_if = NULL;
@@@ -1730,11 -1658,11 +1736,11 @@@
  		tt_tot = tt_len / sizeof(struct batadv_tt_change);
  
  		len = sizeof(*tt_response) + tt_len;
 -		skb = dev_alloc_skb(len + ETH_HLEN);
 +		skb = dev_alloc_skb(len + ETH_HLEN + NET_IP_ALIGN);
  		if (!skb)
  			goto unlock;
  
 -		skb_reserve(skb, ETH_HLEN);
 +		skb_reserve(skb, ETH_HLEN + NET_IP_ALIGN);
  		packet_pos = skb_put(skb, len);
  		tt_response = (struct batadv_tt_query_packet *)packet_pos;
  		tt_response->ttvn = req_ttvn;
@@@ -1805,7 -1733,7 +1811,7 @@@ static boo
  batadv_send_my_tt_response(struct batadv_priv *bat_priv,
  			   struct batadv_tt_query_packet *tt_request)
  {
 -	struct batadv_orig_node *orig_node = NULL;
 +	struct batadv_orig_node *orig_node;
  	struct batadv_neigh_node *neigh_node = NULL;
  	struct batadv_hard_iface *primary_if = NULL;
  	uint8_t my_ttvn, req_ttvn, ttvn;
@@@ -1857,11 -1785,11 +1863,11 @@@
  		tt_tot = tt_len / sizeof(struct batadv_tt_change);
  
  		len = sizeof(*tt_response) + tt_len;
 -		skb = dev_alloc_skb(len + ETH_HLEN);
 +		skb = dev_alloc_skb(len + ETH_HLEN + NET_IP_ALIGN);
  		if (!skb)
  			goto unlock;
  
 -		skb_reserve(skb, ETH_HLEN);
 +		skb_reserve(skb, ETH_HLEN + NET_IP_ALIGN);
  		packet_pos = skb_put(skb, len);
  		tt_response = (struct batadv_tt_query_packet *)packet_pos;
  		tt_response->ttvn = req_ttvn;
@@@ -1971,7 -1899,7 +1977,7 @@@ static void _batadv_tt_update_changes(s
  static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv,
  				  struct batadv_tt_query_packet *tt_response)
  {
 -	struct batadv_orig_node *orig_node = NULL;
 +	struct batadv_orig_node *orig_node;
  
  	orig_node = batadv_orig_hash_find(bat_priv, tt_response->src);
  	if (!orig_node)
@@@ -2013,7 -1941,7 +2019,7 @@@ static void batadv_tt_update_changes(st
  
  bool batadv_is_my_client(struct batadv_priv *bat_priv, const uint8_t *addr)
  {
 -	struct batadv_tt_local_entry *tt_local_entry = NULL;
 +	struct batadv_tt_local_entry *tt_local_entry;
  	bool ret = false;
  
  	tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr);
@@@ -2022,8 -1950,7 +2028,8 @@@
  	/* Check if the client has been logically deleted (but is kept for
  	 * consistency purpose)
  	 */
 -	if (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING)
 +	if ((tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING) ||
 +	    (tt_local_entry->common.flags & BATADV_TT_CLIENT_ROAM))
  		goto out;
  	ret = true;
  out:
@@@ -2074,6 -2001,10 +2080,6 @@@ void batadv_handle_tt_response(struct b
  
  	/* Recalculate the CRC for this orig_node and store it */
  	orig_node->tt_crc = batadv_tt_global_crc(bat_priv, orig_node);
 -	/* Roaming phase is over: tables are in sync again. I can
 -	 * unset the flag
 -	 */
 -	orig_node->tt_poss_change = false;
  out:
  	if (orig_node)
  		batadv_orig_node_free_ref(orig_node);
@@@ -2192,11 -2123,11 +2198,11 @@@ static void batadv_send_roam_adv(struc
  	if (!batadv_tt_check_roam_count(bat_priv, client))
  		goto out;
  
 -	skb = dev_alloc_skb(sizeof(*roam_adv_packet) + ETH_HLEN);
 +	skb = dev_alloc_skb(sizeof(*roam_adv_packet) + ETH_HLEN + NET_IP_ALIGN);
  	if (!skb)
  		goto out;
  
 -	skb_reserve(skb, ETH_HLEN);
 +	skb_reserve(skb, ETH_HLEN + NET_IP_ALIGN);
  
  	roam_adv_packet = (struct batadv_roam_adv_packet *)skb_put(skb, len);
  
@@@ -2364,6 -2295,7 +2370,6 @@@ static int batadv_tt_commit_changes(str
  	batadv_dbg(BATADV_DBG_TT, bat_priv,
  		   "Local changes committed, updating to ttvn %u\n",
  		   (uint8_t)atomic_read(&bat_priv->tt.vn));
 -	bat_priv->tt.poss_change = false;
  
  	/* reset the sending counter */
  	atomic_set(&bat_priv->tt.ogm_append_cnt, BATADV_TT_OGM_APPEND_MAX);
@@@ -2475,6 -2407,11 +2481,6 @@@ void batadv_tt_update_orig(struct batad
  		 */
  		if (orig_node->tt_crc != tt_crc)
  			goto request_table;
 -
 -		/* Roaming phase is over: tables are in sync again. I can
 -		 * unset the flag
 -		 */
 -		orig_node->tt_poss_change = false;
  	} else {
  		/* if we missed more than one change or our tables are not
  		 * in sync anymore -> request fresh tt data
@@@ -2507,44 -2444,25 +2513,51 @@@ bool batadv_tt_global_client_is_roaming
  	if (!tt_global_entry)
  		goto out;
  
 -	ret = tt_global_entry->common.flags & BATADV_TT_CLIENT_ROAM;
 +	ret = !!(tt_global_entry->common.flags & BATADV_TT_CLIENT_ROAM);
  	batadv_tt_global_entry_free_ref(tt_global_entry);
  out:
  	return ret;
  }
  
 +/**
 + * batadv_tt_local_client_is_roaming - tells whether the client is roaming
 + * @bat_priv: the bat priv with all the soft interface information
 + * @addr: the MAC address of the local client to query
 + *
 + * Returns true if the local client is known to be roaming (it is not served by
 + * this node anymore) or not. If yes, the client is still present in the table
 + * to keep the latter consistent with the node TTVN
 + */
 +bool batadv_tt_local_client_is_roaming(struct batadv_priv *bat_priv,
 +				       uint8_t *addr)
 +{
 +	struct batadv_tt_local_entry *tt_local_entry;
 +	bool ret = false;
 +
 +	tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr);
 +	if (!tt_local_entry)
 +		goto out;
 +
 +	ret = tt_local_entry->common.flags & BATADV_TT_CLIENT_ROAM;
 +	batadv_tt_local_entry_free_ref(tt_local_entry);
 +out:
 +	return ret;
 +
 +}
 +
  bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv,
  					  struct batadv_orig_node *orig_node,
  					  const unsigned char *addr)
  {
  	bool ret = false;
  
+ 	/* if the originator is a backbone node (meaning it belongs to the same
+ 	 * LAN of this node) the temporary client must not be added because to
+ 	 * reach such destination the node must use the LAN instead of the mesh
+ 	 */
+ 	if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig))
+ 		goto out;
+ 
  	if (!batadv_tt_global_add(bat_priv, orig_node, addr,
  				  BATADV_TT_CLIENT_TEMP,
  				  atomic_read(&orig_node->last_ttvn)))
diff --combined net/bluetooth/hci_core.c
index 5a3f941,a0a2f97..f01e5e1
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@@ -405,7 -405,7 +405,7 @@@ struct inquiry_entry *hci_inquiry_cache
  	struct discovery_state *cache = &hdev->discovery;
  	struct inquiry_entry *e;
  
 -	BT_DBG("cache %p, %s", cache, batostr(bdaddr));
 +	BT_DBG("cache %p, %pMR", cache, bdaddr);
  
  	list_for_each_entry(e, &cache->all, all) {
  		if (!bacmp(&e->data.bdaddr, bdaddr))
@@@ -421,7 -421,7 +421,7 @@@ struct inquiry_entry *hci_inquiry_cache
  	struct discovery_state *cache = &hdev->discovery;
  	struct inquiry_entry *e;
  
 -	BT_DBG("cache %p, %s", cache, batostr(bdaddr));
 +	BT_DBG("cache %p, %pMR", cache, bdaddr);
  
  	list_for_each_entry(e, &cache->unknown, list) {
  		if (!bacmp(&e->data.bdaddr, bdaddr))
@@@ -438,7 -438,7 +438,7 @@@ struct inquiry_entry *hci_inquiry_cache
  	struct discovery_state *cache = &hdev->discovery;
  	struct inquiry_entry *e;
  
 -	BT_DBG("cache %p bdaddr %s state %d", cache, batostr(bdaddr), state);
 +	BT_DBG("cache %p bdaddr %pMR state %d", cache, bdaddr, state);
  
  	list_for_each_entry(e, &cache->resolve, list) {
  		if (!bacmp(bdaddr, BDADDR_ANY) && e->name_state == state)
@@@ -475,7 -475,7 +475,7 @@@ bool hci_inquiry_cache_update(struct hc
  	struct discovery_state *cache = &hdev->discovery;
  	struct inquiry_entry *ie;
  
 -	BT_DBG("cache %p, %s", cache, batostr(&data->bdaddr));
 +	BT_DBG("cache %p, %pMR", cache, &data->bdaddr);
  
  	if (ssp)
  		*ssp = data->ssp_mode;
@@@ -1259,7 -1259,7 +1259,7 @@@ int hci_add_link_key(struct hci_dev *hd
  		list_add(&key->list, &hdev->link_keys);
  	}
  
 -	BT_DBG("%s key for %s type %u", hdev->name, batostr(bdaddr), type);
 +	BT_DBG("%s key for %pMR type %u", hdev->name, bdaddr, type);
  
  	/* Some buggy controller combinations generate a changed
  	 * combination key for legacy pairing even when there's no
@@@ -1338,7 -1338,7 +1338,7 @@@ int hci_remove_link_key(struct hci_dev 
  	if (!key)
  		return -ENOENT;
  
 -	BT_DBG("%s removing %s", hdev->name, batostr(bdaddr));
 +	BT_DBG("%s removing %pMR", hdev->name, bdaddr);
  
  	list_del(&key->list);
  	kfree(key);
@@@ -1354,7 -1354,7 +1354,7 @@@ int hci_remove_ltk(struct hci_dev *hdev
  		if (bacmp(bdaddr, &k->bdaddr))
  			continue;
  
 -		BT_DBG("%s removing %s", hdev->name, batostr(bdaddr));
 +		BT_DBG("%s removing %pMR", hdev->name, bdaddr);
  
  		list_del(&k->list);
  		kfree(k);
@@@ -1401,7 -1401,7 +1401,7 @@@ int hci_remove_remote_oob_data(struct h
  	if (!data)
  		return -ENOENT;
  
 -	BT_DBG("%s removing %s", hdev->name, batostr(bdaddr));
 +	BT_DBG("%s removing %pMR", hdev->name, bdaddr);
  
  	list_del(&data->list);
  	kfree(data);
@@@ -1440,7 -1440,7 +1440,7 @@@ int hci_add_remote_oob_data(struct hci_
  	memcpy(data->hash, hash, sizeof(data->hash));
  	memcpy(data->randomizer, randomizer, sizeof(data->randomizer));
  
 -	BT_DBG("%s for %s", hdev->name, batostr(bdaddr));
 +	BT_DBG("%s for %pMR", hdev->name, bdaddr);
  
  	return 0;
  }
@@@ -1754,11 -1754,11 +1754,11 @@@ int hci_register_dev(struct hci_dev *hd
  	if (hdev->dev_type != HCI_AMP)
  		set_bit(HCI_AUTO_OFF, &hdev->dev_flags);
  
  	hci_notify(hdev, HCI_DEV_REG);
  	hci_dev_hold(hdev);
  
+ 	schedule_work(&hdev->power_on);
+ 
  	return id;
  
  err_wqueue:
@@@ -2153,10 -2153,9 +2153,10 @@@ static void hci_add_acl_hdr(struct sk_b
  	hdr->dlen   = cpu_to_le16(len);
  }
  
 -static void hci_queue_acl(struct hci_conn *conn, struct sk_buff_head *queue,
 +static void hci_queue_acl(struct hci_chan *chan, struct sk_buff_head *queue,
  			  struct sk_buff *skb, __u16 flags)
  {
 +	struct hci_conn *conn = chan->conn;
  	struct hci_dev *hdev = conn->hdev;
  	struct sk_buff *list;
  
@@@ -2164,18 -2163,7 +2164,18 @@@
  	skb->data_len = 0;
  
  	bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
 -	hci_add_acl_hdr(skb, conn->handle, flags);
 +
 +	switch (hdev->dev_type) {
 +	case HCI_BREDR:
 +		hci_add_acl_hdr(skb, conn->handle, flags);
 +		break;
 +	case HCI_AMP:
 +		hci_add_acl_hdr(skb, chan->handle, flags);
 +		break;
 +	default:
 +		BT_ERR("%s unknown dev_type %d", hdev->name, hdev->dev_type);
 +		return;
 +	}
  
  	list = skb_shinfo(skb)->frag_list;
  	if (!list) {
@@@ -2214,13 -2202,14 +2214,13 @@@
  
  void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags)
  {
 -	struct hci_conn *conn = chan->conn;
 -	struct hci_dev *hdev = conn->hdev;
 +	struct hci_dev *hdev = chan->conn->hdev;
  
  	BT_DBG("%s chan %p flags 0x%4.4x", hdev->name, chan, flags);
  
  	skb->dev = (void *) hdev;
  
 -	hci_queue_acl(conn, &chan->data_q, skb, flags);
 +	hci_queue_acl(chan, &chan->data_q, skb, flags);
  
  	queue_work(hdev->workqueue, &hdev->tx_work);
  }
@@@ -2322,8 -2311,8 +2322,8 @@@ static void hci_link_tx_to(struct hci_d
  	/* Kill stalled connections */
  	list_for_each_entry_rcu(c, &h->list, list) {
  		if (c->type == type && c->sent) {
 -			BT_ERR("%s killing stalled connection %s",
 -			       hdev->name, batostr(&c->dst));
 +			BT_ERR("%s killing stalled connection %pMR",
 +			       hdev->name, &c->dst);
  			hci_acl_disconn(c, HCI_ERROR_REMOTE_USER_TERM);
  		}
  	}
@@@ -2392,9 -2381,6 +2392,9 @@@ static struct hci_chan *hci_chan_sent(s
  	case ACL_LINK:
  		cnt = hdev->acl_cnt;
  		break;
 +	case AMP_LINK:
 +		cnt = hdev->block_cnt;
 +		break;
  	case SCO_LINK:
  	case ESCO_LINK:
  		cnt = hdev->sco_cnt;
@@@ -2524,19 -2510,11 +2524,19 @@@ static void hci_sched_acl_blk(struct hc
  	struct hci_chan *chan;
  	struct sk_buff *skb;
  	int quote;
 +	u8 type;
  
  	__check_timeout(hdev, cnt);
  
 +	BT_DBG("%s", hdev->name);
 +
 +	if (hdev->dev_type == HCI_AMP)
 +		type = AMP_LINK;
 +	else
 +		type = ACL_LINK;
 +
  	while (hdev->block_cnt > 0 &&
 -	       (chan = hci_chan_sent(hdev, ACL_LINK, &quote))) {
 +	       (chan = hci_chan_sent(hdev, type, &quote))) {
  		u32 priority = (skb_peek(&chan->data_q))->priority;
  		while (quote > 0 && (skb = skb_peek(&chan->data_q))) {
  			int blocks;
@@@ -2569,19 -2547,14 +2569,19 @@@
  	}
  
  	if (cnt != hdev->block_cnt)
 -		hci_prio_recalculate(hdev, ACL_LINK);
 +		hci_prio_recalculate(hdev, type);
  }
  
  static void hci_sched_acl(struct hci_dev *hdev)
  {
  	BT_DBG("%s", hdev->name);
  
 -	if (!hci_conn_num(hdev, ACL_LINK))
 +	/* No ACL link over BR/EDR controller */
 +	if (!hci_conn_num(hdev, ACL_LINK) && hdev->dev_type == HCI_BREDR)
 +		return;
 +
 +	/* No AMP link over AMP controller */
 +	if (!hci_conn_num(hdev, AMP_LINK) && hdev->dev_type == HCI_AMP)
  		return;
  
  	switch (hdev->flow_ctl_mode) {
diff --combined net/bluetooth/mgmt.c
index 399e502,91de423..158a87b
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@@ -326,7 -326,7 +326,7 @@@ static int read_index_list(struct sock 
  	struct hci_dev *d;
  	size_t rp_len;
  	u16 count;
- 	int i, err;
+ 	int err;
  
  	BT_DBG("sock %p", sk);
  
@@@ -347,9 -347,7 +347,7 @@@
  		return -ENOMEM;
  	}
  
- 	rp->num_controllers = cpu_to_le16(count);
- 
- 	i = 0;
+ 	count = 0;
  	list_for_each_entry(d, &hci_dev_list, list) {
  		if (test_bit(HCI_SETUP, &d->dev_flags))
  			continue;
@@@ -357,10 -355,13 +355,13 @@@
  		if (!mgmt_valid_hdev(d))
  			continue;
  
- 		rp->index[i++] = cpu_to_le16(d->id);
+ 		rp->index[count++] = cpu_to_le16(d->id);
  		BT_DBG("Added hci%u", d->id);
  	}
  
+ 	rp->num_controllers = cpu_to_le16(count);
+ 	rp_len = sizeof(*rp) + (2 * count);
+ 
  	read_unlock(&hci_dev_list_lock);
  
  	err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
@@@ -1366,6 -1367,7 +1367,7 @@@ static int remove_uuid(struct sock *sk
  			continue;
  
  		list_del(&match->list);
+ 		kfree(match);
  		found++;
  	}
  
@@@ -3125,9 -3127,6 +3127,9 @@@ int mgmt_disconnect_failed(struct hci_d
  	struct pending_cmd *cmd;
  	int err;
  
 +	mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
 +			     hdev);
 +
  	cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
  	if (!cmd)
  		return -ENOENT;
@@@ -3140,6 -3139,8 +3142,6 @@@
  
  	mgmt_pending_remove(cmd);
  
 -	mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
 -			     hdev);
  	return err;
  }
  
diff --combined net/bluetooth/smp.c
index 9176bc1,a592337..68a9587
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@@ -167,7 -167,7 +167,7 @@@ static struct sk_buff *smp_build_cmd(st
  
  	lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
  	lh->len = cpu_to_le16(sizeof(code) + dlen);
 -	lh->cid = cpu_to_le16(L2CAP_CID_SMP);
 +	lh->cid = __constant_cpu_to_le16(L2CAP_CID_SMP);
  
  	memcpy(skb_put(skb, sizeof(code)), &code, sizeof(code));
  
@@@ -267,7 -267,7 +267,7 @@@ static void smp_failure(struct l2cap_co
  
  	clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->hcon->flags);
  	mgmt_auth_failed(conn->hcon->hdev, conn->dst, hcon->type,
- 			 hcon->dst_type, reason);
+ 			 hcon->dst_type, HCI_ERROR_AUTH_FAILURE);
  
  	cancel_delayed_work_sync(&conn->security_timer);
  
diff --combined net/core/dev.c
index 2705a2a,c0946cb..974199d
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@@ -176,10 -176,8 +176,10 @@@
  #define PTYPE_HASH_MASK	(PTYPE_HASH_SIZE - 1)
  
  static DEFINE_SPINLOCK(ptype_lock);
 +static DEFINE_SPINLOCK(offload_lock);
  static struct list_head ptype_base[PTYPE_HASH_SIZE] __read_mostly;
  static struct list_head ptype_all __read_mostly;	/* Taps */
 +static struct list_head offload_base __read_mostly;
  
  /*
   * The @dev_base_head list is protected by @dev_base_lock and the rtnl
@@@ -472,82 -470,6 +472,82 @@@ void dev_remove_pack(struct packet_typ
  }
  EXPORT_SYMBOL(dev_remove_pack);
  
 +
 +/**
 + *	dev_add_offload - register offload handlers
 + *	@po: protocol offload declaration
 + *
 + *	Add protocol offload handlers to the networking stack. The passed
 + *	&proto_offload is linked into kernel lists and may not be freed until
 + *	it has been removed from the kernel lists.
 + *
 + *	This call does not sleep therefore it can not
 + *	guarantee all CPU's that are in middle of receiving packets
 + *	will see the new offload handlers (until the next received packet).
 + */
 +void dev_add_offload(struct packet_offload *po)
 +{
 +	struct list_head *head = &offload_base;
 +
 +	spin_lock(&offload_lock);
 +	list_add_rcu(&po->list, head);
 +	spin_unlock(&offload_lock);
 +}
 +EXPORT_SYMBOL(dev_add_offload);
 +
 +/**
 + *	__dev_remove_offload	 - remove offload handler
 + *	@po: packet offload declaration
 + *
 + *	Remove a protocol offload handler that was previously added to the
 + *	kernel offload handlers by dev_add_offload(). The passed &offload_type
 + *	is removed from the kernel lists and can be freed or reused once this
 + *	function returns.
 + *
 + *      The packet type might still be in use by receivers
 + *	and must not be freed until after all the CPU's have gone
 + *	through a quiescent state.
 + */
 +void __dev_remove_offload(struct packet_offload *po)
 +{
 +	struct list_head *head = &offload_base;
 +	struct packet_offload *po1;
 +
 +	spin_lock(&offload_lock);
 +
 +	list_for_each_entry(po1, head, list) {
 +		if (po == po1) {
 +			list_del_rcu(&po->list);
 +			goto out;
 +		}
 +	}
 +
 +	pr_warn("dev_remove_offload: %p not found\n", po);
 +out:
 +	spin_unlock(&offload_lock);
 +}
 +EXPORT_SYMBOL(__dev_remove_offload);
 +
 +/**
 + *	dev_remove_offload	 - remove packet offload handler
 + *	@po: packet offload declaration
 + *
 + *	Remove a packet offload handler that was previously added to the kernel
 + *	offload handlers by dev_add_offload(). The passed &offload_type is
 + *	removed from the kernel lists and can be freed or reused once this
 + *	function returns.
 + *
 + *	This call sleeps to guarantee that no CPU is looking at the packet
 + *	type after return.
 + */
 +void dev_remove_offload(struct packet_offload *po)
 +{
 +	__dev_remove_offload(po);
 +
 +	synchronize_net();
 +}
 +EXPORT_SYMBOL(dev_remove_offload);
 +
  /******************************************************************************
  
  		      Device Boot-time Settings Routines
@@@ -2072,7 -1994,7 +2072,7 @@@ struct sk_buff *skb_gso_segment(struct 
  	netdev_features_t features)
  {
  	struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT);
 -	struct packet_type *ptype;
 +	struct packet_offload *ptype;
  	__be16 type = skb->protocol;
  	int vlan_depth = ETH_HLEN;
  	int err;
@@@ -2101,17 -2023,18 +2101,17 @@@
  	}
  
  	rcu_read_lock();
 -	list_for_each_entry_rcu(ptype,
 -			&ptype_base[ntohs(type) & PTYPE_HASH_MASK], list) {
 -		if (ptype->type == type && !ptype->dev && ptype->gso_segment) {
 +	list_for_each_entry_rcu(ptype, &offload_base, list) {
 +		if (ptype->type == type && ptype->callbacks.gso_segment) {
  			if (unlikely(skb->ip_summed != CHECKSUM_PARTIAL)) {
 -				err = ptype->gso_send_check(skb);
 +				err = ptype->callbacks.gso_send_check(skb);
  				segs = ERR_PTR(err);
  				if (err || skb_gso_ok(skb, features))
  					break;
  				__skb_push(skb, (skb->data -
  						 skb_network_header(skb)));
  			}
 -			segs = ptype->gso_segment(skb, features);
 +			segs = ptype->callbacks.gso_segment(skb, features);
  			break;
  		}
  	}
@@@ -2895,8 -2818,10 +2895,10 @@@ static int get_rps_cpu(struct net_devic
  		if (unlikely(tcpu != next_cpu) &&
  		    (tcpu == RPS_NO_CPU || !cpu_online(tcpu) ||
  		     ((int)(per_cpu(softnet_data, tcpu).input_queue_head -
- 		      rflow->last_qtail)) >= 0))
+ 		      rflow->last_qtail)) >= 0)) {
+ 			tcpu = next_cpu;
  			rflow = set_rps_cpu(dev, skb, rflow, next_cpu);
+ 		}
  
  		if (tcpu != RPS_NO_CPU && cpu_online(tcpu)) {
  			*rflowp = rflow;
@@@ -3521,9 -3446,9 +3523,9 @@@ static void flush_backlog(void *arg
  
  static int napi_gro_complete(struct sk_buff *skb)
  {
 -	struct packet_type *ptype;
 +	struct packet_offload *ptype;
  	__be16 type = skb->protocol;
 -	struct list_head *head = &ptype_base[ntohs(type) & PTYPE_HASH_MASK];
 +	struct list_head *head = &offload_base;
  	int err = -ENOENT;
  
  	if (NAPI_GRO_CB(skb)->count == 1) {
@@@ -3533,10 -3458,10 +3535,10 @@@
  
  	rcu_read_lock();
  	list_for_each_entry_rcu(ptype, head, list) {
 -		if (ptype->type != type || ptype->dev || !ptype->gro_complete)
 +		if (ptype->type != type || !ptype->callbacks.gro_complete)
  			continue;
  
 -		err = ptype->gro_complete(skb);
 +		err = ptype->callbacks.gro_complete(skb);
  		break;
  	}
  	rcu_read_unlock();
@@@ -3583,9 -3508,9 +3585,9 @@@ EXPORT_SYMBOL(napi_gro_flush)
  enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
  {
  	struct sk_buff **pp = NULL;
 -	struct packet_type *ptype;
 +	struct packet_offload *ptype;
  	__be16 type = skb->protocol;
 -	struct list_head *head = &ptype_base[ntohs(type) & PTYPE_HASH_MASK];
 +	struct list_head *head = &offload_base;
  	int same_flow;
  	int mac_len;
  	enum gro_result ret;
@@@ -3598,7 -3523,7 +3600,7 @@@
  
  	rcu_read_lock();
  	list_for_each_entry_rcu(ptype, head, list) {
 -		if (ptype->type != type || ptype->dev || !ptype->gro_receive)
 +		if (ptype->type != type || !ptype->callbacks.gro_receive)
  			continue;
  
  		skb_set_network_header(skb, skb_gro_offset(skb));
@@@ -3608,7 -3533,7 +3610,7 @@@
  		NAPI_GRO_CB(skb)->flush = 0;
  		NAPI_GRO_CB(skb)->free = 0;
  
 -		pp = ptype->gro_receive(&napi->gro_list, skb);
 +		pp = ptype->callbacks.gro_receive(&napi->gro_list, skb);
  		break;
  	}
  	rcu_read_unlock();
@@@ -6341,6 -6266,7 +6343,6 @@@ int dev_change_net_namespace(struct net
  		goto out;
  
  	/* Ensure the device has been registrered */
 -	err = -EINVAL;
  	if (dev->reg_state != NETREG_REGISTERED)
  		goto out;
  
@@@ -6738,8 -6664,6 +6740,8 @@@ static int __init net_dev_init(void
  	for (i = 0; i < PTYPE_HASH_SIZE; i++)
  		INIT_LIST_HEAD(&ptype_base[i]);
  
 +	INIT_LIST_HEAD(&offload_base);
 +
  	if (register_pernet_subsys(&netdev_net_ops))
  		goto out;
  
diff --combined net/ipv4/ip_vti.c
index 516188b,858fddf..f4a825d
--- a/net/ipv4/ip_vti.c
+++ b/net/ipv4/ip_vti.c
@@@ -66,6 -66,20 +66,6 @@@ static void vti_tunnel_setup(struct net
  static void vti_dev_free(struct net_device *dev);
  static int vti_tunnel_bind_dev(struct net_device *dev);
  
 -/* Locking : hash tables are protected by RCU and RTNL */
 -
 -#define for_each_ip_tunnel_rcu(start) \
 -	for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))
 -
 -/* often modified stats are per cpu, other are shared (netdev->stats) */
 -struct pcpu_tstats {
 -	u64	rx_packets;
 -	u64	rx_bytes;
 -	u64	tx_packets;
 -	u64	tx_bytes;
 -	struct	u64_stats_sync	syncp;
 -};
 -
  #define VTI_XMIT(stats1, stats2) do {				\
  	int err;						\
  	int pkt_len = skb->len;					\
@@@ -128,19 -142,19 +128,19 @@@ static struct ip_tunnel *vti_tunnel_loo
  	struct ip_tunnel *t;
  	struct vti_net *ipn = net_generic(net, vti_net_id);
  
 -	for_each_ip_tunnel_rcu(ipn->tunnels_r_l[h0 ^ h1])
 +	for_each_ip_tunnel_rcu(t, ipn->tunnels_r_l[h0 ^ h1])
  		if (local == t->parms.iph.saddr &&
  		    remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP))
  			return t;
 -	for_each_ip_tunnel_rcu(ipn->tunnels_r[h0])
 +	for_each_ip_tunnel_rcu(t, ipn->tunnels_r[h0])
  		if (remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP))
  			return t;
  
 -	for_each_ip_tunnel_rcu(ipn->tunnels_l[h1])
 +	for_each_ip_tunnel_rcu(t, ipn->tunnels_l[h1])
  		if (local == t->parms.iph.saddr && (t->dev->flags&IFF_UP))
  			return t;
  
 -	for_each_ip_tunnel_rcu(ipn->tunnels_wc[0])
 +	for_each_ip_tunnel_rcu(t, ipn->tunnels_wc[0])
  		if (t && (t->dev->flags&IFF_UP))
  			return t;
  	return NULL;
@@@ -324,12 -338,17 +324,17 @@@ static int vti_rcv(struct sk_buff *skb
  	if (tunnel != NULL) {
  		struct pcpu_tstats *tstats;
  
+ 		if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
+ 			return -1;
+ 
  		tstats = this_cpu_ptr(tunnel->dev->tstats);
  		u64_stats_update_begin(&tstats->syncp);
  		tstats->rx_packets++;
  		tstats->rx_bytes += skb->len;
  		u64_stats_update_end(&tstats->syncp);
  
+ 		skb->mark = 0;
+ 		secpath_reset(skb);
  		skb->dev = tunnel->dev;
  		return 1;
  	}
diff --combined net/ipv4/tcp.c
index 733f485,083092e..4aefa0b
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@@ -536,14 -536,13 +536,14 @@@ int tcp_ioctl(struct sock *sk, int cmd
  {
  	struct tcp_sock *tp = tcp_sk(sk);
  	int answ;
 +	bool slow;
  
  	switch (cmd) {
  	case SIOCINQ:
  		if (sk->sk_state == TCP_LISTEN)
  			return -EINVAL;
  
 -		lock_sock(sk);
 +		slow = lock_sock_fast(sk);
  		if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV))
  			answ = 0;
  		else if (sock_flag(sk, SOCK_URGINLINE) ||
@@@ -558,7 -557,7 +558,7 @@@
  				answ--;
  		} else
  			answ = tp->urg_seq - tp->copied_seq;
 -		release_sock(sk);
 +		unlock_sock_fast(sk, slow);
  		break;
  	case SIOCATMARK:
  		answ = tp->urg_data && tp->urg_seq == tp->copied_seq;
@@@ -1213,7 -1212,7 +1213,7 @@@ new_segment
  wait_for_sndbuf:
  			set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
  wait_for_memory:
- 			if (copied && likely(!tp->repair))
+ 			if (copied)
  				tcp_push(sk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH);
  
  			if ((err = sk_stream_wait_memory(sk, &timeo)) != 0)
@@@ -1224,7 -1223,7 +1224,7 @@@
  	}
  
  out:
- 	if (copied && likely(!tp->repair))
+ 	if (copied)
  		tcp_push(sk, flags, mss_now, tp->nonagle);
  	release_sock(sk);
  	return copied + copied_syn;
diff --combined net/ipv4/tcp_input.c
index 7839d51,609ff98..fc67831
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@@ -3552,24 -3552,6 +3552,24 @@@ static bool tcp_process_frto(struct soc
  	return false;
  }
  
 +/* RFC 5961 7 [ACK Throttling] */
 +static void tcp_send_challenge_ack(struct sock *sk)
 +{
 +	/* unprotected vars, we dont care of overwrites */
 +	static u32 challenge_timestamp;
 +	static unsigned int challenge_count;
 +	u32 now = jiffies / HZ;
 +
 +	if (now != challenge_timestamp) {
 +		challenge_timestamp = now;
 +		challenge_count = 0;
 +	}
 +	if (++challenge_count <= sysctl_tcp_challenge_ack_limit) {
 +		NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPCHALLENGEACK);
 +		tcp_send_ack(sk);
 +	}
 +}
 +
  /* This routine deals with incoming acks, but not outgoing ones. */
  static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
  {
@@@ -3589,14 -3571,8 +3589,14 @@@
  	/* If the ack is older than previous acks
  	 * then we can probably ignore it.
  	 */
 -	if (before(ack, prior_snd_una))
 +	if (before(ack, prior_snd_una)) {
 +		/* RFC 5961 5.2 [Blind Data Injection Attack].[Mitigation] */
 +		if (before(ack, prior_snd_una - tp->max_window)) {
 +			tcp_send_challenge_ack(sk);
 +			return -1;
 +		}
  		goto old_ack;
 +	}
  
  	/* If the ack includes data we haven't sent yet, discard
  	 * this segment (RFC793 Section 3.9).
@@@ -5268,6 -5244,23 +5268,6 @@@ out
  }
  #endif /* CONFIG_NET_DMA */
  
 -static void tcp_send_challenge_ack(struct sock *sk)
 -{
 -	/* unprotected vars, we dont care of overwrites */
 -	static u32 challenge_timestamp;
 -	static unsigned int challenge_count;
 -	u32 now = jiffies / HZ;
 -
 -	if (now != challenge_timestamp) {
 -		challenge_timestamp = now;
 -		challenge_count = 0;
 -	}
 -	if (++challenge_count <= sysctl_tcp_challenge_ack_limit) {
 -		NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPCHALLENGEACK);
 -		tcp_send_ack(sk);
 -	}
 -}
 -
  /* Does PAWS and seqno based validation of an incoming segment, flags will
   * play significant role here.
   */
@@@ -5320,11 -5313,6 +5320,6 @@@ static bool tcp_validate_incoming(struc
  		goto discard;
  	}
  
- 	/* ts_recent update must be made after we are sure that the packet
- 	 * is in window.
- 	 */
- 	tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq);
- 
  	/* step 3: check security and precedence [ignored] */
  
  	/* step 4: Check for a SYN
@@@ -5559,6 -5547,11 +5554,11 @@@ step5
  	if (th->ack && tcp_ack(sk, skb, FLAG_SLOWPATH) < 0)
  		goto discard;
  
+ 	/* ts_recent update must be made after we are sure that the packet
+ 	 * is in window.
+ 	 */
+ 	tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq);
+ 
  	tcp_rcv_rtt_measure_ts(sk, skb);
  
  	/* Process urgent data. */
@@@ -5995,7 -5988,7 +5995,7 @@@ int tcp_rcv_state_process(struct sock *
  				 */
  				if (req) {
  					tcp_synack_rtt_meas(sk, req);
 -					tp->total_retrans = req->retrans;
 +					tp->total_retrans = req->num_retrans;
  
  					reqsk_fastopen_remove(sk, req, false);
  				} else {
@@@ -6137,6 -6130,11 +6137,11 @@@
  	} else
  		goto discard;
  
+ 	/* ts_recent update must be made after we are sure that the packet
+ 	 * is in window.
+ 	 */
+ 	tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq);
+ 
  	/* step 6: check the URG bit */
  	tcp_urg(sk, skb, th);
  
diff --combined net/ipv6/ipv6_sockglue.c
index a7bee6a,e02faed..4b4172d
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@@ -397,7 -397,7 +397,7 @@@ static int do_ipv6_setsockopt(struct so
  		if (optname == IPV6_RTHDR && opt && opt->srcrt) {
  			struct ipv6_rt_hdr *rthdr = opt->srcrt;
  			switch (rthdr->type) {
 -#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
 +#if IS_ENABLED(CONFIG_IPV6_MIP6)
  			case IPV6_SRCRT_TYPE_2:
  				if (rthdr->hdrlen != 2 ||
  				    rthdr->segments_left != 1)
@@@ -827,6 -827,7 +827,7 @@@ pref_skip_coa
  		if (val < 0 || val > 255)
  			goto e_inval;
  		np->min_hopcount = val;
+ 		retv = 0;
  		break;
  	case IPV6_DONTFRAG:
  		np->dontfrag = valbool;
diff --combined net/mac80211/cfg.c
index 5eab132,7371f67..7669002
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@@ -372,11 -372,10 +372,11 @@@ static int ieee80211_config_default_mgm
  
  static void rate_idx_to_bitrate(struct rate_info *rate, struct sta_info *sta, int idx)
  {
 +	enum ieee80211_band band = ieee80211_get_sdata_band(sta->sdata);
 +
  	if (!(rate->flags & RATE_INFO_FLAGS_MCS)) {
  		struct ieee80211_supported_band *sband;
 -		sband = sta->local->hw.wiphy->bands[
 -				sta->local->oper_channel->band];
 +		sband = sta->local->hw.wiphy->bands[band];
  		rate->legacy = sband->bitrates[idx].bitrate;
  	} else
  		rate->mcs = idx;
@@@ -533,8 -532,6 +533,8 @@@ static void ieee80211_get_et_stats(stru
  				   u64 *data)
  {
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 +	struct ieee80211_chanctx_conf *chanctx_conf;
 +	struct ieee80211_channel *channel;
  	struct sta_info *sta;
  	struct ieee80211_local *local = sdata->local;
  	struct station_info sinfo;
@@@ -610,26 -607,19 +610,26 @@@
  do_survey:
  	i = STA_STATS_LEN - STA_STATS_SURVEY_LEN;
  	/* Get survey stats for current channel */
 -	q = 0;
 -	while (true) {
 -		survey.filled = 0;
 -		if (drv_get_survey(local, q, &survey) != 0) {
 -			survey.filled = 0;
 -			break;
 -		}
 +	survey.filled = 0;
  
 -		if (survey.channel &&
 -		    (local->oper_channel->center_freq ==
 -		     survey.channel->center_freq))
 -			break;
 -		q++;
 +	rcu_read_lock();
 +	chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
 +	if (chanctx_conf)
 +		channel = chanctx_conf->channel;
 +	else
 +		channel = NULL;
 +	rcu_read_unlock();
 +
 +	if (channel) {
 +		q = 0;
 +		do {
 +			survey.filled = 0;
 +			if (drv_get_survey(local, q, &survey) != 0) {
 +				survey.filled = 0;
 +				break;
 +			}
 +			q++;
 +		} while (channel != survey.channel);
  	}
  
  	if (survey.filled)
@@@ -734,42 -724,47 +734,42 @@@ static int ieee80211_get_station(struc
  	return ret;
  }
  
 -static int ieee80211_set_channel(struct wiphy *wiphy,
 -				 struct net_device *netdev,
 -				 struct ieee80211_channel *chan,
 -				 enum nl80211_channel_type channel_type)
 +static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
 +					 struct ieee80211_channel *chan,
 +					 enum nl80211_channel_type channel_type)
  {
  	struct ieee80211_local *local = wiphy_priv(wiphy);
 -	struct ieee80211_sub_if_data *sdata = NULL;
 -
 -	if (netdev)
 -		sdata = IEEE80211_DEV_TO_SUB_IF(netdev);
 -
 -	switch (ieee80211_get_channel_mode(local, NULL)) {
 -	case CHAN_MODE_HOPPING:
 -		return -EBUSY;
 -	case CHAN_MODE_FIXED:
 -		if (local->oper_channel != chan ||
 -		    (!sdata && local->_oper_channel_type != channel_type))
 -			return -EBUSY;
 -		if (!sdata && local->_oper_channel_type == channel_type)
 -			return 0;
 -		break;
 -	case CHAN_MODE_UNDEFINED:
 -		break;
 -	}
 -
 -	if (!ieee80211_set_channel_type(local, sdata, channel_type))
 -		return -EBUSY;
 +	struct ieee80211_sub_if_data *sdata;
 +	int ret = 0;
  
 -	local->oper_channel = chan;
 +	if (local->monitor_channel == chan &&
 +	    local->monitor_channel_type == channel_type)
 +		return 0;
  
 -	/* auto-detects changes */
 -	ieee80211_hw_config(local, 0);
 +	mutex_lock(&local->iflist_mtx);
 +	if (local->use_chanctx) {
 +		sdata = rcu_dereference_protected(
 +				local->monitor_sdata,
 +				lockdep_is_held(&local->iflist_mtx));
 +		if (sdata) {
 +			ieee80211_vif_release_channel(sdata);
 +			ret = ieee80211_vif_use_channel(
 +					sdata, chan, channel_type,
 +					IEEE80211_CHANCTX_EXCLUSIVE);
 +		}
 +	} else if (local->open_count == local->monitors) {
 +		local->_oper_channel = chan;
 +		local->_oper_channel_type = channel_type;
 +		ieee80211_hw_config(local, 0);
 +	}
  
 -	return 0;
 -}
 +	if (ret == 0) {
 +		local->monitor_channel = chan;
 +		local->monitor_channel_type = channel_type;
 +	}
 +	mutex_unlock(&local->iflist_mtx);
  
 -static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
 -					 struct ieee80211_channel *chan,
 -					 enum nl80211_channel_type channel_type)
 -{
 -	return ieee80211_set_channel(wiphy, NULL, chan, channel_type);
 +	return ret;
  }
  
  static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
@@@ -884,13 -879,8 +884,13 @@@ static int ieee80211_start_ap(struct wi
  	if (old)
  		return -EALREADY;
  
 -	err = ieee80211_set_channel(wiphy, dev, params->channel,
 -				    params->channel_type);
 +	/* TODO: make hostapd tell us what it wants */
 +	sdata->smps_mode = IEEE80211_SMPS_OFF;
 +	sdata->needed_rx_chains = sdata->local->rx_chains;
 +
 +	err = ieee80211_vif_use_channel(sdata, params->channel,
 +					params->channel_type,
 +					IEEE80211_CHANCTX_SHARED);
  	if (err)
  		return err;
  
@@@ -973,8 -963,6 +973,8 @@@ static int ieee80211_stop_ap(struct wip
  	sta_info_flush(sdata->local, sdata);
  	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
  
 +	ieee80211_vif_release_channel(sdata);
 +
  	return 0;
  }
  
@@@ -1031,10 -1019,9 +1031,10 @@@ static int sta_apply_parameters(struct 
  	int i, j;
  	struct ieee80211_supported_band *sband;
  	struct ieee80211_sub_if_data *sdata = sta->sdata;
 +	enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
  	u32 mask, set;
  
 -	sband = local->hw.wiphy->bands[local->oper_channel->band];
 +	sband = local->hw.wiphy->bands[band];
  
  	mask = params->sta_flags_mask;
  	set = params->sta_flags_set;
@@@ -1149,7 -1136,7 +1149,7 @@@
  					rates |= BIT(j);
  			}
  		}
 -		sta->sta.supp_rates[local->oper_channel->band] = rates;
 +		sta->sta.supp_rates[band] = rates;
  	}
  
  	if (params->ht_capa)
@@@ -1157,11 -1144,6 +1157,11 @@@
  						  params->ht_capa,
  						  &sta->sta.ht_cap);
  
 +	if (params->vht_capa)
 +		ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
 +						    params->vht_capa,
 +						    &sta->sta.vht_cap);
 +
  	if (ieee80211_vif_is_mesh(&sdata->vif)) {
  #ifdef CONFIG_MAC80211_MESH
  		if (sdata->u.mesh.security & IEEE80211_MESH_SEC_SECURED)
@@@ -1682,13 -1664,8 +1682,13 @@@ static int ieee80211_join_mesh(struct w
  	if (err)
  		return err;
  
 -	err = ieee80211_set_channel(wiphy, dev, setup->channel,
 -				    setup->channel_type);
 +	/* can mesh use other SMPS modes? */
 +	sdata->smps_mode = IEEE80211_SMPS_OFF;
 +	sdata->needed_rx_chains = sdata->local->rx_chains;
 +
 +	err = ieee80211_vif_use_channel(sdata, setup->channel,
 +					setup->channel_type,
 +					IEEE80211_CHANCTX_SHARED);
  	if (err)
  		return err;
  
@@@ -1702,7 -1679,6 +1702,7 @@@ static int ieee80211_leave_mesh(struct 
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
  
  	ieee80211_stop_mesh(sdata);
 +	ieee80211_vif_release_channel(sdata);
  
  	return 0;
  }
@@@ -1712,14 -1688,10 +1712,14 @@@ static int ieee80211_change_bss(struct 
  				struct net_device *dev,
  				struct bss_parameters *params)
  {
 -	struct ieee80211_sub_if_data *sdata;
 +	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 +	enum ieee80211_band band;
  	u32 changed = 0;
  
 -	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 +	if (!rtnl_dereference(sdata->u.ap.beacon))
 +		return -ENOENT;
 +
 +	band = ieee80211_get_sdata_band(sdata);
  
  	if (params->use_cts_prot >= 0) {
  		sdata->vif.bss_conf.use_cts_prot = params->use_cts_prot;
@@@ -1732,7 -1704,7 +1732,7 @@@
  	}
  
  	if (!sdata->vif.bss_conf.use_short_slot &&
 -	    sdata->local->oper_channel->band == IEEE80211_BAND_5GHZ) {
 +	    band == IEEE80211_BAND_5GHZ) {
  		sdata->vif.bss_conf.use_short_slot = true;
  		changed |= BSS_CHANGED_ERP_SLOT;
  	}
@@@ -1746,7 -1718,9 +1746,7 @@@
  	if (params->basic_rates) {
  		int i, j;
  		u32 rates = 0;
 -		struct ieee80211_local *local = wiphy_priv(wiphy);
 -		struct ieee80211_supported_band *sband =
 -			wiphy->bands[local->oper_channel->band];
 +		struct ieee80211_supported_band *sband = wiphy->bands[band];
  
  		for (i = 0; i < params->basic_rates_len; i++) {
  			int rate = (params->basic_rates[i] & 0x7f) * 5;
@@@ -1855,16 -1829,7 +1855,16 @@@ static int ieee80211_scan(struct wiphy 
  		 * beaconing hasn't been configured yet
  		 */
  	case NL80211_IFTYPE_AP:
 -		if (sdata->u.ap.beacon)
 +		/*
 +		 * If the scan has been forced (and the driver supports
 +		 * forcing), don't care about being beaconing already.
 +		 * This will create problems to the attached stations (e.g. all
 +		 * the  frames sent while scanning on other channel will be
 +		 * lost)
 +		 */
 +		if (sdata->u.ap.beacon &&
 +		    (!(wiphy->features & NL80211_FEATURE_AP_SCAN) ||
 +		     !(req->flags & NL80211_SCAN_FLAG_AP)))
  			return -EOPNOTSUPP;
  		break;
  	default:
@@@ -1907,6 -1872,20 +1907,6 @@@ static int ieee80211_auth(struct wiphy 
  static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev,
  			   struct cfg80211_assoc_request *req)
  {
 -	struct ieee80211_local *local = wiphy_priv(wiphy);
 -	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 -
 -	switch (ieee80211_get_channel_mode(local, sdata)) {
 -	case CHAN_MODE_HOPPING:
 -		return -EBUSY;
 -	case CHAN_MODE_FIXED:
 -		if (local->oper_channel == req->bss->channel)
 -			break;
 -		return -EBUSY;
 -	case CHAN_MODE_UNDEFINED:
 -		break;
 -	}
 -
  	return ieee80211_mgd_assoc(IEEE80211_DEV_TO_SUB_IF(dev), req);
  }
  
@@@ -1925,12 -1904,30 +1925,12 @@@ static int ieee80211_disassoc(struct wi
  static int ieee80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
  			       struct cfg80211_ibss_params *params)
  {
 -	struct ieee80211_local *local = wiphy_priv(wiphy);
 -	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 -
 -	switch (ieee80211_get_channel_mode(local, sdata)) {
 -	case CHAN_MODE_HOPPING:
 -		return -EBUSY;
 -	case CHAN_MODE_FIXED:
 -		if (!params->channel_fixed)
 -			return -EBUSY;
 -		if (local->oper_channel == params->channel)
 -			break;
 -		return -EBUSY;
 -	case CHAN_MODE_UNDEFINED:
 -		break;
 -	}
 -
 -	return ieee80211_ibss_join(sdata, params);
 +	return ieee80211_ibss_join(IEEE80211_DEV_TO_SUB_IF(dev), params);
  }
  
  static int ieee80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
  {
 -	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 -
 -	return ieee80211_ibss_leave(sdata);
 +	return ieee80211_ibss_leave(IEEE80211_DEV_TO_SUB_IF(dev));
  }
  
  static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
@@@ -1974,13 -1971,9 +1974,13 @@@ static int ieee80211_set_tx_power(struc
  				  enum nl80211_tx_power_setting type, int mbm)
  {
  	struct ieee80211_local *local = wiphy_priv(wiphy);
 -	struct ieee80211_channel *chan = local->oper_channel;
 +	struct ieee80211_channel *chan = local->_oper_channel;
  	u32 changes = 0;
  
 +	/* FIXME */
 +	if (local->use_chanctx)
 +		return -EOPNOTSUPP;
 +
  	switch (type) {
  	case NL80211_TX_POWER_AUTOMATIC:
  		local->user_power_level = -1;
@@@ -2074,12 -2067,13 +2074,12 @@@ int __ieee80211_request_smps(struct iee
  
  	/*
  	 * If not associated, or current association is not an HT
 -	 * association, there's no need to send an action frame.
 +	 * association, there's no need to do anything, just store
 +	 * the new value until we associate.
  	 */
  	if (!sdata->u.mgd.associated ||
 -	    sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) {
 -		ieee80211_recalc_smps(sdata->local);
 +	    sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT)
  		return 0;
 -	}
  
  	ap = sdata->u.mgd.associated->bssid;
  
@@@ -2195,9 -2189,6 +2195,9 @@@ static int ieee80211_start_roc_work(str
  
  	lockdep_assert_held(&local->mtx);
  
 +	if (local->use_chanctx && !local->ops->remain_on_channel)
 +		return -EOPNOTSUPP;
 +
  	roc = kzalloc(sizeof(*roc), GFP_KERNEL);
  	if (!roc)
  		return -ENOMEM;
@@@ -2524,20 -2515,10 +2524,20 @@@ static int ieee80211_mgmt_tx(struct wip
  
  	/* Check if the operating channel is the requested channel */
  	if (!need_offchan) {
 -		need_offchan = chan != local->oper_channel;
 -		if (channel_type_valid &&
 -		    channel_type != local->_oper_channel_type)
 +		struct ieee80211_chanctx_conf *chanctx_conf;
 +
 +		rcu_read_lock();
 +		chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
 +
 +		if (chanctx_conf) {
 +			need_offchan = chan != chanctx_conf->channel;
 +			if (channel_type_valid &&
 +			    channel_type != chanctx_conf->channel_type)
 +				need_offchan = true;
 +		} else {
  			need_offchan = true;
 +		}
 +		rcu_read_unlock();
  	}
  
  	if (need_offchan && !offchan) {
@@@ -2613,6 -2594,9 +2613,9 @@@ static void ieee80211_mgmt_frame_regist
  		else
  			local->probe_req_reg--;
  
+ 		if (!local->open_count)
+ 			break;
+ 
  		ieee80211_queue_work(&local->hw, &local->reconfig_filter);
  		break;
  	default:
@@@ -2686,7 -2670,7 +2689,7 @@@ static u16 ieee80211_get_tdls_sta_capab
  	u16 capab;
  
  	capab = 0;
 -	if (local->oper_channel->band != IEEE80211_BAND_2GHZ)
 +	if (ieee80211_get_sdata_band(sdata) != IEEE80211_BAND_2GHZ)
  		return capab;
  
  	if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE))
@@@ -2718,7 -2702,7 +2721,7 @@@ ieee80211_prep_tdls_encap_data(struct w
  			       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;
 +	enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
  	struct ieee80211_tdls_data *tf;
  
  	tf = (void *)skb_put(skb, offsetof(struct ieee80211_tdls_data, u));
@@@ -2738,8 -2722,10 +2741,8 @@@
  		tf->u.setup_req.capability =
  			cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
  
 -		ieee80211_add_srates_ie(sdata, skb, false,
 -					local->oper_channel->band);
 -		ieee80211_add_ext_srates_ie(sdata, skb, false,
 -					    local->oper_channel->band);
 +		ieee80211_add_srates_ie(sdata, skb, false, band);
 +		ieee80211_add_ext_srates_ie(sdata, skb, false, band);
  		ieee80211_tdls_add_ext_capab(skb);
  		break;
  	case WLAN_TDLS_SETUP_RESPONSE:
@@@ -2752,8 -2738,10 +2755,8 @@@
  		tf->u.setup_resp.capability =
  			cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
  
 -		ieee80211_add_srates_ie(sdata, skb, false,
 -					local->oper_channel->band);
 -		ieee80211_add_ext_srates_ie(sdata, skb, false,
 -					    local->oper_channel->band);
 +		ieee80211_add_srates_ie(sdata, skb, false, band);
 +		ieee80211_add_ext_srates_ie(sdata, skb, false, band);
  		ieee80211_tdls_add_ext_capab(skb);
  		break;
  	case WLAN_TDLS_SETUP_CONFIRM:
@@@ -2791,7 -2779,7 +2794,7 @@@ ieee80211_prep_tdls_direct(struct wiph
  			   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;
 +	enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
  	struct ieee80211_mgmt *mgmt;
  
  	mgmt = (void *)skb_put(skb, 24);
@@@ -2814,8 -2802,10 +2817,8 @@@
  		mgmt->u.action.u.tdls_discover_resp.capability =
  			cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
  
 -		ieee80211_add_srates_ie(sdata, skb, false,
 -					local->oper_channel->band);
 -		ieee80211_add_ext_srates_ie(sdata, skb, false,
 -					    local->oper_channel->band);
 +		ieee80211_add_srates_ie(sdata, skb, false, band);
 +		ieee80211_add_ext_srates_ie(sdata, skb, false, band);
  		ieee80211_tdls_add_ext_capab(skb);
  		break;
  	default:
@@@ -2832,6 -2822,7 +2835,6 @@@ static int ieee80211_tdls_mgmt(struct w
  {
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
  	struct ieee80211_local *local = sdata->local;
 -	struct ieee80211_tx_info *info;
  	struct sk_buff *skb = NULL;
  	bool send_direct;
  	int ret;
@@@ -2857,6 -2848,7 +2860,6 @@@
  	if (!skb)
  		return -ENOMEM;
  
 -	info = IEEE80211_SKB_CB(skb);
  	skb_reserve(skb, local->hw.extra_tx_headroom);
  
  	switch (action_code) {
@@@ -2993,19 -2985,12 +2996,19 @@@ static int ieee80211_probe_client(struc
  	bool qos;
  	struct ieee80211_tx_info *info;
  	struct sta_info *sta;
 +	struct ieee80211_chanctx_conf *chanctx_conf;
 +	enum ieee80211_band band;
  
  	rcu_read_lock();
 +	chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
 +	if (WARN_ON(!chanctx_conf)) {
 +		rcu_read_unlock();
 +		return -EINVAL;
 +	}
 +	band = chanctx_conf->channel->band;
  	sta = sta_info_get(sdata, peer);
  	if (sta) {
  		qos = test_sta_flag(sta, WLAN_STA_WME);
 -		rcu_read_unlock();
  	} else {
  		rcu_read_unlock();
  		return -ENOLINK;
@@@ -3023,10 -3008,8 +3026,10 @@@
  	}
  
  	skb = dev_alloc_skb(local->hw.extra_tx_headroom + size);
 -	if (!skb)
 +	if (!skb) {
 +		rcu_read_unlock();
  		return -ENOMEM;
 +	}
  
  	skb->dev = dev;
  
@@@ -3051,9 -3034,8 +3054,9 @@@
  		nullfunc->qos_ctrl = cpu_to_le16(7);
  
  	local_bh_disable();
 -	ieee80211_xmit(sdata, skb);
 +	ieee80211_xmit(sdata, skb, band);
  	local_bh_enable();
 +	rcu_read_unlock();
  
  	*cookie = (unsigned long) skb;
  	return 0;
@@@ -3063,19 -3045,10 +3066,19 @@@ static struct ieee80211_channel 
  ieee80211_cfg_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
  			  enum nl80211_channel_type *type)
  {
 -	struct ieee80211_local *local = wiphy_priv(wiphy);
 +	struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
 +	struct ieee80211_chanctx_conf *chanctx_conf;
 +	struct ieee80211_channel *chan = NULL;
 +
 +	rcu_read_lock();
 +	chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
 +	if (chanctx_conf) {
 +		*type = chanctx_conf->channel_type;
 +		chan = chanctx_conf->channel;
 +	}
 +	rcu_read_unlock();
  
 -	*type = local->_oper_channel_type;
 -	return local->oper_channel;
 +	return chan;
  }
  
  #ifdef CONFIG_PM
diff --combined net/mac80211/ieee80211_i.h
index 3026519,156e583..32e4785
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@@ -280,27 -280,23 +280,27 @@@ struct probe_resp 
  	u8 data[0];
  };
  
 -struct ieee80211_if_ap {
 -	struct beacon_data __rcu *beacon;
 -	struct probe_resp __rcu *probe_resp;
 -
 -	struct list_head vlans;
 -
 +struct ps_data {
  	/* yes, this looks ugly, but guarantees that we can later use
  	 * bitmap_empty :)
  	 * NB: don't touch this bitmap, use sta_info_{set,clear}_tim_bit */
  	u8 tim[sizeof(unsigned long) * BITS_TO_LONGS(IEEE80211_MAX_AID + 1)];
 -	struct sk_buff_head ps_bc_buf;
 +	struct sk_buff_head bc_buf;
  	atomic_t num_sta_ps; /* number of stations in PS mode */
 -	atomic_t num_mcast_sta; /* number of stations receiving multicast */
  	int dtim_count;
  	bool dtim_bc_mc;
  };
  
 +struct ieee80211_if_ap {
 +	struct beacon_data __rcu *beacon;
 +	struct probe_resp __rcu *probe_resp;
 +
 +	struct list_head vlans;
 +
 +	struct ps_data ps;
 +	atomic_t num_mcast_sta; /* number of stations receiving multicast */
 +};
 +
  struct ieee80211_if_wds {
  	struct sta_info *sta;
  	u8 remote_addr[ETH_ALEN];
@@@ -320,6 -316,7 +320,6 @@@ struct mesh_stats 
  	__u32 dropped_frames_ttl;	/* Not transmitted since mesh_ttl == 0*/
  	__u32 dropped_frames_no_route;	/* Not transmitted, no route found */
  	__u32 dropped_frames_congestion;/* Not forwarded due to congestion */
 -	atomic_t estab_plinks;
  };
  
  #define PREQ_Q_F_START		0x1
@@@ -381,9 -378,8 +381,9 @@@ struct ieee80211_mgd_auth_data 
  	u8 key_len, key_idx;
  	bool done;
  
 -	size_t ie_len;
 -	u8 ie[];
 +	u16 sae_trans, sae_status;
 +	size_t data_len;
 +	u8 data[];
  };
  
  struct ieee80211_mgd_assoc_data {
@@@ -437,6 -433,7 +437,6 @@@ struct ieee80211_if_managed 
  	bool powersave; /* powersave requested for this iface */
  	bool broken_ap; /* AP is broken -- turn off powersave */
  	enum ieee80211_smps_mode req_smps, /* requested smps mode */
 -				 ap_smps, /* smps mode AP thinks we're in */
  				 driver_smps_mode; /* smps mode request */
  
  	struct work_struct request_smps_work;
@@@ -602,7 -599,6 +602,7 @@@ struct ieee80211_if_mesh 
  	int preq_queue_len;
  	struct mesh_stats mshstats;
  	struct mesh_config mshcfg;
 +	atomic_t estab_plinks;
  	u32 mesh_seqnum;
  	bool accepting_plinks;
  	int num_gates;
@@@ -614,7 -610,7 +614,7 @@@
  		IEEE80211_MESH_SEC_SECURED = 0x2,
  	} security;
  	/* Extensible Synchronization Framework */
 -	struct ieee80211_mesh_sync_ops *sync_ops;
 +	const struct ieee80211_mesh_sync_ops *sync_ops;
  	s64 sync_offset_clockdrift_max;
  	spinlock_t sync_offset_lock;
  	bool adjusting_tbtt;
@@@ -662,30 -658,6 +662,30 @@@ enum ieee80211_sdata_state_bits 
  	SDATA_STATE_OFFCHANNEL,
  };
  
 +/**
 + * enum ieee80211_chanctx_mode - channel context configuration mode
 + *
 + * @IEEE80211_CHANCTX_SHARED: channel context may be used by
 + *	multiple interfaces
 + * @IEEE80211_CHANCTX_EXCLUSIVE: channel context can be used
 + *	only by a single interface. This can be used for example for
 + *	non-fixed channel IBSS.
 + */
 +enum ieee80211_chanctx_mode {
 +	IEEE80211_CHANCTX_SHARED,
 +	IEEE80211_CHANCTX_EXCLUSIVE
 +};
 +
 +struct ieee80211_chanctx {
 +	struct list_head list;
 +	struct rcu_head rcu_head;
 +
 +	enum ieee80211_chanctx_mode mode;
 +	int refcount;
 +
 +	struct ieee80211_chanctx_conf conf;
 +};
 +
  struct ieee80211_sub_if_data {
  	struct list_head list;
  
@@@ -732,17 -704,11 +732,17 @@@
  
  	struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS];
  
 +	/* used to reconfigure hardware SM PS */
 +	struct work_struct recalc_smps;
 +
  	struct work_struct work;
  	struct sk_buff_head skb_queue;
  
  	bool arp_filter_state;
  
 +	u8 needed_rx_chains;
 +	enum ieee80211_smps_mode smps_mode;
 +
  	/*
  	 * AP this belongs to: self in AP mode and
  	 * corresponding AP in VLAN mode, NULL for
@@@ -783,21 -749,6 +783,21 @@@ struct ieee80211_sub_if_data *vif_to_sd
  	return container_of(p, struct ieee80211_sub_if_data, vif);
  }
  
 +static inline enum ieee80211_band
 +ieee80211_get_sdata_band(struct ieee80211_sub_if_data *sdata)
 +{
 +	enum ieee80211_band band = IEEE80211_BAND_2GHZ;
 +	struct ieee80211_chanctx_conf *chanctx_conf;
 +
 +	rcu_read_lock();
 +	chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
 +	if (!WARN_ON(!chanctx_conf))
 +		band = chanctx_conf->channel->band;
 +	rcu_read_unlock();
 +
 +	return band;
 +}
 +
  enum sdata_queue_type {
  	IEEE80211_SDATA_QUEUE_TYPE_FRAME	= 0,
  	IEEE80211_SDATA_QUEUE_AGG_START		= 1,
@@@ -870,7 -821,6 +870,7 @@@ enum 
   * @SCAN_SUSPEND: Suspend the scan and go back to operating channel to
   *	send out data
   * @SCAN_RESUME: Resume the scan and scan the next channel
 + * @SCAN_ABORT: Abort the scan and go back to operating channel
   */
  enum mac80211_scan_state {
  	SCAN_DECISION,
@@@ -878,7 -828,6 +878,7 @@@
  	SCAN_SEND_PROBE,
  	SCAN_SUSPEND,
  	SCAN_RESUME,
 +	SCAN_ABORT,
  };
  
  struct ieee80211_local {
@@@ -909,14 -858,15 +909,14 @@@
  
  	bool wiphy_ciphers_allocated;
  
 +	bool use_chanctx;
 +
  	/* protects the aggregated multicast list and filter calls */
  	spinlock_t filter_lock;
  
  	/* used for uploading changed mc list */
  	struct work_struct reconfig_filter;
  
 -	/* used to reconfigure hardware SM PS */
 -	struct work_struct recalc_smps;
 -
  	/* aggregated multicast list */
  	struct netdev_hw_addr_list mc_list;
  
@@@ -953,9 -903,6 +953,9 @@@
  	/* wowlan is enabled -- don't reconfig on resume */
  	bool wowlan;
  
 +	/* number of RX chains the hardware has */
 +	u8 rx_chains;
 +
  	int tx_headroom; /* required headroom for hardware/radiotap */
  
  	/* Tasklet and skb queue to process calls from IRQ mode. All frames
@@@ -1033,19 -980,13 +1033,19 @@@
  	enum mac80211_scan_state next_scan_state;
  	struct delayed_work scan_work;
  	struct ieee80211_sub_if_data __rcu *scan_sdata;
 +	struct ieee80211_channel *csa_channel;
 +	/* For backward compatibility only -- do not use */
 +	struct ieee80211_channel *_oper_channel;
  	enum nl80211_channel_type _oper_channel_type;
 -	struct ieee80211_channel *oper_channel, *csa_channel;
  
  	/* Temporary remain-on-channel for off-channel operations */
  	struct ieee80211_channel *tmp_channel;
  	enum nl80211_channel_type tmp_channel_type;
  
 +	/* channel contexts */
 +	struct list_head chanctx_list;
 +	struct mutex chanctx_mtx;
 +
  	/* SNMP counters */
  	/* dot11CountersTable */
  	u32 dot11TransmittedFragmentCount;
@@@ -1150,8 -1091,6 +1150,8 @@@
  
  	/* virtual monitor interface */
  	struct ieee80211_sub_if_data __rcu *monitor_sdata;
 +	struct ieee80211_channel *monitor_channel;
 +	enum nl80211_channel_type monitor_channel_type;
  };
  
  static inline struct ieee80211_sub_if_data *
@@@ -1194,8 -1133,6 +1194,8 @@@ struct ieee802_11_elems 
  	u8 *wmm_param;
  	struct ieee80211_ht_cap *ht_cap_elem;
  	struct ieee80211_ht_operation *ht_operation;
 +	struct ieee80211_vht_cap *vht_cap_elem;
 +	struct ieee80211_vht_operation *vht_operation;
  	struct ieee80211_meshconf_ie *mesh_config;
  	u8 *mesh_id;
  	u8 *peering;
@@@ -1377,6 -1314,8 +1377,8 @@@ netdev_tx_t ieee80211_monitor_start_xmi
  					 struct net_device *dev);
  netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
  				       struct net_device *dev);
+ void ieee80211_purge_tx_queue(struct ieee80211_hw *hw,
+ 			      struct sk_buff_head *skbs);
  
  /* HT */
  void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
@@@ -1422,13 -1361,6 +1424,13 @@@ void ieee80211_ba_session_work(struct w
  void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid);
  void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid);
  
 +u8 ieee80211_mcs_to_chains(const struct ieee80211_mcs_info *mcs);
 +
 +/* VHT */
 +void ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
 +					 struct ieee80211_supported_band *sband,
 +					 struct ieee80211_vht_cap *vht_cap_ie,
 +					 struct ieee80211_sta_vht_cap *vht_cap);
  /* Spectrum management */
  void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
  				       struct ieee80211_mgmt *mgmt,
@@@ -1463,42 -1395,11 +1465,42 @@@ void mac80211_ev_michael_mic_failure(st
  				     gfp_t gfp);
  void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
  			       bool bss_notify);
 -void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb);
 +void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
 +		    enum ieee80211_band band);
 +
 +void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
 +				 struct sk_buff *skb, int tid,
 +				 enum ieee80211_band band);
  
 -void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata,
 -			  struct sk_buff *skb, int tid);
 -static void inline ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata,
 +static inline void
 +ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
 +			  struct sk_buff *skb, int tid,
 +			  enum ieee80211_band band)
 +{
 +	rcu_read_lock();
 +	__ieee80211_tx_skb_tid_band(sdata, skb, tid, band);
 +	rcu_read_unlock();
 +}
 +
 +static inline void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata,
 +					struct sk_buff *skb, int tid)
 +{
 +	struct ieee80211_chanctx_conf *chanctx_conf;
 +
 +	rcu_read_lock();
 +	chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
 +	if (WARN_ON(!chanctx_conf)) {
 +		rcu_read_unlock();
 +		kfree_skb(skb);
 +		return;
 +	}
 +
 +	__ieee80211_tx_skb_tid_band(sdata, skb, tid,
 +				    chanctx_conf->channel->band);
 +	rcu_read_unlock();
 +}
 +
 +static inline void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata,
  				    struct sk_buff *skb)
  {
  	/* Send all internal mgmt frames on VO. Accordingly set TID to 7. */
@@@ -1545,7 -1446,7 +1547,7 @@@ static inline void ieee80211_add_pendin
  }
  
  void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
 -			 u16 transaction, u16 auth_alg,
 +			 u16 transaction, u16 auth_alg, u16 status,
  			 u8 *extra, size_t extra_len, const u8 *bssid,
  			 const u8 *da, const u8 *key, u8 key_len, u8 key_idx);
  void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
@@@ -1565,7 -1466,7 +1567,7 @@@ void ieee80211_send_probe_req(struct ie
  			      const u8 *ssid, size_t ssid_len,
  			      const u8 *ie, size_t ie_len,
  			      u32 ratemask, bool directed, bool no_cck,
 -			      struct ieee80211_channel *channel);
 +			      struct ieee80211_channel *channel, bool scan);
  
  void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
  				  const size_t supp_rates_len,
@@@ -1575,7 -1476,7 +1577,7 @@@ u32 ieee80211_sta_get_rates(struct ieee
  			    enum ieee80211_band band, u32 *basic_rates);
  int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
  			     enum ieee80211_smps_mode smps_mode);
 -void ieee80211_recalc_smps(struct ieee80211_local *local);
 +void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata);
  
  size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
  			  const u8 *ids, int n_ids, size_t offset);
@@@ -1596,19 -1497,21 +1598,19 @@@ int ieee80211_add_ext_srates_ie(struct 
  				enum ieee80211_band band);
  
  /* channel management */
  enum nl80211_channel_type
  ieee80211_ht_oper_to_channel_type(struct ieee80211_ht_operation *ht_oper);
  
 +int __must_check
 +ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
 +			  struct ieee80211_channel *channel,
 +			  enum nl80211_channel_type channel_type,
 +			  enum ieee80211_chanctx_mode mode);
 +void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata);
 +
 +void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
 +				   struct ieee80211_chanctx *chanctx);
 +
  #ifdef CONFIG_MAC80211_NOINLINE
  #define debug_noinline noinline
  #else
diff --combined net/mac80211/main.c
index fd8345c,f57f597..d6e43b0
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@@ -93,21 -93,23 +93,21 @@@ static void ieee80211_reconfig_filter(s
  	ieee80211_configure_filter(local);
  }
  
 -int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
 +static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local)
  {
  	struct ieee80211_channel *chan;
 -	int ret = 0;
 +	u32 changed = 0;
  	int power;
  	enum nl80211_channel_type channel_type;
  	u32 offchannel_flag;
  
 -	might_sleep();
 -
  	offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL;
  	if (local->scan_channel) {
  		chan = local->scan_channel;
  		/* If scanning on oper channel, use whatever channel-type
  		 * is currently in use.
  		 */
 -		if (chan == local->oper_channel)
 +		if (chan == local->_oper_channel)
  			channel_type = local->_oper_channel_type;
  		else
  			channel_type = NL80211_CHAN_NO_HT;
@@@ -115,11 -117,11 +115,11 @@@
  		chan = local->tmp_channel;
  		channel_type = local->tmp_channel_type;
  	} else {
 -		chan = local->oper_channel;
 +		chan = local->_oper_channel;
  		channel_type = local->_oper_channel_type;
  	}
  
 -	if (chan != local->oper_channel ||
 +	if (chan != local->_oper_channel ||
  	    channel_type != local->_oper_channel_type)
  		local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL;
  	else
@@@ -162,21 -164,6 +162,21 @@@
  		local->hw.conf.power_level = power;
  	}
  
 +	return changed;
 +}
 +
 +int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
 +{
 +	int ret = 0;
 +
 +	might_sleep();
 +
 +	if (!local->use_chanctx)
 +		changed |= ieee80211_hw_conf_chan(local);
 +	else
 +		changed &= ~(IEEE80211_CONF_CHANGE_CHANNEL |
 +			     IEEE80211_CONF_CHANGE_POWER);
 +
  	if (changed && local->open_count) {
  		ret = drv_config(local, changed);
  		/*
@@@ -372,6 -359,14 +372,6 @@@ void ieee80211_restart_hw(struct ieee80
  }
  EXPORT_SYMBOL(ieee80211_restart_hw);
  
 -static void ieee80211_recalc_smps_work(struct work_struct *work)
 -{
 -	struct ieee80211_local *local =
 -		container_of(work, struct ieee80211_local, recalc_smps);
 -
 -	ieee80211_recalc_smps(local);
 -}
 -
  #ifdef CONFIG_INET
  static int ieee80211_ifa_changed(struct notifier_block *nb,
  				 unsigned long data, void *arg)
@@@ -545,7 -540,6 +545,7 @@@ struct ieee80211_hw *ieee80211_alloc_hw
  	struct ieee80211_local *local;
  	int priv_size, i;
  	struct wiphy *wiphy;
 +	bool use_chanctx;
  
  	if (WARN_ON(!ops->tx || !ops->start || !ops->stop || !ops->config ||
  		    !ops->add_interface || !ops->remove_interface ||
@@@ -555,14 -549,6 +555,14 @@@
  	if (WARN_ON(ops->sta_state && (ops->sta_add || ops->sta_remove)))
  		return NULL;
  
 +	/* check all or no channel context operations exist */
 +	i = !!ops->add_chanctx + !!ops->remove_chanctx +
 +	    !!ops->change_chanctx + !!ops->assign_vif_chanctx +
 +	    !!ops->unassign_vif_chanctx;
 +	if (WARN_ON(i != 0 && i != 5))
 +		return NULL;
 +	use_chanctx = i == 5;
 +
  	/* Ensure 32-byte alignment of our private data and hw private data.
  	 * We use the wiphy priv data for both our ieee80211_local and for
  	 * the driver's private data
@@@ -598,14 -584,8 +598,14 @@@
  	if (ops->remain_on_channel)
  		wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
  
 -	wiphy->features = NL80211_FEATURE_SK_TX_STATUS |
 -			  NL80211_FEATURE_HT_IBSS;
 +	wiphy->features |= NL80211_FEATURE_SK_TX_STATUS |
 +			   NL80211_FEATURE_SAE |
 +			   NL80211_FEATURE_HT_IBSS;
 +
 +	if (!ops->hw_scan)
 +		wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN |
 +				   NL80211_FEATURE_AP_SCAN;
 +
  
  	if (!ops->set_key)
  		wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
@@@ -619,7 -599,6 +619,7 @@@
  	local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN);
  
  	local->ops = ops;
 +	local->use_chanctx = use_chanctx;
  
  	/* set up some defaults */
  	local->hw.queues = 1;
@@@ -647,9 -626,6 +647,9 @@@
  	spin_lock_init(&local->filter_lock);
  	spin_lock_init(&local->queue_stop_reason_lock);
  
 +	INIT_LIST_HEAD(&local->chanctx_list);
 +	mutex_init(&local->chanctx_mtx);
 +
  	/*
  	 * The rx_skb_queue is only accessed from tasklets,
  	 * but other SKB queues are used from within IRQ
@@@ -665,6 -641,7 +665,6 @@@
  	INIT_WORK(&local->restart_work, ieee80211_restart_work);
  
  	INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter);
 -	INIT_WORK(&local->recalc_smps, ieee80211_recalc_smps_work);
  	local->smps_mode = IEEE80211_SMPS_OFF;
  
  	INIT_WORK(&local->dynamic_ps_enable_work,
@@@ -742,25 -719,6 +742,25 @@@ int ieee80211_register_hw(struct ieee80
  	if ((hw->flags & IEEE80211_HW_SCAN_WHILE_IDLE) && !local->ops->hw_scan)
  		return -EINVAL;
  
 +	if (!local->use_chanctx) {
 +		for (i = 0; i < local->hw.wiphy->n_iface_combinations; i++) {
 +			const struct ieee80211_iface_combination *comb;
 +
 +			comb = &local->hw.wiphy->iface_combinations[i];
 +
 +			if (comb->num_different_channels > 1)
 +				return -EINVAL;
 +		}
 +	} else {
 +		/*
 +		 * WDS is currently prohibited when channel contexts are used
 +		 * because there's no clear definition of which channel WDS
 +		 * type interfaces use
 +		 */
 +		if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_WDS))
 +			return -EINVAL;
 +	}
 +
  	/* Only HW csum features are currently compatible with mac80211 */
  	feature_whitelist = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
  			    NETIF_F_HW_CSUM;
@@@ -770,8 -728,6 +770,8 @@@
  	if (hw->max_report_rates == 0)
  		hw->max_report_rates = hw->max_rates;
  
 +	local->rx_chains = 1;
 +
  	/*
  	 * generic code guarantees at least one band,
  	 * set this very early because much code assumes
@@@ -787,29 -743,18 +787,29 @@@
  		sband = local->hw.wiphy->bands[band];
  		if (!sband)
  			continue;
 -		if (!local->oper_channel) {
 +		if (!local->use_chanctx && !local->_oper_channel) {
  			/* init channel we're on */
  			local->hw.conf.channel =
 -			local->oper_channel = &sband->channels[0];
 +			local->_oper_channel = &sband->channels[0];
  			local->hw.conf.channel_type = NL80211_CHAN_NO_HT;
  		}
 +		if (!local->monitor_channel) {
 +			local->monitor_channel = &sband->channels[0];
 +			local->monitor_channel_type = NL80211_CHAN_NO_HT;
 +		}
  		channels += sband->n_channels;
  
  		if (max_bitrates < sband->n_bitrates)
  			max_bitrates = sband->n_bitrates;
  		supp_ht = supp_ht || sband->ht_cap.ht_supported;
  		supp_vht = supp_vht || sband->vht_cap.vht_supported;
 +
 +		if (sband->ht_cap.ht_supported)
 +			local->rx_chains =
 +				max(ieee80211_mcs_to_chains(&sband->ht_cap.mcs),
 +				    local->rx_chains);
 +
 +		/* TODO: consider VHT for RX chains, hopefully it's the same */
  	}
  
  	local->int_scan_req = kzalloc(sizeof(*local->int_scan_req) +
@@@ -833,13 -778,19 +833,13 @@@
  	hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
  	hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_MONITOR);
  
 -	/*
 -	 * mac80211 doesn't support more than 1 channel, and also not more
 -	 * than one IBSS interface
 -	 */
 +	/* mac80211 doesn't support more than one IBSS interface right now */
  	for (i = 0; i < hw->wiphy->n_iface_combinations; i++) {
  		const struct ieee80211_iface_combination *c;
  		int j;
  
  		c = &hw->wiphy->iface_combinations[i];
  
 -		if (c->num_different_channels > 1)
 -			return -EINVAL;
 -
  		for (j = 0; j < c->n_limits; j++)
  			if ((c->limits[j].types & BIT(NL80211_IFTYPE_ADHOC)) &&
  			    c->limits[j].max > 1)
@@@ -881,7 -832,7 +881,7 @@@
  
  	if (supp_vht)
  		local->scan_ies_len +=
 -			2 + sizeof(struct ieee80211_vht_capabilities);
 +			2 + sizeof(struct ieee80211_vht_cap);
  
  	if (!local->ops->hw_scan) {
  		/* For hw_scan, driver needs to set these up. */
@@@ -920,8 -871,10 +920,10 @@@
  				local->hw.wiphy->cipher_suites,
  				sizeof(u32) * local->hw.wiphy->n_cipher_suites,
  				GFP_KERNEL);
- 			if (!suites)
- 				return -ENOMEM;
+ 			if (!suites) {
+ 				result = -ENOMEM;
+ 				goto fail_wiphy_register;
+ 			}
  			for (r = 0; r < local->hw.wiphy->n_cipher_suites; r++) {
  				u32 suite = local->hw.wiphy->cipher_suites[r];
  				if (suite == WLAN_CIPHER_SUITE_WEP40 ||
diff --combined net/mac80211/scan.c
index 13d2329,43e60b5..8e9bb168
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@@ -336,10 -336,6 +336,10 @@@ EXPORT_SYMBOL(ieee80211_scan_completed)
  
  static int ieee80211_start_sw_scan(struct ieee80211_local *local)
  {
 +	/* Software scan is not supported in multi-channel cases */
 +	if (local->use_chanctx)
 +		return -EOPNOTSUPP;
 +
  	/*
  	 * Hardware/driver doesn't support hw_scan, so use software
  	 * scanning instead. First send a nullfunc frame with power save
@@@ -421,7 -417,7 +421,7 @@@ static void ieee80211_scan_state_send_p
  			local->scan_req->ie, local->scan_req->ie_len,
  			local->scan_req->rates[band], false,
  			local->scan_req->no_cck,
 -			local->hw.conf.channel);
 +			local->hw.conf.channel, true);
  
  	/*
  	 * After sending probe requests, wait for probe responses
@@@ -466,7 -462,6 +466,7 @@@ static int __ieee80211_start_scan(struc
  			sizeof(*local->hw_scan_req) +
  			req->n_channels * sizeof(req->channels[0]);
  		local->hw_scan_req->ie = ies;
 +		local->hw_scan_req->flags = req->flags;
  
  		local->hw_scan_band = 0;
  
@@@ -485,7 -480,7 +485,7 @@@
  	if (local->ops->hw_scan) {
  		__set_bit(SCAN_HW_SCANNING, &local->scanning);
  	} else if ((req->n_channels == 1) &&
 -		   (req->channels[0] == local->oper_channel)) {
 +		   (req->channels[0] == local->_oper_channel)) {
  		/*
  		 * If we are scanning only on the operating channel
  		 * then we do not need to stop normal activities
@@@ -567,7 -562,6 +567,7 @@@ static void ieee80211_scan_state_decisi
  	unsigned long min_beacon_int = 0;
  	struct ieee80211_sub_if_data *sdata;
  	struct ieee80211_channel *next_chan;
 +	enum mac80211_scan_state next_scan_state;
  
  	/*
  	 * check if at least one STA interface is associated,
@@@ -626,18 -620,10 +626,18 @@@
  			usecs_to_jiffies(min_beacon_int * 1024) *
  			local->hw.conf.listen_interval);
  
 -	if (associated && (!tx_empty || bad_latency || listen_int_exceeded))
 -		local->next_scan_state = SCAN_SUSPEND;
 -	else
 -		local->next_scan_state = SCAN_SET_CHANNEL;
 +	if (associated && !tx_empty) {
 +		if (local->scan_req->flags & NL80211_SCAN_FLAG_LOW_PRIORITY)
 +			next_scan_state = SCAN_ABORT;
 +		else
 +			next_scan_state = SCAN_SUSPEND;
 +	} else if (associated && (bad_latency || listen_int_exceeded)) {
 +		next_scan_state = SCAN_SUSPEND;
 +	} else {
 +		next_scan_state = SCAN_SET_CHANNEL;
 +	}
 +
 +	local->next_scan_state = next_scan_state;
  
  	*next_delay = 0;
  }
@@@ -808,9 -794,6 +808,9 @@@ void ieee80211_scan_work(struct work_st
  		case SCAN_RESUME:
  			ieee80211_scan_state_resume(local, &next_delay);
  			break;
 +		case SCAN_ABORT:
 +			aborted = true;
 +			goto out_complete;
  		}
  	} while (next_delay == 0);
  
@@@ -934,7 -917,7 +934,7 @@@ int ieee80211_request_sched_scan_start(
  				       struct cfg80211_sched_scan_request *req)
  {
  	struct ieee80211_local *local = sdata->local;
- 	struct ieee80211_sched_scan_ies sched_scan_ies;
+ 	struct ieee80211_sched_scan_ies sched_scan_ies = {};
  	int ret, i;
  
  	mutex_lock(&local->mtx);
diff --combined net/mac80211/sta_info.c
index f7bb54f,d2eb64e..e9d5768
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@@ -98,7 -98,6 +98,7 @@@ static void free_sta_work(struct work_s
  	struct tid_ampdu_tx *tid_tx;
  	struct ieee80211_sub_if_data *sdata = sta->sdata;
  	struct ieee80211_local *local = sdata->local;
 +	struct ps_data *ps;
  
  	/*
  	 * At this point, when being called as call_rcu callback,
@@@ -108,22 -107,18 +108,22 @@@
  	 */
  
  	if (test_sta_flag(sta, WLAN_STA_PS_STA)) {
 -		BUG_ON(!sdata->bss);
 +		if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
 +		    sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
 +			ps = &sdata->bss->ps;
 +		else
 +			return;
  
  		clear_sta_flag(sta, WLAN_STA_PS_STA);
  
 -		atomic_dec(&sdata->bss->num_sta_ps);
 +		atomic_dec(&ps->num_sta_ps);
  		sta_info_recalc_tim(sta);
  	}
  
  	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
  		local->total_ps_buffered -= skb_queue_len(&sta->ps_tx_buf[ac]);
- 		__skb_queue_purge(&sta->ps_tx_buf[ac]);
- 		__skb_queue_purge(&sta->tx_filtered[ac]);
+ 		ieee80211_purge_tx_queue(&local->hw, &sta->ps_tx_buf[ac]);
+ 		ieee80211_purge_tx_queue(&local->hw, &sta->tx_filtered[ac]);
  	}
  
  #ifdef CONFIG_MAC80211_MESH
@@@ -146,7 -141,7 +146,7 @@@
  		tid_tx = rcu_dereference_raw(sta->ampdu_mlme.tid_tx[i]);
  		if (!tid_tx)
  			continue;
- 		__skb_queue_purge(&tid_tx->pending);
+ 		ieee80211_purge_tx_queue(&local->hw, &tid_tx->pending);
  		kfree(tid_tx);
  	}
  
@@@ -507,22 -502,22 +507,22 @@@ int sta_info_insert(struct sta_info *st
  	return err;
  }
  
 -static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid)
 +static inline void __bss_tim_set(u8 *tim, u16 id)
  {
  	/*
  	 * This format has been mandated by the IEEE specifications,
  	 * so this line may not be changed to use the __set_bit() format.
  	 */
 -	bss->tim[aid / 8] |= (1 << (aid % 8));
 +	tim[id / 8] |= (1 << (id % 8));
  }
  
 -static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, u16 aid)
 +static inline void __bss_tim_clear(u8 *tim, u16 id)
  {
  	/*
  	 * This format has been mandated by the IEEE specifications,
  	 * so this line may not be changed to use the __clear_bit() format.
  	 */
 -	bss->tim[aid / 8] &= ~(1 << (aid % 8));
 +	tim[id / 8] &= ~(1 << (id % 8));
  }
  
  static unsigned long ieee80211_tids_for_ac(int ac)
@@@ -546,23 -541,14 +546,23 @@@
  void sta_info_recalc_tim(struct sta_info *sta)
  {
  	struct ieee80211_local *local = sta->local;
 -	struct ieee80211_if_ap *bss = sta->sdata->bss;
 +	struct ps_data *ps;
  	unsigned long flags;
  	bool indicate_tim = false;
  	u8 ignore_for_tim = sta->sta.uapsd_queues;
  	int ac;
 +	u16 id;
 +
 +	if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
 +	    sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
 +		if (WARN_ON_ONCE(!sta->sdata->bss))
 +			return;
  
 -	if (WARN_ON_ONCE(!sta->sdata->bss))
 +		ps = &sta->sdata->bss->ps;
 +		id = sta->sta.aid;
 +	} else {
  		return;
 +	}
  
  	/* No need to do anything if the driver does all */
  	if (local->hw.flags & IEEE80211_HW_AP_LINK_PS)
@@@ -601,9 -587,9 +601,9 @@@
  	spin_lock_irqsave(&local->tim_lock, flags);
  
  	if (indicate_tim)
 -		__bss_tim_set(bss, sta->sta.aid);
 +		__bss_tim_set(ps->tim, id);
  	else
 -		__bss_tim_clear(bss, sta->sta.aid);
 +		__bss_tim_clear(ps->tim, id);
  
  	if (local->ops->set_tim) {
  		local->tim_in_locked_section = true;
@@@ -907,8 -893,8 +907,8 @@@ void ieee80211_sta_expire(struct ieee80
  			continue;
  
  		if (time_after(jiffies, sta->last_rx + exp_time)) {
 -			ibss_dbg(sdata, "expiring inactive STA %pM\n",
 -				 sta->sta.addr);
 +			sta_dbg(sta->sdata, "expiring inactive STA %pM\n",
 +				sta->sta.addr);
  			WARN_ON(__sta_info_destroy(sta));
  		}
  	}
@@@ -962,17 -948,10 +962,17 @@@ static void clear_sta_ps_flags(void *_s
  {
  	struct sta_info *sta = _sta;
  	struct ieee80211_sub_if_data *sdata = sta->sdata;
 +	struct ps_data *ps;
 +
 +	if (sdata->vif.type == NL80211_IFTYPE_AP ||
 +	    sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
 +		ps = &sdata->bss->ps;
 +	else
 +		return;
  
  	clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
  	if (test_and_clear_sta_flag(sta, WLAN_STA_PS_STA))
 -		atomic_dec(&sdata->bss->num_sta_ps);
 +		atomic_dec(&ps->num_sta_ps);
  }
  
  /* powersave support code */
@@@ -982,6 -961,7 +982,7 @@@ void ieee80211_sta_ps_deliver_wakeup(st
  	struct ieee80211_local *local = sdata->local;
  	struct sk_buff_head pending;
  	int filtered = 0, buffered = 0, ac;
+ 	unsigned long flags;
  
  	clear_sta_flag(sta, WLAN_STA_SP);
  
@@@ -997,12 -977,16 +998,16 @@@
  	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
  		int count = skb_queue_len(&pending), tmp;
  
+ 		spin_lock_irqsave(&sta->tx_filtered[ac].lock, flags);
  		skb_queue_splice_tail_init(&sta->tx_filtered[ac], &pending);
+ 		spin_unlock_irqrestore(&sta->tx_filtered[ac].lock, flags);
  		tmp = skb_queue_len(&pending);
  		filtered += tmp - count;
  		count = tmp;
  
+ 		spin_lock_irqsave(&sta->ps_tx_buf[ac].lock, flags);
  		skb_queue_splice_tail_init(&sta->ps_tx_buf[ac], &pending);
+ 		spin_unlock_irqrestore(&sta->ps_tx_buf[ac].lock, flags);
  		tmp = skb_queue_len(&pending);
  		buffered += tmp - count;
  	}
@@@ -1029,7 -1013,6 +1034,7 @@@ static void ieee80211_send_null_respons
  	__le16 fc;
  	bool qos = test_sta_flag(sta, WLAN_STA_WME);
  	struct ieee80211_tx_info *info;
 +	struct ieee80211_chanctx_conf *chanctx_conf;
  
  	if (qos) {
  		fc = cpu_to_le16(IEEE80211_FTYPE_DATA |
@@@ -1079,16 -1062,7 +1084,16 @@@
  
  	drv_allow_buffered_frames(local, sta, BIT(tid), 1, reason, false);
  
 -	ieee80211_xmit(sdata, skb);
 +	rcu_read_lock();
 +	chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
 +	if (WARN_ON(!chanctx_conf)) {
 +		rcu_read_unlock();
 +		kfree_skb(skb);
 +		return;
 +	}
 +
 +	ieee80211_xmit(sdata, skb, chanctx_conf->channel->band);
 +	rcu_read_unlock();
  }
  
  static void
diff --combined net/mac80211/status.c
index 21fa5c7,101eb88..2482478
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@@ -189,31 -189,30 +189,31 @@@ static void ieee80211_frame_acked(struc
  	}
  
  	if (ieee80211_is_action(mgmt->frame_control) &&
 -	    sdata->vif.type == NL80211_IFTYPE_STATION &&
  	    mgmt->u.action.category == WLAN_CATEGORY_HT &&
 -	    mgmt->u.action.u.ht_smps.action == WLAN_HT_ACTION_SMPS) {
 +	    mgmt->u.action.u.ht_smps.action == WLAN_HT_ACTION_SMPS &&
 +	    sdata->vif.type == NL80211_IFTYPE_STATION &&
 +	    ieee80211_sdata_running(sdata)) {
  		/*
  		 * This update looks racy, but isn't -- if we come
  		 * here we've definitely got a station that we're
  		 * talking to, and on a managed interface that can
  		 * only be the AP. And the only other place updating
 -		 * this variable is before we're associated.
 +		 * this variable in managed mode is before association.
  		 */
  		switch (mgmt->u.action.u.ht_smps.smps_control) {
  		case WLAN_HT_SMPS_CONTROL_DYNAMIC:
 -			sta->sdata->u.mgd.ap_smps = IEEE80211_SMPS_DYNAMIC;
 +			sdata->smps_mode = IEEE80211_SMPS_DYNAMIC;
  			break;
  		case WLAN_HT_SMPS_CONTROL_STATIC:
 -			sta->sdata->u.mgd.ap_smps = IEEE80211_SMPS_STATIC;
 +			sdata->smps_mode = IEEE80211_SMPS_STATIC;
  			break;
  		case WLAN_HT_SMPS_CONTROL_DISABLED:
  		default: /* shouldn't happen since we don't send that */
 -			sta->sdata->u.mgd.ap_smps = IEEE80211_SMPS_OFF;
 +			sdata->smps_mode = IEEE80211_SMPS_OFF;
  			break;
  		}
  
 -		ieee80211_queue_work(&local->hw, &local->recalc_smps);
 +		ieee80211_queue_work(&local->hw, &sdata->recalc_smps);
  	}
  }
  
@@@ -669,3 -668,12 +669,12 @@@ void ieee80211_free_txskb(struct ieee80
  	dev_kfree_skb_any(skb);
  }
  EXPORT_SYMBOL(ieee80211_free_txskb);
+ 
+ void ieee80211_purge_tx_queue(struct ieee80211_hw *hw,
+ 			      struct sk_buff_head *skbs)
+ {
+ 	struct sk_buff *skb;
+ 
+ 	while ((skb = __skb_dequeue(skbs)))
+ 		ieee80211_free_txskb(hw, skb);
+ }
diff --combined net/mac80211/tx.c
index 065f81c,b858ebe..6f19818
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@@ -324,20 -324,22 +324,20 @@@ static void purge_old_ps_buffers(struc
  	struct ieee80211_sub_if_data *sdata;
  	struct sta_info *sta;
  
 -	/*
 -	 * virtual interfaces are protected by RCU
 -	 */
 -	rcu_read_lock();
 -
  	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
 -		struct ieee80211_if_ap *ap;
 -		if (sdata->vif.type != NL80211_IFTYPE_AP)
 +		struct ps_data *ps;
 +
 +		if (sdata->vif.type == NL80211_IFTYPE_AP)
 +			ps = &sdata->u.ap.ps;
 +		else
  			continue;
 -		ap = &sdata->u.ap;
 -		skb = skb_dequeue(&ap->ps_bc_buf);
 +
 +		skb = skb_dequeue(&ps->bc_buf);
  		if (skb) {
  			purged++;
  			dev_kfree_skb(skb);
  		}
 -		total += skb_queue_len(&ap->ps_bc_buf);
 +		total += skb_queue_len(&ps->bc_buf);
  	}
  
  	/*
@@@ -358,6 -360,8 +358,6 @@@
  		}
  	}
  
 -	rcu_read_unlock();
 -
  	local->total_ps_buffered = total;
  	ps_dbg_hw(&local->hw, "PS buffers full - purged %d frames\n", purged);
  }
@@@ -367,7 -371,6 +367,7 @@@ ieee80211_tx_h_multicast_ps_buf(struct 
  {
  	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
 +	struct ps_data *ps;
  
  	/*
  	 * broadcast/multicast frame
@@@ -377,24 -380,16 +377,24 @@@
  	 * This is done either by the hardware or us.
  	 */
  
 -	/* powersaving STAs only in AP/VLAN mode */
 -	if (!tx->sdata->bss)
 +	/* powersaving STAs currently only in AP/VLAN mode */
 +	if (tx->sdata->vif.type == NL80211_IFTYPE_AP ||
 +	    tx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
 +		if (!tx->sdata->bss)
 +			return TX_CONTINUE;
 +
 +		ps = &tx->sdata->bss->ps;
 +	} else {
  		return TX_CONTINUE;
 +	}
 +
  
  	/* no buffering for ordered frames */
  	if (ieee80211_has_order(hdr->frame_control))
  		return TX_CONTINUE;
  
  	/* no stations in PS mode */
 -	if (!atomic_read(&tx->sdata->bss->num_sta_ps))
 +	if (!atomic_read(&ps->num_sta_ps))
  		return TX_CONTINUE;
  
  	info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM;
@@@ -409,14 -404,14 +409,14 @@@
  	if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
  		purge_old_ps_buffers(tx->local);
  
 -	if (skb_queue_len(&tx->sdata->bss->ps_bc_buf) >= AP_MAX_BC_BUFFER) {
 +	if (skb_queue_len(&ps->bc_buf) >= AP_MAX_BC_BUFFER) {
  		ps_dbg(tx->sdata,
  		       "BC TX buffer full - dropping the oldest frame\n");
 -		dev_kfree_skb(skb_dequeue(&tx->sdata->bss->ps_bc_buf));
 +		dev_kfree_skb(skb_dequeue(&ps->bc_buf));
  	} else
  		tx->local->total_ps_buffered++;
  
 -	skb_queue_tail(&tx->sdata->bss->ps_bc_buf, tx->skb);
 +	skb_queue_tail(&ps->bc_buf, tx->skb);
  
  	return TX_QUEUED;
  }
@@@ -956,6 -951,7 +956,6 @@@ ieee80211_tx_h_fragment(struct ieee8021
  	fragnum = 0;
  
  	skb_queue_walk(&tx->skbs, skb) {
 -		int next_len;
  		const __le16 morefrags = cpu_to_le16(IEEE80211_FCTL_MOREFRAGS);
  
  		hdr = (void *)skb->data;
@@@ -974,6 -970,7 +974,6 @@@
  			info->flags &= ~IEEE80211_TX_CTL_RATE_CTRL_PROBE;
  		} else {
  			hdr->frame_control &= ~morefrags;
 -			next_len = 0;
  		}
  		hdr->seq_ctrl |= cpu_to_le16(fragnum & IEEE80211_SCTL_FRAG);
  		fragnum++;
@@@ -1361,7 -1358,7 +1361,7 @@@ static int invoke_tx_handlers(struct ie
  		if (tx->skb)
  			ieee80211_free_txskb(&tx->local->hw, tx->skb);
  		else
- 			__skb_queue_purge(&tx->skbs);
+ 			ieee80211_purge_tx_queue(&tx->local->hw, &tx->skbs);
  		return -1;
  	} else if (unlikely(res == TX_QUEUED)) {
  		I802_DEBUG_INC(tx->local->tx_handlers_queued);
@@@ -1375,8 -1372,7 +1375,8 @@@
   * Returns false if the frame couldn't be transmitted but was queued instead.
   */
  static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata,
 -			 struct sk_buff *skb, bool txpending)
 +			 struct sk_buff *skb, bool txpending,
 +			 enum ieee80211_band band)
  {
  	struct ieee80211_local *local = sdata->local;
  	struct ieee80211_tx_data tx;
@@@ -1390,18 -1386,20 +1390,18 @@@
  		return true;
  	}
  
 -	rcu_read_lock();
 -
  	/* initialises tx */
  	led_len = skb->len;
  	res_prepare = ieee80211_tx_prepare(sdata, &tx, skb);
  
  	if (unlikely(res_prepare == TX_DROP)) {
  		ieee80211_free_txskb(&local->hw, skb);
 -		goto out;
 +		return true;
  	} else if (unlikely(res_prepare == TX_QUEUED)) {
 -		goto out;
 +		return true;
  	}
  
 -	info->band = local->hw.conf.channel->band;
 +	info->band = band;
  
  	/* set up hw_queue value early */
  	if (!(info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) ||
@@@ -1412,7 -1410,8 +1412,7 @@@
  	if (!invoke_tx_handlers(&tx))
  		result = __ieee80211_tx(local, &tx.skbs, led_len,
  					tx.sta, txpending);
 - out:
 -	rcu_read_unlock();
 +
  	return result;
  }
  
@@@ -1447,8 -1446,7 +1447,8 @@@ static int ieee80211_skb_resize(struct 
  	return 0;
  }
  
 -void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
 +void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
 +		    enum ieee80211_band band)
  {
  	struct ieee80211_local *local = sdata->local;
  	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@@ -1456,6 -1454,8 +1456,6 @@@
  	int headroom;
  	bool may_encrypt;
  
 -	rcu_read_lock();
 -
  	may_encrypt = !(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT);
  
  	headroom = local->tx_headroom;
@@@ -1466,6 -1466,7 +1466,6 @@@
  
  	if (ieee80211_skb_resize(sdata, skb, headroom, may_encrypt)) {
  		ieee80211_free_txskb(&local->hw, skb);
 -		rcu_read_unlock();
  		return;
  	}
  
@@@ -1477,11 -1478,13 +1477,11 @@@
  	    !is_multicast_ether_addr(hdr->addr1) &&
  	    mesh_nexthop_resolve(skb, sdata)) {
  		/* skb queued: don't free */
 -		rcu_read_unlock();
  		return;
  	}
  
  	ieee80211_set_qos_hdr(sdata, skb);
 -	ieee80211_tx(sdata, skb, false);
 -	rcu_read_unlock();
 +	ieee80211_tx(sdata, skb, false, band);
  }
  
  static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb)
@@@ -1571,8 -1574,7 +1571,8 @@@ netdev_tx_t ieee80211_monitor_start_xmi
  					 struct net_device *dev)
  {
  	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 -	struct ieee80211_channel *chan = local->hw.conf.channel;
 +	struct ieee80211_chanctx_conf *chanctx_conf;
 +	struct ieee80211_channel *chan;
  	struct ieee80211_radiotap_header *prthdr =
  		(struct ieee80211_radiotap_header *)skb->data;
  	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@@ -1581,6 -1583,26 +1581,6 @@@
  	u16 len_rthdr;
  	int hdrlen;
  
 -	/*
 -	 * Frame injection is not allowed if beaconing is not allowed
 -	 * or if we need radar detection. Beaconing is usually not allowed when
 -	 * the mode or operation (Adhoc, AP, Mesh) does not support DFS.
 -	 * Passive scan is also used in world regulatory domains where
 -	 * your country is not known and as such it should be treated as
 -	 * NO TX unless the channel is explicitly allowed in which case
 -	 * your current regulatory domain would not have the passive scan
 -	 * flag.
 -	 *
 -	 * Since AP mode uses monitor interfaces to inject/TX management
 -	 * frames we can make AP mode the exception to this rule once it
 -	 * supports radar detection as its implementation can deal with
 -	 * radar detection by itself. We can do that later by adding a
 -	 * monitor flag interfaces used for AP support.
 -	 */
 -	if ((chan->flags & (IEEE80211_CHAN_NO_IBSS | IEEE80211_CHAN_RADAR |
 -	     IEEE80211_CHAN_PASSIVE_SCAN)))
 -		goto fail;
 -
  	/* check for not even having the fixed radiotap header part */
  	if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header)))
  		goto fail; /* too short to be possibly valid */
@@@ -1666,45 -1688,11 +1666,45 @@@
  		}
  	}
  
 -	ieee80211_xmit(sdata, skb);
 +	chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
 +	if (!chanctx_conf) {
 +		tmp_sdata = rcu_dereference(local->monitor_sdata);
 +		if (tmp_sdata)
 +			chanctx_conf =
 +				rcu_dereference(tmp_sdata->vif.chanctx_conf);
 +	}
 +	if (!chanctx_conf)
 +		goto fail_rcu;
 +
 +	chan = chanctx_conf->channel;
 +
 +	/*
 +	 * Frame injection is not allowed if beaconing is not allowed
 +	 * or if we need radar detection. Beaconing is usually not allowed when
 +	 * the mode or operation (Adhoc, AP, Mesh) does not support DFS.
 +	 * Passive scan is also used in world regulatory domains where
 +	 * your country is not known and as such it should be treated as
 +	 * NO TX unless the channel is explicitly allowed in which case
 +	 * your current regulatory domain would not have the passive scan
 +	 * flag.
 +	 *
 +	 * Since AP mode uses monitor interfaces to inject/TX management
 +	 * frames we can make AP mode the exception to this rule once it
 +	 * supports radar detection as its implementation can deal with
 +	 * radar detection by itself. We can do that later by adding a
 +	 * monitor flag interfaces used for AP support.
 +	 */
 +	if ((chan->flags & (IEEE80211_CHAN_NO_IBSS | IEEE80211_CHAN_RADAR |
 +			    IEEE80211_CHAN_PASSIVE_SCAN)))
 +		goto fail_rcu;
 +
 +	ieee80211_xmit(sdata, skb, chan->band);
  	rcu_read_unlock();
  
  	return NETDEV_TX_OK;
  
 +fail_rcu:
 +	rcu_read_unlock();
  fail:
  	dev_kfree_skb(skb);
  	return NETDEV_TX_OK; /* meaning, we dealt with the skb */
@@@ -1746,9 -1734,6 +1746,9 @@@ netdev_tx_t ieee80211_subif_start_xmit(
  	bool multicast;
  	u32 info_flags = 0;
  	u16 info_id = 0;
 +	struct ieee80211_chanctx_conf *chanctx_conf;
 +	struct ieee80211_sub_if_data *ap_sdata;
 +	enum ieee80211_band band;
  
  	if (unlikely(skb->len < ETH_HLEN))
  		goto fail;
@@@ -1758,10 -1743,9 +1758,10 @@@
  	ethertype = (skb->data[12] << 8) | skb->data[13];
  	fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA);
  
 +	rcu_read_lock();
 +
  	switch (sdata->vif.type) {
  	case NL80211_IFTYPE_AP_VLAN:
 -		rcu_read_lock();
  		sta = rcu_dereference(sdata->u.vlan.sta);
  		if (sta) {
  			fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
@@@ -1774,12 -1758,7 +1774,12 @@@
  			authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
  			wme_sta = test_sta_flag(sta, WLAN_STA_WME);
  		}
 -		rcu_read_unlock();
 +		ap_sdata = container_of(sdata->bss, struct ieee80211_sub_if_data,
 +					u.ap);
 +		chanctx_conf = rcu_dereference(ap_sdata->vif.chanctx_conf);
 +		if (!chanctx_conf)
 +			goto fail_rcu;
 +		band = chanctx_conf->channel->band;
  		if (sta)
  			break;
  		/* fall through */
@@@ -1790,11 -1769,6 +1790,11 @@@
  		memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN);
  		memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN);
  		hdrlen = 24;
 +		if (sdata->vif.type == NL80211_IFTYPE_AP)
 +			chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
 +		if (!chanctx_conf)
 +			goto fail_rcu;
 +		band = chanctx_conf->channel->band;
  		break;
  	case NL80211_IFTYPE_WDS:
  		fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
@@@ -1804,20 -1778,15 +1804,20 @@@
  		memcpy(hdr.addr3, skb->data, ETH_ALEN);
  		memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
  		hdrlen = 30;
 +		/*
 +		 * This is the exception! WDS style interfaces are prohibited
 +		 * when channel contexts are in used so this must be valid
 +		 */
 +		band = local->hw.conf.channel->band;
  		break;
  #ifdef CONFIG_MAC80211_MESH
  	case NL80211_IFTYPE_MESH_POINT:
  		if (!sdata->u.mesh.mshcfg.dot11MeshTTL) {
  			/* Do not send frames with mesh_ttl == 0 */
  			sdata->u.mesh.mshstats.dropped_frames_ttl++;
 -			goto fail;
 +			goto fail_rcu;
  		}
 -		rcu_read_lock();
 +
  		if (!is_multicast_ether_addr(skb->data)) {
  			mpath = mesh_path_lookup(skb->data, sdata);
  			if (!mpath)
@@@ -1834,6 -1803,7 +1834,6 @@@
  		    !(mppath && !ether_addr_equal(mppath->mpp, skb->data))) {
  			hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc,
  					skb->data, skb->data + ETH_ALEN);
 -			rcu_read_unlock();
  			meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr,
  					sdata, NULL, NULL);
  		} else {
@@@ -1849,6 -1819,7 +1849,6 @@@
  				mesh_da = mppath->mpp;
  			else if (mpath)
  				mesh_da = mpath->dst;
 -			rcu_read_unlock();
  
  			hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc,
  					mesh_da, sdata->vif.addr);
@@@ -1868,16 -1839,13 +1868,16 @@@
  							skb->data + ETH_ALEN);
  
  		}
 +		chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
 +		if (!chanctx_conf)
 +			goto fail_rcu;
 +		band = chanctx_conf->channel->band;
  		break;
  #endif
  	case NL80211_IFTYPE_STATION:
  		if (sdata->wdev.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) {
  			bool tdls_peer = false;
  
 -			rcu_read_lock();
  			sta = sta_info_get(sdata, skb->data);
  			if (sta) {
  				authorized = test_sta_flag(sta,
@@@ -1888,6 -1856,7 +1888,6 @@@
  				tdls_auth = test_sta_flag(sta,
  						WLAN_STA_TDLS_PEER_AUTH);
  			}
 -			rcu_read_unlock();
  
  			/*
  			 * If the TDLS link is enabled, send everything
@@@ -1902,7 -1871,7 +1902,7 @@@
  		if (tdls_direct) {
  			/* link during setup - throw out frames to peer */
  			if (!tdls_auth)
 -				goto fail;
 +				goto fail_rcu;
  
  			/* DA SA BSSID */
  			memcpy(hdr.addr1, skb->data, ETH_ALEN);
@@@ -1927,10 -1896,6 +1927,10 @@@
  			memcpy(hdr.addr3, skb->data, ETH_ALEN);
  			hdrlen = 24;
  		}
 +		chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
 +		if (!chanctx_conf)
 +			goto fail_rcu;
 +		band = chanctx_conf->channel->band;
  		break;
  	case NL80211_IFTYPE_ADHOC:
  		/* DA SA BSSID */
@@@ -1938,13 -1903,9 +1938,13 @@@
  		memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
  		memcpy(hdr.addr3, sdata->u.ibss.bssid, ETH_ALEN);
  		hdrlen = 24;
 +		chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
 +		if (!chanctx_conf)
 +			goto fail_rcu;
 +		band = chanctx_conf->channel->band;
  		break;
  	default:
 -		goto fail;
 +		goto fail_rcu;
  	}
  
  	/*
@@@ -1954,11 -1915,13 +1954,11 @@@
  	 */
  	multicast = is_multicast_ether_addr(hdr.addr1);
  	if (!multicast) {
 -		rcu_read_lock();
  		sta = sta_info_get(sdata, hdr.addr1);
  		if (sta) {
  			authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
  			wme_sta = test_sta_flag(sta, WLAN_STA_WME);
  		}
 -		rcu_read_unlock();
  	}
  
  	/* For mesh, the use of the QoS header is mandatory */
@@@ -1986,7 -1949,7 +1986,7 @@@
  
  		I802_DEBUG_INC(local->tx_handlers_drop_unauth_port);
  
 -		goto fail;
 +		goto fail_rcu;
  	}
  
  	if (unlikely(!multicast && skb->sk &&
@@@ -2041,7 -2004,7 +2041,7 @@@
  		kfree_skb(tmp_skb);
  
  		if (!skb)
 -			goto fail;
 +			goto fail_rcu;
  	}
  
  	hdr.frame_control = fc;
@@@ -2089,7 -2052,7 +2089,7 @@@
  		head_need = max_t(int, 0, head_need);
  		if (ieee80211_skb_resize(sdata, skb, head_need, true)) {
  			ieee80211_free_txskb(&local->hw, skb);
 -			return NETDEV_TX_OK;
 +			goto fail_rcu;
  		}
  	}
  
@@@ -2141,13 -2104,10 +2141,13 @@@
  	info->flags = info_flags;
  	info->ack_frame_id = info_id;
  
 -	ieee80211_xmit(sdata, skb);
 +	ieee80211_xmit(sdata, skb, band);
 +	rcu_read_unlock();
  
  	return NETDEV_TX_OK;
  
 + fail_rcu:
 +	rcu_read_unlock();
   fail:
  	dev_kfree_skb(skb);
  	return NETDEV_TX_OK;
@@@ -2160,10 -2120,13 +2160,13 @@@
   */
  void ieee80211_clear_tx_pending(struct ieee80211_local *local)
  {
+ 	struct sk_buff *skb;
  	int i;
  
- 	for (i = 0; i < local->hw.queues; i++)
- 		skb_queue_purge(&local->pending[i]);
+ 	for (i = 0; i < local->hw.queues; i++) {
+ 		while ((skb = skb_dequeue(&local->pending[i])) != NULL)
+ 			ieee80211_free_txskb(&local->hw, skb);
+ 	}
  }
  
  /*
@@@ -2179,18 -2142,11 +2182,18 @@@ static bool ieee80211_tx_pending_skb(st
  	struct sta_info *sta;
  	struct ieee80211_hdr *hdr;
  	bool result;
 +	struct ieee80211_chanctx_conf *chanctx_conf;
  
  	sdata = vif_to_sdata(info->control.vif);
  
  	if (info->flags & IEEE80211_TX_INTFL_NEED_TXPROCESSING) {
 -		result = ieee80211_tx(sdata, skb, true);
 +		chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
 +		if (unlikely(!chanctx_conf)) {
 +			dev_kfree_skb(skb);
 +			return true;
 +		}
 +		result = ieee80211_tx(sdata, skb, true,
 +				      chanctx_conf->channel->band);
  	} else {
  		struct sk_buff_head skbs;
  
@@@ -2258,8 -2214,9 +2261,8 @@@ void ieee80211_tx_pending(unsigned lon
  /* functions for drivers to get certain frames */
  
  static void ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
 -				     struct ieee80211_if_ap *bss,
 -				     struct sk_buff *skb,
 -				     struct beacon_data *beacon)
 +				     struct ps_data *ps,
 +				     struct sk_buff *skb)
  {
  	u8 *pos, *tim;
  	int aid0 = 0;
@@@ -2267,27 -2224,27 +2270,27 @@@
  
  	/* Generate bitmap for TIM only if there are any STAs in power save
  	 * mode. */
 -	if (atomic_read(&bss->num_sta_ps) > 0)
 +	if (atomic_read(&ps->num_sta_ps) > 0)
  		/* in the hope that this is faster than
  		 * checking byte-for-byte */
 -		have_bits = !bitmap_empty((unsigned long*)bss->tim,
 +		have_bits = !bitmap_empty((unsigned long*)ps->tim,
  					  IEEE80211_MAX_AID+1);
  
 -	if (bss->dtim_count == 0)
 -		bss->dtim_count = sdata->vif.bss_conf.dtim_period - 1;
 +	if (ps->dtim_count == 0)
 +		ps->dtim_count = sdata->vif.bss_conf.dtim_period - 1;
  	else
 -		bss->dtim_count--;
 +		ps->dtim_count--;
  
  	tim = pos = (u8 *) skb_put(skb, 6);
  	*pos++ = WLAN_EID_TIM;
  	*pos++ = 4;
 -	*pos++ = bss->dtim_count;
 +	*pos++ = ps->dtim_count;
  	*pos++ = sdata->vif.bss_conf.dtim_period;
  
 -	if (bss->dtim_count == 0 && !skb_queue_empty(&bss->ps_bc_buf))
 +	if (ps->dtim_count == 0 && !skb_queue_empty(&ps->bc_buf))
  		aid0 = 1;
  
 -	bss->dtim_bc_mc = aid0 == 1;
 +	ps->dtim_bc_mc = aid0 == 1;
  
  	if (have_bits) {
  		/* Find largest even number N1 so that bits numbered 1 through
@@@ -2295,14 -2252,14 +2298,14 @@@
  		 * (N2 + 1) x 8 through 2007 are 0. */
  		n1 = 0;
  		for (i = 0; i < IEEE80211_MAX_TIM_LEN; i++) {
 -			if (bss->tim[i]) {
 +			if (ps->tim[i]) {
  				n1 = i & 0xfe;
  				break;
  			}
  		}
  		n2 = n1;
  		for (i = IEEE80211_MAX_TIM_LEN - 1; i >= n1; i--) {
 -			if (bss->tim[i]) {
 +			if (ps->tim[i]) {
  				n2 = i;
  				break;
  			}
@@@ -2312,7 -2269,7 +2315,7 @@@
  		*pos++ = n1 | aid0;
  		/* Part Virt Bitmap */
  		skb_put(skb, n2 - n1);
 -		memcpy(pos, bss->tim + n1, n2 - n1 + 1);
 +		memcpy(pos, ps->tim + n1, n2 - n1 + 1);
  
  		tim[1] = n2 - n1 + 4;
  	} else {
@@@ -2329,16 -2286,16 +2332,16 @@@ struct sk_buff *ieee80211_beacon_get_ti
  	struct sk_buff *skb = NULL;
  	struct ieee80211_tx_info *info;
  	struct ieee80211_sub_if_data *sdata = NULL;
 -	struct ieee80211_if_ap *ap = NULL;
 -	struct beacon_data *beacon;
 -	enum ieee80211_band band = local->oper_channel->band;
 +	enum ieee80211_band band;
  	struct ieee80211_tx_rate_control txrc;
 +	struct ieee80211_chanctx_conf *chanctx_conf;
  
  	rcu_read_lock();
  
  	sdata = vif_to_sdata(vif);
 +	chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
  
 -	if (!ieee80211_sdata_running(sdata))
 +	if (!ieee80211_sdata_running(sdata) || !chanctx_conf)
  		goto out;
  
  	if (tim_offset)
@@@ -2347,9 -2304,8 +2350,9 @@@
  		*tim_length = 0;
  
  	if (sdata->vif.type == NL80211_IFTYPE_AP) {
 -		ap = &sdata->u.ap;
 -		beacon = rcu_dereference(ap->beacon);
 +		struct ieee80211_if_ap *ap = &sdata->u.ap;
 +		struct beacon_data *beacon = rcu_dereference(ap->beacon);
 +
  		if (beacon) {
  			/*
  			 * headroom, head length,
@@@ -2373,12 -2329,14 +2376,12 @@@
  			 * of the tim bitmap in mac80211 and the driver.
  			 */
  			if (local->tim_in_locked_section) {
 -				ieee80211_beacon_add_tim(sdata, ap, skb,
 -							 beacon);
 +				ieee80211_beacon_add_tim(sdata, &ap->ps, skb);
  			} else {
  				unsigned long flags;
  
  				spin_lock_irqsave(&local->tim_lock, flags);
 -				ieee80211_beacon_add_tim(sdata, ap, skb,
 -							 beacon);
 +				ieee80211_beacon_add_tim(sdata, &ap->ps, skb);
  				spin_unlock_irqrestore(&local->tim_lock, flags);
  			}
  
@@@ -2454,8 -2412,6 +2457,8 @@@
  		*pos++ = WLAN_EID_SSID;
  		*pos++ = 0x0;
  
 +		band = chanctx_conf->channel->band;
 +
  		if (ieee80211_add_srates_ie(sdata, skb, true, band) ||
  		    mesh_add_ds_params_ie(skb, sdata) ||
  		    ieee80211_add_ext_srates_ie(sdata, skb, true, band) ||
@@@ -2473,8 -2429,6 +2476,8 @@@
  		goto out;
  	}
  
 +	band = chanctx_conf->channel->band;
 +
  	info = IEEE80211_SKB_CB(skb);
  
  	info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
@@@ -2702,40 -2656,29 +2705,40 @@@ ieee80211_get_buffered_bc(struct ieee80
  	struct sk_buff *skb = NULL;
  	struct ieee80211_tx_data tx;
  	struct ieee80211_sub_if_data *sdata;
 -	struct ieee80211_if_ap *bss = NULL;
 -	struct beacon_data *beacon;
 +	struct ps_data *ps;
  	struct ieee80211_tx_info *info;
 +	struct ieee80211_chanctx_conf *chanctx_conf;
  
  	sdata = vif_to_sdata(vif);
 -	bss = &sdata->u.ap;
  
  	rcu_read_lock();
 -	beacon = rcu_dereference(bss->beacon);
 +	chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
  
 -	if (sdata->vif.type != NL80211_IFTYPE_AP || !beacon || !beacon->head)
 +	if (!chanctx_conf)
  		goto out;
  
 -	if (bss->dtim_count != 0 || !bss->dtim_bc_mc)
 +	if (sdata->vif.type == NL80211_IFTYPE_AP) {
 +		struct beacon_data *beacon =
 +				rcu_dereference(sdata->u.ap.beacon);
 +
 +		if (!beacon || !beacon->head)
 +			goto out;
 +
 +		ps = &sdata->u.ap.ps;
 +	} else {
 +		goto out;
 +	}
 +
 +	if (ps->dtim_count != 0 || !ps->dtim_bc_mc)
  		goto out; /* send buffered bc/mc only after DTIM beacon */
  
  	while (1) {
 -		skb = skb_dequeue(&bss->ps_bc_buf);
 +		skb = skb_dequeue(&ps->bc_buf);
  		if (!skb)
  			goto out;
  		local->total_ps_buffered--;
  
 -		if (!skb_queue_empty(&bss->ps_bc_buf) && skb->len >= 2) {
 +		if (!skb_queue_empty(&ps->bc_buf) && skb->len >= 2) {
  			struct ieee80211_hdr *hdr =
  				(struct ieee80211_hdr *) skb->data;
  			/* more buffered multicast/broadcast frames ==> set
@@@ -2753,7 -2696,7 +2756,7 @@@
  	info = IEEE80211_SKB_CB(skb);
  
  	tx.flags |= IEEE80211_TX_PS_BUFFERED;
 -	info->band = local->oper_channel->band;
 +	info->band = chanctx_conf->channel->band;
  
  	if (invoke_tx_handlers(&tx))
  		skb = NULL;
@@@ -2764,9 -2707,8 +2767,9 @@@
  }
  EXPORT_SYMBOL(ieee80211_get_buffered_bc);
  
 -void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata,
 -			  struct sk_buff *skb, int tid)
 +void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
 +				 struct sk_buff *skb, int tid,
 +				 enum ieee80211_band band)
  {
  	int ac = ieee802_1d_to_ac[tid & 7];
  
@@@ -2783,6 -2725,6 +2786,6 @@@
  	 * requirements are that we do not come into tx with bhs on.
  	 */
  	local_bh_disable();
 -	ieee80211_xmit(sdata, skb);
 +	ieee80211_xmit(sdata, skb, band);
  	local_bh_enable();
  }
diff --combined net/mac80211/util.c
index 9556391,0151ae3..acbb8c9
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@@ -769,18 -769,6 +769,18 @@@ u32 ieee802_11_parse_elems_crc(u8 *star
  			else
  				elem_parse_failed = true;
  			break;
 +		case WLAN_EID_VHT_CAPABILITY:
 +			if (elen >= sizeof(struct ieee80211_vht_cap))
 +				elems->vht_cap_elem = (void *)pos;
 +			else
 +				elem_parse_failed = true;
 +			break;
 +		case WLAN_EID_VHT_OPERATION:
 +			if (elen >= sizeof(struct ieee80211_vht_operation))
 +				elems->vht_operation = (void *)pos;
 +			else
 +				elem_parse_failed = true;
 +			break;
  		case WLAN_EID_MESH_ID:
  			elems->mesh_id = pos;
  			elems->mesh_id_len = elen;
@@@ -849,7 -837,7 +849,7 @@@
  		if (elem_parse_failed)
  			elems->parse_error = true;
  		else
 -			set_bit(id, seen_elems);
 +			__set_bit(id, seen_elems);
  
  		left -= elen;
  		pos += elen;
@@@ -872,7 -860,6 +872,7 @@@ void ieee80211_set_wmm_default(struct i
  {
  	struct ieee80211_local *local = sdata->local;
  	struct ieee80211_tx_queue_params qparam;
 +	struct ieee80211_chanctx_conf *chanctx_conf;
  	int ac;
  	bool use_11b, enable_qos;
  	int aCWmin, aCWmax;
@@@ -885,12 -872,8 +885,12 @@@
  
  	memset(&qparam, 0, sizeof(qparam));
  
 -	use_11b = (local->oper_channel->band == IEEE80211_BAND_2GHZ) &&
 +	rcu_read_lock();
 +	chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
 +	use_11b = (chanctx_conf &&
 +		   chanctx_conf->channel->band == IEEE80211_BAND_2GHZ) &&
  		 !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE);
 +	rcu_read_unlock();
  
  	/*
  	 * By default disable QoS in STA mode for old access points, which do
@@@ -969,7 -952,7 +969,7 @@@ void ieee80211_sta_def_wmm_params(struc
  				  const size_t supp_rates_len,
  				  const u8 *supp_rates)
  {
 -	struct ieee80211_local *local = sdata->local;
 +	struct ieee80211_chanctx_conf *chanctx_conf;
  	int i, have_higher_than_11mbit = 0;
  
  	/* cf. IEEE 802.11 9.2.12 */
@@@ -977,16 -960,11 +977,16 @@@
  		if ((supp_rates[i] & 0x7f) * 5 > 110)
  			have_higher_than_11mbit = 1;
  
 -	if (local->oper_channel->band == IEEE80211_BAND_2GHZ &&
 +	rcu_read_lock();
 +	chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
 +
 +	if (chanctx_conf &&
 +	    chanctx_conf->channel->band == IEEE80211_BAND_2GHZ &&
  	    have_higher_than_11mbit)
  		sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
  	else
  		sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
 +	rcu_read_unlock();
  
  	ieee80211_set_wmm_default(sdata, true);
  }
@@@ -1018,7 -996,7 +1018,7 @@@ u32 ieee80211_mandatory_rates(struct ie
  }
  
  void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
 -			 u16 transaction, u16 auth_alg,
 +			 u16 transaction, u16 auth_alg, u16 status,
  			 u8 *extra, size_t extra_len, const u8 *da,
  			 const u8 *bssid, const u8 *key, u8 key_len, u8 key_idx)
  {
@@@ -1043,7 -1021,7 +1043,7 @@@
  	memcpy(mgmt->bssid, bssid, ETH_ALEN);
  	mgmt->u.auth.auth_alg = cpu_to_le16(auth_alg);
  	mgmt->u.auth.auth_transaction = cpu_to_le16(transaction);
 -	mgmt->u.auth.status_code = cpu_to_le16(0);
 +	mgmt->u.auth.status_code = cpu_to_le16(status);
  	if (extra)
  		memcpy(skb_put(skb, extra_len), extra, extra_len);
  
@@@ -1256,7 -1234,7 +1256,7 @@@ void ieee80211_send_probe_req(struct ie
  			      const u8 *ssid, size_t ssid_len,
  			      const u8 *ie, size_t ie_len,
  			      u32 ratemask, bool directed, bool no_cck,
 -			      struct ieee80211_channel *channel)
 +			      struct ieee80211_channel *channel, bool scan)
  {
  	struct sk_buff *skb;
  
@@@ -1267,10 -1245,7 +1267,10 @@@
  		if (no_cck)
  			IEEE80211_SKB_CB(skb)->flags |=
  				IEEE80211_TX_CTL_NO_CCK_RATE;
 -		ieee80211_tx_skb(sdata, skb);
 +		if (scan)
 +			ieee80211_tx_skb_tid_band(sdata, skb, 7, channel->band);
 +		else
 +			ieee80211_tx_skb(sdata, skb);
  	}
  }
  
@@@ -1333,7 -1308,6 +1333,7 @@@ int ieee80211_reconfig(struct ieee80211
  {
  	struct ieee80211_hw *hw = &local->hw;
  	struct ieee80211_sub_if_data *sdata;
 +	struct ieee80211_chanctx *ctx;
  	struct sta_info *sta;
  	int res, i;
  
@@@ -1406,12 -1380,6 +1406,12 @@@
  			res = drv_add_interface(local, sdata);
  	}
  
 +	/* add channel contexts */
 +	mutex_lock(&local->chanctx_mtx);
 +	list_for_each_entry(ctx, &local->chanctx_list, list)
 +		WARN_ON(drv_add_chanctx(local, ctx));
 +	mutex_unlock(&local->chanctx_mtx);
 +
  	/* add STAs back */
  	mutex_lock(&local->sta_mtx);
  	list_for_each_entry(sta, &local->sta_list, list) {
@@@ -1452,22 -1420,11 +1452,22 @@@
  
  	/* Finally also reconfigure all the BSS information */
  	list_for_each_entry(sdata, &local->interfaces, list) {
 +		struct ieee80211_chanctx_conf *ctx_conf;
  		u32 changed;
  
  		if (!ieee80211_sdata_running(sdata))
  			continue;
  
 +		mutex_lock(&local->chanctx_mtx);
 +		ctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
 +				lockdep_is_held(&local->chanctx_mtx));
 +		if (ctx_conf) {
 +			ctx = container_of(ctx_conf, struct ieee80211_chanctx,
 +					   conf);
 +			drv_assign_vif_chanctx(local, sdata, ctx);
 +		}
 +		mutex_unlock(&local->chanctx_mtx);
 +
  		/* common change flags for all interface types */
  		changed = BSS_CHANGED_ERP_CTS_PROT |
  			  BSS_CHANGED_ERP_PREAMBLE |
@@@ -1534,6 -1491,8 +1534,8 @@@
  		list_for_each_entry(sdata, &local->interfaces, list) {
  			if (sdata->vif.type != NL80211_IFTYPE_STATION)
  				continue;
+ 			if (!sdata->u.mgd.associated)
+ 				continue;
  
  			ieee80211_send_nullfunc(local, sdata, 0);
  		}
@@@ -1658,24 -1617,68 +1660,24 @@@ void ieee80211_resume_disconnect(struc
  }
  EXPORT_SYMBOL_GPL(ieee80211_resume_disconnect);
  
 -static int check_mgd_smps(struct ieee80211_if_managed *ifmgd,
 -			  enum ieee80211_smps_mode *smps_mode)
 -{
 -	if (ifmgd->associated) {
 -		*smps_mode = ifmgd->ap_smps;
 -
 -		if (*smps_mode == IEEE80211_SMPS_AUTOMATIC) {
 -			if (ifmgd->powersave)
 -				*smps_mode = IEEE80211_SMPS_DYNAMIC;
 -			else
 -				*smps_mode = IEEE80211_SMPS_OFF;
 -		}
 -
 -		return 1;
 -	}
 -
 -	return 0;
 -}
 -
 -void ieee80211_recalc_smps(struct ieee80211_local *local)
 +void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata)
  {
 -	struct ieee80211_sub_if_data *sdata;
 -	enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_OFF;
 -	int count = 0;
 -
 -	mutex_lock(&local->iflist_mtx);
 -
 -	/*
 -	 * This function could be improved to handle multiple
 -	 * interfaces better, but right now it makes any
 -	 * non-station interfaces force SM PS to be turned
 -	 * off. If there are multiple station interfaces it
 -	 * could also use the best possible mode, e.g. if
 -	 * one is in static and the other in dynamic then
 -	 * dynamic is ok.
 -	 */
 -
 -	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;
 +	struct ieee80211_local *local = sdata->local;
 +	struct ieee80211_chanctx_conf *chanctx_conf;
 +	struct ieee80211_chanctx *chanctx;
  
 -		count += check_mgd_smps(&sdata->u.mgd, &smps_mode);
 +	mutex_lock(&local->chanctx_mtx);
  
 -		if (count > 1) {
 -			smps_mode = IEEE80211_SMPS_OFF;
 -			break;
 -		}
 -	}
 +	chanctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
 +					lockdep_is_held(&local->chanctx_mtx));
  
 -	if (smps_mode == local->smps_mode)
 +	if (WARN_ON_ONCE(!chanctx_conf))
  		goto unlock;
  
 - set:
 -	local->smps_mode = smps_mode;
 -	/* changed flag is auto-detected for this */
 -	ieee80211_hw_config(local, 0);
 +	chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
 +	ieee80211_recalc_smps_chanctx(local, chanctx);
   unlock:
 -	mutex_unlock(&local->iflist_mtx);
 +	mutex_unlock(&local->chanctx_mtx);
  }
  
  static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id)
@@@ -1815,8 -1818,8 +1817,8 @@@ u8 *ieee80211_ie_build_vht_cap(u8 *pos
  	__le32 tmp;
  
  	*pos++ = WLAN_EID_VHT_CAPABILITY;
 -	*pos++ = sizeof(struct ieee80211_vht_capabilities);
 -	memset(pos, 0, sizeof(struct ieee80211_vht_capabilities));
 +	*pos++ = sizeof(struct ieee80211_vht_cap);
 +	memset(pos, 0, sizeof(struct ieee80211_vht_cap));
  
  	/* capability flags */
  	tmp = cpu_to_le32(cap);
@@@ -1974,19 -1977,3 +1976,19 @@@ int ieee80211_ave_rssi(struct ieee80211
  	return ifmgd->ave_beacon_signal;
  }
  EXPORT_SYMBOL_GPL(ieee80211_ave_rssi);
 +
 +u8 ieee80211_mcs_to_chains(const struct ieee80211_mcs_info *mcs)
 +{
 +	if (!mcs)
 +		return 1;
 +
 +	/* TODO: consider rx_highest */
 +
 +	if (mcs->rx_mask[3])
 +		return 4;
 +	if (mcs->rx_mask[2])
 +		return 3;
 +	if (mcs->rx_mask[1])
 +		return 2;
 +	return 1;
 +}

-- 
LinuxNextTracking


More information about the linux-merge mailing list