Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/holtmann/bluet...
authorDavid S. Miller <davem@davemloft.net>
Mon, 20 Apr 2009 09:16:44 +0000 (02:16 -0700)
committerDavid S. Miller <davem@davemloft.net>
Mon, 20 Apr 2009 09:16:44 +0000 (02:16 -0700)
36 files changed:
drivers/net/Kconfig
drivers/net/cxgb3/cxgb3_main.c
drivers/net/cxgb3/t3_hw.c
drivers/net/macvlan.c
drivers/net/ps3_gelic_wireless.c
drivers/net/wireless/airo.c
drivers/net/wireless/ar9170/hw.h
drivers/net/wireless/ar9170/usb.c
drivers/net/wireless/at76c50x-usb.c
drivers/net/wireless/ath9k/recv.c
drivers/net/wireless/b43/dma.c
drivers/net/wireless/b43/main.c
drivers/net/wireless/b43/phy_common.c
drivers/net/wireless/b43/phy_common.h
drivers/net/wireless/iwlwifi/iwl3945-base.c
drivers/net/wireless/libertas/rx.c
drivers/net/wireless/orinoco/hw.c
drivers/net/wireless/p54/p54.h
drivers/net/wireless/p54/p54spi.c
drivers/net/wireless/p54/p54usb.c
drivers/net/wireless/rt2x00/rt2x00dev.c
drivers/net/wireless/rt2x00/rt73usb.c
net/8021q/vlan_dev.c
net/ax25/ax25_uid.c
net/core/dev.c
net/ipv4/tcp_output.c
net/mac80211/main.c
net/mac80211/mlme.c
net/mac80211/rx.c
net/mac80211/wext.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nfnetlink.c
net/sched/sch_netem.c
net/wireless/core.h
net/wireless/reg.c
net/wireless/scan.c

index 9e92154..214a92d 100644 (file)
@@ -28,9 +28,9 @@ if NETDEVICES
 
 config COMPAT_NET_DEV_OPS
        default y
-       bool "Enable older network device API compatiablity"
+       bool "Enable older network device API compatibility"
        ---help---
-          This option enables kernel compatiability with older network devices
+          This option enables kernel compatibility with older network devices
           that do not use net_device_ops interface.
 
          If unsure, say Y.
index ab0e5fe..7ea4841 100644 (file)
@@ -1117,8 +1117,8 @@ static void cxgb_down(struct adapter *adapter)
        spin_unlock_irq(&adapter->work_lock);
 
        free_irq_resources(adapter);
-       flush_workqueue(cxgb3_wq);      /* wait for external IRQ handler */
        quiesce_rx(adapter);
+       flush_workqueue(cxgb3_wq);      /* wait for external IRQ handler */
 }
 
 static void schedule_chk_task(struct adapter *adap)
@@ -1187,6 +1187,9 @@ static int offload_close(struct t3cdev *tdev)
 
        sysfs_remove_group(&tdev->lldev->dev.kobj, &offload_attr_group);
 
+       /* Flush work scheduled while releasing TIDs */
+       flush_scheduled_work();
+
        tdev->lldev = NULL;
        cxgb3_set_dummy_ops(tdev);
        t3_tp_set_offload_mode(adapter, 0);
@@ -1232,6 +1235,10 @@ static int cxgb_close(struct net_device *dev)
        struct port_info *pi = netdev_priv(dev);
        struct adapter *adapter = pi->adapter;
 
+       
+       if (!adapter->open_device_map)
+               return 0;
+
        /* Stop link fault interrupts */
        t3_xgm_intr_disable(adapter, pi->port_id);
        t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset);
@@ -1247,8 +1254,7 @@ static int cxgb_close(struct net_device *dev)
        spin_unlock_irq(&adapter->work_lock);
 
        if (!(adapter->open_device_map & PORT_MASK))
-               cancel_rearming_delayed_workqueue(cxgb3_wq,
-                                                 &adapter->adap_check_task);
+               cancel_delayed_work_sync(&adapter->adap_check_task);
 
        if (!adapter->open_device_map)
                cxgb_down(adapter);
@@ -2493,6 +2499,7 @@ static void check_link_status(struct adapter *adapter)
 
                spin_lock_irq(&adapter->work_lock);
                if (p->link_fault) {
+                       t3_link_fault(adapter, i);
                        spin_unlock_irq(&adapter->work_lock);
                        continue;
                }
@@ -2554,9 +2561,7 @@ static void t3_adap_check_task(struct work_struct *work)
 
        adapter->check_task_cnt++;
 
-       /* Check link status for PHYs without interrupts */
-       if (p->linkpoll_period)
-               check_link_status(adapter);
+       check_link_status(adapter);
 
        /* Accumulate MAC stats if needed */
        if (!p->linkpoll_period ||
@@ -2680,21 +2685,6 @@ void t3_os_ext_intr_handler(struct adapter *adapter)
        spin_unlock(&adapter->work_lock);
 }
 
-static void link_fault_task(struct work_struct *work)
-{
-       struct adapter *adapter = container_of(work, struct adapter,
-                                              link_fault_handler_task);
-       int i;
-
-       for_each_port(adapter, i) {
-               struct net_device *netdev = adapter->port[i];
-               struct port_info *pi = netdev_priv(netdev);
-
-               if (pi->link_fault)
-                       t3_link_fault(adapter, i);
-       }
-}
-
 void t3_os_link_fault_handler(struct adapter *adapter, int port_id)
 {
        struct net_device *netdev = adapter->port[port_id];
@@ -2702,7 +2692,6 @@ void t3_os_link_fault_handler(struct adapter *adapter, int port_id)
 
        spin_lock(&adapter->work_lock);
        pi->link_fault = 1;
-       queue_work(cxgb3_wq, &adapter->link_fault_handler_task);
        spin_unlock(&adapter->work_lock);
 }
 
@@ -2838,6 +2827,9 @@ static pci_ers_result_t t3_io_error_detected(struct pci_dev *pdev,
        struct adapter *adapter = pci_get_drvdata(pdev);
        int ret;
 
+       if (state == pci_channel_io_perm_failure)
+               return PCI_ERS_RESULT_DISCONNECT;
+
        ret = t3_adapter_error(adapter, 0);
 
        /* Request a slot reset. */
@@ -2932,8 +2924,13 @@ static int __devinit cxgb_enable_msix(struct adapter *adap)
        while ((err = pci_enable_msix(adap->pdev, entries, vectors)) > 0)
                vectors = err;
 
-       if (!err && vectors < (adap->params.nports + 1))
+       if (err < 0)
+               pci_disable_msix(adap->pdev);
+
+       if (!err && vectors < (adap->params.nports + 1)) {
+               pci_disable_msix(adap->pdev);
                err = -1;
+       }
 
        if (!err) {
                for (i = 0; i < vectors; ++i)
@@ -3082,7 +3079,6 @@ static int __devinit init_one(struct pci_dev *pdev,
 
        INIT_LIST_HEAD(&adapter->adapter_list);
        INIT_WORK(&adapter->ext_intr_handler_task, ext_intr_task);
-       INIT_WORK(&adapter->link_fault_handler_task, link_fault_task);
        INIT_WORK(&adapter->fatal_error_handler_task, fatal_error_task);
        INIT_DELAYED_WORK(&adapter->adap_check_task, t3_adap_check_task);
 
index 31ed31a..e1bd690 100644 (file)
@@ -1202,7 +1202,6 @@ void t3_link_changed(struct adapter *adapter, int port_id)
        struct cphy *phy = &pi->phy;
        struct cmac *mac = &pi->mac;
        struct link_config *lc = &pi->link_config;
-       int force_link_down = 0;
 
        phy->ops->get_link_status(phy, &link_ok, &speed, &duplex, &fc);
 
@@ -1218,14 +1217,9 @@ void t3_link_changed(struct adapter *adapter, int port_id)
                status = t3_read_reg(adapter, A_XGM_INT_STATUS + mac->offset);
                if (status & F_LINKFAULTCHANGE) {
                        mac->stats.link_faults++;
-                       force_link_down = 1;
+                       pi->link_fault = 1;
                }
                t3_open_rx_traffic(mac, rx_cfg, rx_hash_high, rx_hash_low);
-
-               if (force_link_down) {
-                       t3_os_link_fault_handler(adapter, port_id);
-                       return;
-               }
        }
 
        if (lc->requested_fc & PAUSE_AUTONEG)
@@ -1292,9 +1286,6 @@ void t3_link_fault(struct adapter *adapter, int port_id)
                /* Account link faults only when the phy reports a link up */
                if (link_ok)
                        mac->stats.link_faults++;
-
-               msleep(1000);
-               t3_os_link_fault_handler(adapter, port_id);
        } else {
                if (link_ok)
                        t3_write_reg(adapter, A_XGM_XAUI_ACT_CTRL + mac->offset,
index 70d3ef4..214a8cf 100644 (file)
@@ -376,7 +376,8 @@ static u32 macvlan_ethtool_get_rx_csum(struct net_device *dev)
        const struct macvlan_dev *vlan = netdev_priv(dev);
        struct net_device *lowerdev = vlan->lowerdev;
 
-       if (lowerdev->ethtool_ops->get_rx_csum == NULL)
+       if (lowerdev->ethtool_ops == NULL ||
+           lowerdev->ethtool_ops->get_rx_csum == NULL)
                return 0;
        return lowerdev->ethtool_ops->get_rx_csum(lowerdev);
 }
@@ -387,7 +388,8 @@ static int macvlan_ethtool_get_settings(struct net_device *dev,
        const struct macvlan_dev *vlan = netdev_priv(dev);
        struct net_device *lowerdev = vlan->lowerdev;
 
-       if (!lowerdev->ethtool_ops->get_settings)
+       if (!lowerdev->ethtool_ops ||
+           !lowerdev->ethtool_ops->get_settings)
                return -EOPNOTSUPP;
 
        return lowerdev->ethtool_ops->get_settings(lowerdev, cmd);
@@ -398,7 +400,8 @@ static u32 macvlan_ethtool_get_flags(struct net_device *dev)
        const struct macvlan_dev *vlan = netdev_priv(dev);
        struct net_device *lowerdev = vlan->lowerdev;
 
-       if (!lowerdev->ethtool_ops->get_flags)
+       if (!lowerdev->ethtool_ops ||
+           !lowerdev->ethtool_ops->get_flags)
                return 0;
        return lowerdev->ethtool_ops->get_flags(lowerdev);
 }
index a5ac2bd..4f3ada6 100644 (file)
@@ -2101,6 +2101,9 @@ static int gelic_wl_associate_bss(struct gelic_wl_info *wl,
        if (ret) {
                pr_debug("%s: WEP/WPA setup failed %d\n", __func__,
                         ret);
+               ret = -EPERM;
+               gelic_wl_send_iwap_event(wl, NULL);
+               goto out;
        }
 
        /* start association */
index f21a617..c36d3a3 100644 (file)
@@ -6713,11 +6713,11 @@ static int airo_set_auth(struct net_device *dev,
                                local->config.authType = AUTH_ENCRYPT;
                        } else
                                return -EINVAL;
-                       break;
 
                        /* Commit the changes to flags if needed */
                        if (local->config.authType != currentAuthType)
                                set_bit (FLAG_COMMIT, &local->flags);
+                       break;
                }
 
        case IW_AUTH_WPA_ENABLED:
index 13091bd..53e250a 100644 (file)
@@ -310,7 +310,7 @@ struct ar9170_tx_control {
 
 struct ar9170_rx_head {
        u8 plcp[12];
-};
+} __packed;
 
 struct ar9170_rx_tail {
        union {
@@ -318,16 +318,16 @@ struct ar9170_rx_tail {
                        u8 rssi_ant0, rssi_ant1, rssi_ant2,
                           rssi_ant0x, rssi_ant1x, rssi_ant2x,
                           rssi_combined;
-               };
+               } __packed;
                u8 rssi[7];
-       };
+       } __packed;
 
        u8 evm_stream0[6], evm_stream1[6];
        u8 phy_err;
        u8 SAidx, DAidx;
        u8 error;
        u8 status;
-};
+} __packed;
 
 #define AR9170_ENC_ALG_NONE                    0x0
 #define AR9170_ENC_ALG_WEP64                   0x1
index ad29684..c9e422e 100644 (file)
@@ -59,6 +59,8 @@ static struct usb_device_id ar9170_usb_ids[] = {
        { USB_DEVICE(0x0cf3, 0x9170) },
        /* Atheros TG121N */
        { USB_DEVICE(0x0cf3, 0x1001) },
+       /* Cace Airpcap NX */
+       { USB_DEVICE(0xcace, 0x0300) },
        /* D-Link DWA 160A */
        { USB_DEVICE(0x07d1, 0x3c10) },
        /* Netgear WNDA3100 */
@@ -67,6 +69,8 @@ static struct usb_device_id ar9170_usb_ids[] = {
        { USB_DEVICE(0x0846, 0x9001) },
        /* Zydas ZD1221 */
        { USB_DEVICE(0x0ace, 0x1221) },
+       /* ZyXEL NWD271N */
+       { USB_DEVICE(0x0586, 0x3417) },
        /* Z-Com UB81 BG */
        { USB_DEVICE(0x0cde, 0x0023) },
        /* Z-Com UB82 ABG */
index 0c02f1c..744f4f4 100644 (file)
@@ -250,6 +250,8 @@ static struct usb_device_id dev_table[] = {
        { USB_DEVICE(0x03eb, 0x7617), USB_DEVICE_DATA(BOARD_505A) },
        /* Siemens Gigaset USB WLAN Adapter 11 */
        { USB_DEVICE(0x1690, 0x0701), USB_DEVICE_DATA(BOARD_505A) },
+       /* OQO Model 01+ Internal Wi-Fi */
+       { USB_DEVICE(0x1557, 0x0002), USB_DEVICE_DATA(BOARD_505A) },
        /*
         * at76c505amx-rfmd
         */
index 71cb18d..dd1f301 100644 (file)
@@ -493,6 +493,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
        int hdrlen, padsize, retval;
        bool decrypt_error = false;
        u8 keyix;
+       __le16 fc;
 
        spin_lock_bh(&sc->rx.rxbuflock);
 
@@ -606,6 +607,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
                /* see if any padding is done by the hw and remove it */
                hdr = (struct ieee80211_hdr *)skb->data;
                hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+               fc = hdr->frame_control;
 
                /* The MAC header is padded to have 32-bit boundary if the
                 * packet payload is non-zero. The general calculation for
@@ -690,7 +692,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
                        sc->rx.rxotherant = 0;
                }
 
-               if (ieee80211_is_beacon(hdr->frame_control) &&
+               if (ieee80211_is_beacon(fc) &&
                                (sc->sc_flags & SC_OP_WAIT_FOR_BEACON)) {
                        sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON;
                        ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP);
index e228c1d..eae680b 100644 (file)
@@ -555,11 +555,32 @@ address_error:
        return 1;
 }
 
+static bool b43_rx_buffer_is_poisoned(struct b43_dmaring *ring, struct sk_buff *skb)
+{
+       unsigned char *f = skb->data + ring->frameoffset;
+
+       return ((f[0] & f[1] & f[2] & f[3] & f[4] & f[5] & f[6] & f[7]) == 0xFF);
+}
+
+static void b43_poison_rx_buffer(struct b43_dmaring *ring, struct sk_buff *skb)
+{
+       struct b43_rxhdr_fw4 *rxhdr;
+       unsigned char *frame;
+
+       /* This poisons the RX buffer to detect DMA failures. */
+
+       rxhdr = (struct b43_rxhdr_fw4 *)(skb->data);
+       rxhdr->frame_len = 0;
+
+       B43_WARN_ON(ring->rx_buffersize < ring->frameoffset + sizeof(struct b43_plcp_hdr6) + 2);
+       frame = skb->data + ring->frameoffset;
+       memset(frame, 0xFF, sizeof(struct b43_plcp_hdr6) + 2 /* padding */);
+}
+
 static int setup_rx_descbuffer(struct b43_dmaring *ring,
                               struct b43_dmadesc_generic *desc,
                               struct b43_dmadesc_meta *meta, gfp_t gfp_flags)
 {
-       struct b43_rxhdr_fw4 *rxhdr;
        dma_addr_t dmaaddr;
        struct sk_buff *skb;
 
@@ -568,6 +589,7 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring,
        skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags);
        if (unlikely(!skb))
                return -ENOMEM;
+       b43_poison_rx_buffer(ring, skb);
        dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0);
        if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize, 0)) {
                /* ugh. try to realloc in zone_dma */
@@ -578,6 +600,7 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring,
                skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags);
                if (unlikely(!skb))
                        return -ENOMEM;
+               b43_poison_rx_buffer(ring, skb);
                dmaaddr = map_descbuffer(ring, skb->data,
                                         ring->rx_buffersize, 0);
                if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize, 0)) {
@@ -592,9 +615,6 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring,
        ring->ops->fill_descriptor(ring, desc, dmaaddr,
                                   ring->rx_buffersize, 0, 0, 0);
 
-       rxhdr = (struct b43_rxhdr_fw4 *)(skb->data);
-       rxhdr->frame_len = 0;
-
        return 0;
 }
 
@@ -1483,12 +1503,17 @@ static void dma_rx(struct b43_dmaring *ring, int *slot)
                        len = le16_to_cpu(rxhdr->frame_len);
                } while (len == 0 && i++ < 5);
                if (unlikely(len == 0)) {
-                       /* recycle the descriptor buffer. */
-                       sync_descbuffer_for_device(ring, meta->dmaaddr,
-                                                  ring->rx_buffersize);
-                       goto drop;
+                       dmaaddr = meta->dmaaddr;
+                       goto drop_recycle_buffer;
                }
        }
+       if (unlikely(b43_rx_buffer_is_poisoned(ring, skb))) {
+               /* Something went wrong with the DMA.
+                * The device did not touch the buffer and did not overwrite the poison. */
+               b43dbg(ring->dev->wl, "DMA RX: Dropping poisoned buffer.\n");
+               dmaaddr = meta->dmaaddr;
+               goto drop_recycle_buffer;
+       }
        if (unlikely(len > ring->rx_buffersize)) {
                /* The data did not fit into one descriptor buffer
                 * and is split over multiple buffers.
@@ -1501,6 +1526,7 @@ static void dma_rx(struct b43_dmaring *ring, int *slot)
                while (1) {
                        desc = ops->idx2desc(ring, *slot, &meta);
                        /* recycle the descriptor buffer. */
+                       b43_poison_rx_buffer(ring, meta->skb);
                        sync_descbuffer_for_device(ring, meta->dmaaddr,
                                                   ring->rx_buffersize);
                        *slot = next_slot(ring, *slot);
@@ -1519,8 +1545,7 @@ static void dma_rx(struct b43_dmaring *ring, int *slot)
        err = setup_rx_descbuffer(ring, desc, meta, GFP_ATOMIC);
        if (unlikely(err)) {
                b43dbg(ring->dev->wl, "DMA RX: setup_rx_descbuffer() failed\n");
-               sync_descbuffer_for_device(ring, dmaaddr, ring->rx_buffersize);
-               goto drop;
+               goto drop_recycle_buffer;
        }
 
        unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0);
@@ -1530,6 +1555,11 @@ static void dma_rx(struct b43_dmaring *ring, int *slot)
        b43_rx(ring->dev, skb, rxhdr);
 drop:
        return;
+
+drop_recycle_buffer:
+       /* Poison and recycle the RX buffer. */
+       b43_poison_rx_buffer(ring, skb);
+       sync_descbuffer_for_device(ring, dmaaddr, ring->rx_buffersize);
 }
 
 void b43_dma_rx(struct b43_dmaring *ring)
index 4896e08..79b685e 100644 (file)
@@ -3974,6 +3974,11 @@ static void setup_struct_phy_for_init(struct b43_wldev *dev,
        phy->next_txpwr_check_time = jiffies;
        /* PHY TX errors counter. */
        atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT);
+
+#if B43_DEBUG
+       phy->phy_locked = 0;
+       phy->radio_locked = 0;
+#endif
 }
 
 static void setup_struct_wldev_for_init(struct b43_wldev *dev)
index 026b61c..e176b6e 100644 (file)
@@ -131,12 +131,16 @@ void b43_radio_lock(struct b43_wldev *dev)
 {
        u32 macctl;
 
+#if B43_DEBUG
+       B43_WARN_ON(dev->phy.radio_locked);
+       dev->phy.radio_locked = 1;
+#endif
+
        macctl = b43_read32(dev, B43_MMIO_MACCTL);
-       B43_WARN_ON(macctl & B43_MACCTL_RADIOLOCK);
        macctl |= B43_MACCTL_RADIOLOCK;
        b43_write32(dev, B43_MMIO_MACCTL, macctl);
-       /* Commit the write and wait for the device
-        * to exit any radio register access. */
+       /* Commit the write and wait for the firmware
+        * to finish any radio register access. */
        b43_read32(dev, B43_MMIO_MACCTL);
        udelay(10);
 }
@@ -145,11 +149,15 @@ void b43_radio_unlock(struct b43_wldev *dev)
 {
        u32 macctl;
 
+#if B43_DEBUG
+       B43_WARN_ON(!dev->phy.radio_locked);
+       dev->phy.radio_locked = 0;
+#endif
+
        /* Commit any write */
        b43_read16(dev, B43_MMIO_PHY_VER);
        /* unlock */
        macctl = b43_read32(dev, B43_MMIO_MACCTL);
-       B43_WARN_ON(!(macctl & B43_MACCTL_RADIOLOCK));
        macctl &= ~B43_MACCTL_RADIOLOCK;
        b43_write32(dev, B43_MMIO_MACCTL, macctl);
 }
index c9f5430..b2d9910 100644 (file)
@@ -245,8 +245,10 @@ struct b43_phy {
        atomic_t txerr_cnt;
 
 #ifdef CONFIG_B43_DEBUG
-       /* PHY registers locked by b43_phy_lock()? */
+       /* PHY registers locked (w.r.t. firmware) */
        bool phy_locked;
+       /* Radio registers locked (w.r.t. firmware) */
+       bool radio_locked;
 #endif /* B43_DEBUG */
 };
 
index ce72928..8d738d7 100644 (file)
@@ -4913,6 +4913,8 @@ static int iwl3945_setup_mac(struct iwl_priv *priv)
 
        hw->wiphy->custom_regulatory = true;
 
+       hw->wiphy->max_scan_ssids = 1; /* WILL FIX */
+
        /* Default value; 4 EDCA QOS priorities */
        hw->queues = 4;
 
index 63d7e19..8e66977 100644 (file)
@@ -170,6 +170,7 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb)
                lbs_deb_rx("rx err: frame received with bad length\n");
                dev->stats.rx_length_errors++;
                ret = 0;
+               dev_kfree_skb(skb);
                goto done;
        }
 
@@ -181,6 +182,7 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb)
                lbs_pr_alert("rxpd not ok\n");
                dev->stats.rx_errors++;
                ret = 0;
+               dev_kfree_skb(skb);
                goto done;
        }
 
index 081428d..632fac8 100644 (file)
@@ -372,15 +372,13 @@ int __orinoco_hw_set_tkip_key(hermes_t *hw, int key_idx, int set_tx,
        }
 
        /* Wait upto 100ms for tx queue to empty */
-       k = 100;
-       do {
-               k--;
+       for (k = 100; k > 0; k--) {
                udelay(1000);
                ret = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_TXQUEUEEMPTY,
                                          &xmitting);
-               if (ret)
+               if (ret || !xmitting)
                        break;
-       } while ((k > 0) && xmitting);
+       }
 
        if (k == 0)
                ret = -ETIMEDOUT;
index 2dda5fe..ecf8b6e 100644 (file)
@@ -14,9 +14,9 @@
  * published by the Free Software Foundation.
  */
 
-#ifdef CONFIG_MAC80211_LEDS
+#ifdef CONFIG_P54_LEDS
 #include <linux/leds.h>
-#endif /* CONFIG_MAC80211_LEDS */
+#endif /* CONFIG_P54_LEDS */
 
 enum p54_control_frame_types {
        P54_CONTROL_TYPE_SETUP = 0,
@@ -116,7 +116,7 @@ enum fw_state {
        FW_STATE_RESETTING,
 };
 
-#ifdef CONFIG_MAC80211_LEDS
+#ifdef CONFIG_P54_LEDS
 
 #define P54_LED_MAX_NAME_LEN 31
 
@@ -129,7 +129,7 @@ struct p54_led_dev {
        unsigned int registered;
 };
 
-#endif /* CONFIG_MAC80211_LEDS */
+#endif /* CONFIG_P54_LEDS */
 
 struct p54_common {
        struct ieee80211_hw *hw;
@@ -177,10 +177,10 @@ struct p54_common {
        u8 privacy_caps;
        u8 rx_keycache_size;
        /* LED management */
-       #ifdef CONFIG_MAC80211_LEDS
+#ifdef CONFIG_P54_LEDS
        struct p54_led_dev assoc_led;
        struct p54_led_dev tx_led;
-       #endif /* CONFIG_MAC80211_LEDS */
+#endif /* CONFIG_P54_LEDS */
        u16 softled_state;              /* bit field of glowing LEDs */
 };
 
index 2b222aa..d1fe577 100644 (file)
@@ -457,9 +457,10 @@ static int p54spi_wq_tx(struct p54s_priv *priv)
        struct ieee80211_tx_info *info;
        struct p54_tx_info *minfo;
        struct p54s_tx_info *dinfo;
+       unsigned long flags;
        int ret = 0;
 
-       spin_lock_bh(&priv->tx_lock);
+       spin_lock_irqsave(&priv->tx_lock, flags);
 
        while (!list_empty(&priv->tx_pending)) {
                entry = list_entry(priv->tx_pending.next,
@@ -467,7 +468,7 @@ static int p54spi_wq_tx(struct p54s_priv *priv)
 
                list_del_init(&entry->tx_list);
 
-               spin_unlock_bh(&priv->tx_lock);
+               spin_unlock_irqrestore(&priv->tx_lock, flags);
 
                dinfo = container_of((void *) entry, struct p54s_tx_info,
                                     tx_list);
@@ -479,16 +480,14 @@ static int p54spi_wq_tx(struct p54s_priv *priv)
 
                ret = p54spi_tx_frame(priv, skb);
 
-               spin_lock_bh(&priv->tx_lock);
-
                if (ret < 0) {
                        p54_free_skb(priv->hw, skb);
-                       goto out;
+                       return ret;
                }
-       }
 
-out:
-       spin_unlock_bh(&priv->tx_lock);
+               spin_lock_irqsave(&priv->tx_lock, flags);
+       }
+       spin_unlock_irqrestore(&priv->tx_lock, flags);
        return ret;
 }
 
@@ -498,12 +497,13 @@ static void p54spi_op_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct p54_tx_info *mi = (struct p54_tx_info *) info->rate_driver_data;
        struct p54s_tx_info *di = (struct p54s_tx_info *) mi->data;
+       unsigned long flags;
 
        BUILD_BUG_ON(sizeof(*di) > sizeof((mi->data)));
 
-       spin_lock_bh(&priv->tx_lock);
+       spin_lock_irqsave(&priv->tx_lock, flags);
        list_add_tail(&di->tx_list, &priv->tx_pending);
-       spin_unlock_bh(&priv->tx_lock);
+       spin_unlock_irqrestore(&priv->tx_lock, flags);
 
        queue_work(priv->hw->workqueue, &priv->work);
 }
@@ -604,6 +604,7 @@ out:
 static void p54spi_op_stop(struct ieee80211_hw *dev)
 {
        struct p54s_priv *priv = dev->priv;
+       unsigned long flags;
 
        if (mutex_lock_interruptible(&priv->mutex)) {
                /* FIXME: how to handle this error? */
@@ -615,9 +616,9 @@ static void p54spi_op_stop(struct ieee80211_hw *dev)
        cancel_work_sync(&priv->work);
 
        p54spi_power_off(priv);
-       spin_lock_bh(&priv->tx_lock);
+       spin_lock_irqsave(&priv->tx_lock, flags);
        INIT_LIST_HEAD(&priv->tx_pending);
-       spin_unlock_bh(&priv->tx_lock);
+       spin_unlock_irqrestore(&priv->tx_lock, flags);
 
        priv->fw_state = FW_STATE_OFF;
        mutex_unlock(&priv->mutex);
index da6640a..6cc6cbc 100644 (file)
@@ -71,6 +71,7 @@ static struct usb_device_id p54u_table[] __devinitdata = {
        {USB_DEVICE(0x1260, 0xee22)},   /* SMC 2862W-G version 2 */
        {USB_DEVICE(0x13b1, 0x000a)},   /* Linksys WUSB54G ver 2 */
        {USB_DEVICE(0x13B1, 0x000C)},   /* Linksys WUSB54AG */
+       {USB_DEVICE(0x1413, 0x5400)},   /* Telsey 802.11g USB2.0 Adapter */
        {USB_DEVICE(0x1435, 0x0427)},   /* Inventel UR054G */
        {USB_DEVICE(0x2001, 0x3704)},   /* DLink DWL-G122 rev A2 */
        {USB_DEVICE(0x413c, 0x8102)},   /* Spinnaker DUT */
index 05f94e2..5752aaa 100644 (file)
@@ -646,10 +646,8 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev)
         * Register HW.
         */
        status = ieee80211_register_hw(rt2x00dev->hw);
-       if (status) {
-               rt2x00lib_remove_hw(rt2x00dev);
+       if (status)
                return status;
-       }
 
        set_bit(DEVICE_STATE_REGISTERED_HW, &rt2x00dev->flags);
 
index 420fff4..853b2b2 100644 (file)
@@ -2369,6 +2369,8 @@ static struct usb_device_id rt73usb_device_table[] = {
        /* Buffalo */
        { USB_DEVICE(0x0411, 0x00d8), USB_DEVICE_DATA(&rt73usb_ops) },
        { USB_DEVICE(0x0411, 0x00f4), USB_DEVICE_DATA(&rt73usb_ops) },
+       { USB_DEVICE(0x0411, 0x0116), USB_DEVICE_DATA(&rt73usb_ops) },
+       { USB_DEVICE(0x0411, 0x0119), USB_DEVICE_DATA(&rt73usb_ops) },
        /* CNet */
        { USB_DEVICE(0x1371, 0x9022), USB_DEVICE_DATA(&rt73usb_ops) },
        { USB_DEVICE(0x1371, 0x9032), USB_DEVICE_DATA(&rt73usb_ops) },
index 1b34135..6b09213 100644 (file)
@@ -668,7 +668,8 @@ static int vlan_ethtool_get_settings(struct net_device *dev,
        const struct vlan_dev_info *vlan = vlan_dev_info(dev);
        struct net_device *real_dev = vlan->real_dev;
 
-       if (!real_dev->ethtool_ops->get_settings)
+       if (!real_dev->ethtool_ops ||
+           !real_dev->ethtool_ops->get_settings)
                return -EOPNOTSUPP;
 
        return real_dev->ethtool_ops->get_settings(real_dev, cmd);
index 57aeba7..832bcf0 100644 (file)
@@ -148,9 +148,13 @@ static void *ax25_uid_seq_start(struct seq_file *seq, loff_t *pos)
 {
        struct ax25_uid_assoc *pt;
        struct hlist_node *node;
-       int i = 0;
+       int i = 1;
 
        read_lock(&ax25_uid_lock);
+
+       if (*pos == 0)
+               return SEQ_START_TOKEN;
+
        ax25_uid_for_each(pt, node, &ax25_uid_list) {
                if (i == *pos)
                        return pt;
@@ -162,8 +166,10 @@ static void *ax25_uid_seq_start(struct seq_file *seq, loff_t *pos)
 static void *ax25_uid_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
        ++*pos;
-
-       return hlist_entry(((ax25_uid_assoc *)v)->uid_node.next,
+       if (v == SEQ_START_TOKEN)
+               return ax25_uid_list.first;
+       else
+               return hlist_entry(((ax25_uid_assoc *)v)->uid_node.next,
                           ax25_uid_assoc, uid_node);
 }
 
index 343883f..001a4c5 100644 (file)
@@ -1336,7 +1336,12 @@ static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
 {
        struct packet_type *ptype;
 
+#ifdef CONFIG_NET_CLS_ACT
+       if (!(skb->tstamp.tv64 && (G_TC_FROM(skb->tc_verd) & AT_INGRESS)))
+               net_timestamp(skb);
+#else
        net_timestamp(skb);
+#endif
 
        rcu_read_lock();
        list_for_each_entry_rcu(ptype, &ptype_all, list) {
@@ -4400,7 +4405,7 @@ int register_netdevice(struct net_device *dev)
        dev->iflink = -1;
 
 #ifdef CONFIG_COMPAT_NET_DEV_OPS
-       /* Netdevice_ops API compatiability support.
+       /* Netdevice_ops API compatibility support.
         * This is temporary until all network devices are converted.
         */
        if (dev->netdev_ops) {
@@ -4411,7 +4416,7 @@ int register_netdevice(struct net_device *dev)
                        dev->name, netdev_drivername(dev, drivername, 64));
 
                /* This works only because net_device_ops and the
-                  compatiablity structure are the same. */
+                  compatibility structure are the same. */
                dev->netdev_ops = (void *) &(dev->init);
        }
 #endif
index 53300fa..59aec60 100644 (file)
@@ -778,7 +778,7 @@ static void tcp_adjust_pcount(struct sock *sk, struct sk_buff *skb, int decr)
 
        if (tp->lost_skb_hint &&
            before(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(tp->lost_skb_hint)->seq) &&
-           (tcp_is_fack(tp) || TCP_SKB_CB(skb)->sacked))
+           (tcp_is_fack(tp) || (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED)))
                tp->lost_cnt_hint -= decr;
 
        tcp_verify_left_out(tp);
index a6f1d8a..fbcbed6 100644 (file)
@@ -258,7 +258,7 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
                        (chan->max_power - local->power_constr_level) :
                        chan->max_power;
 
-       if (local->user_power_level)
+       if (local->user_power_level >= 0)
                power = min(power, local->user_power_level);
 
        if (local->hw.conf.power_level != power) {
index 7ecda9d..1619e0c 100644 (file)
@@ -441,6 +441,9 @@ static bool ieee80211_check_tim(struct ieee802_11_elems *elems, u16 aid)
        u8 index, indexn1, indexn2;
        struct ieee80211_tim_ie *tim = (struct ieee80211_tim_ie *) elems->tim;
 
+       if (unlikely(!tim || elems->tim_len < 4))
+               return false;
+
        aid &= 0x3fff;
        index = aid / 8;
        mask  = 1 << (aid & 7);
@@ -945,9 +948,13 @@ void ieee80211_beacon_loss_work(struct work_struct *work)
                             u.mgd.beacon_loss_work);
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 
-       printk(KERN_DEBUG "%s: driver reports beacon loss from AP %pM "
-              "- sending probe request\n", sdata->dev->name,
-              sdata->u.mgd.bssid);
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+       if (net_ratelimit()) {
+               printk(KERN_DEBUG "%s: driver reports beacon loss from AP %pM "
+                      "- sending probe request\n", sdata->dev->name,
+                      sdata->u.mgd.bssid);
+       }
+#endif
 
        ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL;
        ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid,
@@ -1007,9 +1014,13 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata)
              (local->hw.conf.flags & IEEE80211_CONF_PS)) &&
            time_after(jiffies,
                       ifmgd->last_beacon + IEEE80211_MONITORING_INTERVAL)) {
-               printk(KERN_DEBUG "%s: beacon loss from AP %pM "
-                      "- sending probe request\n",
-                      sdata->dev->name, ifmgd->bssid);
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+               if (net_ratelimit()) {
+                       printk(KERN_DEBUG "%s: beacon loss from AP %pM "
+                              "- sending probe request\n",
+                              sdata->dev->name, ifmgd->bssid);
+               }
+#endif
                ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL;
                ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid,
                                         ifmgd->ssid_len, NULL, 0);
@@ -2105,12 +2116,13 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work)
        struct ieee80211_local *local =
                container_of(work, struct ieee80211_local,
                             dynamic_ps_enable_work);
+       /* XXX: using scan_sdata is completely broken! */
        struct ieee80211_sub_if_data *sdata = local->scan_sdata;
 
        if (local->hw.conf.flags & IEEE80211_CONF_PS)
                return;
 
-       if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)
+       if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK && sdata)
                ieee80211_send_nullfunc(local, sdata, 1);
 
        local->hw.conf.flags |= IEEE80211_CONF_PS;
index 64ebe66..5fa7aed 100644 (file)
@@ -29,6 +29,7 @@
 static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
                                           struct tid_ampdu_rx *tid_agg_rx,
                                           struct sk_buff *skb,
+                                          struct ieee80211_rx_status *status,
                                           u16 mpdu_seq_num,
                                           int bar_req);
 /*
@@ -1688,7 +1689,7 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx)
                /* manage reordering buffer according to requested */
                /* sequence number */
                rcu_read_lock();
-               ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, NULL,
+               ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, NULL, NULL,
                                                 start_seq_num, 1);
                rcu_read_unlock();
                return RX_DROP_UNUSABLE;
@@ -2293,6 +2294,7 @@ static inline u16 seq_sub(u16 sq1, u16 sq2)
 static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
                                           struct tid_ampdu_rx *tid_agg_rx,
                                           struct sk_buff *skb,
+                                          struct ieee80211_rx_status *rxstatus,
                                           u16 mpdu_seq_num,
                                           int bar_req)
 {
@@ -2374,6 +2376,8 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
 
        /* put the frame in the reordering buffer */
        tid_agg_rx->reorder_buf[index] = skb;
+       memcpy(tid_agg_rx->reorder_buf[index]->cb, rxstatus,
+              sizeof(*rxstatus));
        tid_agg_rx->stored_mpdu_num++;
        /* release the buffer until next missing frame */
        index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn)
@@ -2399,7 +2403,8 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
 }
 
 static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
-                                    struct sk_buff *skb)
+                                    struct sk_buff *skb,
+                                    struct ieee80211_rx_status *status)
 {
        struct ieee80211_hw *hw = &local->hw;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
@@ -2448,7 +2453,7 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
 
        /* according to mpdu sequence number deal with reordering buffer */
        mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4;
-       ret = ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb,
+       ret = ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, status,
                                                mpdu_seq_num, 0);
  end_reorder:
        return ret;
@@ -2512,7 +2517,7 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
                return;
        }
 
-       if (!ieee80211_rx_reorder_ampdu(local, skb))
+       if (!ieee80211_rx_reorder_ampdu(local, skb, status))
                __ieee80211_rx_handle_packet(hw, skb, status, rate);
 
        rcu_read_unlock();
index deb4ece..959aa83 100644 (file)
@@ -417,6 +417,7 @@ static int ieee80211_ioctl_siwtxpower(struct net_device *dev,
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct ieee80211_channel* chan = local->hw.conf.channel;
+       bool reconf = false;
        u32 reconf_flags = 0;
        int new_power_level;
 
@@ -427,14 +428,38 @@ static int ieee80211_ioctl_siwtxpower(struct net_device *dev,
        if (!chan)
                return -EINVAL;
 
-       if (data->txpower.fixed)
-               new_power_level = min(data->txpower.value, chan->max_power);
-       else /* Automatic power level setting */
-               new_power_level = chan->max_power;
+       /* only change when not disabling */
+       if (!data->txpower.disabled) {
+               if (data->txpower.fixed) {
+                       if (data->txpower.value < 0)
+                               return -EINVAL;
+                       new_power_level = data->txpower.value;
+                       /*
+                        * Debatable, but we cannot do a fixed power
+                        * level above the regulatory constraint.
+                        * Use "iwconfig wlan0 txpower 15dBm" instead.
+                        */
+                       if (new_power_level > chan->max_power)
+                               return -EINVAL;
+               } else {
+                       /*
+                        * Automatic power level setting, max being the value
+                        * passed in from userland.
+                        */
+                       if (data->txpower.value < 0)
+                               new_power_level = -1;
+                       else
+                               new_power_level = data->txpower.value;
+               }
+
+               reconf = true;
 
-       local->user_power_level = new_power_level;
-       if (local->hw.conf.power_level != new_power_level)
-               reconf_flags |= IEEE80211_CONF_CHANGE_POWER;
+               /*
+                * ieee80211_hw_config() will limit to the channel's
+                * max power and possibly power constraint from AP.
+                */
+               local->user_power_level = new_power_level;
+       }
 
        if (local->hw.conf.radio_enabled != !(data->txpower.disabled)) {
                local->hw.conf.radio_enabled = !(data->txpower.disabled);
@@ -442,7 +467,7 @@ static int ieee80211_ioctl_siwtxpower(struct net_device *dev,
                ieee80211_led_radio(local, local->hw.conf.radio_enabled);
        }
 
-       if (reconf_flags)
+       if (reconf || reconf_flags)
                ieee80211_hw_config(local, reconf_flags);
 
        return 0;
@@ -530,7 +555,7 @@ static int ieee80211_ioctl_giwfrag(struct net_device *dev,
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 
        frag->value = local->fragmentation_threshold;
-       frag->disabled = (frag->value >= IEEE80211_MAX_RTS_THRESHOLD);
+       frag->disabled = (frag->value >= IEEE80211_MAX_FRAG_THRESHOLD);
        frag->fixed = 1;
 
        return 0;
index c6439c7..0ea36e0 100644 (file)
@@ -512,7 +512,7 @@ static int ctnetlink_conntrack_event(struct notifier_block *this,
 
        skb = ctnetlink_alloc_skb(tuple(ct, IP_CT_DIR_ORIGINAL), GFP_ATOMIC);
        if (!skb)
-               return NOTIFY_DONE;
+               goto errout;
 
        b = skb->tail;
 
@@ -591,8 +591,9 @@ static int ctnetlink_conntrack_event(struct notifier_block *this,
 nla_put_failure:
        rcu_read_unlock();
 nlmsg_failure:
-       nfnetlink_set_err(0, group, -ENOBUFS);
        kfree_skb(skb);
+errout:
+       nfnetlink_set_err(0, group, -ENOBUFS);
        return NOTIFY_DONE;
 }
 #endif /* CONFIG_NF_CONNTRACK_EVENTS */
@@ -1564,7 +1565,7 @@ static int ctnetlink_expect_event(struct notifier_block *this,
 
        skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC);
        if (!skb)
-               return NOTIFY_DONE;
+               goto errout;
 
        b = skb->tail;
 
@@ -1589,8 +1590,9 @@ static int ctnetlink_expect_event(struct notifier_block *this,
 nla_put_failure:
        rcu_read_unlock();
 nlmsg_failure:
-       nfnetlink_set_err(0, 0, -ENOBUFS);
        kfree_skb(skb);
+errout:
+       nfnetlink_set_err(0, 0, -ENOBUFS);
        return NOTIFY_DONE;
 }
 #endif
index 2785d66..b8ab37a 100644 (file)
@@ -203,7 +203,7 @@ static int __init nfnetlink_init(void)
                                     nfnetlink_rcv, NULL, THIS_MODULE);
        if (!nfnl) {
                printk(KERN_ERR "cannot initialize nfnetlink!\n");
-               return -1;
+               return -ENOMEM;
        }
 
        return 0;
index d876b87..2b88295 100644 (file)
@@ -280,6 +280,14 @@ static struct sk_buff *netem_dequeue(struct Qdisc *sch)
                        if (unlikely(!skb))
                                return NULL;
 
+#ifdef CONFIG_NET_CLS_ACT
+                       /*
+                        * If it's at ingress let's pretend the delay is
+                        * from the network (tstamp will be updated).
+                        */
+                       if (G_TC_FROM(skb->tc_verd) & AT_INGRESS)
+                               skb->tstamp.tv64 = 0;
+#endif
                        pr_debug("netem_dequeue: return skb=%p\n", skb);
                        sch->q.qlen--;
                        return skb;
index d43daa2..0a592e4 100644 (file)
@@ -90,7 +90,7 @@ struct cfg80211_internal_bss {
        struct rb_node rbn;
        unsigned long ts;
        struct kref ref;
-       bool hold;
+       bool hold, ies_allocated;
 
        /* must be last because of priv member */
        struct cfg80211_bss pub;
index 6327e16..6c1993d 100644 (file)
@@ -2095,11 +2095,12 @@ int set_regdom(const struct ieee80211_regdomain *rd)
 /* Caller must hold cfg80211_mutex */
 void reg_device_remove(struct wiphy *wiphy)
 {
-       struct wiphy *request_wiphy;
+       struct wiphy *request_wiphy = NULL;
 
        assert_cfg80211_lock();
 
-       request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);
+       if (last_request)
+               request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);
 
        kfree(wiphy->regd);
        if (!last_request || !request_wiphy)
index 2a00e36..2ae65b3 100644 (file)
@@ -58,6 +58,10 @@ static void bss_release(struct kref *ref)
        bss = container_of(ref, struct cfg80211_internal_bss, ref);
        if (bss->pub.free_priv)
                bss->pub.free_priv(&bss->pub);
+
+       if (bss->ies_allocated)
+               kfree(bss->pub.information_elements);
+
        kfree(bss);
 }
 
@@ -360,19 +364,41 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
 
        found = rb_find_bss(dev, res);
 
-       if (found && overwrite) {
-               list_replace(&found->list, &res->list);
-               rb_replace_node(&found->rbn, &res->rbn,
-                               &dev->bss_tree);
-               kref_put(&found->ref, bss_release);
-               found = res;
-       } else if (found) {
+       if (found) {
                kref_get(&found->ref);
                found->pub.beacon_interval = res->pub.beacon_interval;
                found->pub.tsf = res->pub.tsf;
                found->pub.signal = res->pub.signal;
                found->pub.capability = res->pub.capability;
                found->ts = res->ts;
+
+               /* overwrite IEs */
+               if (overwrite) {
+                       size_t used = dev->wiphy.bss_priv_size + sizeof(*res);
+                       size_t ielen = res->pub.len_information_elements;
+
+                       if (ksize(found) >= used + ielen) {
+                               memcpy(found->pub.information_elements,
+                                      res->pub.information_elements, ielen);
+                               found->pub.len_information_elements = ielen;
+                       } else {
+                               u8 *ies = found->pub.information_elements;
+
+                               if (found->ies_allocated) {
+                                       if (ksize(ies) < ielen)
+                                               ies = krealloc(ies, ielen,
+                                                              GFP_ATOMIC);
+                               } else
+                                       ies = kmalloc(ielen, GFP_ATOMIC);
+
+                               if (ies) {
+                                       memcpy(ies, res->pub.information_elements, ielen);
+                                       found->ies_allocated = true;
+                                       found->pub.information_elements = ies;
+                               }
+                       }
+               }
+
                kref_put(&res->ref, bss_release);
        } else {
                /* this "consumes" the reference */