]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
authorDavid S. Miller <davem@davemloft.net>
Wed, 30 Jul 2008 04:51:00 +0000 (21:51 -0700)
committerDavid S. Miller <davem@davemloft.net>
Wed, 30 Jul 2008 04:51:00 +0000 (21:51 -0700)
46 files changed:
Documentation/rfkill.txt
drivers/net/ps3_gelic_wireless.c
drivers/net/wireless/ath5k/base.c
drivers/net/wireless/ath5k/base.h
drivers/net/wireless/ath5k/hw.c
drivers/net/wireless/b43/main.c
drivers/net/wireless/b43/xmit.c
drivers/net/wireless/b43legacy/main.c
drivers/net/wireless/b43legacy/xmit.c
drivers/net/wireless/ipw2100.c
drivers/net/wireless/iwlwifi/iwl-3945.c
drivers/net/wireless/iwlwifi/iwl-core.c
drivers/net/wireless/iwlwifi/iwl-debug.h
drivers/net/wireless/iwlwifi/iwl-led.c
drivers/net/wireless/iwlwifi/iwl-scan.c
drivers/net/wireless/iwlwifi/iwl-tx.c
drivers/net/wireless/iwlwifi/iwl3945-base.c
drivers/net/wireless/libertas/persistcfg.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/rt2x00/rt2500usb.c
drivers/net/wireless/rt2x00/rt2x00.h
drivers/net/wireless/rt2x00/rt2x00config.c
drivers/net/wireless/rt2x00/rt2x00dev.c
drivers/net/wireless/rt2x00/rt2x00lib.h
drivers/net/wireless/rt2x00/rt2x00mac.c
drivers/net/wireless/rt2x00/rt2x00queue.c
drivers/net/wireless/rt2x00/rt2x00queue.h
drivers/net/wireless/rt2x00/rt2x00usb.c
drivers/net/wireless/rt2x00/rt2x00usb.h
drivers/net/wireless/rt2x00/rt61pci.c
drivers/net/wireless/rt2x00/rt73usb.c
drivers/net/wireless/rtl8187.h
drivers/net/wireless/rtl8187_dev.c
drivers/net/wireless/zd1211rw/zd_mac.c
include/linux/rfkill.h
include/linux/skbuff.h
include/net/mac80211.h
net/core/skbuff.c
net/mac80211/cfg.c
net/mac80211/main.c
net/mac80211/mlme.c
net/mac80211/tx.c
net/mac80211/wep.c
net/mac80211/wme.c
net/rfkill/rfkill.c
net/wireless/nl80211.c

index 0843ed0163a5810fc564844b1929cf4fbe7673eb..28b6ec87c64209b10a83dfe1a7bfcebf6f231991 100644 (file)
@@ -390,9 +390,10 @@ rfkill lines are inactive, it must return RFKILL_STATE_SOFT_BLOCKED if its soft
 rfkill input line is active.  Only if none of the rfkill input lines are
 active, will it return RFKILL_STATE_UNBLOCKED.
 
-If it doesn't implement the get_state() hook, it must make sure that its calls
-to rfkill_force_state() are enough to keep the status always up-to-date, and it
-must do a rfkill_force_state() on resume from sleep.
+Since the device has a hardware rfkill line, it IS subject to state changes
+external to rfkill.  Therefore, the driver must make sure that it calls
+rfkill_force_state() to keep the status always up-to-date, and it must do a
+rfkill_force_state() on resume from sleep.
 
 Every time the driver gets a notification from the card that one of its rfkill
 lines changed state (polling might be needed on badly designed cards that don't
@@ -422,13 +423,24 @@ of the hardware is unknown), or read-write (where the hardware can be queried
 about its current state).
 
 The rfkill class will call the get_state hook of a device every time it needs
-to know the *real* current state of the hardware.  This can happen often.
+to know the *real* current state of the hardware.  This can happen often, but
+it does not do any polling, so it is not enough on hardware that is subject
+to state changes outside of the rfkill subsystem.
+
+Therefore, calling rfkill_force_state() when a state change happens is
+mandatory when the device has a hardware rfkill line, or when something else
+like the firmware could cause its state to be changed without going through the
+rfkill class.
 
 Some hardware provides events when its status changes.  In these cases, it is
 best for the driver to not provide a get_state hook, and instead register the
 rfkill class *already* with the correct status, and keep it updated using
 rfkill_force_state() when it gets an event from the hardware.
 
+rfkill_force_state() must be used on the device resume handlers to update the
+rfkill status, should there be any chance of the device status changing during
+the sleep.
+
 There is no provision for a statically-allocated rfkill struct.  You must
 use rfkill_allocate() to allocate one.
 
index 6b2dee0cf3a9b60cee6e22f275a804e65598f0dc..a834b52a6a2c4019a36bb752b812566ae89c57c9 100644 (file)
@@ -1024,7 +1024,7 @@ static int gelic_wl_set_encode(struct net_device *netdev,
        struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
        struct iw_point *enc = &data->encoding;
        __u16 flags;
-       unsigned int irqflag;
+       unsigned long irqflag;
        int key_index, index_specified;
        int ret = 0;
 
@@ -1097,7 +1097,7 @@ static int gelic_wl_get_encode(struct net_device *netdev,
 {
        struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
        struct iw_point *enc = &data->encoding;
-       unsigned int irqflag;
+       unsigned long irqflag;
        unsigned int key_index, index_specified;
        int ret = 0;
 
@@ -1215,7 +1215,7 @@ static int gelic_wl_set_encodeext(struct net_device *netdev,
        struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
        __u16 alg;
        __u16 flags;
-       unsigned int irqflag;
+       unsigned long irqflag;
        int key_index;
        int ret = 0;
 
@@ -1303,7 +1303,7 @@ static int gelic_wl_get_encodeext(struct net_device *netdev,
        struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
        struct iw_point *enc = &data->encoding;
        struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
-       unsigned int irqflag;
+       unsigned long irqflag;
        int key_index;
        int ret = 0;
        int max_key_len;
@@ -1426,7 +1426,7 @@ static int gelic_wl_priv_set_psk(struct net_device *net_dev,
 {
        struct gelic_wl_info *wl = port_wl(netdev_priv(net_dev));
        unsigned int len;
-       unsigned int irqflag;
+       unsigned long irqflag;
        int ret = 0;
 
        pr_debug("%s:<- len=%d\n", __func__, data->data.length);
@@ -1467,7 +1467,7 @@ static int gelic_wl_priv_get_psk(struct net_device *net_dev,
 {
        struct gelic_wl_info *wl = port_wl(netdev_priv(net_dev));
        char *p;
-       unsigned int irqflag;
+       unsigned long irqflag;
        unsigned int i;
 
        pr_debug("%s:<-\n", __func__);
index d9769c527346874f6f876babf37f67a11ebcd32e..ff3fad794b610c465c52295005caf6a4e5fbee57 100644 (file)
@@ -43,7 +43,9 @@
 #include <linux/version.h>
 #include <linux/module.h>
 #include <linux/delay.h>
+#include <linux/hardirq.h>
 #include <linux/if.h>
+#include <linux/io.h>
 #include <linux/netdevice.h>
 #include <linux/cache.h>
 #include <linux/pci.h>
@@ -471,9 +473,6 @@ ath5k_pci_probe(struct pci_dev *pdev,
        /* Set private data */
        pci_set_drvdata(pdev, hw);
 
-       /* Enable msi for devices that support it */
-       pci_enable_msi(pdev);
-
        /* Setup interrupt handler */
        ret = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc);
        if (ret) {
@@ -551,7 +550,6 @@ err_ah:
 err_irq:
        free_irq(pdev->irq, sc);
 err_free:
-       pci_disable_msi(pdev);
        ieee80211_free_hw(hw);
 err_map:
        pci_iounmap(pdev, mem);
@@ -573,7 +571,6 @@ ath5k_pci_remove(struct pci_dev *pdev)
        ath5k_detach(pdev, hw);
        ath5k_hw_detach(sc->ah);
        free_irq(pdev->irq, sc);
-       pci_disable_msi(pdev);
        pci_iounmap(pdev, sc->iobase);
        pci_release_region(pdev, 0);
        pci_disable_device(pdev);
@@ -590,6 +587,9 @@ ath5k_pci_suspend(struct pci_dev *pdev, pm_message_t state)
        ath5k_led_off(sc);
 
        ath5k_stop_hw(sc);
+
+       free_irq(pdev->irq, sc);
+       pci_disable_msi(pdev);
        pci_save_state(pdev);
        pci_disable_device(pdev);
        pci_set_power_state(pdev, PCI_D3hot);
@@ -605,15 +605,12 @@ ath5k_pci_resume(struct pci_dev *pdev)
        struct ath5k_hw *ah = sc->ah;
        int i, err;
 
-       err = pci_set_power_state(pdev, PCI_D0);
-       if (err)
-               return err;
+       pci_restore_state(pdev);
 
        err = pci_enable_device(pdev);
        if (err)
                return err;
 
-       pci_restore_state(pdev);
        /*
         * Suspend/Resume resets the PCI configuration space, so we have to
         * re-disable the RETRY_TIMEOUT register (0x41) to keep
@@ -621,7 +618,17 @@ ath5k_pci_resume(struct pci_dev *pdev)
         */
        pci_write_config_byte(pdev, 0x41, 0);
 
-       ath5k_init(sc);
+       pci_enable_msi(pdev);
+
+       err = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc);
+       if (err) {
+               ATH5K_ERR(sc, "request_irq failed\n");
+               goto err_msi;
+       }
+
+       err = ath5k_init(sc);
+       if (err)
+               goto err_irq;
        ath5k_led_enable(sc);
 
        /*
@@ -635,6 +642,12 @@ ath5k_pci_resume(struct pci_dev *pdev)
                ath5k_hw_reset_key(ah, i);
 
        return 0;
+err_irq:
+       free_irq(pdev->irq, sc);
+err_msi:
+       pci_disable_msi(pdev);
+       pci_disable_device(pdev);
+       return err;
 }
 #endif /* CONFIG_PM */
 
@@ -1224,7 +1237,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
 
        pktlen = skb->len;
 
-       if (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT)) {
+       if (info->control.hw_key) {
                keyidx = info->control.hw_key->hw_key_idx;
                pktlen += info->control.icv_len;
        }
@@ -1249,6 +1262,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
 
        txq->link = &ds->ds_link;
        ath5k_hw_tx_start(ah, txq->qnum);
+       mmiowb();
        spin_unlock_bh(&txq->lock);
 
        return 0;
@@ -1583,7 +1597,6 @@ ath5k_rx_stop(struct ath5k_softc *sc)
        ath5k_hw_stop_pcu_recv(ah);     /* disable PCU */
        ath5k_hw_set_rx_filter(ah, 0);  /* clear recv filter */
        ath5k_hw_stop_rx_dma(ah);       /* disable DMA engine */
-       mdelay(3);                      /* 3ms is long enough for 1 frame */
 
        ath5k_debug_printrxbuffs(sc, ah);
 
@@ -1682,31 +1695,44 @@ ath5k_tasklet_rx(unsigned long data)
        struct ath5k_rx_status rs = {};
        struct sk_buff *skb;
        struct ath5k_softc *sc = (void *)data;
-       struct ath5k_buf *bf;
+       struct ath5k_buf *bf, *bf_last;
        struct ath5k_desc *ds;
        int ret;
        int hdrlen;
        int pad;
 
        spin_lock(&sc->rxbuflock);
+       if (list_empty(&sc->rxbuf)) {
+               ATH5K_WARN(sc, "empty rx buf pool\n");
+               goto unlock;
+       }
+       bf_last = list_entry(sc->rxbuf.prev, struct ath5k_buf, list);
        do {
                rxs.flag = 0;
 
-               if (unlikely(list_empty(&sc->rxbuf))) {
-                       ATH5K_WARN(sc, "empty rx buf pool\n");
-                       break;
-               }
                bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list);
                BUG_ON(bf->skb == NULL);
                skb = bf->skb;
                ds = bf->desc;
 
-               /* TODO only one segment */
-               pci_dma_sync_single_for_cpu(sc->pdev, sc->desc_daddr,
-                               sc->desc_len, PCI_DMA_FROMDEVICE);
-
-               if (unlikely(ds->ds_link == bf->daddr)) /* this is the end */
-                       break;
+               /*
+                * last buffer must not be freed to ensure proper hardware
+                * function. When the hardware finishes also a packet next to
+                * it, we are sure, it doesn't use it anymore and we can go on.
+                */
+               if (bf_last == bf)
+                       bf->flags |= 1;
+               if (bf->flags) {
+                       struct ath5k_buf *bf_next = list_entry(bf->list.next,
+                                       struct ath5k_buf, list);
+                       ret = sc->ah->ah_proc_rx_desc(sc->ah, bf_next->desc,
+                                       &rs);
+                       if (ret)
+                               break;
+                       bf->flags &= ~1;
+                       /* skip the overwritten one (even status is martian) */
+                       goto next;
+               }
 
                ret = sc->ah->ah_proc_rx_desc(sc->ah, ds, &rs);
                if (unlikely(ret == -EINPROGRESS))
@@ -1752,8 +1778,6 @@ ath5k_tasklet_rx(unsigned long data)
                                goto next;
                }
 accept:
-               pci_dma_sync_single_for_cpu(sc->pdev, bf->skbaddr,
-                               rs.rs_datalen, PCI_DMA_FROMDEVICE);
                pci_unmap_single(sc->pdev, bf->skbaddr, sc->rxbufsize,
                                PCI_DMA_FROMDEVICE);
                bf->skb = NULL;
@@ -1816,6 +1840,7 @@ accept:
 next:
                list_move_tail(&bf->list, &sc->rxbuf);
        } while (ath5k_rxbuf_setup(sc, bf) == 0);
+unlock:
        spin_unlock(&sc->rxbuflock);
 }
 
@@ -1840,9 +1865,6 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
        list_for_each_entry_safe(bf, bf0, &txq->q, list) {
                ds = bf->desc;
 
-               /* TODO only one segment */
-               pci_dma_sync_single_for_cpu(sc->pdev, sc->desc_daddr,
-                               sc->desc_len, PCI_DMA_FROMDEVICE);
                ret = sc->ah->ah_proc_tx_desc(sc->ah, ds, &ts);
                if (unlikely(ret == -EINPROGRESS))
                        break;
@@ -2015,8 +2037,6 @@ ath5k_beacon_send(struct ath5k_softc *sc)
                ATH5K_WARN(sc, "beacon queue %u didn't stop?\n", sc->bhalq);
                /* NB: hw still stops DMA, so proceed */
        }
-       pci_dma_sync_single_for_cpu(sc->pdev, bf->skbaddr, bf->skb->len,
-                       PCI_DMA_TODEVICE);
 
        ath5k_hw_put_tx_buf(ah, sc->bhalq, bf->daddr);
        ath5k_hw_tx_start(ah, sc->bhalq);
@@ -2240,6 +2260,7 @@ ath5k_init(struct ath5k_softc *sc)
 
        ret = 0;
 done:
+       mmiowb();
        mutex_unlock(&sc->lock);
        return ret;
 }
@@ -2272,6 +2293,7 @@ ath5k_stop_locked(struct ath5k_softc *sc)
        if (!test_bit(ATH_STAT_INVALID, sc->status)) {
                ath5k_led_off(sc);
                ath5k_hw_set_intr(ah, 0);
+               synchronize_irq(sc->pdev->irq);
        }
        ath5k_txq_cleanup(sc);
        if (!test_bit(ATH_STAT_INVALID, sc->status)) {
@@ -2321,9 +2343,13 @@ ath5k_stop_hw(struct ath5k_softc *sc)
                }
        }
        ath5k_txbuf_free(sc, sc->bbuf);
+       mmiowb();
        mutex_unlock(&sc->lock);
 
        del_timer_sync(&sc->calib_tim);
+       tasklet_kill(&sc->rxtq);
+       tasklet_kill(&sc->txtq);
+       tasklet_kill(&sc->restq);
 
        return ret;
 }
@@ -2550,8 +2576,6 @@ ath5k_init_leds(struct ath5k_softc *sc)
        struct pci_dev *pdev = sc->pdev;
        char name[ATH5K_LED_MAX_NAME_LEN + 1];
 
-       sc->led_on = 0;  /* active low */
-
        /*
         * Auto-enable soft led processing for IBM cards and for
         * 5211 minipci cards.
@@ -2560,11 +2584,13 @@ ath5k_init_leds(struct ath5k_softc *sc)
            pdev->device == PCI_DEVICE_ID_ATHEROS_AR5211) {
                __set_bit(ATH_STAT_LEDSOFT, sc->status);
                sc->led_pin = 0;
+               sc->led_on = 0;  /* active low */
        }
        /* Enable softled on PIN1 on HP Compaq nc6xx, nc4000 & nx5000 laptops */
        if (pdev->subsystem_vendor == PCI_VENDOR_ID_COMPAQ) {
                __set_bit(ATH_STAT_LEDSOFT, sc->status);
                sc->led_pin = 1;
+               sc->led_on = 1;  /* active high */
        }
        if (!test_bit(ATH_STAT_LEDSOFT, sc->status))
                goto out;
@@ -2783,6 +2809,7 @@ ath5k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                /* XXX: assoc id is set to 0 for now, mac80211 doesn't have
                 * a clean way of letting us retrieve this yet. */
                ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
+               mmiowb();
        }
 
        if (conf->changed & IEEE80211_IFCC_BEACON &&
@@ -2971,6 +2998,7 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
        }
 
 unlock:
+       mmiowb();
        mutex_unlock(&sc->lock);
        return ret;
 }
@@ -3032,8 +3060,6 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
 
        ath5k_debug_dump_skb(sc, skb, "BC  ", 1);
 
-       mutex_lock(&sc->lock);
-
        if (sc->opmode != IEEE80211_IF_TYPE_IBSS) {
                ret = -EIO;
                goto end;
@@ -3044,11 +3070,12 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
        ret = ath5k_beacon_setup(sc, sc->bbuf);
        if (ret)
                sc->bbuf->skb = NULL;
-       else
+       else {
                ath5k_beacon_config(sc);
+               mmiowb();
+       }
 
 end:
-       mutex_unlock(&sc->lock);
        return ret;
 }
 
index 47f414b09e67f30032e3a67ca055ca1a650be458..d7e03e6b827126720834b1a3b0ecd7e32590e7e2 100644 (file)
@@ -56,7 +56,7 @@
 
 struct ath5k_buf {
        struct list_head        list;
-       unsigned int            flags;  /* tx descriptor flags */
+       unsigned int            flags;  /* rx descriptor flags */
        struct ath5k_desc       *desc;  /* virtual addr of desc */
        dma_addr_t              daddr;  /* physical addr of desc */
        struct sk_buff          *skb;   /* skbuff for buf */
index c6d12c53bda42b2d78b711599eec30ff41142b21..7ca87a55731253ac4b0a139c9334593e99941f17 100644 (file)
@@ -1440,6 +1440,7 @@ int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
 
                /* Stop queue */
                ath5k_hw_reg_write(ah, tx_queue, AR5K_CR);
+               ath5k_hw_reg_read(ah, AR5K_CR);
        } else {
                /*
                 * Schedule TX disable and wait until queue is empty
@@ -1456,6 +1457,8 @@ int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
 
                /* Clear register */
                ath5k_hw_reg_write(ah, 0, AR5K_QCU_TXD);
+               if (pending)
+                       return -EBUSY;
        }
 
        /* TODO: Check for success else return error */
@@ -1716,6 +1719,7 @@ enum ath5k_int ath5k_hw_set_intr(struct ath5k_hw *ah, enum ath5k_int new_mask)
 
        /* ..re-enable interrupts */
        ath5k_hw_reg_write(ah, AR5K_IER_ENABLE, AR5K_IER);
+       ath5k_hw_reg_read(ah, AR5K_IER);
 
        return old_mask;
 }
index e78319aa47c17c6edc95e593df8b1ffd1cb8cb82..3bf3a869361f13fec7ff1b4a48bdd5ae9ddc363b 100644 (file)
@@ -4645,8 +4645,7 @@ static int b43_wireless_init(struct ssb_device *dev)
        }
 
        /* fill hw info */
-       hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
-                   IEEE80211_HW_RX_INCLUDES_FCS |
+       hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
                    IEEE80211_HW_SIGNAL_DBM |
                    IEEE80211_HW_NOISE_DBM;
 
index 8d54502222a6ed78534b8681f5f7fcbe1f12064b..9dda8169f7cc428fb754f03bbcb224a9227a66d4 100644 (file)
@@ -192,7 +192,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
        const struct b43_phy *phy = &dev->phy;
        const struct ieee80211_hdr *wlhdr =
            (const struct ieee80211_hdr *)fragment_data;
-       int use_encryption = (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT));
+       int use_encryption = !!info->control.hw_key;
        __le16 fctl = wlhdr->frame_control;
        struct ieee80211_rate *fbrate;
        u8 rate, rate_fb;
index a1b8bf3ee73245ebe1d9802581f4537827a4624f..2541c81932f058cd3eb960ddef99d0a53621f8c0 100644 (file)
@@ -3702,8 +3702,7 @@ static int b43legacy_wireless_init(struct ssb_device *dev)
        }
 
        /* fill hw info */
-       hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
-                   IEEE80211_HW_RX_INCLUDES_FCS |
+       hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
                    IEEE80211_HW_SIGNAL_DBM |
                    IEEE80211_HW_NOISE_DBM;
        hw->queues = 1; /* FIXME: hardware has more queues */
@@ -3846,10 +3845,10 @@ static int b43legacy_resume(struct ssb_device *dev)
                        goto out;
                }
        }
-       mutex_unlock(&wl->mutex);
 
        b43legacydbg(wl, "Device resumed.\n");
 out:
+       mutex_unlock(&wl->mutex);
        return err;
 }
 
index e969ed8d412dd6d42638e12521dac9a7a57b5600..68e1f8c78727dd1d4c2504f12b41a75d5080d06e 100644 (file)
@@ -192,7 +192,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
                               u16 cookie)
 {
        const struct ieee80211_hdr *wlhdr;
-       int use_encryption = (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT));
+       int use_encryption = !!info->control.hw_key;
        u16 fctl;
        u8 rate;
        struct ieee80211_rate *rate_fb;
index 5bf9e00b070c4478706ff094c8828c80b8efb7cd..c6f886ec08a395893772d50bf6d3e1c241109bb2 100644 (file)
@@ -6442,6 +6442,7 @@ static int ipw2100_resume(struct pci_dev *pci_dev)
        if (err) {
                printk(KERN_ERR "%s: pci_enable_device failed on resume\n",
                       dev->name);
+               mutex_unlock(&priv->action_mutex);
                return err;
        }
        pci_restore_state(pci_dev);
@@ -7146,7 +7147,7 @@ static int ipw2100_wx_get_rate(struct net_device *dev,
        err = ipw2100_get_ordinal(priv, IPW_ORD_CURRENT_TX_RATE, &val, &len);
        if (err) {
                IPW_DEBUG_WX("failed querying ordinals.\n");
-               return err;
+               goto done;
        }
 
        switch (val & TX_RATE_MASK) {
index c2a76785b665b36730e5233d3bec655ca8c6127a..a51e0eaa1334336f71281bda765212c5fba0090f 100644 (file)
@@ -630,7 +630,9 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl3945_priv *priv,
                                   struct ieee80211_rx_status *stats)
 {
        struct iwl3945_rx_packet *pkt = (struct iwl3945_rx_packet *)rxb->skb->data;
+#ifdef CONFIG_IWL3945_LEDS
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)IWL_RX_DATA(pkt);
+#endif
        struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
        struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt);
        short len = le16_to_cpu(rx_hdr->len);
index a44188bf4459dcb299edea84988e08139ef5514a..e3427c205ccf22a21fbd3572b6c80e451ae93346 100644 (file)
@@ -818,8 +818,7 @@ int iwl_setup_mac(struct iwl_priv *priv)
        hw->rate_control_algorithm = "iwl-4965-rs";
 
        /* Tell mac80211 our characteristics */
-       hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
-                   IEEE80211_HW_SIGNAL_DBM |
+       hw->flags = IEEE80211_HW_SIGNAL_DBM |
                    IEEE80211_HW_NOISE_DBM;
        /* Default value; 4 EDCA QOS priorities */
        hw->queues = 4;
index 58384805a49436201d5a159d0c5439996de38fca..d6d729e86bdb4bad4f836b86a64d7c72979f7c0a 100644 (file)
@@ -68,12 +68,8 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv);
 #endif
 
 #else
-static inline void IWL_DEBUG(int level, const char *fmt, ...)
-{
-}
-static inline void IWL_DEBUG_LIMIT(int level, const char *fmt, ...)
-{
-}
+#define IWL_DEBUG(level, fmt, args...)
+#define IWL_DEBUG_LIMIT(level, fmt, args...)
 #endif                         /* CONFIG_IWLWIFI_DEBUG */
 
 
index 899d7a2567a8dd42045f6753ec72c6e86208902f..61250e6a7d1b32a0867aa495efdbae3258f1d838 100644 (file)
@@ -268,7 +268,9 @@ static int iwl_get_blink_rate(struct iwl_priv *priv)
        if (tpt < 0) /* wrapparound */
                tpt = -tpt;
 
-       IWL_DEBUG_LED("tpt %lld current_tpt %lld\n", tpt, current_tpt);
+       IWL_DEBUG_LED("tpt %lld current_tpt %llu\n",
+               (long long)tpt,
+               (unsigned long long)current_tpt);
        priv->led_tpt = current_tpt;
 
        if (!priv->allow_blinking)
index efc750d2fc5ca988c7fbf5df3686da883b396422..5a00ac23e2d010c32440406bf1eadc045849e5c2 100644 (file)
@@ -270,6 +270,7 @@ static void iwl_rx_scan_results_notif(struct iwl_priv *priv,
 static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
                                       struct iwl_rx_mem_buffer *rxb)
 {
+#ifdef CONFIG_IWLWIFI_DEBUG
        struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
        struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw;
 
@@ -277,6 +278,7 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
                       scan_notif->scanned_channels,
                       scan_notif->tsf_low,
                       scan_notif->tsf_high, scan_notif->status);
+#endif
 
        /* The HW is no longer scanning */
        clear_bit(STATUS_SCAN_HW, &priv->status);
index 9b50b1052b09fe6f750c1693b12dfafca4b3f2f6..f72cd0bf6aa333f9e2f64f1a8f9a3105c5efc37a 100644 (file)
@@ -906,7 +906,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
         * first entry */
        iwl_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len);
 
-       if (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT))
+       if (info->control.hw_key)
                iwl_tx_cmd_build_hwcrypto(priv, info, tx_cmd, skb, sta_id);
 
        /* Set up TFD's 2nd entry to point directly to remainder of skb,
index 4a22d3fba75b36ff66fff021dfa5adb3f688abf9..7c82ecfa30a4bf189613fcc6327d88f0ef8fef29 100644 (file)
@@ -2667,7 +2667,7 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, struct sk_buff *skb)
         * first entry */
        iwl3945_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len);
 
-       if (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT))
+       if (info->control.hw_key)
                iwl3945_build_tx_cmd_hwcrypto(priv, info, out_cmd, skb, 0);
 
        /* Set up TFD's 2nd entry to point directly to remainder of skb,
@@ -7899,8 +7899,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
        priv->ibss_beacon = NULL;
 
        /* Tell mac80211 our characteristics */
-       hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
-                   IEEE80211_HW_SIGNAL_DBM |
+       hw->flags = IEEE80211_HW_SIGNAL_DBM |
                    IEEE80211_HW_NOISE_DBM;
 
        /* 4 EDCA QOS priorities */
index 6d0ff8decaf7ef50e3175f26a50b888a8169f147..3309a9c3cfef3f66c84f5f1cb67388dda176c5e6 100644 (file)
@@ -48,7 +48,7 @@ static ssize_t bootflag_get(struct device *dev,
        if (ret)
                return ret;
 
-       return snprintf(buf, 12, "0x%x\n", le32_to_cpu(defs.bootflag));
+       return snprintf(buf, 12, "%d\n", le32_to_cpu(defs.bootflag));
 }
 
 /**
@@ -63,8 +63,8 @@ static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr,
        int ret;
 
        memset(&cmd, 0, sizeof(cmd));
-       ret = sscanf(buf, "%x", &datum);
-       if (ret != 1)
+       ret = sscanf(buf, "%d", &datum);
+       if ((ret != 1) || (datum > 1))
                return -EINVAL;
 
        *((__le32 *)&cmd.data[0]) = cpu_to_le32(!!datum);
@@ -91,7 +91,7 @@ static ssize_t boottime_get(struct device *dev,
        if (ret)
                return ret;
 
-       return snprintf(buf, 12, "0x%x\n", defs.boottime);
+       return snprintf(buf, 12, "%d\n", defs.boottime);
 }
 
 /**
@@ -106,8 +106,8 @@ static ssize_t boottime_set(struct device *dev,
        int ret;
 
        memset(&cmd, 0, sizeof(cmd));
-       ret = sscanf(buf, "%x", &datum);
-       if (ret != 1)
+       ret = sscanf(buf, "%d", &datum);
+       if ((ret != 1) || (datum > 255))
                return -EINVAL;
 
        /* A too small boot time will result in the device booting into
@@ -143,7 +143,7 @@ static ssize_t channel_get(struct device *dev,
        if (ret)
                return ret;
 
-       return snprintf(buf, 12, "0x%x\n", le16_to_cpu(defs.channel));
+       return snprintf(buf, 12, "%d\n", le16_to_cpu(defs.channel));
 }
 
 /**
@@ -154,11 +154,11 @@ static ssize_t channel_set(struct device *dev, struct device_attribute *attr,
 {
        struct lbs_private *priv = to_net_dev(dev)->priv;
        struct cmd_ds_mesh_config cmd;
-       uint16_t datum;
+       uint32_t datum;
        int ret;
 
        memset(&cmd, 0, sizeof(cmd));
-       ret = sscanf(buf, "%hx", &datum);
+       ret = sscanf(buf, "%d", &datum);
        if (ret != 1 || datum < 1 || datum > 11)
                return -EINVAL;
 
@@ -274,8 +274,8 @@ static ssize_t protocol_id_set(struct device *dev,
        int ret;
 
        memset(&cmd, 0, sizeof(cmd));
-       ret = sscanf(buf, "%x", &datum);
-       if (ret != 1)
+       ret = sscanf(buf, "%d", &datum);
+       if ((ret != 1) || (datum > 255))
                return -EINVAL;
 
        /* fetch all other Information Element parameters */
@@ -328,8 +328,8 @@ static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr,
        int ret;
 
        memset(&cmd, 0, sizeof(cmd));
-       ret = sscanf(buf, "%x", &datum);
-       if (ret != 1)
+       ret = sscanf(buf, "%d", &datum);
+       if ((ret != 1) || (datum > 255))
                return -EINVAL;
 
        /* fetch all other Information Element parameters */
@@ -382,8 +382,8 @@ static ssize_t capability_set(struct device *dev, struct device_attribute *attr,
        int ret;
 
        memset(&cmd, 0, sizeof(cmd));
-       ret = sscanf(buf, "%x", &datum);
-       if (ret != 1)
+       ret = sscanf(buf, "%d", &datum);
+       if ((ret != 1) || (datum > 255))
                return -EINVAL;
 
        /* fetch all other Information Element parameters */
index 5816230d58f82505a18b5bd6c93d1481e7cc8c55..248d31a7aa33ff8c7990c6a4b6231729be589c8b 100644 (file)
@@ -500,7 +500,7 @@ failed_hw:
        device_unregister(data->dev);
 failed_drvdata:
        ieee80211_free_hw(hw);
-       hwsim_radios[i] = 0;
+       hwsim_radios[i] = NULL;
 failed:
        mac80211_hwsim_free();
        return err;
index 3558cb210747a1b6ba6f8cde0962f925747e9eab..3078417b326b263cac8e51c1bd981acda67f2420 100644 (file)
@@ -1121,6 +1121,7 @@ static void rt2500usb_write_beacon(struct queue_entry *entry)
        int pipe = usb_sndbulkpipe(usb_dev, 1);
        int length;
        u16 reg;
+       u32 word, len;
 
        /*
         * Add the descriptor in front of the skb.
@@ -1129,6 +1130,17 @@ static void rt2500usb_write_beacon(struct queue_entry *entry)
        memcpy(entry->skb->data, skbdesc->desc, skbdesc->desc_len);
        skbdesc->desc = entry->skb->data;
 
+       /*
+        * Adjust the beacon databyte count. The current number is
+        * calculated before this function gets called, but falsely
+        * assumes that the descriptor was already present in the SKB.
+        */
+       rt2x00_desc_read(skbdesc->desc, 0, &word);
+       len  = rt2x00_get_field32(word, TXD_W0_DATABYTE_COUNT);
+       len += skbdesc->desc_len;
+       rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, len);
+       rt2x00_desc_write(skbdesc->desc, 0, word);
+
        /*
         * Disable beaconing while we are reloading the beacon data,
         * otherwise we might be sending out invalid data.
@@ -1650,7 +1662,6 @@ static void rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
         * Initialize all hw fields.
         */
        rt2x00dev->hw->flags =
-           IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
            IEEE80211_HW_RX_INCLUDES_FCS |
            IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
            IEEE80211_HW_SIGNAL_DBM;
index 07b03b3c7ef1655407debfd19664c5ff47a5e86f..db2dc976d831cdafa75fb060b0576e301dc78bcb 100644 (file)
 #define SHORT_PIFS             ( SIFS + SHORT_SLOT_TIME )
 #define DIFS                   ( PIFS + SLOT_TIME )
 #define SHORT_DIFS             ( SHORT_PIFS + SHORT_SLOT_TIME )
-#define EIFS                   ( SIFS + (8 * (IEEE80211_HEADER + ACK_SIZE)) )
+#define EIFS                   ( SIFS + DIFS + \
+                                 (8 * (IEEE80211_HEADER + ACK_SIZE)) )
+#define SHORT_EIFS             ( SIFS + SHORT_DIFS + \
+                                 (8 * (IEEE80211_HEADER + ACK_SIZE)) )
 
 /*
  * Chipset identification
@@ -597,6 +600,7 @@ enum rt2x00_flags {
        DEVICE_STARTED_SUSPEND,
        DEVICE_ENABLED_RADIO,
        DEVICE_DISABLED_RADIO_HW,
+       DEVICE_DIRTY_CONFIG,
 
        /*
         * Driver features
index f20ca712504f734a39e8d5ee5a2264ad955365f7..3f89516e8332128bf77c7b93959b7ea519556a57 100644 (file)
@@ -271,7 +271,7 @@ config:
                libconf.sifs = SIFS;
                libconf.pifs = short_slot_time ? SHORT_PIFS : PIFS;
                libconf.difs = short_slot_time ? SHORT_DIFS : DIFS;
-               libconf.eifs = EIFS;
+               libconf.eifs = short_slot_time ? SHORT_EIFS : EIFS;
        }
 
        libconf.conf = conf;
index 8c93eb8353b0bc4c2b49d47926b5357263ab20ec..f42283ad7b023b697e4aa9375b5c01557ae54f2b 100644 (file)
@@ -1013,6 +1013,7 @@ int rt2x00lib_start(struct rt2x00_dev *rt2x00dev)
        rt2x00dev->intf_associated = 0;
 
        __set_bit(DEVICE_STARTED, &rt2x00dev->flags);
+       __set_bit(DEVICE_DIRTY_CONFIG, &rt2x00dev->flags);
 
        return 0;
 }
@@ -1237,9 +1238,9 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev)
        /*
         * Reconfigure device.
         */
-       rt2x00lib_config(rt2x00dev, &rt2x00dev->hw->conf, 1);
-       if (!rt2x00dev->hw->conf.radio_enabled)
-               rt2x00lib_disable_radio(rt2x00dev);
+       retval = rt2x00mac_config(rt2x00dev->hw, &rt2x00dev->hw->conf);
+       if (retval)
+               goto exit;
 
        /*
         * Iterator over each active interface to
index f2c9b0e79b5f005bd883cc81c9a80cf725b7c718..c5fb3a72cf37e5f0bff29c367d98d08f27536571 100644 (file)
@@ -124,13 +124,6 @@ void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
  */
 void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
 
-/**
- * rt2x00queue_free_skb - free a skb
- * @rt2x00dev: Pointer to &struct rt2x00_dev.
- * @skb: The skb to free.
- */
-void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
-
 /**
  * rt2x00queue_write_tx_frame - Write TX frame to hardware
  * @queue: Queue over which the frame should be send
index f1dcbaa80c3c2415e3f2de1c7f88945d9cfbf09b..c3ee4ecba792dcb95a8224a21391a2f9dde54860 100644 (file)
@@ -63,7 +63,7 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
         */
        memcpy(skb->cb, frag_skb->cb, sizeof(skb->cb));
        rts_info = IEEE80211_SKB_CB(skb);
-       rts_info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT;
+       rts_info->control.hw_key = NULL;
        rts_info->flags &= ~IEEE80211_TX_CTL_USE_RTS_CTS;
        rts_info->flags &= ~IEEE80211_TX_CTL_USE_CTS_PROTECT;
        rts_info->flags &= ~IEEE80211_TX_CTL_REQ_TX_STATUS;
@@ -83,6 +83,7 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
                                  (struct ieee80211_rts *)(skb->data));
 
        if (rt2x00queue_write_tx_frame(queue, skb)) {
+               dev_kfree_skb_any(skb);
                WARNING(rt2x00dev, "Failed to send RTS/CTS frame.\n");
                return NETDEV_TX_BUSY;
        }
@@ -96,7 +97,6 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
        struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data;
        enum data_queue_qid qid = skb_get_queue_mapping(skb);
-       struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
        struct data_queue *queue;
        u16 frame_control;
 
@@ -152,18 +152,6 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
                }
        }
 
-       /*
-        * XXX: This is as wrong as the old mac80211 code was,
-        *      due to beacons not getting sequence numbers assigned
-        *      properly.
-        */
-       if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
-               if (tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
-                       intf->seqno += 0x10;
-               ieee80211hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
-               ieee80211hdr->seq_ctrl |= cpu_to_le16(intf->seqno);
-       }
-
        if (rt2x00queue_write_tx_frame(queue, skb)) {
                ieee80211_stop_queue(rt2x00dev->hw, qid);
                return NETDEV_TX_BUSY;
@@ -322,6 +310,7 @@ EXPORT_SYMBOL_GPL(rt2x00mac_remove_interface);
 int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
+       int force_reconfig;
 
        /*
         * Mac80211 might be calling this function while we are trying
@@ -341,7 +330,17 @@ int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
                        rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF);
        }
 
-       rt2x00lib_config(rt2x00dev, conf, 0);
+       /*
+        * When the DEVICE_DIRTY_CONFIG flag is set, the device has recently
+        * been started and the configuration must be forced upon the hardware.
+        * Otherwise registers will not be intialized correctly and could
+        * result in non-working hardware because essential registers aren't
+        * initialized.
+        */
+       force_reconfig =
+           __test_and_clear_bit(DEVICE_DIRTY_CONFIG, &rt2x00dev->flags);
+
+       rt2x00lib_config(rt2x00dev, conf, force_reconfig);
 
        /*
         * Reenable RX only if the radio should be on.
index 7f442030f5ad187a34b375a7ab4f19fa05c19a7b..3b27f6aa860ce604911a9781ccfcd4aee9f6a090 100644 (file)
@@ -120,6 +120,7 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
 {
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
+       struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data;
        struct ieee80211_rate *rate =
            ieee80211_get_tx_rate(rt2x00dev->hw, tx_info);
@@ -199,6 +200,31 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
                txdesc->ifs = IFS_SIFS;
        }
 
+       /*
+        * Hardware should insert sequence counter.
+        * FIXME: We insert a software sequence counter first for
+        * hardware that doesn't support hardware sequence counting.
+        *
+        * This is wrong because beacons are not getting sequence
+        * numbers assigned properly.
+        *
+        * A secondary problem exists for drivers that cannot toggle
+        * sequence counting per-frame, since those will override the
+        * sequence counter given by mac80211.
+        */
+       if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
+               spin_lock(&intf->lock);
+
+               if (test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags))
+                       intf->seqno += 0x10;
+               hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
+               hdr->seq_ctrl |= cpu_to_le16(intf->seqno);
+
+               spin_unlock(&intf->lock);
+
+               __set_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags);
+       }
+
        /*
         * PLCP setup
         * Length calculation depends on OFDM/CCK rate.
@@ -466,9 +492,12 @@ void rt2x00queue_init_rx(struct rt2x00_dev *rt2x00dev)
        if (!rt2x00dev->ops->lib->init_rxentry)
                return;
 
-       for (i = 0; i < queue->limit; i++)
+       for (i = 0; i < queue->limit; i++) {
+               queue->entries[i].flags = 0;
+
                rt2x00dev->ops->lib->init_rxentry(rt2x00dev,
                                                  &queue->entries[i]);
+       }
 }
 
 void rt2x00queue_init_tx(struct rt2x00_dev *rt2x00dev)
@@ -482,9 +511,12 @@ void rt2x00queue_init_tx(struct rt2x00_dev *rt2x00dev)
                if (!rt2x00dev->ops->lib->init_txentry)
                        continue;
 
-               for (i = 0; i < queue->limit; i++)
+               for (i = 0; i < queue->limit; i++) {
+                       queue->entries[i].flags = 0;
+
                        rt2x00dev->ops->lib->init_txentry(rt2x00dev,
                                                          &queue->entries[i]);
+               }
        }
 }
 
index 8945945c892e04f5c6ea3cc728366499e64d3a09..a4a8c57004db179d2df8777c45e421786f68a6af 100644 (file)
@@ -199,6 +199,7 @@ struct txdone_entry_desc {
  * @ENTRY_TXD_RTS_FRAME: This frame is a RTS frame.
  * @ENTRY_TXD_CTS_FRAME: This frame is a CTS-to-self frame.
  * @ENTRY_TXD_OFDM_RATE: This frame is send out with an OFDM rate.
+ * @ENTRY_TXD_GENERATE_SEQ: This frame requires sequence counter.
  * @ENTRY_TXD_FIRST_FRAGMENT: This is the first frame.
  * @ENTRY_TXD_MORE_FRAG: This frame is followed by another fragment.
  * @ENTRY_TXD_REQ_TIMESTAMP: Require timestamp to be inserted.
@@ -210,6 +211,7 @@ enum txentry_desc_flags {
        ENTRY_TXD_RTS_FRAME,
        ENTRY_TXD_CTS_FRAME,
        ENTRY_TXD_OFDM_RATE,
+       ENTRY_TXD_GENERATE_SEQ,
        ENTRY_TXD_FIRST_FRAGMENT,
        ENTRY_TXD_MORE_FRAG,
        ENTRY_TXD_REQ_TIMESTAMP,
index 83862e7f7aec1f03b4de6ea221f1d90491e30277..933e6cc9359db871aafc87a0eec318c5326cbd6f 100644 (file)
@@ -122,6 +122,38 @@ int rt2x00usb_vendor_request_buff(struct rt2x00_dev *rt2x00dev,
 }
 EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_buff);
 
+int rt2x00usb_vendor_request_large_buff(struct rt2x00_dev *rt2x00dev,
+                                       const u8 request, const u8 requesttype,
+                                       const u16 offset, void *buffer,
+                                       const u16 buffer_length,
+                                       const int timeout)
+{
+       int status = 0;
+       unsigned char *tb;
+       u16 off, len, bsize;
+
+       mutex_lock(&rt2x00dev->usb_cache_mutex);
+
+       tb  = buffer;
+       off = offset;
+       len = buffer_length;
+       while (len && !status) {
+               bsize = min_t(u16, CSR_CACHE_SIZE, len);
+               status = rt2x00usb_vendor_req_buff_lock(rt2x00dev, request,
+                                                       requesttype, off, tb,
+                                                       bsize, timeout);
+
+               tb  += bsize;
+               len -= bsize;
+               off += bsize;
+       }
+
+       mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+       return status;
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_large_buff);
+
 /*
  * TX data handlers.
  */
index aad794adf52cc87632df22fe3c011f89391d6da8..ee3875f894aa9ba1d37a430e7a2e0da870a4dc11 100644 (file)
@@ -70,8 +70,7 @@
 /*
  * Cache size
  */
-#define CSR_CACHE_SIZE                 8
-#define CSR_CACHE_SIZE_FIRMWARE                64
+#define CSR_CACHE_SIZE                 64
 
 /*
  * USB request types.
@@ -171,6 +170,25 @@ int rt2x00usb_vendor_req_buff_lock(struct rt2x00_dev *rt2x00dev,
                                   const u16 offset, void *buffer,
                                   const u16 buffer_length, const int timeout);
 
+/**
+ * rt2x00usb_vendor_request_large_buff - Send register command to device (buffered)
+ * @rt2x00dev: Pointer to &struct rt2x00_dev
+ * @request: USB vendor command (See &enum rt2x00usb_vendor_request)
+ * @requesttype: Request type &USB_VENDOR_REQUEST_*
+ * @offset: Register start offset to perform action on
+ * @buffer: Buffer where information will be read/written to by device
+ * @buffer_length: Size of &buffer
+ * @timeout: Operation timeout
+ *
+ * This function is used to transfer register data in blocks larger
+ * then CSR_CACHE_SIZE. Use for firmware upload, keys and beacons.
+ */
+int rt2x00usb_vendor_request_large_buff(struct rt2x00_dev *rt2x00dev,
+                                       const u8 request, const u8 requesttype,
+                                       const u16 offset, void *buffer,
+                                       const u16 buffer_length,
+                                       const int timeout);
+
 /**
  * rt2x00usb_vendor_request_sw - Send single register command to device
  * @rt2x00dev: Pointer to &struct rt2x00_dev
index f7c1f92c1448ac6aa7b61b9403054bb64b7593b7..fbe2a652e014b0c194aee79d0c3aa82ad2045dfe 100644 (file)
@@ -1544,7 +1544,8 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
        rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min);
        rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max);
        rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER);
-       rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, 1);
+       rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE,
+                          test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags));
        rt2x00_set_field32(&word, TXD_W1_BUFFER_COUNT, 1);
        rt2x00_desc_write(txd, 1, word);
 
@@ -2278,7 +2279,6 @@ static void rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
         * Initialize all hw fields.
         */
        rt2x00dev->hw->flags =
-           IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
            IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
            IEEE80211_HW_SIGNAL_DBM;
        rt2x00dev->hw->extra_tx_headroom = 0;
index d383735ab8f2dec53431bf3aa079a3490fa2c782..9761eaaa08be789e0cc970272719860ca3116526 100644 (file)
@@ -890,9 +890,6 @@ static int rt73usb_load_firmware(struct rt2x00_dev *rt2x00dev, const void *data,
        unsigned int i;
        int status;
        u32 reg;
-       const char *ptr = data;
-       char *cache;
-       int buflen;
 
        /*
         * Wait for stable hardware.
@@ -911,31 +908,12 @@ static int rt73usb_load_firmware(struct rt2x00_dev *rt2x00dev, const void *data,
 
        /*
         * Write firmware to device.
-        * We setup a seperate cache for this action,
-        * since we are going to write larger chunks of data
-        * then normally used cache size.
         */
-       cache = kmalloc(CSR_CACHE_SIZE_FIRMWARE, GFP_KERNEL);
-       if (!cache) {
-               ERROR(rt2x00dev, "Failed to allocate firmware cache.\n");
-               return -ENOMEM;
-       }
-
-       for (i = 0; i < len; i += CSR_CACHE_SIZE_FIRMWARE) {
-               buflen = min_t(int, len - i, CSR_CACHE_SIZE_FIRMWARE);
-
-               memcpy(cache, ptr, buflen);
-
-               rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE,
-                                        USB_VENDOR_REQUEST_OUT,
-                                        FIRMWARE_IMAGE_BASE + i, 0,
-                                        cache, buflen,
-                                        REGISTER_TIMEOUT32(buflen));
-
-               ptr += buflen;
-       }
-
-       kfree(cache);
+       rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE,
+                                           USB_VENDOR_REQUEST_OUT,
+                                           FIRMWARE_IMAGE_BASE,
+                                           data, len,
+                                           REGISTER_TIMEOUT32(len));
 
        /*
         * Send firmware request to device to load firmware,
@@ -1303,7 +1281,8 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
        rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min);
        rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max);
        rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER);
-       rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, 1);
+       rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE,
+                          test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags));
        rt2x00_desc_write(txd, 1, word);
 
        rt2x00_desc_read(txd, 2, &word);
@@ -1352,6 +1331,7 @@ static void rt73usb_write_beacon(struct queue_entry *entry)
        struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
        unsigned int beacon_base;
        u32 reg;
+       u32 word, len;
 
        /*
         * Add the descriptor in front of the skb.
@@ -1360,6 +1340,17 @@ static void rt73usb_write_beacon(struct queue_entry *entry)
        memcpy(entry->skb->data, skbdesc->desc, skbdesc->desc_len);
        skbdesc->desc = entry->skb->data;
 
+       /*
+        * Adjust the beacon databyte count. The current number is
+        * calculated before this function gets called, but falsely
+        * assumes that the descriptor was already present in the SKB.
+        */
+       rt2x00_desc_read(skbdesc->desc, 0, &word);
+       len  = rt2x00_get_field32(word, TXD_W0_DATABYTE_COUNT);
+       len += skbdesc->desc_len;
+       rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, len);
+       rt2x00_desc_write(skbdesc->desc, 0, word);
+
        /*
         * Disable beaconing while we are reloading the beacon data,
         * otherwise we might be sending out invalid data.
@@ -1374,10 +1365,10 @@ static void rt73usb_write_beacon(struct queue_entry *entry)
         * Write entire beacon with descriptor to register.
         */
        beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
-       rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE,
-                                USB_VENDOR_REQUEST_OUT, beacon_base, 0,
-                                entry->skb->data, entry->skb->len,
-                                REGISTER_TIMEOUT32(entry->skb->len));
+       rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE,
+                                           USB_VENDOR_REQUEST_OUT, beacon_base,
+                                           entry->skb->data, entry->skb->len,
+                                           REGISTER_TIMEOUT32(entry->skb->len));
 
        /*
         * Clean up the beacon skb.
@@ -1871,7 +1862,6 @@ static void rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
         * Initialize all hw fields.
         */
        rt2x00dev->hw->flags =
-           IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
            IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
            IEEE80211_HW_SIGNAL_DBM;
        rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE;
index 3afb49f8866a542dc4f06fcf41d32de96a8f0ab5..1b0d750f662383176a31a1e674b539ed05441584 100644 (file)
@@ -47,11 +47,13 @@ struct rtl8187_rx_hdr {
 struct rtl8187b_rx_hdr {
        __le32 flags;
        __le64 mac_time;
-       u8 noise;
-       u8 signal;
+       u8 sq;
+       u8 rssi;
        u8 agc;
-       u8 reserved;
-       __le32 unused;
+       u8 flags2;
+       __le16 snr_long2end;
+       s8 pwdb_g12;
+       u8 fot;
 } __attribute__((packed));
 
 /* {rtl8187,rtl8187b}_tx_info is in skb */
@@ -100,6 +102,7 @@ struct rtl8187_priv {
        struct usb_device *udev;
        u32 rx_conf;
        u16 txpwr_base;
+       u16 seqno;
        u8 asic_rev;
        u8 is_rtl8187b;
        enum {
index d3067b1216caad08de4b94c03b6eb412e00a0276..177988efd66022810d301fc406d1e38d403ca75a 100644 (file)
@@ -169,6 +169,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
 {
        struct rtl8187_priv *priv = dev->priv;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data;
        unsigned int ep;
        void *buf;
        struct urb *urb;
@@ -234,6 +235,20 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
                        ep = epmap[skb_get_queue_mapping(skb)];
        }
 
+       /* FIXME: The sequence that follows is needed for this driver to
+        * work with mac80211 since "mac80211: fix TX sequence numbers".
+        * As with the temporary code in rt2x00, changes will be needed
+        * to get proper sequence numbers on beacons. In addition, this
+        * patch places the sequence number in the hardware state, which
+        * limits us to a single virtual state.
+        */
+       if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
+               if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
+                       priv->seqno += 0x10;
+               ieee80211hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
+               ieee80211hdr->seq_ctrl |= cpu_to_le16(priv->seqno);
+       }
+
        info->driver_data[0] = dev;
        info->driver_data[1] = urb;
 
@@ -257,6 +272,7 @@ static void rtl8187_rx_cb(struct urb *urb)
        struct ieee80211_rx_status rx_status = { 0 };
        int rate, signal;
        u32 flags;
+       u32 quality;
 
        spin_lock(&priv->rx_queue.lock);
        if (skb->next)
@@ -280,44 +296,57 @@ static void rtl8187_rx_cb(struct urb *urb)
                flags = le32_to_cpu(hdr->flags);
                signal = hdr->signal & 0x7f;
                rx_status.antenna = (hdr->signal >> 7) & 1;
-               rx_status.signal = signal;
                rx_status.noise = hdr->noise;
                rx_status.mactime = le64_to_cpu(hdr->mac_time);
-               priv->signal = signal;
                priv->quality = signal;
+               rx_status.qual = priv->quality;
                priv->noise = hdr->noise;
+               rate = (flags >> 20) & 0xF;
+               if (rate > 3) { /* OFDM rate */
+                       if (signal > 90)
+                               signal = 90;
+                       else if (signal < 25)
+                               signal = 25;
+                       signal = 90 - signal;
+               } else {        /* CCK rate */
+                       if (signal > 95)
+                               signal = 95;
+                       else if (signal < 30)
+                               signal = 30;
+                       signal = 95 - signal;
+               }
+               rx_status.signal = signal;
+               priv->signal = signal;
        } else {
                struct rtl8187b_rx_hdr *hdr =
                        (typeof(hdr))(skb_tail_pointer(skb) - sizeof(*hdr));
+               /* The Realtek datasheet for the RTL8187B shows that the RX
+                * header contains the following quantities: signal quality,
+                * RSSI, AGC, the received power in dB, and the measured SNR.
+                * In testing, none of these quantities show qualitative
+                * agreement with AP signal strength, except for the AGC,
+                * which is inversely proportional to the strength of the
+                * signal. In the following, the quality and signal strength
+                * are derived from the AGC. The arbitrary scaling constants
+                * are chosen to make the results close to the values obtained
+                * for a BCM4312 using b43 as the driver. The noise is ignored
+                * for now.
+                */
                flags = le32_to_cpu(hdr->flags);
-               signal = hdr->agc >> 1;
-               rx_status.antenna = (hdr->signal >> 7) & 1;
-               rx_status.signal = 64 - min(hdr->noise, (u8)64);
-               rx_status.noise = hdr->noise;
+               quality = 170 - hdr->agc;
+               if (quality > 100)
+                       quality = 100;
+               signal = 14 - hdr->agc / 2;
+               rx_status.qual = quality;
+               priv->quality = quality;
+               rx_status.signal = signal;
+               priv->signal = signal;
+               rx_status.antenna = (hdr->rssi >> 7) & 1;
                rx_status.mactime = le64_to_cpu(hdr->mac_time);
-               priv->signal = hdr->signal;
-               priv->quality = hdr->agc >> 1;
-               priv->noise = hdr->noise;
+               rate = (flags >> 20) & 0xF;
        }
 
        skb_trim(skb, flags & 0x0FFF);
-       rate = (flags >> 20) & 0xF;
-       if (rate > 3) { /* OFDM rate */
-               if (signal > 90)
-                       signal = 90;
-               else if (signal < 25)
-                       signal = 25;
-               signal = 90 - signal;
-       } else {        /* CCK rate */
-               if (signal > 95)
-                       signal = 95;
-               else if (signal < 30)
-                       signal = 30;
-               signal = 95 - signal;
-       }
-
-       rx_status.qual = priv->quality;
-       rx_status.signal = signal;
        rx_status.rate_idx = rate;
        rx_status.freq = dev->conf.channel->center_freq;
        rx_status.band = dev->conf.channel->band;
@@ -1015,9 +1044,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
 
        priv->mode = IEEE80211_IF_TYPE_MNTR;
        dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
-                    IEEE80211_HW_RX_INCLUDES_FCS |
-                    IEEE80211_HW_SIGNAL_UNSPEC;
-       dev->max_signal = 65;
+                    IEEE80211_HW_RX_INCLUDES_FCS;
 
        eeprom.data = dev;
        eeprom.register_read = rtl8187_eeprom_register_read;
@@ -1132,10 +1159,16 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
                (*channel++).hw_value = txpwr >> 8;
        }
 
-       if (priv->is_rtl8187b)
+       if (priv->is_rtl8187b) {
                printk(KERN_WARNING "rtl8187: 8187B chip detected. Support "
                        "is EXPERIMENTAL, and could damage your\n"
                        "         hardware, use at your own risk\n");
+               dev->flags |= IEEE80211_HW_SIGNAL_DBM;
+       } else {
+               dev->flags |= IEEE80211_HW_SIGNAL_UNSPEC;
+               dev->max_signal = 65;
+       }
+
        if ((id->driver_info == DEVICE_RTL8187) && priv->is_rtl8187b)
                printk(KERN_INFO "rtl8187: inconsistency between id with OEM"
                       " info!\n");
index fcc532bb6a7efe0a13482458ff9572c854ca37aa..4d7b98b050304684d6b9d09d4b3dbc34209348fb 100644 (file)
@@ -935,7 +935,6 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf)
        hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &mac->band;
 
        hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
-                   IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
                    IEEE80211_HW_SIGNAL_DB;
 
        hw->max_signal = 100;
index c5f6e54ec6ae6dd42106b340823e85f84250ec04..741d1a62cc3f28e68ff4ce0f2e0ac5ef636aabb7 100644 (file)
@@ -68,7 +68,8 @@ enum rfkill_state {
  * @user_claim_unsupported: Whether the hardware supports exclusive
  *     RF-kill control by userspace. Set this before registering.
  * @user_claim: Set when the switch is controlled exlusively by userspace.
- * @mutex: Guards switch state transitions
+ * @mutex: Guards switch state transitions.  It serializes callbacks
+ *     and also protects the state.
  * @data: Pointer to the RF button drivers private data which will be
  *     passed along when toggling radio state.
  * @toggle_radio(): Mandatory handler to control state of the radio.
@@ -89,12 +90,13 @@ struct rfkill {
        const char *name;
        enum rfkill_type type;
 
-       enum rfkill_state state;
        bool user_claim_unsupported;
        bool user_claim;
 
+       /* the mutex serializes callbacks and also protects
+        * the state */
        struct mutex mutex;
-
+       enum rfkill_state state;
        void *data;
        int (*toggle_radio)(void *data, enum rfkill_state state);
        int (*get_state)(void *data, enum rfkill_state *state);
index 7ea44f6621f265a003ad6eb28c9f3934d1dc94e2..a640385e0598b7f127cb21e7688618643152064e 100644 (file)
@@ -316,7 +316,10 @@ struct sk_buff {
 #ifdef CONFIG_IPV6_NDISC_NODETYPE
        __u8                    ndisc_nodetype:2;
 #endif
-       /* 14 bit hole */
+#if defined(CONFIG_MAC80211) || defined(CONFIG_MAC80211_MODULE)
+       __u8                    do_not_encrypt:1;
+#endif
+       /* 0/13/14 bit hole */
 
 #ifdef CONFIG_NET_DMA
        dma_cookie_t            dma_cookie;
index 4dd3d93e196025d162217a0d6107a28733ac7af9..b52721008be81dd34e3b6379e8729c5abf439b0a 100644 (file)
@@ -206,8 +206,6 @@ struct ieee80211_bss_conf {
  * These flags are used with the @flags member of &ieee80211_tx_info.
  *
  * @IEEE80211_TX_CTL_REQ_TX_STATUS: request TX status callback for this frame.
- * @IEEE80211_TX_CTL_DO_NOT_ENCRYPT: send this frame without encryption;
- *     e.g., for EAPOL frame
  * @IEEE80211_TX_CTL_USE_RTS_CTS: use RTS-CTS before sending frame
  * @IEEE80211_TX_CTL_USE_CTS_PROTECT: use CTS protection for the frame (e.g.,
  *     for combined 802.11g / 802.11b networks)
@@ -220,7 +218,6 @@ struct ieee80211_bss_conf {
  * @IEEE80211_TX_CTL_SHORT_PREAMBLE: TBD
  * @IEEE80211_TX_CTL_LONG_RETRY_LIMIT: this frame should be send using the
  *     through set_retry_limit configured long retry value
- * @IEEE80211_TX_CTL_EAPOL_FRAME: internal to mac80211
  * @IEEE80211_TX_CTL_SEND_AFTER_DTIM: send this frame after DTIM beacon
  * @IEEE80211_TX_CTL_AMPDU: this frame should be sent as part of an A-MPDU
  * @IEEE80211_TX_CTL_OFDM_HT: this frame can be sent in HT OFDM rates. number
@@ -253,7 +250,6 @@ struct ieee80211_bss_conf {
  */
 enum mac80211_tx_control_flags {
        IEEE80211_TX_CTL_REQ_TX_STATUS          = BIT(0),
-       IEEE80211_TX_CTL_DO_NOT_ENCRYPT         = BIT(1),
        IEEE80211_TX_CTL_USE_RTS_CTS            = BIT(2),
        IEEE80211_TX_CTL_USE_CTS_PROTECT        = BIT(3),
        IEEE80211_TX_CTL_NO_ACK                 = BIT(4),
@@ -263,7 +259,6 @@ enum mac80211_tx_control_flags {
        IEEE80211_TX_CTL_FIRST_FRAGMENT         = BIT(8),
        IEEE80211_TX_CTL_SHORT_PREAMBLE         = BIT(9),
        IEEE80211_TX_CTL_LONG_RETRY_LIMIT       = BIT(10),
-       IEEE80211_TX_CTL_EAPOL_FRAME            = BIT(11),
        IEEE80211_TX_CTL_SEND_AFTER_DTIM        = BIT(12),
        IEEE80211_TX_CTL_AMPDU                  = BIT(13),
        IEEE80211_TX_CTL_OFDM_HT                = BIT(14),
@@ -323,7 +318,6 @@ struct ieee80211_tx_info {
                        struct ieee80211_vif *vif;
                        struct ieee80211_key_conf *hw_key;
                        unsigned long jiffies;
-                       int ifindex;
                        u16 aid;
                        s8 rts_cts_rate_idx, alt_retry_rate_idx;
                        u8 retry_limit;
@@ -746,7 +740,6 @@ enum ieee80211_tkip_key_type {
  *     Measurement, Channel Switch, Quieting, TPC
  */
 enum ieee80211_hw_flags {
-       IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE           = 1<<0,
        IEEE80211_HW_RX_INCLUDES_FCS                    = 1<<1,
        IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING        = 1<<2,
        IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE          = 1<<3,
index 4e0c922741897eb1ad158880ea9cb96f692894fe..84640172d65d7901387925d49654de4b0ddb41e7 100644 (file)
@@ -485,6 +485,9 @@ static struct sk_buff *__skb_clone(struct sk_buff *n, struct sk_buff *skb)
        C(head);
        C(data);
        C(truesize);
+#if defined(CONFIG_MAC80211) || defined(CONFIG_MAC80211_MODULE)
+       C(do_not_encrypt);
+#endif
        atomic_set(&n->users, 1);
 
        atomic_inc(&(skb_shinfo(skb)->dataref));
index 8e7ba0e62cf5dcfcda5e278d92777a512175ed8d..297c257864c771c069c44f2b04aa68c2ad1b48c7 100644 (file)
@@ -81,6 +81,7 @@ static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex,
                                  enum nl80211_iftype type, u32 *flags,
                                  struct vif_params *params)
 {
+       struct ieee80211_local *local = wiphy_priv(wiphy);
        struct net_device *dev;
        enum ieee80211_if_types itype;
        struct ieee80211_sub_if_data *sdata;
@@ -95,6 +96,9 @@ static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex,
        if (itype == IEEE80211_IF_TYPE_INVALID)
                return -EINVAL;
 
+       if (dev == local->mdev)
+               return -EOPNOTSUPP;
+
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
        ret = ieee80211_if_change_type(sdata, itype);
@@ -117,12 +121,16 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
                             u8 key_idx, u8 *mac_addr,
                             struct key_params *params)
 {
+       struct ieee80211_local *local = wiphy_priv(wiphy);
        struct ieee80211_sub_if_data *sdata;
        struct sta_info *sta = NULL;
        enum ieee80211_key_alg alg;
        struct ieee80211_key *key;
        int err;
 
+       if (dev == local->mdev)
+               return -EOPNOTSUPP;
+
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
        switch (params->cipher) {
@@ -167,10 +175,14 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
 static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
                             u8 key_idx, u8 *mac_addr)
 {
+       struct ieee80211_local *local = wiphy_priv(wiphy);
        struct ieee80211_sub_if_data *sdata;
        struct sta_info *sta;
        int ret;
 
+       if (dev == local->mdev)
+               return -EOPNOTSUPP;
+
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
        rcu_read_lock();
@@ -211,7 +223,8 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
                             void (*callback)(void *cookie,
                                              struct key_params *params))
 {
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_local *local = wiphy_priv(wiphy);
+       struct ieee80211_sub_if_data *sdata;
        struct sta_info *sta = NULL;
        u8 seq[6] = {0};
        struct key_params params;
@@ -220,6 +233,11 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
        u16 iv16;
        int err = -ENOENT;
 
+       if (dev == local->mdev)
+               return -EOPNOTSUPP;
+
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
        rcu_read_lock();
 
        if (mac_addr) {
@@ -293,8 +311,12 @@ static int ieee80211_config_default_key(struct wiphy *wiphy,
                                        struct net_device *dev,
                                        u8 key_idx)
 {
+       struct ieee80211_local *local = wiphy_priv(wiphy);
        struct ieee80211_sub_if_data *sdata;
 
+       if (dev == local->mdev)
+               return -EOPNOTSUPP;
+
        rcu_read_lock();
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@@ -475,9 +497,15 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
 static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
                                struct beacon_parameters *params)
 {
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_local *local = wiphy_priv(wiphy);
+       struct ieee80211_sub_if_data *sdata;
        struct beacon_data *old;
 
+       if (dev == local->mdev)
+               return -EOPNOTSUPP;
+
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
        if (sdata->vif.type != IEEE80211_IF_TYPE_AP)
                return -EINVAL;
 
@@ -492,9 +520,15 @@ static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
 static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
                                struct beacon_parameters *params)
 {
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_local *local = wiphy_priv(wiphy);
+       struct ieee80211_sub_if_data *sdata;
        struct beacon_data *old;
 
+       if (dev == local->mdev)
+               return -EOPNOTSUPP;
+
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
        if (sdata->vif.type != IEEE80211_IF_TYPE_AP)
                return -EINVAL;
 
@@ -508,9 +542,15 @@ static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
 
 static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
 {
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_local *local = wiphy_priv(wiphy);
+       struct ieee80211_sub_if_data *sdata;
        struct beacon_data *old;
 
+       if (dev == local->mdev)
+               return -EOPNOTSUPP;
+
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
        if (sdata->vif.type != IEEE80211_IF_TYPE_AP)
                return -EINVAL;
 
@@ -646,11 +686,14 @@ static void sta_apply_parameters(struct ieee80211_local *local,
 static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
                                 u8 *mac, struct station_parameters *params)
 {
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct ieee80211_local *local = wiphy_priv(wiphy);
        struct sta_info *sta;
        struct ieee80211_sub_if_data *sdata;
        int err;
 
+       if (dev == local->mdev || params->vlan == local->mdev)
+               return -EOPNOTSUPP;
+
        /* Prevent a race with changing the rate control algorithm */
        if (!netif_running(dev))
                return -ENETDOWN;
@@ -701,10 +744,15 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
 static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
                                 u8 *mac)
 {
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_local *local = wiphy_priv(wiphy);
+       struct ieee80211_sub_if_data *sdata;
        struct sta_info *sta;
 
+       if (dev == local->mdev)
+               return -EOPNOTSUPP;
+
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
        if (mac) {
                rcu_read_lock();
 
@@ -730,10 +778,13 @@ static int ieee80211_change_station(struct wiphy *wiphy,
                                    u8 *mac,
                                    struct station_parameters *params)
 {
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct ieee80211_local *local = wiphy_priv(wiphy);
        struct sta_info *sta;
        struct ieee80211_sub_if_data *vlansdata;
 
+       if (dev == local->mdev || params->vlan == local->mdev)
+               return -EOPNOTSUPP;
+
        rcu_read_lock();
 
        /* XXX: get sta belonging to dev */
@@ -752,7 +803,7 @@ static int ieee80211_change_station(struct wiphy *wiphy,
                        return -EINVAL;
                }
 
-               sta->sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
+               sta->sdata = vlansdata;
                ieee80211_send_layer2_update(sta);
        }
 
@@ -767,15 +818,20 @@ static int ieee80211_change_station(struct wiphy *wiphy,
 static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev,
                                 u8 *dst, u8 *next_hop)
 {
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_local *local = wiphy_priv(wiphy);
+       struct ieee80211_sub_if_data *sdata;
        struct mesh_path *mpath;
        struct sta_info *sta;
        int err;
 
+       if (dev == local->mdev)
+               return -EOPNOTSUPP;
+
        if (!netif_running(dev))
                return -ENETDOWN;
 
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
        if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)
                return -ENOTSUPP;
 
@@ -817,14 +873,19 @@ static int ieee80211_change_mpath(struct wiphy *wiphy,
                                    struct net_device *dev,
                                    u8 *dst, u8 *next_hop)
 {
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_local *local = wiphy_priv(wiphy);
+       struct ieee80211_sub_if_data *sdata;
        struct mesh_path *mpath;
        struct sta_info *sta;
 
+       if (dev == local->mdev)
+               return -EOPNOTSUPP;
+
        if (!netif_running(dev))
                return -ENETDOWN;
 
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
        if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)
                return -ENOTSUPP;
 
@@ -891,9 +952,15 @@ static int ieee80211_get_mpath(struct wiphy *wiphy, struct net_device *dev,
                               u8 *dst, u8 *next_hop, struct mpath_info *pinfo)
 
 {
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_local *local = wiphy_priv(wiphy);
+       struct ieee80211_sub_if_data *sdata;
        struct mesh_path *mpath;
 
+       if (dev == local->mdev)
+               return -EOPNOTSUPP;
+
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
        if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)
                return -ENOTSUPP;
 
@@ -913,9 +980,15 @@ static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev,
                                 int idx, u8 *dst, u8 *next_hop,
                                 struct mpath_info *pinfo)
 {
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_local *local = wiphy_priv(wiphy);
+       struct ieee80211_sub_if_data *sdata;
        struct mesh_path *mpath;
 
+       if (dev == local->mdev)
+               return -EOPNOTSUPP;
+
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
        if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)
                return -ENOTSUPP;
 
index f1a83d450ea0a338d1464adbf3bdec2b48f5eff4..a4c5b90de76987afb4523cf7ed37efbdab7788ef 100644 (file)
@@ -1233,18 +1233,12 @@ static void ieee80211_tasklet_handler(unsigned long data)
 /* Remove added headers (e.g., QoS control), encryption header/MIC, etc. to
  * make a prepared TX frame (one that has been given to hw) to look like brand
  * new IEEE 802.11 frame that is ready to go through TX processing again.
- * Also, tx_packet_data in cb is restored from tx_control. */
+ */
 static void ieee80211_remove_tx_extra(struct ieee80211_local *local,
                                      struct ieee80211_key *key,
                                      struct sk_buff *skb)
 {
        int hdrlen, iv_len, mic_len;
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-
-       info->flags &=  IEEE80211_TX_CTL_REQ_TX_STATUS |
-                       IEEE80211_TX_CTL_DO_NOT_ENCRYPT |
-                       IEEE80211_TX_CTL_REQUEUE |
-                       IEEE80211_TX_CTL_EAPOL_FRAME;
 
        hdrlen = ieee80211_get_hdrlen_from_skb(skb);
 
@@ -1731,8 +1725,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        result = ieee80211_wep_init(local);
 
        if (result < 0) {
-               printk(KERN_DEBUG "%s: Failed to initialize wep\n",
-                      wiphy_name(local->hw.wiphy));
+               printk(KERN_DEBUG "%s: Failed to initialize wep: %d\n",
+                      wiphy_name(local->hw.wiphy), result);
                goto fail_wep;
        }
 
index d7c371e36bf0d5cb3d9d4d35898ec32eda2c31d8..acb04133a95dc699735fcb1932fe16a64b4d720a 100644 (file)
@@ -606,7 +606,6 @@ void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb,
                      int encrypt)
 {
        struct ieee80211_sub_if_data *sdata;
-       struct ieee80211_tx_info *info;
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        skb->dev = sdata->local->mdev;
@@ -614,11 +613,8 @@ void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb,
        skb_set_network_header(skb, 0);
        skb_set_transport_header(skb, 0);
 
-       info = IEEE80211_SKB_CB(skb);
-       memset(info, 0, sizeof(struct ieee80211_tx_info));
-       info->control.ifindex = sdata->dev->ifindex;
-       if (!encrypt)
-               info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT;
+       skb->iif = sdata->dev->ifindex;
+       skb->do_not_encrypt = !encrypt;
 
        dev_queue_xmit(skb);
 }
@@ -3303,6 +3299,7 @@ void ieee80211_start_mesh(struct net_device *dev)
        ifsta = &sdata->u.sta;
        ifsta->state = IEEE80211_MESH_UP;
        ieee80211_sta_timer((unsigned long)sdata);
+       ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON);
 }
 #endif
 
index 0fbadd8b983c821df9de353217e998058565718f..69019e943873b697a4d383b0933318928512b4e5 100644 (file)
@@ -305,7 +305,7 @@ static void purge_old_ps_buffers(struct ieee80211_local *local)
        rcu_read_unlock();
 
        local->total_ps_buffered = total;
-#ifdef MAC80211_VERBOSE_PS_DEBUG
+#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
        printk(KERN_DEBUG "%s: PS buffers full - purged %d frames\n",
               wiphy_name(local->hw.wiphy), purged);
 #endif
@@ -342,7 +342,7 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)
                        purge_old_ps_buffers(tx->local);
                if (skb_queue_len(&tx->sdata->bss->ps_bc_buf) >=
                    AP_MAX_BC_BUFFER) {
-#ifdef MAC80211_VERBOSE_PS_DEBUG
+#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
                        if (net_ratelimit()) {
                                printk(KERN_DEBUG "%s: BC TX buffer full - "
                                       "dropping the oldest frame\n",
@@ -389,7 +389,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
                        purge_old_ps_buffers(tx->local);
                if (skb_queue_len(&sta->ps_tx_buf) >= STA_MAX_TX_BUFFER) {
                        struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf);
-#ifdef MAC80211_VERBOSE_PS_DEBUG
+#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
                        if (net_ratelimit()) {
                                printk(KERN_DEBUG "%s: STA %s TX "
                                       "buffer full - dropping oldest frame\n",
@@ -439,14 +439,14 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
        u16 fc = tx->fc;
 
-       if (unlikely(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT))
+       if (unlikely(tx->skb->do_not_encrypt))
                tx->key = NULL;
        else if (tx->sta && (key = rcu_dereference(tx->sta->key)))
                tx->key = key;
        else if ((key = rcu_dereference(tx->sdata->default_key)))
                tx->key = key;
        else if (tx->sdata->drop_unencrypted &&
-                !(info->flags & IEEE80211_TX_CTL_EAPOL_FRAME) &&
+                (tx->skb->protocol != cpu_to_be16(ETH_P_PAE)) &&
                 !(info->flags & IEEE80211_TX_CTL_INJECTED)) {
                I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted);
                return TX_DROP;
@@ -476,7 +476,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
        }
 
        if (!tx->key || !(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
-               info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT;
+               tx->skb->do_not_encrypt = 1;
 
        return TX_CONTINUE;
 }
@@ -732,6 +732,7 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
                memcpy(skb_put(frag, copylen), pos, copylen);
                memcpy(frag->cb, first->cb, sizeof(frag->cb));
                skb_copy_queue_mapping(frag, first);
+               frag->do_not_encrypt = first->do_not_encrypt;
 
                pos += copylen;
                left -= copylen;
@@ -852,7 +853,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
 
        sband = tx->local->hw.wiphy->bands[tx->channel->band];
 
-       info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT;
+       skb->do_not_encrypt = 1;
        info->flags |= IEEE80211_TX_CTL_INJECTED;
        tx->flags &= ~IEEE80211_TX_FRAGMENTED;
 
@@ -925,8 +926,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
                                skb_trim(skb, skb->len - FCS_LEN);
                        }
                        if (*iterator.this_arg & IEEE80211_RADIOTAP_F_WEP)
-                               info->flags &=
-                                       ~IEEE80211_TX_CTL_DO_NOT_ENCRYPT;
+                               tx->skb->do_not_encrypt = 0;
                        if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG)
                                tx->flags |= IEEE80211_TX_FRAGMENTED;
                        break;
@@ -1042,10 +1042,9 @@ static int ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
                                struct sk_buff *skb,
                                struct net_device *mdev)
 {
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct net_device *dev;
 
-       dev = dev_get_by_index(&init_net, info->control.ifindex);
+       dev = dev_get_by_index(&init_net, skb->iif);
        if (unlikely(dev && !is_ieee80211_device(dev, mdev))) {
                dev_put(dev);
                dev = NULL;
@@ -1306,8 +1305,8 @@ int ieee80211_master_start_xmit(struct sk_buff *skb,
        bool may_encrypt;
        int ret;
 
-       if (info->control.ifindex)
-               odev = dev_get_by_index(&init_net, info->control.ifindex);
+       if (skb->iif)
+               odev = dev_get_by_index(&init_net, skb->iif);
        if (unlikely(odev && !is_ieee80211_device(odev, dev))) {
                dev_put(odev);
                odev = NULL;
@@ -1321,9 +1320,13 @@ int ieee80211_master_start_xmit(struct sk_buff *skb,
                return 0;
        }
 
+       memset(info, 0, sizeof(*info));
+
+       info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
+
        osdata = IEEE80211_DEV_TO_SUB_IF(odev);
 
-       may_encrypt = !(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT);
+       may_encrypt = !skb->do_not_encrypt;
 
        headroom = osdata->local->tx_headroom;
        if (may_encrypt)
@@ -1348,7 +1351,6 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb,
                                 struct net_device *dev)
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct ieee80211_radiotap_header *prthdr =
                (struct ieee80211_radiotap_header *)skb->data;
        u16 len_rthdr;
@@ -1371,11 +1373,11 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb,
        skb->dev = local->mdev;
 
        /* needed because we set skb device to master */
-       info->control.ifindex = dev->ifindex;
+       skb->iif = dev->ifindex;
 
-       info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT;
-       /* Interfaces should always request a status report */
-       info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
+       /* sometimes we do encrypt injected frames, will be fixed
+        * up in radiotap parser if not wanted */
+       skb->do_not_encrypt = 0;
 
        /*
         * fix up the pointers accounting for the radiotap
@@ -1419,7 +1421,6 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
                               struct net_device *dev)
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_tx_info *info;
        struct ieee80211_sub_if_data *sdata;
        int ret = 1, head_need;
        u16 ethertype, hdrlen,  meshhdrlen = 0;
@@ -1645,14 +1646,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
        nh_pos += hdrlen;
        h_pos += hdrlen;
 
-       info = IEEE80211_SKB_CB(skb);
-       memset(info, 0, sizeof(*info));
-       info->control.ifindex = dev->ifindex;
-       if (ethertype == ETH_P_PAE)
-               info->flags |= IEEE80211_TX_CTL_EAPOL_FRAME;
-
-       /* Interfaces should always request a status report */
-       info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
+       skb->iif = dev->ifindex;
 
        skb->dev = local->mdev;
        dev->stats.tx_packets++;
@@ -1922,6 +1916,8 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
 
        info = IEEE80211_SKB_CB(skb);
 
+       skb->do_not_encrypt = 1;
+
        info->band = band;
        rate_control_get_rate(local->mdev, sband, skb, &rsel);
 
@@ -1931,7 +1927,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
                               "no rate found\n",
                               wiphy_name(local->hw.wiphy));
                }
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                skb = NULL;
                goto out;
        }
@@ -1940,7 +1936,6 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
        info->tx_rate_idx = rsel.rate_idx;
 
        info->flags |= IEEE80211_TX_CTL_NO_ACK;
-       info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT;
        info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
        info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
        if (sdata->bss_conf.use_short_preamble &&
index 872d2fcd1a5b169495c19ca26bda925c3b89bdbd..5c2bf0a3d4db67a7e4c7a8c55a3b4cb997b86cdb 100644 (file)
@@ -31,13 +31,13 @@ int ieee80211_wep_init(struct ieee80211_local *local)
        local->wep_tx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0,
                                                CRYPTO_ALG_ASYNC);
        if (IS_ERR(local->wep_tx_tfm))
-               return -ENOMEM;
+               return PTR_ERR(local->wep_tx_tfm);
 
        local->wep_rx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0,
                                                CRYPTO_ALG_ASYNC);
        if (IS_ERR(local->wep_rx_tfm)) {
                crypto_free_blkcipher(local->wep_tx_tfm);
-               return -ENOMEM;
+               return PTR_ERR(local->wep_rx_tfm);
        }
 
        return 0;
index 07edda0b8a5c1c78fef73e9bdca5cf1dbf23abd5..28437f0001db04946b49c330c172b423e92d0913 100644 (file)
@@ -188,6 +188,9 @@ int ieee80211_ht_agg_queue_add(struct ieee80211_local *local,
 {
        int i;
 
+       /* XXX: currently broken due to cb/requeue use */
+       return -EPERM;
+
        /* prepare the filter and save it for the SW queue
         * matching the received HW queue */
 
index 7a560b785097e2971aa916d73c2ea2b72107cb8d..c6f2f388cb72e24a51e4abdc3ac0ffcfa238a71c 100644 (file)
@@ -130,7 +130,6 @@ static void update_rfkill_state(struct rfkill *rfkill)
 
 /**
  * rfkill_toggle_radio - wrapper for toggle_radio hook
- *
  * @rfkill: the rfkill struct to use
  * @force: calls toggle_radio even if cache says it is not needed,
  *     and also makes sure notifications of the state will be
@@ -141,8 +140,8 @@ static void update_rfkill_state(struct rfkill *rfkill)
  * calls and handling all the red tape such as issuing notifications
  * if the call is successful.
  *
- * Note that @force cannot override a (possibly cached) state of
- * RFKILL_STATE_HARD_BLOCKED.  Any device making use of
+ * Note that the @force parameter cannot override a (possibly cached)
+ * state of RFKILL_STATE_HARD_BLOCKED.  Any device making use of
  * RFKILL_STATE_HARD_BLOCKED implements either get_state() or
  * rfkill_force_state(), so the cache either is bypassed or valid.
  *
@@ -150,7 +149,7 @@ static void update_rfkill_state(struct rfkill *rfkill)
  * even if the radio is in RFKILL_STATE_HARD_BLOCKED state, so as to
  * give the driver a hint that it should double-BLOCK the transmitter.
  *
- * Caller must have aquired rfkill_mutex.
+ * Caller must have acquired rfkill->mutex.
  */
 static int rfkill_toggle_radio(struct rfkill *rfkill,
                                enum rfkill_state state,
@@ -200,12 +199,12 @@ static int rfkill_toggle_radio(struct rfkill *rfkill,
 
 /**
  * rfkill_switch_all - Toggle state of all switches of given type
- * @type: type of interfaces to be affeceted
+ * @type: type of interfaces to be affected
  * @state: the new state
  *
- * This function toggles state of all switches of given type unless
- * a specific switch is claimed by userspace in which case it is
- * left alone.
+ * This function toggles the state of all switches of given type,
+ * unless a specific switch is claimed by userspace (in which case,
+ * that switch is left alone).
  */
 void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state)
 {
@@ -216,8 +215,11 @@ void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state)
        rfkill_states[type] = state;
 
        list_for_each_entry(rfkill, &rfkill_list, node) {
-               if ((!rfkill->user_claim) && (rfkill->type == type))
+               if ((!rfkill->user_claim) && (rfkill->type == type)) {
+                       mutex_lock(&rfkill->mutex);
                        rfkill_toggle_radio(rfkill, state, 0);
+                       mutex_unlock(&rfkill->mutex);
+               }
        }
 
        mutex_unlock(&rfkill_mutex);
@@ -228,7 +230,7 @@ EXPORT_SYMBOL(rfkill_switch_all);
  * rfkill_epo - emergency power off all transmitters
  *
  * This kicks all rfkill devices to RFKILL_STATE_SOFT_BLOCKED, ignoring
- * everything in its path but rfkill_mutex.
+ * everything in its path but rfkill_mutex and rfkill->mutex.
  */
 void rfkill_epo(void)
 {
@@ -236,7 +238,9 @@ void rfkill_epo(void)
 
        mutex_lock(&rfkill_mutex);
        list_for_each_entry(rfkill, &rfkill_list, node) {
+               mutex_lock(&rfkill->mutex);
                rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1);
+               mutex_unlock(&rfkill->mutex);
        }
        mutex_unlock(&rfkill_mutex);
 }
@@ -252,7 +256,12 @@ EXPORT_SYMBOL_GPL(rfkill_epo);
  * a notification by the firmware/hardware of the current *real*
  * state of the radio rfkill switch.
  *
- * It may not be called from an atomic context.
+ * Devices which are subject to external changes on their rfkill
+ * state (such as those caused by a hardware rfkill line) MUST
+ * have their driver arrange to call rfkill_force_state() as soon
+ * as possible after such a change.
+ *
+ * This function may not be called from an atomic context.
  */
 int rfkill_force_state(struct rfkill *rfkill, enum rfkill_state state)
 {
@@ -367,6 +376,9 @@ static ssize_t rfkill_claim_store(struct device *dev,
        if (!capable(CAP_NET_ADMIN))
                return -EPERM;
 
+       if (rfkill->user_claim_unsupported)
+               return -EOPNOTSUPP;
+
        /*
         * Take the global lock to make sure the kernel is not in
         * the middle of rfkill_switch_all
@@ -375,19 +387,17 @@ static ssize_t rfkill_claim_store(struct device *dev,
        if (error)
                return error;
 
-       if (rfkill->user_claim_unsupported) {
-               error = -EOPNOTSUPP;
-               goto out_unlock;
-       }
        if (rfkill->user_claim != claim) {
-               if (!claim)
+               if (!claim) {
+                       mutex_lock(&rfkill->mutex);
                        rfkill_toggle_radio(rfkill,
                                            rfkill_states[rfkill->type],
                                            0);
+                       mutex_unlock(&rfkill->mutex);
+               }
                rfkill->user_claim = claim;
        }
 
-out_unlock:
        mutex_unlock(&rfkill_mutex);
 
        return error ? error : count;
@@ -516,8 +526,11 @@ static void rfkill_remove_switch(struct rfkill *rfkill)
 {
        mutex_lock(&rfkill_mutex);
        list_del_init(&rfkill->node);
-       rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1);
        mutex_unlock(&rfkill_mutex);
+
+       mutex_lock(&rfkill->mutex);
+       rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1);
+       mutex_unlock(&rfkill->mutex);
 }
 
 /**
@@ -526,9 +539,10 @@ static void rfkill_remove_switch(struct rfkill *rfkill)
  * @type: type of the switch (RFKILL_TYPE_*)
  *
  * This function should be called by the network driver when it needs
- * rfkill structure. Once the structure is allocated the driver shoud
- * finish its initialization by setting name, private data, enable_radio
+ * rfkill structure.  Once the structure is allocated the driver should
+ * finish its initialization by setting the name, private data, enable_radio
  * and disable_radio methods and then register it with rfkill_register().
+ *
  * NOTE: If registration fails the structure shoudl be freed by calling
  * rfkill_free() otherwise rfkill_unregister() should be used.
  */
@@ -560,7 +574,7 @@ EXPORT_SYMBOL(rfkill_allocate);
  * rfkill_free - Mark rfkill structure for deletion
  * @rfkill: rfkill structure to be destroyed
  *
- * Decrements reference count of rfkill structure so it is destroyed.
+ * Decrements reference count of the rfkill structure so it is destroyed.
  * Note that rfkill_free() should _not_ be called after rfkill_unregister().
  */
 void rfkill_free(struct rfkill *rfkill)
@@ -585,8 +599,10 @@ static void rfkill_led_trigger_register(struct rfkill *rfkill)
 static void rfkill_led_trigger_unregister(struct rfkill *rfkill)
 {
 #ifdef CONFIG_RFKILL_LEDS
-       if (rfkill->led_trigger.name)
+       if (rfkill->led_trigger.name) {
                led_trigger_unregister(&rfkill->led_trigger);
+               rfkill->led_trigger.name = NULL;
+       }
 #endif
 }
 
@@ -622,8 +638,8 @@ int rfkill_register(struct rfkill *rfkill)
 
        error = device_add(dev);
        if (error) {
-               rfkill_led_trigger_unregister(rfkill);
                rfkill_remove_switch(rfkill);
+               rfkill_led_trigger_unregister(rfkill);
                return error;
        }
 
index b7fefffd2d0d02e26e307ab6fa78c7120170763c..59eb2cf42e5f68059618f56f67b3f3f38e2a4c66 100644 (file)
@@ -29,16 +29,16 @@ static struct genl_family nl80211_fam = {
 };
 
 /* internal helper: get drv and dev */
-static int get_drv_dev_by_info_ifindex(struct genl_info *info,
+static int get_drv_dev_by_info_ifindex(struct nlattr **attrs,
                                       struct cfg80211_registered_device **drv,
                                       struct net_device **dev)
 {
        int ifindex;
 
-       if (!info->attrs[NL80211_ATTR_IFINDEX])
+       if (!attrs[NL80211_ATTR_IFINDEX])
                return -EINVAL;
 
-       ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
+       ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]);
        *dev = dev_get_by_index(&init_net, ifindex);
        if (!*dev)
                return -ENODEV;
@@ -291,21 +291,31 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *
 
        mutex_lock(&cfg80211_drv_mutex);
        list_for_each_entry(dev, &cfg80211_drv_list, list) {
-               if (++wp_idx < wp_start)
+               if (wp_idx < wp_start) {
+                       wp_idx++;
                        continue;
+               }
                if_idx = 0;
 
                mutex_lock(&dev->devlist_mtx);
                list_for_each_entry(wdev, &dev->netdev_list, list) {
-                       if (++if_idx < if_start)
+                       if (if_idx < if_start) {
+                               if_idx++;
                                continue;
+                       }
                        if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid,
                                               cb->nlh->nlmsg_seq, NLM_F_MULTI,
-                                              wdev->netdev) < 0)
-                               break;
+                                              wdev->netdev) < 0) {
+                               mutex_unlock(&dev->devlist_mtx);
+                               goto out;
+                       }
+                       if_idx++;
                }
                mutex_unlock(&dev->devlist_mtx);
+
+               wp_idx++;
        }
+ out:
        mutex_unlock(&cfg80211_drv_mutex);
 
        cb->args[0] = wp_idx;
@@ -321,7 +331,7 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
        struct net_device *netdev;
        int err;
 
-       err = get_drv_dev_by_info_ifindex(info, &dev, &netdev);
+       err = get_drv_dev_by_info_ifindex(info->attrs, &dev, &netdev);
        if (err)
                return err;
 
@@ -392,7 +402,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
        } else
                return -EINVAL;
 
-       err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+       err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
        if (err)
                return err;
        ifindex = dev->ifindex;
@@ -477,7 +487,7 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
        int ifindex, err;
        struct net_device *dev;
 
-       err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+       err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
        if (err)
                return err;
        ifindex = dev->ifindex;
@@ -545,7 +555,7 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
        if (info->attrs[NL80211_ATTR_MAC])
                mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
 
-       err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+       err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
        if (err)
                return err;
 
@@ -618,7 +628,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
        if (!info->attrs[NL80211_ATTR_KEY_DEFAULT])
                return -EINVAL;
 
-       err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+       err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
        if (err)
                return err;
 
@@ -699,7 +709,7 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
                return -EINVAL;
        }
 
-       err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+       err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
        if (err)
                return err;
 
@@ -735,7 +745,7 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
        if (info->attrs[NL80211_ATTR_MAC])
                mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
 
-       err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+       err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
        if (err)
                return err;
 
@@ -764,7 +774,7 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
        struct beacon_parameters params;
        int haveinfo = 0;
 
-       err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+       err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
        if (err)
                return err;
 
@@ -843,7 +853,7 @@ static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info)
        int err;
        struct net_device *dev;
 
-       err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+       err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
        if (err)
                return err;
 
@@ -937,67 +947,78 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
 }
 
 static int nl80211_dump_station(struct sk_buff *skb,
-               struct netlink_callback *cb)
+                               struct netlink_callback *cb)
 {
-       int wp_idx = 0;
-       int if_idx = 0;
-       int sta_idx = cb->args[2];
-       int wp_start = cb->args[0];
-       int if_start = cb->args[1];
        struct station_info sinfo;
        struct cfg80211_registered_device *dev;
-       struct wireless_dev *wdev;
+       struct net_device *netdev;
        u8 mac_addr[ETH_ALEN];
+       int ifidx = cb->args[0];
+       int sta_idx = cb->args[1];
        int err;
-       int exit = 0;
 
-       /* TODO: filter by device */
-       mutex_lock(&cfg80211_drv_mutex);
-       list_for_each_entry(dev, &cfg80211_drv_list, list) {
-               if (exit)
+       if (!ifidx) {
+               err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
+                                 nl80211_fam.attrbuf, nl80211_fam.maxattr,
+                                 nl80211_policy);
+               if (err)
+                       return err;
+
+               if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX])
+                       return -EINVAL;
+
+               ifidx = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]);
+               if (!ifidx)
+                       return -EINVAL;
+       }
+
+       netdev = dev_get_by_index(&init_net, ifidx);
+       if (!netdev)
+               return -ENODEV;
+
+       dev = cfg80211_get_dev_from_ifindex(ifidx);
+       if (IS_ERR(dev)) {
+               err = PTR_ERR(dev);
+               goto out_put_netdev;
+       }
+
+       if (!dev->ops->dump_station) {
+               err = -ENOSYS;
+               goto out_err;
+       }
+
+       rtnl_lock();
+
+       while (1) {
+               err = dev->ops->dump_station(&dev->wiphy, netdev, sta_idx,
+                                            mac_addr, &sinfo);
+               if (err == -ENOENT)
                        break;
-               if (++wp_idx < wp_start)
-                       continue;
-               if_idx = 0;
+               if (err)
+                       goto out_err_rtnl;
 
-               mutex_lock(&dev->devlist_mtx);
-               list_for_each_entry(wdev, &dev->netdev_list, list) {
-                       if (exit)
-                               break;
-                       if (++if_idx < if_start)
-                               continue;
-                       if (!dev->ops->dump_station)
-                               continue;
+               if (nl80211_send_station(skb,
+                               NETLINK_CB(cb->skb).pid,
+                               cb->nlh->nlmsg_seq, NLM_F_MULTI,
+                               netdev, mac_addr,
+                               &sinfo) < 0)
+                       goto out;
 
-                       for (;; ++sta_idx) {
-                               rtnl_lock();
-                               err = dev->ops->dump_station(&dev->wiphy,
-                                               wdev->netdev, sta_idx, mac_addr,
-                                               &sinfo);
-                               rtnl_unlock();
-                               if (err) {
-                                       sta_idx = 0;
-                                       break;
-                               }
-                               if (nl80211_send_station(skb,
-                                               NETLINK_CB(cb->skb).pid,
-                                               cb->nlh->nlmsg_seq, NLM_F_MULTI,
-                                               wdev->netdev, mac_addr,
-                                               &sinfo) < 0) {
-                                       exit = 1;
-                                       break;
-                               }
-                       }
-               }
-               mutex_unlock(&dev->devlist_mtx);
+               sta_idx++;
        }
-       mutex_unlock(&cfg80211_drv_mutex);
 
-       cb->args[0] = wp_idx;
-       cb->args[1] = if_idx;
-       cb->args[2] = sta_idx;
 
-       return skb->len;
+ out:
+       cb->args[1] = sta_idx;
+       err = skb->len;
+ out_err_rtnl:
+       rtnl_unlock();
+ out_err:
+       cfg80211_put_dev(dev);
+ out_put_netdev:
+       dev_put(netdev);
+
+       return err;
 }
 
 static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
@@ -1016,7 +1037,7 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
 
        mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
 
-       err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+       err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
        if (err)
                return err;
 
@@ -1112,7 +1133,7 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
                params.plink_action =
                    nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
 
-       err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+       err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
        if (err)
                return err;
 
@@ -1172,7 +1193,7 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
                                &params.station_flags))
                return -EINVAL;
 
-       err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+       err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
        if (err)
                return err;
 
@@ -1207,7 +1228,7 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
        if (info->attrs[NL80211_ATTR_MAC])
                mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
 
-       err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+       err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
        if (err)
                return err;
 
@@ -1277,68 +1298,78 @@ static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq,
 }
 
 static int nl80211_dump_mpath(struct sk_buff *skb,
-               struct netlink_callback *cb)
+                             struct netlink_callback *cb)
 {
-       int wp_idx = 0;
-       int if_idx = 0;
-       int sta_idx = cb->args[2];
-       int wp_start = cb->args[0];
-       int if_start = cb->args[1];
        struct mpath_info pinfo;
        struct cfg80211_registered_device *dev;
-       struct wireless_dev *wdev;
+       struct net_device *netdev;
        u8 dst[ETH_ALEN];
        u8 next_hop[ETH_ALEN];
+       int ifidx = cb->args[0];
+       int path_idx = cb->args[1];
        int err;
-       int exit = 0;
 
-       /* TODO: filter by device */
-       mutex_lock(&cfg80211_drv_mutex);
-       list_for_each_entry(dev, &cfg80211_drv_list, list) {
-               if (exit)
+       if (!ifidx) {
+               err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
+                                 nl80211_fam.attrbuf, nl80211_fam.maxattr,
+                                 nl80211_policy);
+               if (err)
+                       return err;
+
+               if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX])
+                       return -EINVAL;
+
+               ifidx = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]);
+               if (!ifidx)
+                       return -EINVAL;
+       }
+
+       netdev = dev_get_by_index(&init_net, ifidx);
+       if (!netdev)
+               return -ENODEV;
+
+       dev = cfg80211_get_dev_from_ifindex(ifidx);
+       if (IS_ERR(dev)) {
+               err = PTR_ERR(dev);
+               goto out_put_netdev;
+       }
+
+       if (!dev->ops->dump_mpath) {
+               err = -ENOSYS;
+               goto out_err;
+       }
+
+       rtnl_lock();
+
+       while (1) {
+               err = dev->ops->dump_mpath(&dev->wiphy, netdev, path_idx,
+                                          dst, next_hop, &pinfo);
+               if (err == -ENOENT)
                        break;
-               if (++wp_idx < wp_start)
-                       continue;
-               if_idx = 0;
+               if (err)
+                       goto out_err_rtnl;
 
-               mutex_lock(&dev->devlist_mtx);
-               list_for_each_entry(wdev, &dev->netdev_list, list) {
-                       if (exit)
-                               break;
-                       if (++if_idx < if_start)
-                               continue;
-                       if (!dev->ops->dump_mpath)
-                               continue;
+               if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).pid,
+                                      cb->nlh->nlmsg_seq, NLM_F_MULTI,
+                                      netdev, dst, next_hop,
+                                      &pinfo) < 0)
+                       goto out;
 
-                       for (;; ++sta_idx) {
-                               rtnl_lock();
-                               err = dev->ops->dump_mpath(&dev->wiphy,
-                                               wdev->netdev, sta_idx, dst,
-                                               next_hop, &pinfo);
-                               rtnl_unlock();
-                               if (err) {
-                                       sta_idx = 0;
-                                       break;
-                               }
-                               if (nl80211_send_mpath(skb,
-                                               NETLINK_CB(cb->skb).pid,
-                                               cb->nlh->nlmsg_seq, NLM_F_MULTI,
-                                               wdev->netdev, dst, next_hop,
-                                               &pinfo) < 0) {
-                                       exit = 1;
-                                       break;
-                               }
-                       }
-               }
-               mutex_unlock(&dev->devlist_mtx);
+               path_idx++;
        }
-       mutex_unlock(&cfg80211_drv_mutex);
 
-       cb->args[0] = wp_idx;
-       cb->args[1] = if_idx;
-       cb->args[2] = sta_idx;
 
-       return skb->len;
+ out:
+       cb->args[1] = path_idx;
+       err = skb->len;
+ out_err_rtnl:
+       rtnl_unlock();
+ out_err:
+       cfg80211_put_dev(dev);
+ out_put_netdev:
+       dev_put(netdev);
+
+       return err;
 }
 
 static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
@@ -1358,7 +1389,7 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
 
        dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
 
-       err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+       err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
        if (err)
                return err;
 
@@ -1411,7 +1442,7 @@ static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info)
        dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
        next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);
 
-       err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+       err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
        if (err)
                return err;
 
@@ -1446,7 +1477,7 @@ static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info)
        dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
        next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);
 
-       err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+       err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
        if (err)
                return err;
 
@@ -1475,7 +1506,7 @@ static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info)
        if (info->attrs[NL80211_ATTR_MAC])
                dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
 
-       err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+       err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
        if (err)
                return err;