The following commit has been merged in the master branch: commit 67f4efdce7d85282fbd5832cddc80a07eb89b6d6 Merge: c53aa5058ad5ca8876a47d6639ad4d4f2c5ed584 f4a75d2eb7b1e2206094b901be09adb31ba63681 Author: David S. Miller davem@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@davemloft.net
diff --combined MAINTAINERS index aedb604,bb0b27d..a9c794c --- a/MAINTAINERS +++ b/MAINTAINERS @@@ -2507,6 -2507,7 +2507,7 @@@ M: Joonyoung Shim <jy0922.shim@samsung. M: Seung-Woo Kim sw0312.kim@samsung.com M: Kyungmin Park kyungmin.park@samsung.com L: dri-devel@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@linux-fr.org + L: linux-i2c@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@linux-fr.org + L: linux-i2c@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@lightlink.com L: linux-i2c@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@linux-fr.org + M: Wolfram Sang w.sang@pengutronix.de M: "Ben Dooks (embedded platforms)" ben-linux@fluff.org - M: "Wolfram Sang (embedded platforms)" w.sang@pengutronix.de L: linux-i2c@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@linux-fr.org + L: linux-i2c@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@harbaum.org L: linux-i2c@vger.kernel.org @@@ -3878,9 -3928,7 +3928,9 @@@ M: Greg Rose <gregory.v.rose@intel.com M: Peter P Waskiewicz Jr peter.p.waskiewicz.jr@intel.com M: Alex Duyck alexander.h.duyck@intel.com M: John Ronciak john.ronciak@intel.com +M: Tushar Dave tushar.n.dave@intel.com L: e1000-devel@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@gmail.com M: Sridhar Samudrala sri@us.ibm.com +M: Neil Horman nhorman@tuxdriver.com L: linux-sctp@vger.kernel.org W: http://lksctp.sourceforge.net S: Maintained @@@ -7212,6 -7259,14 +7262,14 @@@ L: linux-xtensa@linux-xtensa.or S: Maintained F: arch/xtensa/
+ THERMAL + M: Zhang Rui rui.zhang@intel.com + L: linux-pm@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@hmh.eng.br L: ibm-acpi-devel@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@gmail.com +L: linux-wireless@vger.kernel.org +S: Maintained +F: drivers/net/wireless/ath/ar5523/ + USB ATTACHED SCSI M: Matthew Wilcox willy@linux.intel.com M: Sarah Sharp sarah.a.sharp@linux.intel.com @@@ -7895,13 -7944,6 +7953,6 @@@ M: Roger Luethi <rl@hellgate.ch S: Maintained F: drivers/net/ethernet/via/via-rhine.c
- VIAPRO SMBUS DRIVER - M: Jean Delvare khali@linux-fr.org - L: linux-i2c@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@via.com.tw M: Harald Welte HaraldWelte@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@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(¶ms_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, ¶ms_le, - sizeof(params_le)); + err = brcmf_fil_cmd_data_set(netdev_priv(ndev), BRCMF_C_SCAN, + ¶ms_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(¶ms, 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, "e))) { + (chan = hci_chan_sent(hdev, type, "e))) { 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; +}