Merge branch 'for-linville' of git://github.com/kvalo/ath6kl
authorJohn W. Linville <linville@tuxdriver.com>
Mon, 3 Oct 2011 18:59:35 +0000 (14:59 -0400)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 3 Oct 2011 18:59:35 +0000 (14:59 -0400)
137 files changed:
Documentation/DocBook/80211.tmpl
MAINTAINERS
drivers/net/wireless/adm8211.c
drivers/net/wireless/at76c50x-usb.c
drivers/net/wireless/ath/ath5k/mac80211-ops.c
drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/debug.c
drivers/net/wireless/ath/ath9k/debug.h
drivers/net/wireless/ath/ath9k/gpio.c
drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
drivers/net/wireless/ath/ath9k/htc_drv_main.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/rc.c
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/ath/carl9170/main.c
drivers/net/wireless/b43/b43.h
drivers/net/wireless/b43/main.c
drivers/net/wireless/b43/phy_lcn.c
drivers/net/wireless/b43/tables_phy_lcn.c
drivers/net/wireless/iwlegacy/iwl-4965-tx.c
drivers/net/wireless/iwlegacy/iwl-core.c
drivers/net/wireless/iwlegacy/iwl-core.h
drivers/net/wireless/iwlegacy/iwl-hcmd.c
drivers/net/wireless/iwlegacy/iwl-tx.c
drivers/net/wireless/iwlegacy/iwl3945-base.c
drivers/net/wireless/iwlegacy/iwl4965-base.c
drivers/net/wireless/iwlwifi/iwl-agn-rs.c
drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
drivers/net/wireless/iwlwifi/iwl-agn-tt.c
drivers/net/wireless/iwlwifi/iwl-agn-tx.c
drivers/net/wireless/iwlwifi/iwl-core.c
drivers/net/wireless/iwlwifi/iwl-core.h
drivers/net/wireless/iwlwifi/iwl-debugfs.c
drivers/net/wireless/iwlwifi/iwl-dev.h
drivers/net/wireless/iwlwifi/iwl-eeprom.c
drivers/net/wireless/iwlwifi/iwl-scan.c
drivers/net/wireless/iwlwifi/iwl-shared.h
drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c
drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
drivers/net/wireless/libertas/cfg.c
drivers/net/wireless/libertas/dev.h
drivers/net/wireless/mwifiex/cfg80211.c
drivers/net/wireless/mwifiex/cfg80211.h
drivers/net/wireless/mwifiex/cmdevt.c
drivers/net/wireless/mwifiex/decl.h
drivers/net/wireless/mwifiex/init.c
drivers/net/wireless/mwifiex/main.c
drivers/net/wireless/mwifiex/main.h
drivers/net/wireless/mwifiex/scan.c
drivers/net/wireless/mwifiex/sta_ioctl.c
drivers/net/wireless/p54/txrx.c
drivers/net/wireless/rt2x00/rt2400pci.c
drivers/net/wireless/rt2x00/rt2500pci.c
drivers/net/wireless/rt2x00/rt2800lib.c
drivers/net/wireless/rt2x00/rt2800lib.h
drivers/net/wireless/rt2x00/rt61pci.c
drivers/net/wireless/rt2x00/rt73usb.c
drivers/net/wireless/rtl818x/rtl8180/dev.c
drivers/net/wireless/rtl818x/rtl8187/dev.c
drivers/net/wireless/rtlwifi/core.c
drivers/net/wireless/rtlwifi/usb.c
drivers/net/wireless/rtlwifi/wifi.h
drivers/net/wireless/wl12xx/Makefile
drivers/net/wireless/wl12xx/cmd.c
drivers/net/wireless/wl12xx/conf.h
drivers/net/wireless/wl12xx/event.c
drivers/net/wireless/wl12xx/init.c
drivers/net/wireless/wl12xx/main.c
drivers/net/wireless/wl12xx/scan.c
drivers/net/wireless/wl12xx/sdio_test.c
drivers/net/wireless/wl12xx/tx.c
drivers/net/wireless/wl12xx/tx.h
drivers/net/wireless/wl12xx/wl12xx.h
drivers/net/wireless/wl3501_cs.c
drivers/net/wireless/zd1211rw/zd_mac.c
drivers/staging/brcm80211/brcmsmac/mac80211_if.c
drivers/staging/winbond/wbusb.c
include/linux/ieee80211.h
include/linux/if_ether.h
include/linux/nl80211.h
include/net/bluetooth/hci.h
include/net/bluetooth/hci_core.h
include/net/bluetooth/l2cap.h
include/net/bluetooth/mgmt.h
include/net/bluetooth/smp.h
include/net/cfg80211.h
include/net/mac80211.h
include/net/nfc/nci_core.h
net/bluetooth/hci_conn.c
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c
net/bluetooth/hci_sock.c
net/bluetooth/hci_sysfs.c
net/bluetooth/hidp/core.c
net/bluetooth/l2cap_core.c
net/bluetooth/mgmt.c
net/bluetooth/smp.c
net/mac80211/Kconfig
net/mac80211/agg-rx.c
net/mac80211/agg-tx.c
net/mac80211/cfg.c
net/mac80211/debugfs.c
net/mac80211/debugfs_netdev.c
net/mac80211/debugfs_sta.c
net/mac80211/driver-ops.h
net/mac80211/driver-trace.h
net/mac80211/ht.c
net/mac80211/ibss.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/key.c
net/mac80211/main.c
net/mac80211/mesh.c
net/mac80211/mesh.h
net/mac80211/mesh_plink.c
net/mac80211/mlme.c
net/mac80211/pm.c
net/mac80211/rate.c
net/mac80211/rc80211_minstrel_ht.c
net/mac80211/rx.c
net/mac80211/scan.c
net/mac80211/sta_info.c
net/mac80211/sta_info.h
net/mac80211/status.c
net/mac80211/tx.c
net/mac80211/util.c
net/mac80211/wme.c
net/mac80211/work.c
net/nfc/nci/core.c
net/nfc/nci/data.c
net/nfc/nci/ntf.c
net/wireless/core.h
net/wireless/mlme.c
net/wireless/nl80211.c
net/wireless/util.c

index 445289cd0e65fb855b66e6967af1de961f5ba2d3..2014155c899d00c7da58f3fbab2409dc2880d139 100644 (file)
           Insert notes about VLAN interfaces with hw crypto here or
           in the hw crypto chapter.
         </para>
+      <section id="ps-client">
+        <title>support for powersaving clients</title>
+!Pinclude/net/mac80211.h AP support for powersaving clients
+      </section>
 !Finclude/net/mac80211.h ieee80211_get_buffered_bc
 !Finclude/net/mac80211.h ieee80211_beacon_get
+!Finclude/net/mac80211.h ieee80211_sta_eosp_irqsafe
+!Finclude/net/mac80211.h ieee80211_frame_release_type
+!Finclude/net/mac80211.h ieee80211_sta_ps_transition
+!Finclude/net/mac80211.h ieee80211_sta_ps_transition_ni
+!Finclude/net/mac80211.h ieee80211_sta_set_buffered
+!Finclude/net/mac80211.h ieee80211_sta_block_awake
       </chapter>
 
       <chapter id="multi-iface">
 !Finclude/net/mac80211.h sta_notify_cmd
 !Finclude/net/mac80211.h ieee80211_find_sta
 !Finclude/net/mac80211.h ieee80211_find_sta_by_ifaddr
-!Finclude/net/mac80211.h ieee80211_sta_block_awake
       </chapter>
 
       <chapter id="hardware-scan-offload">
index 1789ce22ea8c5f66bc92e2f1243a80c894fdbeb3..a31c6140a961acf7e6d38e23a4fdec05a497538e 100644 (file)
@@ -3413,7 +3413,7 @@ M:        Wey-Yi Guy <wey-yi.w.guy@intel.com>
 M:     Intel Linux Wireless <ilw@linux.intel.com>
 L:     linux-wireless@vger.kernel.org
 W:     http://intellinuxwireless.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi.git
 S:     Supported
 F:     drivers/net/wireless/iwlwifi/
 
index 43ebc44fc82cdc24d0cff2cb7a3af4cd24267f6f..3b752d9fb3cd7bd9f72264cdf8f003cecebacaaf 100644 (file)
@@ -1249,7 +1249,8 @@ static int adm8211_hw_reset(struct ieee80211_hw *dev)
        return 0;
 }
 
-static u64 adm8211_get_tsft(struct ieee80211_hw *dev)
+static u64 adm8211_get_tsft(struct ieee80211_hw *dev,
+                           struct ieee80211_vif *vif)
 {
        struct adm8211_priv *priv = dev->priv;
        u32 tsftl;
index 298601436ee2631e2eaa8afc9b3f3989ea459e0b..39322d4121b79f17e90ecd39491b666c28c7217a 100644 (file)
@@ -500,10 +500,9 @@ exit:
 
 #define HEX2STR_BUFFERS 4
 #define HEX2STR_MAX_LEN 64
-#define BIN2HEX(x) ((x) < 10 ? '0' + (x) : (x) + 'A' - 10)
 
 /* Convert binary data into hex string */
-static char *hex2str(void *buf, int len)
+static char *hex2str(void *buf, size_t len)
 {
        static atomic_t a = ATOMIC_INIT(0);
        static char bufs[HEX2STR_BUFFERS][3 * HEX2STR_MAX_LEN + 1];
@@ -514,18 +513,17 @@ static char *hex2str(void *buf, int len)
        if (len > HEX2STR_MAX_LEN)
                len = HEX2STR_MAX_LEN;
 
-       if (len <= 0) {
-               ret[0] = '\0';
-               return ret;
-       }
+       if (len == 0)
+               goto exit;
 
        while (len--) {
-               *obuf++ = BIN2HEX(*ibuf >> 4);
-               *obuf++ = BIN2HEX(*ibuf & 0xf);
+               obuf = pack_hex_byte(obuf, *ibuf++);
                *obuf++ = '-';
-               ibuf++;
        }
-       *(--obuf) = '\0';
+       obuf--;
+
+exit:
+       *obuf = '\0';
 
        return ret;
 }
index 0560234ec3f648603e5159dc1f2aa3d9e6425df0..bba4f6fcf7e2c3641db9fe61cd9c5d05e8fcd09a 100644 (file)
@@ -602,7 +602,7 @@ ath5k_conf_tx(struct ieee80211_hw *hw, u16 queue,
 
 
 static u64
-ath5k_get_tsf(struct ieee80211_hw *hw)
+ath5k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
        struct ath5k_hw *ah = hw->priv;
 
@@ -611,7 +611,7 @@ ath5k_get_tsf(struct ieee80211_hw *hw)
 
 
 static void
-ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf)
+ath5k_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u64 tsf)
 {
        struct ath5k_hw *ah = hw->priv;
 
@@ -620,7 +620,7 @@ ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf)
 
 
 static void
-ath5k_reset_tsf(struct ieee80211_hw *hw)
+ath5k_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
        struct ath5k_hw *ah = hw->priv;
 
index f2c6f2316a3b5edad25f18604fe1200216598b19..08e9341f636825097f5f4bcc1a0ed29209ef8fc4 100644 (file)
@@ -1514,7 +1514,7 @@ static const u32 ar9300_2p2_mac_core[][2] = {
        {0x00008258, 0x00000000},
        {0x0000825c, 0x40000000},
        {0x00008260, 0x00080922},
-       {0x00008264, 0x9bc00010},
+       {0x00008264, 0x9d400010},
        {0x00008268, 0xffffffff},
        {0x0000826c, 0x0000ffff},
        {0x00008270, 0x00000000},
index 94d887b65e6993a778c12dd3ca47d55426a013dd..1e86147831812de4f5b20ed8490dc5cd286dbac6 100644 (file)
@@ -340,7 +340,8 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
 void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
 
 void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an);
-bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an);
+void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
+                      struct ath_node *an);
 
 /********/
 /* VIFs */
index 179da20992703fc99af3840d6e51349de5c5c5a3..a5329c98f9ea53858772503669ba4c50e9e4cd6a 100644 (file)
@@ -876,6 +876,15 @@ void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf,
        TX_SAMP_DBG(rssi) = ts->ts_rssi;
        TX_SAMP_DBG(tid) = ts->tid;
        TX_SAMP_DBG(qid) = ts->qid;
+
+       if (ts->ts_flags & ATH9K_TX_BA) {
+               TX_SAMP_DBG(ba_low) = ts->ba_low;
+               TX_SAMP_DBG(ba_high) = ts->ba_high;
+       } else {
+               TX_SAMP_DBG(ba_low) = 0;
+               TX_SAMP_DBG(ba_high) = 0;
+       }
+
        sc->debug.tsidx = (sc->debug.tsidx + 1) % ATH_DBG_MAX_SAMPLES;
        spin_unlock(&sc->debug.samp_lock);
 
@@ -1516,14 +1525,15 @@ static int open_file_bb_mac_samps(struct inode *inode, struct file *file)
        len += snprintf(buf + len, size - len, "Tx status Dump :\n");
        len += snprintf(buf + len, size - len,
                        "Sample rssi:- ctl0 ctl1 ctl2 ext0 ext1 ext2 comb "
-                       "isok rts_fail data_fail rate tid qid tx_before(ms)\n");
+                       "isok rts_fail data_fail rate tid qid "
+                                       "ba_low  ba_high tx_before(ms)\n");
        for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) {
                for (i = 0; i < ATH_DBG_MAX_SAMPLES; i++) {
                        if (!ATH_SAMP_DBG(ts[i].jiffies))
                                continue;
-                       len += snprintf(buf + len, size - len, "%4d \t"
-                               "%8d %4d %4d %4d %4d %4d %4d %4d %4d "
-                               "%4d %4d %2d %2d %d\n",
+                       len += snprintf(buf + len, size - len, "%-14d"
+                               "%-4d %-4d %-4d %-4d %-4d %-4d %-4d %-4d %-8d "
+                               "%-9d %-4d %-3d %-3d %08x %08x %-11d\n",
                                sampidx,
                                ATH_SAMP_DBG(ts[i].rssi_ctl0),
                                ATH_SAMP_DBG(ts[i].rssi_ctl1),
@@ -1538,6 +1548,8 @@ static int open_file_bb_mac_samps(struct inode *inode, struct file *file)
                                ATH_SAMP_DBG(ts[i].rateindex),
                                ATH_SAMP_DBG(ts[i].tid),
                                ATH_SAMP_DBG(ts[i].qid),
+                               ATH_SAMP_DBG(ts[i].ba_low),
+                               ATH_SAMP_DBG(ts[i].ba_high),
                                jiffies_to_msecs(jiffies -
                                        ATH_SAMP_DBG(ts[i].jiffies)));
                }
@@ -1550,8 +1562,8 @@ static int open_file_bb_mac_samps(struct inode *inode, struct file *file)
                for (i = 0; i < ATH_DBG_MAX_SAMPLES; i++) {
                        if (!ATH_SAMP_DBG(rs[i].jiffies))
                                continue;
-                       len += snprintf(buf + len, size - len, "%4d \t"
-                               "%8d %4d %4d %4d %4d %4d %4d %s %4d %02x %d\n",
+                       len += snprintf(buf + len, size - len, "%-14d"
+                               "%-4d %-4d %-4d %-4d %-4d %-4d %-4d %-9s %-2d %02x %-13d\n",
                                sampidx,
                                ATH_SAMP_DBG(rs[i].rssi_ctl0),
                                ATH_SAMP_DBG(rs[i].rssi_ctl1),
index 39f89bc9abcddfcf45ad6615425ddcafbf48f06b..b93e88bd8c5890aa3fbd111b4025cd121201332b 100644 (file)
@@ -196,6 +196,8 @@ struct ath_dbg_bb_mac_samp {
                u8 rateindex;
                u8 qid;
                u8 tid;
+               u32 ba_low;
+               u32 ba_high;
        } ts[ATH_DBG_MAX_SAMPLES];
        struct {
                u64 jiffies;
index afbf5400a52a55f46fd1a815a46aed93bade7565..fd0f84ebdb51994895966c988ae414acd2f797d5 100644 (file)
@@ -84,9 +84,14 @@ void ath_init_leds(struct ath_softc *sc)
 static bool ath_is_rfkill_set(struct ath_softc *sc)
 {
        struct ath_hw *ah = sc->sc_ah;
+       bool is_blocked;
 
-       return ath9k_hw_gpio_get(ah, ah->rfkill_gpio) ==
+       ath9k_ps_wakeup(sc);
+       is_blocked = ath9k_hw_gpio_get(ah, ah->rfkill_gpio) ==
                                  ah->rfkill_polarity;
+       ath9k_ps_restore(sc);
+
+       return is_blocked;
 }
 
 void ath9k_rfkill_poll_state(struct ieee80211_hw *hw)
index db2352e5cc0d5e660d005ac09204e7c0cc46e8c3..e3a02eb8e0cc768dd44f2b49db655ed9d705c02f 100644 (file)
@@ -228,8 +228,14 @@ void ath9k_init_leds(struct ath9k_htc_priv *priv)
 
 static bool ath_is_rfkill_set(struct ath9k_htc_priv *priv)
 {
-       return ath9k_hw_gpio_get(priv->ah, priv->ah->rfkill_gpio) ==
-               priv->ah->rfkill_polarity;
+       bool is_blocked;
+
+       ath9k_htc_ps_wakeup(priv);
+       is_blocked = ath9k_hw_gpio_get(priv->ah, priv->ah->rfkill_gpio) ==
+                                                priv->ah->rfkill_polarity;
+       ath9k_htc_ps_restore(priv);
+
+       return is_blocked;
 }
 
 void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw)
index 495fdf680a6c5269245ef49672c85a52b5bc057b..17dbbd9d2f53c13a2e4366c0dd4da497c83c6711 100644 (file)
@@ -1563,7 +1563,8 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
        mutex_unlock(&priv->mutex);
 }
 
-static u64 ath9k_htc_get_tsf(struct ieee80211_hw *hw)
+static u64 ath9k_htc_get_tsf(struct ieee80211_hw *hw,
+                            struct ieee80211_vif *vif)
 {
        struct ath9k_htc_priv *priv = hw->priv;
        u64 tsf;
@@ -1577,7 +1578,8 @@ static u64 ath9k_htc_get_tsf(struct ieee80211_hw *hw)
        return tsf;
 }
 
-static void ath9k_htc_set_tsf(struct ieee80211_hw *hw, u64 tsf)
+static void ath9k_htc_set_tsf(struct ieee80211_hw *hw,
+                             struct ieee80211_vif *vif, u64 tsf)
 {
        struct ath9k_htc_priv *priv = hw->priv;
 
@@ -1588,7 +1590,8 @@ static void ath9k_htc_set_tsf(struct ieee80211_hw *hw, u64 tsf)
        mutex_unlock(&priv->mutex);
 }
 
-static void ath9k_htc_reset_tsf(struct ieee80211_hw *hw)
+static void ath9k_htc_reset_tsf(struct ieee80211_hw *hw,
+                               struct ieee80211_vif *vif)
 {
        struct ath9k_htc_priv *priv = hw->priv;
 
index ee39702da5d854632db82a7228d0997e1e55ea91..0ebf7321df123dcbd1f496907f2ea13047ca542b 100644 (file)
@@ -133,7 +133,7 @@ void ath9k_ps_restore(struct ath_softc *sc)
        ath_hw_cycle_counters_update(common);
        spin_unlock(&common->cc_lock);
 
-       ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP);
+       ath9k_hw_setpower(sc->sc_ah, mode);
 
  unlock:
        spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
@@ -1833,8 +1833,7 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw,
        switch (cmd) {
        case STA_NOTIFY_SLEEP:
                an->sleeping = true;
-               if (ath_tx_aggr_sleep(sc, an))
-                       ieee80211_sta_set_tim(sta);
+               ath_tx_aggr_sleep(sta, sc, an);
                break;
        case STA_NOTIFY_AWAKE:
                an->sleeping = false;
@@ -2143,7 +2142,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
        ath9k_ps_restore(sc);
 }
 
-static u64 ath9k_get_tsf(struct ieee80211_hw *hw)
+static u64 ath9k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
        struct ath_softc *sc = hw->priv;
        u64 tsf;
@@ -2157,7 +2156,9 @@ static u64 ath9k_get_tsf(struct ieee80211_hw *hw)
        return tsf;
 }
 
-static void ath9k_set_tsf(struct ieee80211_hw *hw, u64 tsf)
+static void ath9k_set_tsf(struct ieee80211_hw *hw,
+                         struct ieee80211_vif *vif,
+                         u64 tsf)
 {
        struct ath_softc *sc = hw->priv;
 
@@ -2168,7 +2169,7 @@ static void ath9k_set_tsf(struct ieee80211_hw *hw, u64 tsf)
        mutex_unlock(&sc->mutex);
 }
 
-static void ath9k_reset_tsf(struct ieee80211_hw *hw)
+static void ath9k_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
        struct ath_softc *sc = hw->priv;
 
index 4f1301881137ee29f6a09b0823ed9a87912f4b6d..8448281dd0691f53cfa41fb260ff7e60f83e64e0 100644 (file)
@@ -1362,12 +1362,6 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
        if (tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED)
                return;
 
-       if (!(tx_info->flags & IEEE80211_TX_STAT_AMPDU)) {
-               tx_info->status.ampdu_ack_len =
-                       (tx_info->flags & IEEE80211_TX_STAT_ACK ? 1 : 0);
-               tx_info->status.ampdu_len = 1;
-       }
-
        if (!(tx_info->flags & IEEE80211_TX_STAT_ACK))
                tx_status = 1;
 
index bcc0b222ec18b7a0091fc913b6269510e3f3d14c..f658ec60b5103333a77106311b47c0221c79a077 100644 (file)
@@ -205,14 +205,22 @@ static void ath_rx_remove_buffer(struct ath_softc *sc,
 
 static void ath_rx_edma_cleanup(struct ath_softc *sc)
 {
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
        struct ath_buf *bf;
 
        ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_LP);
        ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_HP);
 
        list_for_each_entry(bf, &sc->rx.rxbuf, list) {
-               if (bf->bf_mpdu)
+               if (bf->bf_mpdu) {
+                       dma_unmap_single(sc->dev, bf->bf_buf_addr,
+                                       common->rx_bufsize,
+                                       DMA_BIDIRECTIONAL);
                        dev_kfree_skb_any(bf->bf_mpdu);
+                       bf->bf_buf_addr = 0;
+                       bf->bf_mpdu = NULL;
+               }
        }
 
        INIT_LIST_HEAD(&sc->rx.rxbuf);
@@ -578,22 +586,11 @@ static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb)
 
 static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
 {
-       struct ieee80211_mgmt *mgmt;
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 
        if (skb->len < 24 + 8 + 2 + 2)
                return;
 
-       mgmt = (struct ieee80211_mgmt *)skb->data;
-       if (memcmp(common->curbssid, mgmt->bssid, ETH_ALEN) != 0) {
-               /* TODO:  This doesn't work well if you have stations
-                * associated to two different APs because curbssid
-                * is just the last AP that any of the stations associated
-                * with.
-                */
-               return; /* not from our current AP */
-       }
-
        sc->ps_flags &= ~PS_WAIT_FOR_BEACON;
 
        if (sc->ps_flags & PS_BEACON_SYNC) {
@@ -629,7 +626,7 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
        }
 }
 
-static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb)
+static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb, bool mybeacon)
 {
        struct ieee80211_hdr *hdr;
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
@@ -638,7 +635,7 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb)
 
        /* Process Beacon and CAB receive in PS state */
        if (((sc->ps_flags & PS_WAIT_FOR_BEACON) || ath9k_check_auto_sleep(sc))
-           && ieee80211_is_beacon(hdr->frame_control))
+           && mybeacon)
                ath_rx_ps_beacon(sc, skb);
        else if ((sc->ps_flags & PS_WAIT_FOR_CAB) &&
                 (ieee80211_is_data(hdr->frame_control) ||
@@ -1944,10 +1941,10 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
                spin_lock_irqsave(&sc->sc_pm_lock, flags);
 
                if ((sc->ps_flags & (PS_WAIT_FOR_BEACON |
-                                             PS_WAIT_FOR_CAB |
-                                             PS_WAIT_FOR_PSPOLL_DATA)) ||
-                                               ath9k_check_auto_sleep(sc))
-                       ath_rx_ps(sc, skb);
+                                    PS_WAIT_FOR_CAB |
+                                    PS_WAIT_FOR_PSPOLL_DATA)) ||
+                   ath9k_check_auto_sleep(sc))
+                       ath_rx_ps(sc, skb, rs.is_mybeacon);
                spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
 
                if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx == 3)
index fa3dcfdf71743255771dd4c6f314687ff2ca0b0b..c2bfc57958d82a2737f405167f5f4217f5266f03 100644 (file)
@@ -542,7 +542,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
        /* prepend un-acked frames to the beginning of the pending frame queue */
        if (!skb_queue_empty(&bf_pending)) {
                if (an->sleeping)
-                       ieee80211_sta_set_tim(sta);
+                       ieee80211_sta_set_buffered(sta, tid->tidno, true);
 
                spin_lock_bh(&txq->axq_lock);
                if (clear_filter)
@@ -1153,12 +1153,13 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
        ath_tx_flush_tid(sc, txtid);
 }
 
-bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an)
+void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
+                      struct ath_node *an)
 {
        struct ath_atx_tid *tid;
        struct ath_atx_ac *ac;
        struct ath_txq *txq;
-       bool buffered = false;
+       bool buffered;
        int tidno;
 
        for (tidno = 0, tid = &an->tid[tidno];
@@ -1172,8 +1173,7 @@ bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an)
 
                spin_lock_bh(&txq->axq_lock);
 
-               if (!skb_queue_empty(&tid->buf_q))
-                       buffered = true;
+               buffered = !skb_queue_empty(&tid->buf_q);
 
                tid->sched = false;
                list_del(&tid->list);
@@ -1184,9 +1184,9 @@ bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an)
                }
 
                spin_unlock_bh(&txq->axq_lock);
-       }
 
-       return buffered;
+               ieee80211_sta_set_buffered(sta, tidno, buffered);
+       }
 }
 
 void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)
@@ -2043,10 +2043,9 @@ static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf,
                tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
 
                BUG_ON(nbad > nframes);
-
-               tx_info->status.ampdu_len = nframes;
-               tx_info->status.ampdu_ack_len = nframes - nbad;
        }
+       tx_info->status.ampdu_len = nframes;
+       tx_info->status.ampdu_ack_len = nframes - nbad;
 
        if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 &&
            (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) == 0) {
index af351ecd87c40810ad2c0102b9a3a112a5cbea6d..8b780d6d470f4f4cfb9315382e82811d8cb5c3db 100644 (file)
@@ -1078,7 +1078,8 @@ out:
        mutex_unlock(&ar->mutex);
 }
 
-static u64 carl9170_op_get_tsf(struct ieee80211_hw *hw)
+static u64 carl9170_op_get_tsf(struct ieee80211_hw *hw,
+                              struct ieee80211_vif *vif)
 {
        struct ar9170 *ar = hw->priv;
        struct carl9170_tsf_rsp tsf;
index f8615cdf1075b7102403a1f352821ef756adb505..447a2307c9d9ae2bdb7657c2f0160f978c8e55e9 100644 (file)
 #define B43_MMIO_RADIO_HWENABLED_LO    0x49A
 #define B43_MMIO_GPIO_CONTROL          0x49C
 #define B43_MMIO_GPIO_MASK             0x49E
+#define B43_MMIO_TXE0_CTL              0x500
+#define B43_MMIO_TXE0_AUX              0x502
+#define B43_MMIO_TXE0_TS_LOC           0x504
+#define B43_MMIO_TXE0_TIME_OUT         0x506
+#define B43_MMIO_TXE0_WM_0             0x508
+#define B43_MMIO_TXE0_WM_1             0x50A
+#define B43_MMIO_TXE0_PHYCTL           0x50C
+#define B43_MMIO_TXE0_STATUS           0x50E
+#define B43_MMIO_TXE0_MMPLCP0          0x510
+#define B43_MMIO_TXE0_MMPLCP1          0x512
+#define B43_MMIO_TXE0_PHYCTL1          0x514
+#define B43_MMIO_XMTFIFODEF            0x520
+#define B43_MMIO_XMTFIFO_FRAME_CNT     0x522   /* core rev>= 16 only */
+#define B43_MMIO_XMTFIFO_BYTE_CNT      0x524   /* core rev>= 16 only */
+#define B43_MMIO_XMTFIFO_HEAD          0x526   /* core rev>= 16 only */
+#define B43_MMIO_XMTFIFO_RD_PTR                0x528   /* core rev>= 16 only */
+#define B43_MMIO_XMTFIFO_WR_PTR                0x52A   /* core rev>= 16 only */
+#define B43_MMIO_XMTFIFODEF1           0x52C   /* core rev>= 16 only */
+#define B43_MMIO_XMTFIFOCMD            0x540
+#define B43_MMIO_XMTFIFOFLUSH          0x542
+#define B43_MMIO_XMTFIFOTHRESH         0x544
+#define B43_MMIO_XMTFIFORDY            0x546
+#define B43_MMIO_XMTFIFOPRIRDY         0x548
+#define B43_MMIO_XMTFIFORQPRI          0x54A
+#define B43_MMIO_XMTTPLATETXPTR                0x54C
+#define B43_MMIO_XMTTPLATEPTR          0x550
+#define B43_MMIO_SMPL_CLCT_STRPTR      0x552   /* core rev>= 22 only */
+#define B43_MMIO_SMPL_CLCT_STPPTR      0x554   /* core rev>= 22 only */
+#define B43_MMIO_SMPL_CLCT_CURPTR      0x556   /* core rev>= 22 only */
+#define B43_MMIO_XMTTPLATEDATALO       0x560
+#define B43_MMIO_XMTTPLATEDATAHI       0x562
+#define B43_MMIO_XMTSEL                        0x568
+#define B43_MMIO_XMTTXCNT              0x56A
+#define B43_MMIO_XMTTXSHMADDR          0x56C
 #define B43_MMIO_TSF_CFP_START_LOW     0x604
 #define B43_MMIO_TSF_CFP_START_HIGH    0x606
 #define B43_MMIO_TSF_CFP_PRETBTT       0x612
 #define B43_MMIO_TSF_3                 0x638   /* core rev < 3 only */
 #define B43_MMIO_RNG                   0x65A
 #define B43_MMIO_IFSSLOT               0x684   /* Interframe slot time */
-#define B43_MMIO_IFSCTL                        0x688 /* Interframe space control */
+#define B43_MMIO_IFSCTL                        0x688   /* Interframe space control */
+#define B43_MMIO_IFSSTAT               0x690
+#define B43_MMIO_IFSMEDBUSYCTL         0x692
+#define B43_MMIO_IFTXDUR               0x694
 #define  B43_MMIO_IFSCTL_USE_EDCF      0x0004
 #define B43_MMIO_POWERUP_DELAY         0x6A8
 #define B43_MMIO_BTCOEX_CTL            0x6B4 /* Bluetooth Coexistence Control */
 #define B43_MMIO_BTCOEX_STAT           0x6B6 /* Bluetooth Coexistence Status */
 #define B43_MMIO_BTCOEX_TXCTL          0x6B8 /* Bluetooth Coexistence Transmit Control */
+#define B43_MMIO_WEPCTL                        0x7C0
 
 /* SPROM boardflags_lo values */
 #define B43_BFL_BTCOEXIST              0x0001  /* implements Bluetooth coexistance */
index 56fa3a3648c43dbc32a015ece857a0f3f5bcaeac..43400fb62e1cf5e7b68cec1bebf0c6c892b81908 100644 (file)
@@ -729,52 +729,59 @@ void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on)
        for (i = 0; i < 5; i++)
                b43_ram_write(dev, i * 4, buffer[i]);
 
-       b43_write16(dev, 0x0568, 0x0000);
+       b43_write16(dev, B43_MMIO_XMTSEL, 0x0000);
+
        if (dev->dev->core_rev < 11)
-               b43_write16(dev, 0x07C0, 0x0000);
+               b43_write16(dev, B43_MMIO_WEPCTL, 0x0000);
        else
-               b43_write16(dev, 0x07C0, 0x0100);
+               b43_write16(dev, B43_MMIO_WEPCTL, 0x0100);
+
        value = (ofdm ? 0x41 : 0x40);
-       b43_write16(dev, 0x050C, value);
-       if ((phy->type == B43_PHYTYPE_N) || (phy->type == B43_PHYTYPE_LP))
-               b43_write16(dev, 0x0514, 0x1A02);
-       b43_write16(dev, 0x0508, 0x0000);
-       b43_write16(dev, 0x050A, 0x0000);
-       b43_write16(dev, 0x054C, 0x0000);
-       b43_write16(dev, 0x056A, 0x0014);
-       b43_write16(dev, 0x0568, 0x0826);
-       b43_write16(dev, 0x0500, 0x0000);
-       if (!pa_on && (phy->type == B43_PHYTYPE_N)) {
-               //SPEC TODO
-       }
+       b43_write16(dev, B43_MMIO_TXE0_PHYCTL, value);
+       if (phy->type == B43_PHYTYPE_N || phy->type == B43_PHYTYPE_LP ||
+           phy->type == B43_PHYTYPE_LCN)
+               b43_write16(dev, B43_MMIO_TXE0_PHYCTL1, 0x1A02);
+
+       b43_write16(dev, B43_MMIO_TXE0_WM_0, 0x0000);
+       b43_write16(dev, B43_MMIO_TXE0_WM_1, 0x0000);
+
+       b43_write16(dev, B43_MMIO_XMTTPLATETXPTR, 0x0000);
+       b43_write16(dev, B43_MMIO_XMTTXCNT, 0x0014);
+       b43_write16(dev, B43_MMIO_XMTSEL, 0x0826);
+       b43_write16(dev, B43_MMIO_TXE0_CTL, 0x0000);
+
+       if (!pa_on && phy->type == B43_PHYTYPE_N)
+               ; /*b43_nphy_pa_override(dev, false) */
 
        switch (phy->type) {
        case B43_PHYTYPE_N:
-               b43_write16(dev, 0x0502, 0x00D0);
+       case B43_PHYTYPE_LCN:
+               b43_write16(dev, B43_MMIO_TXE0_AUX, 0x00D0);
                break;
        case B43_PHYTYPE_LP:
-               b43_write16(dev, 0x0502, 0x0050);
+               b43_write16(dev, B43_MMIO_TXE0_AUX, 0x0050);
                break;
        default:
-               b43_write16(dev, 0x0502, 0x0030);
+               b43_write16(dev, B43_MMIO_TXE0_AUX, 0x0030);
        }
+       b43_read16(dev, B43_MMIO_TXE0_AUX);
 
        if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5)
                b43_radio_write16(dev, 0x0051, 0x0017);
        for (i = 0x00; i < max_loop; i++) {
-               value = b43_read16(dev, 0x050E);
+               value = b43_read16(dev, B43_MMIO_TXE0_STATUS);
                if (value & 0x0080)
                        break;
                udelay(10);
        }
        for (i = 0x00; i < 0x0A; i++) {
-               value = b43_read16(dev, 0x050E);
+               value = b43_read16(dev, B43_MMIO_TXE0_STATUS);
                if (value & 0x0400)
                        break;
                udelay(10);
        }
        for (i = 0x00; i < 0x19; i++) {
-               value = b43_read16(dev, 0x0690);
+               value = b43_read16(dev, B43_MMIO_IFSSTAT);
                if (!(value & 0x0100))
                        break;
                udelay(10);
@@ -3599,7 +3606,7 @@ static int b43_op_get_stats(struct ieee80211_hw *hw,
        return 0;
 }
 
-static u64 b43_op_get_tsf(struct ieee80211_hw *hw)
+static u64 b43_op_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
        struct b43_wldev *dev;
@@ -3618,7 +3625,8 @@ static u64 b43_op_get_tsf(struct ieee80211_hw *hw)
        return tsf;
 }
 
-static void b43_op_set_tsf(struct ieee80211_hw *hw, u64 tsf)
+static void b43_op_set_tsf(struct ieee80211_hw *hw,
+                          struct ieee80211_vif *vif, u64 tsf)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
        struct b43_wldev *dev;
index bffeb44b4a4088c3ff22765e55cfd2be81b45871..a13e28ef6246af2dd344025d1b394403572fd5f3 100644 (file)
@@ -433,7 +433,7 @@ static void b43_phy_lcn_sense_setup(struct b43_wldev *dev,
        b43_phy_set(dev, 0x4d0, 0x20);
        b43_radio_write(dev, 0x112, 0x6);
 
-       /* TODO: dummy transmission? */
+       b43_dummy_transmission(dev, true, false);
        /* Wait if not done */
        if (!(b43_phy_read(dev, 0x476) & 0x8000))
                udelay(10);
index 9d484e2f79bfd96f5ad2dd60b25c1334ce173e7f..5176363cadf297f720d7ddca09293a8c96cb5f8e 100644 (file)
@@ -657,8 +657,25 @@ void b43_phy_lcn_load_tx_gain_tab(struct b43_wldev *dev,
        }
 }
 
+/* wlc_lcnphy_load_rfpower */
+static void b43_phy_lcn_load_rfpower(struct b43_wldev *dev)
+{
+       u32 bbmult, rfgain;
+       u8 i;
+
+       for (i = 0; i < 128; i++) {
+               bbmult = b43_lcntab_read(dev, B43_LCNTAB32(0x7, 0x140 + i));
+               bbmult >>= 20;
+               rfgain = b43_lcntab_read(dev, B43_LCNTAB32(0x7, 0xc0 + i));
+
+               /* TODO: calculate value for 0x240 + i table offset
+                * b43_lcntab_write(dev, B43_LCNTAB32(0x7, 0x240 + i), val);
+                */
+       }
+}
+
 /* Not implemented in brcmsmac, noticed in wl in MMIO dump */
-static void b43_phy_lcn_rewrite_tables(struct b43_wldev *dev)
+static void b43_phy_lcn_rewrite_rfpower_table(struct b43_wldev *dev)
 {
        int i;
        u32 tmp;
@@ -685,7 +702,7 @@ void b43_phy_lcn_tables_init(struct b43_wldev *dev)
        b43_phy_lcn_upload_static_tables(dev);
 
        if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
-               if (sprom->boardflags_lo & B43_BFL_EXTLNA)
+               if (sprom->boardflags_lo & B43_BFL_FEM)
                        b43_phy_lcn_load_tx_gain_tab(dev,
                                b43_lcntab_tx_gain_tbl_2ghz_ext_pa_rev0);
                else
@@ -701,7 +718,7 @@ void b43_phy_lcn_tables_init(struct b43_wldev *dev)
        else
                b43err(dev->wl, "SW ctl table is unknown for this card\n");
 
-       /* TODO: various tables ops here */
-       b43_phy_lcn_rewrite_tables(dev);
+       b43_phy_lcn_load_rfpower(dev);
+       b43_phy_lcn_rewrite_rfpower_table(dev);
        b43_phy_lcn_clean_papd_comp_table(dev);
 }
index ac4f64de1363e597c1616f23539896f26f8b53ab..7f12e3638bae4b403916babbc52971a32a3247b8 100644 (file)
@@ -335,7 +335,7 @@ int iwl4965_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
                sta_priv = (void *)sta->drv_priv;
 
        if (sta_priv && sta_priv->asleep &&
-           (info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE)) {
+           (info->flags & IEEE80211_TX_CTL_POLL_RESPONSE)) {
                /*
                 * This sends an asynchronous command to the device,
                 * but we can rely on it being processed before the
index 35cd2537e7fd2cf13bdf8ff185498b108beaee7f..8928d47432df95ba1869831c0bfa42d1114de943 100644 (file)
@@ -937,7 +937,7 @@ void iwl_legacy_irq_handle_error(struct iwl_priv *priv)
                                        &priv->contexts[IWL_RXON_CTX_BSS]);
 #endif
 
-       wake_up_interruptible(&priv->wait_command_queue);
+       wake_up(&priv->wait_command_queue);
 
        /* Keep the restart process from trying to send host
         * commands by clearing the INIT status bit */
@@ -1746,7 +1746,7 @@ int iwl_legacy_force_reset(struct iwl_priv *priv, bool external)
 
        /* Set the FW error flag -- cleared on iwl_down */
        set_bit(STATUS_FW_ERROR, &priv->status);
-       wake_up_interruptible(&priv->wait_command_queue);
+       wake_up(&priv->wait_command_queue);
        /*
         * Keep the restart process from trying to send host
         * commands by clearing the INIT status bit
@@ -2220,7 +2220,8 @@ out:
 }
 EXPORT_SYMBOL(iwl_legacy_mac_config);
 
-void iwl_legacy_mac_reset_tsf(struct ieee80211_hw *hw)
+void iwl_legacy_mac_reset_tsf(struct ieee80211_hw *hw,
+                             struct ieee80211_vif *vif)
 {
        struct iwl_priv *priv = hw->priv;
        unsigned long flags;
index 84da79376ef8c16c835c533d056aa9ea4ca940be..b2df01c8f8f5d64dc0cab2571742c4de9be0bd0a 100644 (file)
@@ -620,7 +620,8 @@ static inline const struct ieee80211_supported_band *iwl_get_hw_mode(
 
 /* mac80211 handlers */
 int iwl_legacy_mac_config(struct ieee80211_hw *hw, u32 changed);
-void iwl_legacy_mac_reset_tsf(struct ieee80211_hw *hw);
+void iwl_legacy_mac_reset_tsf(struct ieee80211_hw *hw,
+                             struct ieee80211_vif *vif);
 void iwl_legacy_mac_bss_info_changed(struct ieee80211_hw *hw,
                                     struct ieee80211_vif *vif,
                                     struct ieee80211_bss_conf *bss_conf,
index 62b4b09122cbac4489561a0a1428cc70d7a5b538..ce1fc9feb61f68487d3bc2f043d9feefa4fc8b72 100644 (file)
@@ -167,7 +167,7 @@ int iwl_legacy_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
                goto out;
        }
 
-       ret = wait_event_interruptible_timeout(priv->wait_command_queue,
+       ret = wait_event_timeout(priv->wait_command_queue,
                        !test_bit(STATUS_HCMD_ACTIVE, &priv->status),
                        HOST_COMPLETE_TIMEOUT);
        if (!ret) {
index 4fff995c6f3e2f4cbb97139d52625fa5ccce2321..ef9e268bf8a074ea3707b04992e758f52dc0eb8d 100644 (file)
@@ -625,6 +625,8 @@ iwl_legacy_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
        cmd = txq->cmd[cmd_index];
        meta = &txq->meta[cmd_index];
 
+       txq->time_stamp = jiffies;
+
        pci_unmap_single(priv->pci_dev,
                         dma_unmap_addr(meta, mapping),
                         dma_unmap_len(meta, len),
@@ -645,7 +647,7 @@ iwl_legacy_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
                clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
                IWL_DEBUG_INFO(priv, "Clearing HCMD_ACTIVE for command %s\n",
                               iwl_legacy_get_cmd_string(cmd->hdr.cmd));
-               wake_up_interruptible(&priv->wait_command_queue);
+               wake_up(&priv->wait_command_queue);
        }
 
        /* Mark as unmapped */
index 015739d204f225bafecc4cf7222c4be6d3ee130d..b282d869a546a79dcdc52fca43788e9069785eb9 100644 (file)
@@ -840,7 +840,7 @@ static void iwl3945_rx_card_state_notif(struct iwl_priv *priv,
                wiphy_rfkill_set_hw_state(priv->hw->wiphy,
                                test_bit(STATUS_RF_KILL_HW, &priv->status));
        else
-               wake_up_interruptible(&priv->wait_command_queue);
+               wake_up(&priv->wait_command_queue);
 }
 
 /**
@@ -2268,7 +2268,7 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
        iwl3945_reg_txpower_periodic(priv);
 
        IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n");
-       wake_up_interruptible(&priv->wait_command_queue);
+       wake_up(&priv->wait_command_queue);
 
        return;
 
@@ -2299,7 +2299,7 @@ static void __iwl3945_down(struct iwl_priv *priv)
        iwl_legacy_clear_driver_stations(priv);
 
        /* Unblock any waiting calls */
-       wake_up_interruptible_all(&priv->wait_command_queue);
+       wake_up_all(&priv->wait_command_queue);
 
        /* Wipe out the EXIT_PENDING status bit if we are not actually
         * exiting the module */
@@ -2852,7 +2852,7 @@ static int iwl3945_mac_start(struct ieee80211_hw *hw)
 
        /* Wait for START_ALIVE from ucode. Otherwise callbacks from
         * mac80211 will not be run successfully. */
-       ret = wait_event_interruptible_timeout(priv->wait_command_queue,
+       ret = wait_event_timeout(priv->wait_command_queue,
                        test_bit(STATUS_READY, &priv->status),
                        UCODE_READY_TIMEOUT);
        if (!ret) {
index 6bc5575c8dff67dfe242b035b7a2ec11c005028f..d2fba9eae1536a00b4f7b833617b1f83ccf11062 100644 (file)
@@ -575,7 +575,7 @@ static void iwl4965_rx_card_state_notif(struct iwl_priv *priv,
                wiphy_rfkill_set_hw_state(priv->hw->wiphy,
                        test_bit(STATUS_RF_KILL_HW, &priv->status));
        else
-               wake_up_interruptible(&priv->wait_command_queue);
+               wake_up(&priv->wait_command_queue);
 }
 
 /**
@@ -925,7 +925,7 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv)
                handled |= CSR_INT_BIT_FH_TX;
                /* Wake up uCode load routine, now that load is complete */
                priv->ucode_write_complete = 1;
-               wake_up_interruptible(&priv->wait_command_queue);
+               wake_up(&priv->wait_command_queue);
        }
 
        if (inta & ~handled) {
@@ -1794,7 +1794,7 @@ static void iwl4965_alive_start(struct iwl_priv *priv)
        iwl4965_rf_kill_ct_config(priv);
 
        IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n");
-       wake_up_interruptible(&priv->wait_command_queue);
+       wake_up(&priv->wait_command_queue);
 
        iwl_legacy_power_update_mode(priv, true);
        IWL_DEBUG_INFO(priv, "Updated power mode\n");
@@ -1827,7 +1827,7 @@ static void __iwl4965_down(struct iwl_priv *priv)
        iwl_legacy_clear_driver_stations(priv);
 
        /* Unblock any waiting calls */
-       wake_up_interruptible_all(&priv->wait_command_queue);
+       wake_up_all(&priv->wait_command_queue);
 
        /* Wipe out the EXIT_PENDING status bit if we are not actually
         * exiting the module */
@@ -2265,7 +2265,7 @@ int iwl4965_mac_start(struct ieee80211_hw *hw)
 
        /* Wait for START_ALIVE from Run Time ucode. Otherwise callbacks from
         * mac80211 will not be run successfully. */
-       ret = wait_event_interruptible_timeout(priv->wait_command_queue,
+       ret = wait_event_timeout(priv->wait_command_queue,
                        test_bit(STATUS_READY, &priv->status),
                        UCODE_READY_TIMEOUT);
        if (!ret) {
index c14f8d6fd7d8d36878f071ba907ebe0661f5c848..7d6a3bf6495097e632a637800de5b4d1cc3e195c 100644 (file)
@@ -2273,9 +2273,6 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
            info->flags & IEEE80211_TX_CTL_NO_ACK)
                return;
 
-       if (!sta || !lq_sta)
-               return;
-
        lq_sta->supp_rates = sta->supp_rates[lq_sta->band];
 
        tid = rs_tl_add_packet(lq_sta, hdr);
index 00e6fc59e4590967625ef963c5ab58d4325b210b..ca632f9b1cc879bdc0ee69605db5590ca55bdd93 100644 (file)
@@ -370,7 +370,7 @@ int iwlagn_set_pan_params(struct iwl_priv *priv)
                        slot1 = IWL_MIN_SLOT_TIME;
                } else if (!ctx_pan->vif->bss_conf.idle &&
                           !ctx_pan->vif->bss_conf.assoc) {
-                       slot1 = bcnint * 3 - IWL_MIN_SLOT_TIME;
+                       slot1 = dtim * bcnint * 3 - IWL_MIN_SLOT_TIME;
                        slot0 = IWL_MIN_SLOT_TIME;
                }
        } else if (ctx_pan->vif) {
index 495f936647414b8ceaf38b74ea5bc7d26cd15a95..c27180a73351752b59015900f90f174b34c0929d 100644 (file)
@@ -114,9 +114,6 @@ static bool iwl_within_ct_kill_margin(struct iwl_priv *priv)
        s32 temp = priv->temperature; /* degrees CELSIUS except specified */
        bool within_margin = false;
 
-       if (priv->cfg->base_params->temperature_kelvin)
-               temp = KELVIN_TO_CELSIUS(priv->temperature);
-
        if (!priv->thermal_throttle.advanced_tt)
                within_margin = ((temp + IWL_TT_CT_KILL_MARGIN) >=
                                CT_KILL_THRESHOLD_LEGACY) ? true : false;
@@ -591,9 +588,6 @@ static void iwl_bg_tt_work(struct work_struct *work)
        if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
                return;
 
-       if (priv->cfg->base_params->temperature_kelvin)
-               temp = KELVIN_TO_CELSIUS(priv->temperature);
-
        if (!priv->thermal_throttle.advanced_tt)
                iwl_legacy_tt_handler(priv, temp, false);
        else
@@ -641,11 +635,13 @@ void iwl_tt_initialize(struct iwl_priv *priv)
 
        if (priv->cfg->base_params->adv_thermal_throttle) {
                IWL_DEBUG_TEMP(priv, "Advanced Thermal Throttling\n");
-               tt->restriction = kzalloc(sizeof(struct iwl_tt_restriction) *
-                                        IWL_TI_STATE_MAX, GFP_KERNEL);
-               tt->transaction = kzalloc(sizeof(struct iwl_tt_trans) *
-                       IWL_TI_STATE_MAX * (IWL_TI_STATE_MAX - 1),
-                       GFP_KERNEL);
+               tt->restriction = kcalloc(IWL_TI_STATE_MAX,
+                                         sizeof(struct iwl_tt_restriction),
+                                         GFP_KERNEL);
+               tt->transaction = kcalloc(IWL_TI_STATE_MAX *
+                                         (IWL_TI_STATE_MAX - 1),
+                                         sizeof(struct iwl_tt_trans),
+                                         GFP_KERNEL);
                if (!tt->restriction || !tt->transaction) {
                        IWL_ERR(priv, "Fallback to Legacy Throttling\n");
                        priv->thermal_throttle.advanced_tt = false;
index 8c0f07f56149bf07ea2208e7dace8ad542baf7ef..dcb3bd67d4f993f0a80dac0ba2ddc5f55dc4b5f2 100644 (file)
@@ -300,7 +300,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
                sta_priv = (void *)info->control.sta->drv_priv;
 
        if (sta_priv && sta_priv->asleep &&
-           (info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE)) {
+           (info->flags & IEEE80211_TX_CTL_POLL_RESPONSE)) {
                /*
                 * This sends an asynchronous command to the device,
                 * but we can rely on it being processed before the
@@ -327,9 +327,6 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
        memset(dev_cmd, 0, sizeof(*dev_cmd));
        tx_cmd = (struct iwl_tx_cmd *) dev_cmd->payload;
 
-       /* Copy MAC header from skb into command buffer */
-       memcpy(tx_cmd->hdr, hdr, hdr_len);
-
        /* Total # bytes to be transmitted */
        len = (u16)skb->len;
        tx_cmd->len = cpu_to_le16(len);
@@ -345,6 +342,8 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
 
        iwl_update_stats(priv, true, fc, len);
 
+       memset(&info->status, 0, sizeof(info->status));
+
        info->driver_data[0] = ctx;
        info->driver_data[1] = dev_cmd;
 
@@ -583,6 +582,9 @@ static void iwl_rx_reply_tx_agg(struct iwl_priv *priv,
                IWL_DEBUG_COEX(priv, "receive reply tx w/ bt_kill\n");
        }
 
+       if (tx_resp->frame_count == 1)
+               return;
+
        /* Construct bit-map of pending frames within Tx window */
        for (i = 0; i < tx_resp->frame_count; i++) {
                u16 fstatus = le16_to_cpu(frame_status[i].status);
@@ -941,7 +943,10 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
                else
                        WARN_ON_ONCE(1);
 
-               if (freed == 0) {
+               info = IEEE80211_SKB_CB(skb);
+               kmem_cache_free(priv->tx_cmd_pool, (info->driver_data[1]));
+
+               if (freed == 1) {
                        /* this is the first skb we deliver in this batch */
                        /* put the rate scaling data there */
                        info = IEEE80211_SKB_CB(skb);
@@ -954,9 +959,6 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
                                                    info);
                }
 
-               info = IEEE80211_SKB_CB(skb);
-               kmem_cache_free(priv->tx_cmd_pool, (info->driver_data[1]));
-
                ieee80211_tx_status_irqsafe(priv->hw, skb);
        }
 
index cea6520fafdb27789de270af3357e7b8739409d5..fc400bb2bdffa8b0c4e646b601a927d608534543 100644 (file)
@@ -125,12 +125,12 @@ int iwl_init_geos(struct iwl_priv *priv)
                return 0;
        }
 
-       channels = kzalloc(sizeof(struct ieee80211_channel) *
-                          priv->channel_count, GFP_KERNEL);
+       channels = kcalloc(priv->channel_count,
+                          sizeof(struct ieee80211_channel), GFP_KERNEL);
        if (!channels)
                return -ENOMEM;
 
-       rates = kzalloc((sizeof(struct ieee80211_rate) * IWL_RATE_COUNT_LEGACY),
+       rates = kcalloc(IWL_RATE_COUNT_LEGACY, sizeof(struct ieee80211_rate),
                        GFP_KERNEL);
        if (!rates) {
                kfree(channels);
index 74d4cff09faec02b3bb3bfed7c9d731d4f4d0e30..e55ffad83950110e44326873935b6a1c14a5edcb 100644 (file)
@@ -108,7 +108,6 @@ struct iwl_lib_ops {
  *     radio tuning when there is a high receiving plcp error rate
  * @chain_noise_scale: default chain noise scale used for gain computation
  * @wd_timeout: TX queues watchdog timeout
- * @temperature_kelvin: temperature report by uCode in kelvin
  * @max_event_log_size: size of event log buffer size for ucode event logging
  * @shadow_reg_enable: HW shadhow register bit
  * @no_idle_support: do not support idle mode
@@ -130,7 +129,6 @@ struct iwl_base_params {
        u8 plcp_delta_threshold;
        s32 chain_noise_scale;
        unsigned int wd_timeout;
-       bool temperature_kelvin;
        u32 max_event_log_size;
        const bool shadow_reg_enable;
        const bool no_idle_support;
@@ -320,7 +318,7 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force);
  ******************************************************************************/
 void iwl_init_scan_params(struct iwl_priv *priv);
 int iwl_scan_cancel(struct iwl_priv *priv);
-int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms);
+void iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms);
 void iwl_force_scan_end(struct iwl_priv *priv);
 int iwl_mac_hw_scan(struct ieee80211_hw *hw,
                    struct ieee80211_vif *vif,
index bf2a678970a9a08ada4efe209a53d491fece370b..6d49dfbee964888685b1e2b1a14a9cbe5f54cb7a 100644 (file)
@@ -715,6 +715,20 @@ static ssize_t iwl_dbgfs_disable_ht40_read(struct file *file,
        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 }
 
+static ssize_t iwl_dbgfs_temperature_read(struct file *file,
+                                        char __user *user_buf,
+                                        size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = file->private_data;
+       char buf[8];
+       int pos = 0;
+       const size_t bufsz = sizeof(buf);
+
+       pos += scnprintf(buf + pos, bufsz - pos, "%d\n", priv->temperature);
+       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+
 static ssize_t iwl_dbgfs_sleep_level_override_write(struct file *file,
                                                    const char __user *user_buf,
                                                    size_t count, loff_t *ppos)
@@ -809,6 +823,7 @@ DEBUGFS_READ_WRITE_FILE_OPS(rx_handlers);
 DEBUGFS_READ_FILE_OPS(qos);
 DEBUGFS_READ_FILE_OPS(thermal_throttling);
 DEBUGFS_READ_WRITE_FILE_OPS(disable_ht40);
+DEBUGFS_READ_FILE_OPS(temperature);
 DEBUGFS_READ_WRITE_FILE_OPS(sleep_level_override);
 DEBUGFS_READ_FILE_OPS(current_sleep_command);
 
@@ -2536,7 +2551,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
        DEBUGFS_ADD_FILE(current_sleep_command, dir_data, S_IRUSR);
        DEBUGFS_ADD_FILE(thermal_throttling, dir_data, S_IRUSR);
        DEBUGFS_ADD_FILE(disable_ht40, dir_data, S_IWUSR | S_IRUSR);
-       DEBUGFS_ADD_U32(temperature, dir_data, &priv->temperature, S_IRUSR);
+       DEBUGFS_ADD_FILE(temperature, dir_data, S_IRUSR);
 
        DEBUGFS_ADD_FILE(rx_statistics, dir_debug, S_IRUSR);
        DEBUGFS_ADD_FILE(tx_statistics, dir_debug, S_IRUSR);
index 4ddaf2c63f50071c06f28a08452b1036f602ab24..257aa9a407ca1ec62d170fc1d6113ae7e984c708 100644 (file)
@@ -877,7 +877,7 @@ struct iwl_priv {
        u8 channel_count;       /* # of channels */
 
        /* thermal calibration */
-       s32 temperature;        /* degrees Kelvin */
+       s32 temperature;        /* Celsius */
        s32 last_temperature;
 
        /* init calibration results */
index 0b669417b0a604f4928f1c559af4322788e20aca..a4e43bd4a54763bfac47354088f027a4023ebc63 100644 (file)
@@ -899,8 +899,9 @@ int iwl_init_channel_map(struct iwl_priv *priv)
        IWL_DEBUG_EEPROM(priv, "Parsing data for %d channels.\n",
                        priv->channel_count);
 
-       priv->channel_info = kzalloc(sizeof(struct iwl_channel_info) *
-                                    priv->channel_count, GFP_KERNEL);
+       priv->channel_info = kcalloc(priv->channel_count,
+                                    sizeof(struct iwl_channel_info),
+                                    GFP_KERNEL);
        if (!priv->channel_info) {
                IWL_ERR(priv, "Could not allocate channel_info\n");
                priv->channel_count = 0;
index 2b6db24daf70d6b04b5a6f5fb4e6925751942a39..c5c95d5319b19f172deb0b806e764e10d1181477 100644 (file)
@@ -114,6 +114,65 @@ static void iwl_complete_scan(struct iwl_priv *priv, bool aborted)
        priv->scan_request = NULL;
 }
 
+static void iwl_process_scan_complete(struct iwl_priv *priv)
+{
+       bool aborted;
+
+       lockdep_assert_held(&priv->shrd->mutex);
+
+       if (!test_and_clear_bit(STATUS_SCAN_COMPLETE, &priv->shrd->status))
+               return;
+
+       IWL_DEBUG_SCAN(priv, "Completed scan.\n");
+
+       cancel_delayed_work(&priv->scan_check);
+
+       aborted = test_and_clear_bit(STATUS_SCAN_ABORTING, &priv->shrd->status);
+       if (aborted)
+               IWL_DEBUG_SCAN(priv, "Aborted scan completed.\n");
+
+       if (!test_and_clear_bit(STATUS_SCANNING, &priv->shrd->status)) {
+               IWL_DEBUG_SCAN(priv, "Scan already completed.\n");
+               goto out_settings;
+       }
+
+       if (priv->scan_type == IWL_SCAN_ROC) {
+               ieee80211_remain_on_channel_expired(priv->hw);
+               priv->hw_roc_channel = NULL;
+               schedule_delayed_work(&priv->hw_roc_disable_work, 10 * HZ);
+       }
+
+       if (priv->scan_type != IWL_SCAN_NORMAL && !aborted) {
+               int err;
+
+               /* Check if mac80211 requested scan during our internal scan */
+               if (priv->scan_request == NULL)
+                       goto out_complete;
+
+               /* If so request a new scan */
+               err = iwl_scan_initiate(priv, priv->scan_vif, IWL_SCAN_NORMAL,
+                                       priv->scan_request->channels[0]->band);
+               if (err) {
+                       IWL_DEBUG_SCAN(priv,
+                               "failed to initiate pending scan: %d\n", err);
+                       aborted = true;
+                       goto out_complete;
+               }
+
+               return;
+       }
+
+out_complete:
+       iwl_complete_scan(priv, aborted);
+
+out_settings:
+       /* Can we still talk to firmware ? */
+       if (!iwl_is_ready_rf(priv->shrd))
+               return;
+
+       iwlagn_post_scan(priv);
+}
+
 void iwl_force_scan_end(struct iwl_priv *priv)
 {
        lockdep_assert_held(&priv->shrd->mutex);
@@ -127,6 +186,7 @@ void iwl_force_scan_end(struct iwl_priv *priv)
        clear_bit(STATUS_SCANNING, &priv->shrd->status);
        clear_bit(STATUS_SCAN_HW, &priv->shrd->status);
        clear_bit(STATUS_SCAN_ABORTING, &priv->shrd->status);
+       clear_bit(STATUS_SCAN_COMPLETE, &priv->shrd->status);
        iwl_complete_scan(priv, true);
 }
 
@@ -169,7 +229,7 @@ int iwl_scan_cancel(struct iwl_priv *priv)
  * @ms: amount of time to wait (in milliseconds) for scan to abort
  *
  */
-int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms)
+void iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms)
 {
        unsigned long timeout = jiffies + msecs_to_jiffies(ms);
 
@@ -181,11 +241,24 @@ int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms)
 
        while (time_before_eq(jiffies, timeout)) {
                if (!test_bit(STATUS_SCAN_HW, &priv->shrd->status))
-                       break;
+                       goto finished;
                msleep(20);
        }
 
-       return test_bit(STATUS_SCAN_HW, &priv->shrd->status);
+       return;
+
+ finished:
+       /*
+        * Now STATUS_SCAN_HW is clear. This means that the
+        * device finished, but the background work is going
+        * to execute at best as soon as we release the mutex.
+        * Since we need to be able to issue a new scan right
+        * after this function returns, run the complete here.
+        * The STATUS_SCAN_COMPLETE bit will then be cleared
+        * and prevent the background work from "completing"
+        * a possible new scan.
+        */
+       iwl_process_scan_complete(priv);
 }
 
 /* Service response to REPLY_SCAN_CMD (0x80) */
@@ -242,10 +315,12 @@ static int iwl_rx_scan_results_notif(struct iwl_priv *priv,
 
        IWL_DEBUG_SCAN(priv, "Scan ch.res: "
                       "%d [802.11%s] "
+                      "probe status: %u:%u "
                       "(TSF: 0x%08X:%08X) - %d "
                       "elapsed=%lu usec\n",
                       notif->channel,
                       notif->band ? "bg" : "a",
+                      notif->probe_status, notif->num_probe_not_sent,
                       le32_to_cpu(notif->tsf_high),
                       le32_to_cpu(notif->tsf_low),
                       le32_to_cpu(notif->statistics[0]),
@@ -267,13 +342,20 @@ static int iwl_rx_scan_complete_notif(struct iwl_priv *priv,
                       scan_notif->tsf_low,
                       scan_notif->tsf_high, scan_notif->status);
 
-       /* The HW is no longer scanning */
-       clear_bit(STATUS_SCAN_HW, &priv->shrd->status);
-
        IWL_DEBUG_SCAN(priv, "Scan on %sGHz took %dms\n",
                       (priv->scan_band == IEEE80211_BAND_2GHZ) ? "2.4" : "5.2",
                       jiffies_to_msecs(jiffies - priv->scan_start));
 
+       /*
+        * When aborting, we run the scan completed background work inline
+        * and the background work must then do nothing. The SCAN_COMPLETE
+        * bit helps implement that logic and thus needs to be set before
+        * queueing the work. Also, since the scan abort waits for SCAN_HW
+        * to clear, we need to set SCAN_COMPLETE before clearing SCAN_HW
+        * to avoid a race there.
+        */
+       set_bit(STATUS_SCAN_COMPLETE, &priv->shrd->status);
+       clear_bit(STATUS_SCAN_HW, &priv->shrd->status);
        queue_work(priv->shrd->workqueue, &priv->scan_completed);
 
        if (priv->iw_mode != NL80211_IFTYPE_ADHOC &&
@@ -872,31 +954,33 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw,
 
        mutex_lock(&priv->shrd->mutex);
 
-       if (test_bit(STATUS_SCANNING, &priv->shrd->status) &&
-           priv->scan_type != IWL_SCAN_NORMAL) {
-               IWL_DEBUG_SCAN(priv, "Scan already in progress.\n");
-               ret = -EAGAIN;
-               goto out_unlock;
-       }
-
-       /* mac80211 will only ask for one band at a time */
-       priv->scan_request = req;
-       priv->scan_vif = vif;
-
        /*
         * If an internal scan is in progress, just set
         * up the scan_request as per above.
         */
        if (priv->scan_type != IWL_SCAN_NORMAL) {
-               IWL_DEBUG_SCAN(priv, "SCAN request during internal scan\n");
+               IWL_DEBUG_SCAN(priv,
+                              "SCAN request during internal scan - defer\n");
+               priv->scan_request = req;
+               priv->scan_vif = vif;
                ret = 0;
-       } else
+       } else {
+               priv->scan_request = req;
+               priv->scan_vif = vif;
+               /*
+                * mac80211 will only ask for one band at a time
+                * so using channels[0] here is ok
+                */
                ret = iwl_scan_initiate(priv, vif, IWL_SCAN_NORMAL,
                                        req->channels[0]->band);
+               if (ret) {
+                       priv->scan_request = NULL;
+                       priv->scan_vif = NULL;
+               }
+       }
 
        IWL_DEBUG_MAC80211(priv, "leave\n");
 
-out_unlock:
        mutex_unlock(&priv->shrd->mutex);
 
        return ret;
@@ -1014,61 +1098,10 @@ static void iwl_bg_abort_scan(struct work_struct *work)
 static void iwl_bg_scan_completed(struct work_struct *work)
 {
        struct iwl_priv *priv =
-           container_of(work, struct iwl_priv, scan_completed);
-       bool aborted;
-
-       IWL_DEBUG_SCAN(priv, "Completed scan.\n");
-
-       cancel_delayed_work(&priv->scan_check);
+               container_of(work, struct iwl_priv, scan_completed);
 
        mutex_lock(&priv->shrd->mutex);
-
-       aborted = test_and_clear_bit(STATUS_SCAN_ABORTING, &priv->shrd->status);
-       if (aborted)
-               IWL_DEBUG_SCAN(priv, "Aborted scan completed.\n");
-
-       if (!test_and_clear_bit(STATUS_SCANNING, &priv->shrd->status)) {
-               IWL_DEBUG_SCAN(priv, "Scan already completed.\n");
-               goto out_settings;
-       }
-
-       if (priv->scan_type == IWL_SCAN_ROC) {
-               ieee80211_remain_on_channel_expired(priv->hw);
-               priv->hw_roc_channel = NULL;
-               schedule_delayed_work(&priv->hw_roc_disable_work, 10 * HZ);
-       }
-
-       if (priv->scan_type != IWL_SCAN_NORMAL && !aborted) {
-               int err;
-
-               /* Check if mac80211 requested scan during our internal scan */
-               if (priv->scan_request == NULL)
-                       goto out_complete;
-
-               /* If so request a new scan */
-               err = iwl_scan_initiate(priv, priv->scan_vif, IWL_SCAN_NORMAL,
-                                       priv->scan_request->channels[0]->band);
-               if (err) {
-                       IWL_DEBUG_SCAN(priv,
-                               "failed to initiate pending scan: %d\n", err);
-                       aborted = true;
-                       goto out_complete;
-               }
-
-               goto out;
-       }
-
-out_complete:
-       iwl_complete_scan(priv, aborted);
-
-out_settings:
-       /* Can we still talk to firmware ? */
-       if (!iwl_is_ready_rf(priv->shrd))
-               goto out;
-
-       iwlagn_post_scan(priv);
-
-out:
+       iwl_process_scan_complete(priv);
        mutex_unlock(&priv->shrd->mutex);
 }
 
index 7abafe16de9a41527b4f2d6213938b26ad90c8cb..8747bbdf898311cfc2a9f75b3111dfb0329577eb 100644 (file)
@@ -489,6 +489,7 @@ static inline void iwl_print_rx_config_cmd(struct iwl_priv *priv,
 #define STATUS_FW_ERROR                17
 #define STATUS_DEVICE_ENABLED  18
 #define STATUS_CHANNEL_SWITCH_PENDING 19
+#define STATUS_SCAN_COMPLETE   20
 
 static inline int iwl_is_ready(struct iwl_shared *shrd)
 {
index 3ef9eac02ff4753348eb2faf092aa38d6b2dddf2..b4eff556cd0a84de0662a8e22b91816a5302e270 100644 (file)
@@ -401,7 +401,7 @@ static void iwl_rx_handle(struct iwl_trans *trans)
 
        while (i != r) {
                int len, err;
-               u16 txq_id, sequence;
+               u16 sequence;
 
                rxb = rxq->queue[i];
 
@@ -452,8 +452,11 @@ static void iwl_rx_handle(struct iwl_trans *trans)
 
                /* warn if this is cmd response / notification and the uCode
                 * didn't set the SEQ_RX_FRAME for a frame that is
-                * uCode-originated*/
-               WARN(txq_id == trans->shrd->cmd_queue && reclaim == false &&
+                * uCode-originated
+                * If you saw this code after the second half of 2012, then
+                * please remove it
+                */
+               WARN(pkt->hdr.cmd != REPLY_TX && reclaim == false &&
                     (!(pkt->hdr.sequence & SEQ_RX_FRAME)),
                     "reclaim is false, SEQ_RX_FRAME unset: %s\n",
                     get_cmd_string(pkt->hdr.cmd));
index b78ac65b277941526018f640681623e8f10d2a26..416e9920e4d95c63ed03ae579457d896ba959382 100644 (file)
@@ -304,8 +304,8 @@ static int iwl_trans_txq_alloc(struct iwl_trans *trans,
 
        txq->q.n_window = slots_num;
 
-       txq->meta = kzalloc(sizeof(txq->meta[0]) * slots_num, GFP_KERNEL);
-       txq->cmd = kzalloc(sizeof(txq->cmd[0]) * slots_num, GFP_KERNEL);
+       txq->meta = kcalloc(slots_num, sizeof(txq->meta[0]), GFP_KERNEL);
+       txq->cmd = kcalloc(slots_num, sizeof(txq->cmd[0]), GFP_KERNEL);
 
        if (!txq->meta || !txq->cmd)
                goto error;
@@ -322,8 +322,8 @@ static int iwl_trans_txq_alloc(struct iwl_trans *trans,
        /* Driver private data, only for Tx (not command) queues,
         * not shared with device. */
        if (txq_id != trans->shrd->cmd_queue) {
-               txq->skbs = kzalloc(sizeof(txq->skbs[0]) *
-                                  TFD_QUEUE_SIZE_MAX, GFP_KERNEL);
+               txq->skbs = kcalloc(TFD_QUEUE_SIZE_MAX, sizeof(txq->skbs[0]),
+                                   GFP_KERNEL);
                if (!txq->skbs) {
                        IWL_ERR(trans, "kmalloc for auxiliary BD "
                                  "structures failed\n");
@@ -534,8 +534,8 @@ static int iwl_trans_tx_alloc(struct iwl_trans *trans)
                goto error;
        }
 
-       trans_pcie->txq = kzalloc(sizeof(struct iwl_tx_queue) *
-                       hw_params(trans).max_txq_num, GFP_KERNEL);
+       trans_pcie->txq = kcalloc(hw_params(trans).max_txq_num,
+                                 sizeof(struct iwl_tx_queue), GFP_KERNEL);
        if (!trans_pcie->txq) {
                IWL_ERR(trans, "Not enough memory for txq\n");
                ret = ENOMEM;
@@ -1101,6 +1101,9 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
                }
        }
 
+       /* Copy MAC header from skb into command buffer */
+       memcpy(tx_cmd->hdr, hdr, hdr_len);
+
        txq = &trans_pcie->txq[txq_id];
        q = &txq->q;
 
index 85b3169c40d70148593a81e4f98f242d04e01d21..610bfcee3cf6462c37c880866840a76398bcb3e8 100644 (file)
@@ -695,7 +695,7 @@ static void lbs_scan_worker(struct work_struct *work)
        tlv = scan_cmd->tlvbuffer;
 
        /* add SSID TLV */
-       if (priv->scan_req->n_ssids)
+       if (priv->scan_req->n_ssids && priv->scan_req->ssids[0].ssid_len > 0)
                tlv += lbs_add_ssid_tlv(tlv,
                                        priv->scan_req->ssids[0].ssid,
                                        priv->scan_req->ssids[0].ssid_len);
@@ -736,7 +736,6 @@ static void lbs_scan_worker(struct work_struct *work)
                        cfg80211_scan_done(priv->scan_req, false);
 
                priv->scan_req = NULL;
-               priv->last_scan = jiffies;
        }
 
        /* Restart network */
@@ -1302,24 +1301,26 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev,
        lbs_deb_enter(LBS_DEB_CFG80211);
 
        if (!sme->bssid) {
-               /* Run a scan if one isn't in-progress already and if the last
-                * scan was done more than 2 seconds ago.
-                */
-               if (priv->scan_req == NULL &&
-                   time_after(jiffies, priv->last_scan + (2 * HZ))) {
-                       struct cfg80211_scan_request *creq;
+               struct cfg80211_scan_request *creq;
 
-                       creq = _new_connect_scan_req(wiphy, sme);
-                       if (!creq) {
-                               ret = -EINVAL;
-                               goto done;
-                       }
+               /*
+                * Scan for the requested network after waiting for existing
+                * scans to finish.
+                */
+               lbs_deb_assoc("assoc: waiting for existing scans\n");
+               wait_event_interruptible_timeout(priv->scan_q,
+                                                (priv->scan_req == NULL),
+                                                (15 * HZ));
 
-                       lbs_deb_assoc("assoc: scanning for compatible AP\n");
-                       _internal_start_scan(priv, true, creq);
+               creq = _new_connect_scan_req(wiphy, sme);
+               if (!creq) {
+                       ret = -EINVAL;
+                       goto done;
                }
 
-               /* Wait for any in-progress scan to complete */
+               lbs_deb_assoc("assoc: scanning for compatible AP\n");
+               _internal_start_scan(priv, true, creq);
+
                lbs_deb_assoc("assoc: waiting for scan to complete\n");
                wait_event_interruptible_timeout(priv->scan_q,
                                                 (priv->scan_req == NULL),
index b9ff0dc53e8df047e4d01f2c2704073f32d96891..fb3e40bf59025fa7bd189f1eae4c61b089d15a20 100644 (file)
@@ -179,7 +179,6 @@ struct lbs_private {
        wait_queue_head_t scan_q;
        /* Whether the scan was initiated internally and not by cfg80211 */
        bool internal_scan;
-       unsigned long last_scan;
 };
 
 extern struct cmd_confirm_sleep confirm_sleep;
index 6fd53e4e3fe646248036a082893cd6a8991ac51b..462c71067bfb83d6d445946e6137991dbc3ab617 100644 (file)
@@ -543,12 +543,28 @@ mwifiex_dump_station_info(struct mwifiex_private *priv,
                ret = -EFAULT;
        }
 
+       /*
+        * Bit 0 in tx_htinfo indicates that current Tx rate is 11n rate. Valid
+        * MCS index values for us are 0 to 7.
+        */
+       if ((priv->tx_htinfo & BIT(0)) && (priv->tx_rate < 8)) {
+               sinfo->txrate.mcs = priv->tx_rate;
+               sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
+               /* 40MHz rate */
+               if (priv->tx_htinfo & BIT(1))
+                       sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
+               /* SGI enabled */
+               if (priv->tx_htinfo & BIT(2))
+                       sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
+       }
+
        sinfo->rx_bytes = priv->stats.rx_bytes;
        sinfo->tx_bytes = priv->stats.tx_bytes;
        sinfo->rx_packets = priv->stats.rx_packets;
        sinfo->tx_packets = priv->stats.tx_packets;
        sinfo->signal = priv->qual_level;
-       sinfo->txrate.legacy = rate.rate;
+       /* bit rate is in 500 kb/s units. Convert it to 100kb/s units */
+       sinfo->txrate.legacy = rate.rate * 5;
 
        return ret;
 }
@@ -565,8 +581,6 @@ mwifiex_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
 {
        struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
 
-       mwifiex_dump_station_info(priv, sinfo);
-
        if (!priv->media_connected)
                return -ENOENT;
        if (memcmp(mac, priv->cfg_bssid, ETH_ALEN))
@@ -768,6 +782,7 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv)
        struct mwifiex_bss_info bss_info;
        int ie_len;
        u8 ie_buf[IEEE80211_MAX_SSID_LEN + sizeof(struct ieee_types_header)];
+       enum ieee80211_band band;
 
        if (mwifiex_get_bss_info(priv, &bss_info))
                return -1;
@@ -780,9 +795,10 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv)
                        bss_info.ssid.ssid_len);
        ie_len = ie_buf[1] + sizeof(struct ieee_types_header);
 
+       band = mwifiex_band_to_radio_type(priv->curr_bss_params.band);
        chan = __ieee80211_get_channel(priv->wdev->wiphy,
                        ieee80211_channel_to_frequency(bss_info.bss_chan,
-                                               priv->curr_bss_params.band));
+                                                      band));
 
        cfg80211_inform_bss(priv->wdev->wiphy, chan,
                bss_info.bssid, 0, WLAN_CAPABILITY_IBSS,
@@ -1146,8 +1162,150 @@ mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info,
        ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
 }
 
+/*
+ *  create a new virtual interface with the given name
+ */
+struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy,
+                                               char *name,
+                                               enum nl80211_iftype type,
+                                               u32 *flags,
+                                               struct vif_params *params)
+{
+       struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
+       struct mwifiex_adapter *adapter;
+       struct net_device *dev;
+       void *mdev_priv;
+
+       if (!priv)
+               return NULL;
+
+       adapter = priv->adapter;
+       if (!adapter)
+               return NULL;
+
+       switch (type) {
+       case NL80211_IFTYPE_UNSPECIFIED:
+       case NL80211_IFTYPE_STATION:
+       case NL80211_IFTYPE_ADHOC:
+               if (priv->bss_mode) {
+                       wiphy_err(wiphy, "cannot create multiple"
+                                       " station/adhoc interfaces\n");
+                       return NULL;
+               }
+
+               if (type == NL80211_IFTYPE_UNSPECIFIED)
+                       priv->bss_mode = NL80211_IFTYPE_STATION;
+               else
+                       priv->bss_mode = type;
+
+               priv->bss_type = MWIFIEX_BSS_TYPE_STA;
+               priv->frame_type = MWIFIEX_DATA_FRAME_TYPE_ETH_II;
+               priv->bss_priority = 0;
+               priv->bss_role = MWIFIEX_BSS_ROLE_STA;
+               priv->bss_index = 0;
+               priv->bss_num = 0;
+
+               break;
+       default:
+               wiphy_err(wiphy, "type not supported\n");
+               return NULL;
+       }
+
+       dev = alloc_netdev_mq(sizeof(struct mwifiex_private *), name,
+                             ether_setup, 1);
+       if (!dev) {
+               wiphy_err(wiphy, "no memory available for netdevice\n");
+               goto error;
+       }
+
+       dev_net_set(dev, wiphy_net(wiphy));
+       dev->ieee80211_ptr = priv->wdev;
+       dev->ieee80211_ptr->iftype = priv->bss_mode;
+       memcpy(dev->dev_addr, wiphy->perm_addr, ETH_ALEN);
+       memcpy(dev->perm_addr, wiphy->perm_addr, ETH_ALEN);
+       SET_NETDEV_DEV(dev, wiphy_dev(wiphy));
+
+       dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
+       dev->watchdog_timeo = MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT;
+       dev->hard_header_len += MWIFIEX_MIN_DATA_HEADER_LEN;
+
+       mdev_priv = netdev_priv(dev);
+       *((unsigned long *) mdev_priv) = (unsigned long) priv;
+
+       priv->netdev = dev;
+       mwifiex_init_priv_params(priv, dev);
+
+       SET_NETDEV_DEV(dev, adapter->dev);
+
+       /* Register network device */
+       if (register_netdevice(dev)) {
+               wiphy_err(wiphy, "cannot register virtual network device\n");
+               goto error;
+       }
+
+       sema_init(&priv->async_sem, 1);
+       priv->scan_pending_on_block = false;
+
+       dev_dbg(adapter->dev, "info: %s: Marvell 802.11 Adapter\n", dev->name);
+
+#ifdef CONFIG_DEBUG_FS
+       mwifiex_dev_debugfs_init(priv);
+#endif
+       return dev;
+error:
+       if (dev && (dev->reg_state == NETREG_UNREGISTERED))
+               free_netdev(dev);
+       priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
+
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(mwifiex_add_virtual_intf);
+
+/*
+ * del_virtual_intf: remove the virtual interface determined by dev
+ */
+int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev)
+{
+       struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
+
+       if (!priv || !dev)
+               return 0;
+
+#ifdef CONFIG_DEBUG_FS
+       mwifiex_dev_debugfs_remove(priv);
+#endif
+
+       if (!netif_queue_stopped(priv->netdev))
+               netif_stop_queue(priv->netdev);
+
+       if (netif_carrier_ok(priv->netdev))
+               netif_carrier_off(priv->netdev);
+
+       if (dev->reg_state == NETREG_REGISTERED)
+               unregister_netdevice(dev);
+
+       if (dev->reg_state == NETREG_UNREGISTERED)
+               free_netdev(dev);
+
+       /* Clear the priv in adapter */
+       priv->netdev = NULL;
+
+       priv->media_connected = false;
+
+       cancel_work_sync(&priv->cfg_workqueue);
+       flush_workqueue(priv->workqueue);
+       destroy_workqueue(priv->workqueue);
+
+       priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mwifiex_del_virtual_intf);
+
 /* station cfg80211 operations */
 static struct cfg80211_ops mwifiex_cfg80211_ops = {
+       .add_virtual_intf = mwifiex_add_virtual_intf,
+       .del_virtual_intf = mwifiex_del_virtual_intf,
        .change_virtual_intf = mwifiex_cfg80211_change_virtual_intf,
        .scan = mwifiex_cfg80211_scan,
        .connect = mwifiex_cfg80211_connect,
@@ -1172,8 +1330,7 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
  * default parameters and handler function pointers, and finally
  * registers the device.
  */
-int mwifiex_register_cfg80211(struct net_device *dev, u8 *mac,
-                             struct mwifiex_private *priv)
+int mwifiex_register_cfg80211(struct mwifiex_private *priv)
 {
        int ret;
        void *wdev_priv;
@@ -1213,12 +1370,15 @@ int mwifiex_register_cfg80211(struct net_device *dev, u8 *mac,
        wdev->wiphy->cipher_suites = mwifiex_cipher_suites;
        wdev->wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites);
 
-       memcpy(wdev->wiphy->perm_addr, mac, 6);
+       memcpy(wdev->wiphy->perm_addr, priv->curr_addr, ETH_ALEN);
        wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
 
        /* We are using custom domains */
        wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
 
+       /* Reserve space for bss band information */
+       wdev->wiphy->bss_priv_size = sizeof(u8);
+
        wdev->wiphy->reg_notifier = mwifiex_reg_notifier;
 
        /* Set struct mwifiex_private pointer in wiphy_priv */
@@ -1240,17 +1400,8 @@ int mwifiex_register_cfg80211(struct net_device *dev, u8 *mac,
                                "info: successfully registered wiphy device\n");
        }
 
-       dev_net_set(dev, wiphy_net(wdev->wiphy));
-       dev->ieee80211_ptr = wdev;
-       memcpy(dev->dev_addr, wdev->wiphy->perm_addr, 6);
-       memcpy(dev->perm_addr, wdev->wiphy->perm_addr, 6);
-       SET_NETDEV_DEV(dev, wiphy_dev(wdev->wiphy));
        priv->wdev = wdev;
 
-       dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
-       dev->watchdog_timeo = MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT;
-       dev->hard_header_len += MWIFIEX_MIN_DATA_HEADER_LEN;
-
        return ret;
 }
 
index c4db8f36aa16e6ee75490e7d5d40273a80c3980b..8d010f2500c5031c6f7cf64853e988ec8010a872 100644 (file)
@@ -24,8 +24,7 @@
 
 #include "main.h"
 
-int mwifiex_register_cfg80211(struct net_device *, u8 *,
-                               struct mwifiex_private *);
+int mwifiex_register_cfg80211(struct mwifiex_private *);
 
 void mwifiex_cfg80211_results(struct work_struct *work);
 #endif
index b5352afb8714884752474936dc8a031b611ecbf3..d12e25d0c88060c5d8968ee504894b57f64f4f77 100644 (file)
@@ -90,6 +90,9 @@ mwifiex_clean_cmd_node(struct mwifiex_adapter *adapter,
        cmd_node->data_buf = NULL;
        cmd_node->wait_q_enabled = false;
 
+       if (cmd_node->cmd_skb)
+               skb_trim(cmd_node->cmd_skb, 0);
+
        if (cmd_node->resp_skb) {
                dev_kfree_skb_any(cmd_node->resp_skb);
                cmd_node->resp_skb = NULL;
index 94ddc9038cb348c337ff902fd0e98a2c60596114..6ca62c809cb90abc1b780cc1405b892a97b8cae3 100644 (file)
@@ -114,14 +114,6 @@ struct mwifiex_txinfo {
        u8 bss_index;
 };
 
-struct mwifiex_bss_attr {
-       u8 bss_type;
-       u8 frame_type;
-       u8 active;
-       u8 bss_priority;
-       u8 bss_num;
-};
-
 enum mwifiex_wmm_ac_e {
        WMM_AC_BK,
        WMM_AC_BE,
index 26e685a31bc09a378524f3ca311dc5277423bb9b..e1076b46401e238263e96b5379259f73467081fa 100644 (file)
@@ -76,7 +76,7 @@ static int mwifiex_init_priv(struct mwifiex_private *priv)
        memset(priv->curr_addr, 0xff, ETH_ALEN);
 
        priv->pkt_tx_ctrl = 0;
-       priv->bss_mode = NL80211_IFTYPE_STATION;
+       priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
        priv->data_rate = 0;    /* Initially indicate the rate as auto */
        priv->is_data_rate_auto = true;
        priv->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR;
index 53579ad83e5c2d8e3b6e07404bf61321f4a1375d..8b05b4f5ffe2d4a7299561a0e47d1d8b1c2e4f1f 100644 (file)
 
 const char driver_version[] = "mwifiex " VERSION " (%s) ";
 
-static struct mwifiex_bss_attr mwifiex_bss_sta[] = {
-       {MWIFIEX_BSS_TYPE_STA, MWIFIEX_DATA_FRAME_TYPE_ETH_II, true, 0, 0},
-};
-
-static int drv_mode = DRV_MODE_STA;
-
-/* Supported drv_mode table */
-static struct mwifiex_drv_mode mwifiex_drv_mode_tbl[] = {
-       {
-               .drv_mode = DRV_MODE_STA,
-               .intf_num = ARRAY_SIZE(mwifiex_bss_sta),
-               .bss_attr = mwifiex_bss_sta,
-       },
-};
-
 /*
  * This function registers the device and performs all the necessary
  * initializations.
@@ -57,7 +42,6 @@ static struct mwifiex_drv_mode mwifiex_drv_mode_tbl[] = {
  * proper cleanup before exiting.
  */
 static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops,
-                           struct mwifiex_drv_mode *drv_mode_ptr,
                            void **padapter)
 {
        struct mwifiex_adapter *adapter;
@@ -78,42 +62,19 @@ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops,
                goto error;
 
        adapter->priv_num = 0;
-       for (i = 0; i < drv_mode_ptr->intf_num; i++) {
-               adapter->priv[i] = NULL;
-
-               if (!drv_mode_ptr->bss_attr[i].active)
-                       continue;
-
-               /* Allocate memory for private structure */
-               adapter->priv[i] = kzalloc(sizeof(struct mwifiex_private),
-                               GFP_KERNEL);
-               if (!adapter->priv[i]) {
-                       dev_err(adapter->dev, "%s: failed to alloc priv[%d]\n",
-                              __func__, i);
-                       goto error;
-               }
 
-               adapter->priv_num++;
-               adapter->priv[i]->adapter = adapter;
-               /* Save bss_type, frame_type & bss_priority */
-               adapter->priv[i]->bss_type = drv_mode_ptr->bss_attr[i].bss_type;
-               adapter->priv[i]->frame_type =
-                                       drv_mode_ptr->bss_attr[i].frame_type;
-               adapter->priv[i]->bss_priority =
-                                       drv_mode_ptr->bss_attr[i].bss_priority;
-
-               if (drv_mode_ptr->bss_attr[i].bss_type == MWIFIEX_BSS_TYPE_STA)
-                       adapter->priv[i]->bss_role = MWIFIEX_BSS_ROLE_STA;
-               else if (drv_mode_ptr->bss_attr[i].bss_type ==
-                                                       MWIFIEX_BSS_TYPE_UAP)
-                       adapter->priv[i]->bss_role = MWIFIEX_BSS_ROLE_UAP;
-
-               /* Save bss_index & bss_num */
-               adapter->priv[i]->bss_index = i;
-               adapter->priv[i]->bss_num = drv_mode_ptr->bss_attr[i].bss_num;
+       /* Allocate memory for private structure */
+       adapter->priv[0] = kzalloc(sizeof(struct mwifiex_private),
+                       GFP_KERNEL);
+       if (!adapter->priv[0]) {
+               dev_err(adapter->dev, "%s: failed to alloc priv[0]\n",
+                      __func__);
+               goto error;
        }
-       adapter->drv_mode = drv_mode_ptr;
 
+       adapter->priv_num++;
+
+       adapter->priv[0]->adapter = adapter;
        if (mwifiex_init_lock_list(adapter))
                goto error;
 
@@ -127,8 +88,10 @@ error:
        dev_dbg(adapter->dev, "info: leave mwifiex_register with error\n");
 
        mwifiex_free_lock_list(adapter);
-       for (i = 0; i < drv_mode_ptr->intf_num; i++)
+
+       for (i = 0; i < adapter->priv_num; i++)
                kfree(adapter->priv[i]);
+
        kfree(adapter);
 
        return -1;
@@ -315,38 +278,6 @@ exit_main_proc:
        return ret;
 }
 
-/*
- * This function initializes the software.
- *
- * The main work includes allocating and initializing the adapter structure
- * and initializing the private structures.
- */
-static int
-mwifiex_init_sw(void *card, struct mwifiex_if_ops *if_ops, void **padapter)
-{
-       int i;
-       struct mwifiex_drv_mode *drv_mode_ptr;
-
-       /* find mwifiex_drv_mode entry from mwifiex_drv_mode_tbl */
-       drv_mode_ptr = NULL;
-       for (i = 0; i < ARRAY_SIZE(mwifiex_drv_mode_tbl); i++) {
-               if (mwifiex_drv_mode_tbl[i].drv_mode == drv_mode) {
-                       drv_mode_ptr = &mwifiex_drv_mode_tbl[i];
-                       break;
-               }
-       }
-
-       if (!drv_mode_ptr) {
-               pr_err("invalid drv_mode=%d\n", drv_mode);
-               return -1;
-       }
-
-       if (mwifiex_register(card, if_ops, drv_mode_ptr, padapter))
-               return -1;
-
-       return 0;
-}
-
 /*
  * This function frees the adapter structure.
  *
@@ -649,8 +580,8 @@ static const struct net_device_ops mwifiex_netdev_ops = {
  *
  * In addition, the CFG80211 work queue is also created.
  */
-static void
-mwifiex_init_priv_params(struct mwifiex_private *priv, struct net_device *dev)
+void mwifiex_init_priv_params(struct mwifiex_private *priv,
+                                               struct net_device *dev)
 {
        dev->netdev_ops = &mwifiex_netdev_ops;
        /* Initialize private structure */
@@ -663,118 +594,6 @@ mwifiex_init_priv_params(struct mwifiex_private *priv, struct net_device *dev)
        memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN);
 }
 
-/*
- * This function adds a new logical interface.
- *
- * It allocates, initializes and registers the interface by performing
- * the following opearations -
- *      - Allocate a new net device structure
- *      - Assign device name
- *      - Register the new device with CFG80211 subsystem
- *      - Initialize semaphore and private structure
- *      - Register the new device with kernel
- *      - Create the complete debug FS structure if configured
- */
-static struct mwifiex_private *mwifiex_add_interface(
-                       struct mwifiex_adapter *adapter,
-                       u8 bss_index, u8 bss_type)
-{
-       struct net_device *dev;
-       struct mwifiex_private *priv;
-       void *mdev_priv;
-
-       dev = alloc_netdev_mq(sizeof(struct mwifiex_private *), "mlan%d",
-                             ether_setup, 1);
-       if (!dev) {
-               dev_err(adapter->dev, "no memory available for netdevice\n");
-               goto error;
-       }
-
-       if (mwifiex_register_cfg80211(dev, adapter->priv[bss_index]->curr_addr,
-                                     adapter->priv[bss_index]) != 0) {
-               dev_err(adapter->dev, "cannot register netdevice with cfg80211\n");
-               goto error;
-       }
-       /* Save the priv pointer in netdev */
-       priv = adapter->priv[bss_index];
-       mdev_priv = netdev_priv(dev);
-       *((unsigned long *) mdev_priv) = (unsigned long) priv;
-
-       priv->netdev = dev;
-
-       sema_init(&priv->async_sem, 1);
-       priv->scan_pending_on_block = false;
-
-       mwifiex_init_priv_params(priv, dev);
-
-       SET_NETDEV_DEV(dev, adapter->dev);
-
-       /* Register network device */
-       if (register_netdev(dev)) {
-               dev_err(adapter->dev, "cannot register virtual network device\n");
-               goto error;
-       }
-
-       dev_dbg(adapter->dev, "info: %s: Marvell 802.11 Adapter\n", dev->name);
-#ifdef CONFIG_DEBUG_FS
-       mwifiex_dev_debugfs_init(priv);
-#endif
-       return priv;
-error:
-       if (dev)
-               free_netdev(dev);
-       return NULL;
-}
-
-/*
- * This function removes a logical interface.
- *
- * It deregisters, resets and frees the interface by performing
- * the following operations -
- *      - Disconnect the device if connected, send wireless event to
- *        notify applications.
- *      - Remove the debug FS structure if configured
- *      - Unregister the device from kernel
- *      - Free the net device structure
- *      - Cancel all works and destroy work queue
- *      - Unregister and free the wireless device from CFG80211 subsystem
- */
-static void
-mwifiex_remove_interface(struct mwifiex_adapter *adapter, u8 bss_index)
-{
-       struct net_device *dev;
-       struct mwifiex_private *priv = adapter->priv[bss_index];
-
-       if (!priv)
-               return;
-       dev = priv->netdev;
-
-       if (priv->media_connected)
-               priv->media_connected = false;
-
-#ifdef CONFIG_DEBUG_FS
-       mwifiex_dev_debugfs_remove(priv);
-#endif
-       /* Last reference is our one */
-       dev_dbg(adapter->dev, "info: %s: refcnt = %d\n",
-                               dev->name, netdev_refcnt_read(dev));
-
-       if (dev->reg_state == NETREG_REGISTERED)
-               unregister_netdev(dev);
-
-       /* Clear the priv in adapter */
-       priv->netdev = NULL;
-       if (dev)
-               free_netdev(dev);
-
-       cancel_work_sync(&priv->cfg_workqueue);
-       flush_workqueue(priv->workqueue);
-       destroy_workqueue(priv->workqueue);
-       wiphy_unregister(priv->wdev->wiphy);
-       wiphy_free(priv->wdev->wiphy);
-       kfree(priv->wdev);
-}
-
 /*
  * This function check if command is pending.
  */
@@ -847,14 +666,14 @@ int
 mwifiex_add_card(void *card, struct semaphore *sem,
                 struct mwifiex_if_ops *if_ops)
 {
-       int i;
        struct mwifiex_adapter *adapter;
        char fmt[64];
+       struct mwifiex_private *priv;
 
        if (down_interruptible(sem))
                goto exit_sem_err;
 
-       if (mwifiex_init_sw(card, if_ops, (void **)&adapter)) {
+       if (mwifiex_register(card, if_ops, (void **)&adapter)) {
                pr_err("%s: software init failed\n", __func__);
                goto err_init_sw;
        }
@@ -888,14 +707,26 @@ mwifiex_add_card(void *card, struct semaphore *sem,
                goto err_init_fw;
        }
 
-       /* Add interfaces */
-       for (i = 0; i < adapter->drv_mode->intf_num; i++) {
-               if (!mwifiex_add_interface(adapter, i,
-                               adapter->drv_mode->bss_attr[i].bss_type)) {
-                       goto err_add_intf;
-               }
+       priv = adapter->priv[0];
+
+       if (mwifiex_register_cfg80211(priv) != 0) {
+               dev_err(adapter->dev, "cannot register netdevice"
+                              " with cfg80211\n");
+                       goto err_init_fw;
+       }
+
+       rtnl_lock();
+       /* Create station interface by default */
+       if (!mwifiex_add_virtual_intf(priv->wdev->wiphy, "mlan%d",
+                               NL80211_IFTYPE_STATION, NULL, NULL)) {
+               rtnl_unlock();
+               dev_err(adapter->dev, "cannot create default station"
+                               " interface\n");
+               goto err_add_intf;
        }
 
+       rtnl_unlock();
+
        up(sem);
 
        mwifiex_drv_get_driver_version(adapter, fmt, sizeof(fmt) - 1);
@@ -904,8 +735,9 @@ mwifiex_add_card(void *card, struct semaphore *sem,
        return 0;
 
 err_add_intf:
-       for (i = 0; i < adapter->priv_num; i++)
-               mwifiex_remove_interface(adapter, i);
+       rtnl_lock();
+       mwifiex_del_virtual_intf(priv->wdev->wiphy, priv->netdev);
+       rtnl_unlock();
 err_init_fw:
        pr_debug("info: %s: unregister device\n", __func__);
        adapter->if_ops.unregister_dev(adapter);
@@ -960,7 +792,7 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem)
        /* Stop data */
        for (i = 0; i < adapter->priv_num; i++) {
                priv = adapter->priv[i];
-               if (priv) {
+               if (priv && priv->netdev) {
                        if (!netif_queue_stopped(priv->netdev))
                                netif_stop_queue(priv->netdev);
                        if (netif_carrier_ok(priv->netdev))
@@ -985,9 +817,20 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem)
                       atomic_read(&adapter->cmd_pending));
        }
 
-       /* Remove interface */
-       for (i = 0; i < adapter->priv_num; i++)
-               mwifiex_remove_interface(adapter, i);
+       for (i = 0; i < adapter->priv_num; i++) {
+               priv = adapter->priv[i];
+
+               if (!priv)
+                       continue;
+
+               rtnl_lock();
+               mwifiex_del_virtual_intf(priv->wdev->wiphy, priv->netdev);
+               rtnl_unlock();
+       }
+
+       wiphy_unregister(priv->wdev->wiphy);
+       wiphy_free(priv->wdev->wiphy);
+       kfree(priv->wdev);
 
        mwifiex_terminate_workqueue(adapter);
 
index e6b6c0cfb63e32df41aee6ad2655bdde8e47dc58..4f4042809f23f39a01a19ed3a2171a62246486cd 100644 (file)
@@ -45,15 +45,6 @@ enum {
        MWIFIEX_SYNC_CMD
 };
 
-#define DRV_MODE_STA       0x1
-
-struct mwifiex_drv_mode {
-       u16 drv_mode;
-       u16 intf_num;
-       struct mwifiex_bss_attr *bss_attr;
-};
-
-
 #define MWIFIEX_MAX_AP                         64
 
 #define MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT       (5 * HZ)
@@ -546,7 +537,6 @@ struct mwifiex_if_ops {
 struct mwifiex_adapter {
        struct mwifiex_private *priv[MWIFIEX_MAX_BSS_NUM];
        u8 priv_num;
-       struct mwifiex_drv_mode *drv_mode;
        const struct firmware *firmware;
        char fw_name[32];
        struct device *dev;
@@ -792,6 +782,8 @@ int mwifiex_cmd_get_hw_spec(struct mwifiex_private *priv,
 int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
                            struct host_cmd_ds_command *resp);
 int is_command_pending(struct mwifiex_adapter *adapter);
+void mwifiex_init_priv_params(struct mwifiex_private *priv,
+                                               struct net_device *dev);
 
 /*
  * This function checks if the queuing is RA based or not.
@@ -958,7 +950,7 @@ int mwifiex_get_bss_info(struct mwifiex_private *,
 int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
                              u8 *bssid, s32 rssi, u8 *ie_buf,
                              size_t ie_len, u16 beacon_period,
-                             u16 cap_info_bitmap,
+                             u16 cap_info_bitmap, u8 band,
                              struct mwifiex_bssdescriptor *bss_desc);
 int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
                                struct mwifiex_bssdescriptor *bss_entry,
@@ -966,6 +958,12 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
 int mwifiex_check_network_compatibility(struct mwifiex_private *priv,
                                        struct mwifiex_bssdescriptor *bss_desc);
 
+struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy,
+                                       char *name, enum nl80211_iftype type,
+                                       u32 *flags, struct vif_params *params);
+int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev);
+
+
 #ifdef CONFIG_DEBUG_FS
 void mwifiex_debugfs_init(void);
 void mwifiex_debugfs_remove(void);
index 8d8588db1cd960d71fc34c4e564768ecf40bd30b..ca3761965e858a8e0855ae304c547adf00c35b58 100644 (file)
@@ -532,7 +532,7 @@ mwifiex_scan_create_channel_list(struct mwifiex_private *priv,
 
                sband = priv->wdev->wiphy->bands[band];
 
-               for (i = 0; (i < sband->n_channels) ; i++, chan_idx++) {
+               for (i = 0; (i < sband->n_channels) ; i++) {
                        ch = &sband->channels[i];
                        if (ch->flags & IEEE80211_CHAN_DISABLED)
                                continue;
@@ -563,6 +563,7 @@ mwifiex_scan_create_channel_list(struct mwifiex_private *priv,
                                scan_chan_list[chan_idx].chan_scan_mode_bitmap
                                        |= MWIFIEX_DISABLE_CHAN_FILT;
                        }
+                       chan_idx++;
                }
 
        }
@@ -1463,9 +1464,9 @@ int mwifiex_check_network_compatibility(struct mwifiex_private *priv,
 }
 
 static int
-mwifiex_update_curr_bss_params(struct mwifiex_private *priv,
-                       u8 *bssid, s32 rssi, const u8 *ie_buf,
-                       size_t ie_len, u16 beacon_period, u16 cap_info_bitmap)
+mwifiex_update_curr_bss_params(struct mwifiex_private *priv, u8 *bssid,
+                              s32 rssi, const u8 *ie_buf, size_t ie_len,
+                              u16 beacon_period, u16 cap_info_bitmap, u8 band)
 {
        struct mwifiex_bssdescriptor *bss_desc = NULL;
        int ret;
@@ -1488,7 +1489,7 @@ mwifiex_update_curr_bss_params(struct mwifiex_private *priv,
 
        ret = mwifiex_fill_new_bss_desc(priv, bssid, rssi, beacon_ie,
                                        ie_len, beacon_period,
-                                       cap_info_bitmap, bss_desc);
+                                       cap_info_bitmap, band, bss_desc);
        if (ret)
                goto done;
 
@@ -1532,6 +1533,11 @@ done:
        return 0;
 }
 
+static void mwifiex_free_bss_priv(struct cfg80211_bss *bss)
+{
+       kfree(bss->priv);
+}
+
 /*
  * This function handles the command response of scan.
  *
@@ -1570,6 +1576,7 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
        struct chan_band_param_set *chan_band;
        u8 is_bgscan_resp;
        unsigned long flags;
+       struct cfg80211_bss *bss;
 
        is_bgscan_resp = (le16_to_cpu(resp->command)
                == HostCmd_CMD_802_11_BG_SCAN_QUERY);
@@ -1751,10 +1758,12 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
                        chan = ieee80211_get_channel(priv->wdev->wiphy, freq);
 
                        if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) {
-                               cfg80211_inform_bss(priv->wdev->wiphy, chan,
-                                       bssid, network_tsf, cap_info_bitmap,
-                                       beacon_period, ie_buf, ie_len, rssi,
-                                       GFP_KERNEL);
+                               bss = cfg80211_inform_bss(priv->wdev->wiphy,
+                                             chan, bssid, network_tsf,
+                                             cap_info_bitmap, beacon_period,
+                                             ie_buf, ie_len, rssi, GFP_KERNEL);
+                               *(u8 *)bss->priv = band;
+                               bss->free_priv = mwifiex_free_bss_priv;
 
                                if (priv->media_connected && !memcmp(bssid,
                                        priv->curr_bss_params.bss_descriptor
@@ -1762,7 +1771,7 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
                                        mwifiex_update_curr_bss_params(priv,
                                                        bssid, rssi, ie_buf,
                                                        ie_len, beacon_period,
-                                                       cap_info_bitmap);
+                                                       cap_info_bitmap, band);
                        }
                } else {
                        dev_dbg(adapter->dev, "missing BSS channel IE\n");
index 1df5ef6b4953bc51b25c59c0e94183077daf5cd5..520800b618e73db7636dcaa050a76ee19174d6cb 100644 (file)
@@ -148,7 +148,7 @@ int mwifiex_request_set_multicast_list(struct mwifiex_private *priv,
 int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
                              u8 *bssid, s32 rssi, u8 *ie_buf,
                              size_t ie_len, u16 beacon_period,
-                             u16 cap_info_bitmap,
+                             u16 cap_info_bitmap, u8 band,
                              struct mwifiex_bssdescriptor *bss_desc)
 {
        int ret;
@@ -159,6 +159,7 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
        bss_desc->beacon_buf_size = ie_len;
        bss_desc->beacon_period = beacon_period;
        bss_desc->cap_info_bitmap = cap_info_bitmap;
+       bss_desc->bss_band = band;
        if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) {
                dev_dbg(priv->adapter->dev, "info: InterpretIE: AP WEP enabled\n");
                bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP;
@@ -211,7 +212,8 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
                ret = mwifiex_fill_new_bss_desc(priv, bss->bssid, bss->signal,
                                                beacon_ie, bss->len_beacon_ies,
                                                bss->beacon_interval,
-                                               bss->capability, bss_desc);
+                                               bss->capability,
+                                               *(u8 *)bss->priv, bss_desc);
                if (ret)
                        goto done;
        }
@@ -653,6 +655,7 @@ mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel)
        u16 curr_chan = 0;
        struct cfg80211_bss *bss = NULL;
        struct ieee80211_channel *chan;
+       enum ieee80211_band band;
 
        memset(&bss_info, 0, sizeof(bss_info));
 
@@ -689,9 +692,9 @@ mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel)
                goto done;
        }
 
+       band = mwifiex_band_to_radio_type(priv->curr_bss_params.band);
        chan = __ieee80211_get_channel(priv->wdev->wiphy,
-                       ieee80211_channel_to_frequency(channel,
-                                               priv->curr_bss_params.band));
+                       ieee80211_channel_to_frequency(channel, band));
 
        /* Find the BSS we want using available scan results */
        bss = cfg80211_get_bss(priv->wdev->wiphy, chan, bss_info.bssid,
@@ -717,51 +720,9 @@ done:
 static int mwifiex_rate_ioctl_get_rate_value(struct mwifiex_private *priv,
                                             struct mwifiex_rate_cfg *rate_cfg)
 {
-       struct mwifiex_adapter *adapter = priv->adapter;
-
        rate_cfg->is_rate_auto = priv->is_data_rate_auto;
-       if (!priv->media_connected) {
-               switch (adapter->config_bands) {
-               case BAND_B:
-                       /* Return the lowest supported rate for B band */
-                       rate_cfg->rate = supported_rates_b[0] & 0x7f;
-                       break;
-               case BAND_G:
-               case BAND_G | BAND_GN:
-                       /* Return the lowest supported rate for G band */
-                       rate_cfg->rate = supported_rates_g[0] & 0x7f;
-                       break;
-               case BAND_B | BAND_G:
-               case BAND_A | BAND_B | BAND_G:
-               case BAND_A | BAND_B:
-               case BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN:
-               case BAND_B | BAND_G | BAND_GN:
-                       /* Return the lowest supported rate for BG band */
-                       rate_cfg->rate = supported_rates_bg[0] & 0x7f;
-                       break;
-               case BAND_A:
-               case BAND_A | BAND_G:
-               case BAND_A | BAND_G | BAND_AN | BAND_GN:
-               case BAND_A | BAND_AN:
-                       /* Return the lowest supported rate for A band */
-                       rate_cfg->rate = supported_rates_a[0] & 0x7f;
-                       break;
-               case BAND_GN:
-                       /* Return the lowest supported rate for N band */
-                       rate_cfg->rate = supported_rates_n[0] & 0x7f;
-                       break;
-               default:
-                       dev_warn(adapter->dev, "invalid band %#x\n",
-                              adapter->config_bands);
-                       break;
-               }
-       } else {
-               return mwifiex_send_cmd_sync(priv,
-                                           HostCmd_CMD_802_11_TX_RATE_QUERY,
-                                           HostCmd_ACT_GEN_GET, 0, NULL);
-       }
-
-       return 0;
+       return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_TX_RATE_QUERY,
+                                    HostCmd_ACT_GEN_GET, 0, NULL);
 }
 
 /*
index 2b97a89e7ff8f17af1c55a2f1db70e29d235afaf..f485784a60aeb0a903871464e6db494c71dc2bf6 100644 (file)
@@ -689,7 +689,7 @@ static void p54_tx_80211_header(struct p54_common *priv, struct sk_buff *skb,
        if (!(info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ))
                *flags |= P54_HDR_FLAG_DATA_OUT_SEQNR;
 
-       if (info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE)
+       if (info->flags & IEEE80211_TX_CTL_POLL_RESPONSE)
                *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL;
 
        if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
index daa32fc9398bb7712886b4707fbd6f1096162680..7e9272b8f01d8718bc047128f8f0a440563a74b8 100644 (file)
@@ -1239,7 +1239,7 @@ static void rt2400pci_fill_rxdone(struct queue_entry *entry,
         * call, we must decrease the higher 32bits with 1 to get
         * to correct value.
         */
-       tsf = rt2x00dev->ops->hw->get_tsf(rt2x00dev->hw);
+       tsf = rt2x00dev->ops->hw->get_tsf(rt2x00dev->hw, NULL);
        rx_low = rt2x00_get_field32(word4, RXD_W4_RX_END_TIME);
        rx_high = upper_32_bits(tsf);
 
@@ -1673,7 +1673,8 @@ static int rt2400pci_conf_tx(struct ieee80211_hw *hw, u16 queue,
        return 0;
 }
 
-static u64 rt2400pci_get_tsf(struct ieee80211_hw *hw)
+static u64 rt2400pci_get_tsf(struct ieee80211_hw *hw,
+                            struct ieee80211_vif *vif)
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
        u64 tsf;
index b46c3b8866fa99b29f582ba016a0cf6377065c51..dcc0e1fcca77726e002ed490dc41aa640655830b 100644 (file)
@@ -1966,7 +1966,8 @@ static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev)
 /*
  * IEEE80211 stack callback functions.
  */
-static u64 rt2500pci_get_tsf(struct ieee80211_hw *hw)
+static u64 rt2500pci_get_tsf(struct ieee80211_hw *hw,
+                            struct ieee80211_vif *vif)
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
        u64 tsf;
index 31c98509f7e6c639565fb7d2c72492fb47d7ba7c..9688dd0a7ebd1b8d7415b47ca65e85ecd2c88410 100644 (file)
@@ -4466,7 +4466,7 @@ int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
 }
 EXPORT_SYMBOL_GPL(rt2800_conf_tx);
 
-u64 rt2800_get_tsf(struct ieee80211_hw *hw)
+u64 rt2800_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
        u64 tsf;
index 7a2511f6785c53d7423abd495c3c10b19c84fe97..6de128e9c612fe6bfc4497b30e4df4286c772d31 100644 (file)
@@ -199,7 +199,7 @@ void rt2800_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx, u32 *iv32,
 int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value);
 int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
                   const struct ieee80211_tx_queue_params *params);
-u64 rt2800_get_tsf(struct ieee80211_hw *hw);
+u64 rt2800_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
 int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                        enum ieee80211_ampdu_mlme_action action,
                        struct ieee80211_sta *sta, u16 tid, u16 *ssn,
index 058ef4b19d1db54896567da65901c2a4ad91ab27..6b6a8e2dcddc952aeb61843d60b73e8335369437 100644 (file)
@@ -2940,7 +2940,7 @@ static int rt61pci_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
        return 0;
 }
 
-static u64 rt61pci_get_tsf(struct ieee80211_hw *hw)
+static u64 rt61pci_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
        u64 tsf;
index 0baeb894f093e11e81f13f3d55c4c1624f546536..6f51e39f5595ae12a8ff2d3f56760a63e181cae2 100644 (file)
@@ -2279,7 +2279,7 @@ static int rt73usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
        return 0;
 }
 
-static u64 rt73usb_get_tsf(struct ieee80211_hw *hw)
+static u64 rt73usb_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
        u64 tsf;
index 66b29dc07cc39ac3cfc2e614db78f0a79878b121..0082015ff664e9e5af45298dd804f46cf028d4a4 100644 (file)
@@ -669,7 +669,8 @@ static void rtl8180_stop(struct ieee80211_hw *dev)
                rtl8180_free_tx_ring(dev, i);
 }
 
-static u64 rtl8180_get_tsf(struct ieee80211_hw *dev)
+static u64 rtl8180_get_tsf(struct ieee80211_hw *dev,
+                          struct ieee80211_vif *vif)
 {
        struct rtl8180_priv *priv = dev->priv;
 
@@ -701,7 +702,7 @@ static void rtl8180_beacon_work(struct work_struct *work)
         * TODO: make hardware update beacon timestamp
         */
        mgmt = (struct ieee80211_mgmt *)skb->data;
-       mgmt->u.beacon.timestamp = cpu_to_le64(rtl8180_get_tsf(dev));
+       mgmt->u.beacon.timestamp = cpu_to_le64(rtl8180_get_tsf(dev, vif));
 
        /* TODO: use actual beacon queue */
        skb_set_queue_mapping(skb, 0);
index 1e0be14d10d4687c6f1ad81b60c31d69c4f931a2..f5afa155ce9134984db0d521aa8c5e407e18eb4f 100644 (file)
@@ -1277,7 +1277,7 @@ static int rtl8187_conf_tx(struct ieee80211_hw *dev, u16 queue,
        return 0;
 }
 
-static u64 rtl8187_get_tsf(struct ieee80211_hw *dev)
+static u64 rtl8187_get_tsf(struct ieee80211_hw *dev, struct ieee80211_vif *vif)
 {
        struct rtl8187_priv *priv = dev->priv;
 
index 04c4e9eb6ee6ed726357fb6bb3ac8da26c4aa7be..21e40f62a8d744a2bead4f190cb72c266028066e 100644 (file)
@@ -775,7 +775,7 @@ out:
        mutex_unlock(&rtlpriv->locks.conf_mutex);
 }
 
-static u64 rtl_op_get_tsf(struct ieee80211_hw *hw)
+static u64 rtl_op_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        u64 tsf;
@@ -784,7 +784,8 @@ static u64 rtl_op_get_tsf(struct ieee80211_hw *hw)
        return tsf;
 }
 
-static void rtl_op_set_tsf(struct ieee80211_hw *hw, u64 tsf)
+static void rtl_op_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                          u64 tsf)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
@@ -794,7 +795,8 @@ static void rtl_op_set_tsf(struct ieee80211_hw *hw, u64 tsf)
        rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_CORRECT_TSF, (u8 *) (&bibss));
 }
 
-static void rtl_op_reset_tsf(struct ieee80211_hw *hw)
+static void rtl_op_reset_tsf(struct ieee80211_hw *hw,
+                            struct ieee80211_vif *vif)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        u8 tmp = 0;
index 8b1cef0ffde6627e9d882bf84ee78dba62ddbc89..b42c2e2b2055463089c0de2a6cc1882f13d9e5c0 100644 (file)
@@ -191,44 +191,6 @@ static void _usb_write32_async(struct rtl_priv *rtlpriv, u32 addr, u32 val)
        _usb_write_async(to_usb_device(dev), addr, val, 4);
 }
 
-static int _usb_nbytes_read_write(struct usb_device *udev, bool read, u32 addr,
-                                 u16 len, u8 *pdata)
-{
-       int status;
-       u8 request;
-       u16 wvalue;
-       u16 index;
-
-       request = REALTEK_USB_VENQT_CMD_REQ;
-       index = REALTEK_USB_VENQT_CMD_IDX; /* n/a */
-       wvalue = (u16)addr;
-       if (read)
-               status = _usbctrl_vendorreq_sync_read(udev, request, wvalue,
-                                                     index, pdata, len);
-       else
-               status = _usbctrl_vendorreq_async_write(udev, request, wvalue,
-                                                       index, pdata, len);
-       return status;
-}
-
-static int _usb_readN_sync(struct rtl_priv *rtlpriv, u32 addr, u16 len,
-                          u8 *pdata)
-{
-       struct device *dev = rtlpriv->io.dev;
-
-       return _usb_nbytes_read_write(to_usb_device(dev), true, addr, len,
-                                      pdata);
-}
-
-static int _usb_writeN_async(struct rtl_priv *rtlpriv, u32 addr, u16 len,
-                            u8 *pdata)
-{
-       struct device *dev = rtlpriv->io.dev;
-
-       return _usb_nbytes_read_write(to_usb_device(dev), false, addr, len,
-                                     pdata);
-}
-
 static void _rtl_usb_io_handler_init(struct device *dev,
                                     struct ieee80211_hw *hw)
 {
@@ -239,11 +201,9 @@ static void _rtl_usb_io_handler_init(struct device *dev,
        rtlpriv->io.write8_async        = _usb_write8_async;
        rtlpriv->io.write16_async       = _usb_write16_async;
        rtlpriv->io.write32_async       = _usb_write32_async;
-       rtlpriv->io.writeN_async        = _usb_writeN_async;
        rtlpriv->io.read8_sync          = _usb_read8_sync;
        rtlpriv->io.read16_sync         = _usb_read16_sync;
        rtlpriv->io.read32_sync         = _usb_read32_sync;
-       rtlpriv->io.readN_sync          = _usb_readN_sync;
 }
 
 static void _rtl_usb_io_handler_release(struct ieee80211_hw *hw)
@@ -863,6 +823,7 @@ static void _rtl_usb_tx_preprocess(struct ieee80211_hw *hw, struct sk_buff *skb,
        u8 tid = 0;
        u16 seq_number = 0;
 
+       memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc));
        if (ieee80211_is_auth(fc)) {
                RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, ("MAC80211_LINKING\n"));
                rtl_ips_nic_on(hw);
index 615f6b4463e6977b50e345f43778b4737c8a0bfe..3126485393d9e2c9e32ef5aaeec074649a01e2fc 100644 (file)
@@ -942,16 +942,12 @@ struct rtl_io {
        unsigned long pci_base_addr;    /*device I/O address */
 
        void (*write8_async) (struct rtl_priv *rtlpriv, u32 addr, u8 val);
-       void (*write16_async) (struct rtl_priv *rtlpriv, u32 addr, u16 val);
-       void (*write32_async) (struct rtl_priv *rtlpriv, u32 addr, u32 val);
-       int (*writeN_async) (struct rtl_priv *rtlpriv, u32 addr, u16 len,
-                            u8 *pdata);
+       void (*write16_async) (struct rtl_priv *rtlpriv, u32 addr, __le16 val);
+       void (*write32_async) (struct rtl_priv *rtlpriv, u32 addr, __le32 val);
 
        u8(*read8_sync) (struct rtl_priv *rtlpriv, u32 addr);
        u16(*read16_sync) (struct rtl_priv *rtlpriv, u32 addr);
        u32(*read32_sync) (struct rtl_priv *rtlpriv, u32 addr);
-       int (*readN_sync) (struct rtl_priv *rtlpriv, u32 addr, u16 len,
-                           u8 *pdata);
 
 };
 
index 521c0414e52e00f2e5bac3e068d47c526f7a82e7..621b3483ca2c578037c8620a3b0dc6cc562be8d6 100644 (file)
@@ -1,16 +1,16 @@
 wl12xx-objs            = main.o cmd.o io.o event.o tx.o rx.o ps.o acx.o \
                          boot.o init.o debugfs.o scan.o
 
-wl12xx_spi-objs        = spi.o
+wl12xx_spi-objs        = spi.o
 wl12xx_sdio-objs       = sdio.o
-wl12xx_sdio_test-objs = sdio_test.o
+wl12xx_sdio_test-objs  = sdio_test.o
 
 wl12xx-$(CONFIG_NL80211_TESTMODE)      += testmode.o
 obj-$(CONFIG_WL12XX)                   += wl12xx.o
 obj-$(CONFIG_WL12XX_SPI)               += wl12xx_spi.o
 obj-$(CONFIG_WL12XX_SDIO)              += wl12xx_sdio.o
 
-obj-$(CONFIG_WL12XX_SDIO_TEST) += wl12xx_sdio_test.o
+obj-$(CONFIG_WL12XX_SDIO_TEST)         += wl12xx_sdio_test.o
 
 # small builtin driver bit
 obj-$(CONFIG_WL12XX_PLATFORM_DATA)     += wl12xx_platform_data.o
index 084262f169b2e3469b3150f21657a08ce0f8a758..287fe95ecb40092e826b821056ee05e093d3f3a0 100644 (file)
@@ -661,12 +661,9 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl)
 
        wl1271_debug(DEBUG_CMD, "cmd role start ap %d", wl->role_id);
 
-       /*
-        * We currently do not support hidden SSID. The real SSID
-        * should be fetched from mac80211 first.
-        */
-       if (wl->ssid_len == 0) {
-               wl1271_warning("Hidden SSID currently not supported for AP");
+       /* trying to use hidden SSID with an old hostapd version */
+       if (wl->ssid_len == 0 && !bss_conf->hidden_ssid) {
+               wl1271_error("got a null SSID from beacon/bss");
                ret = -EINVAL;
                goto out;
        }
@@ -695,9 +692,18 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl)
        cmd->ap.dtim_interval = bss_conf->dtim_period;
        cmd->ap.beacon_expiry = WL1271_AP_DEF_BEACON_EXP;
        cmd->channel = wl->channel;
-       cmd->ap.ssid_len = wl->ssid_len;
-       cmd->ap.ssid_type = WL12XX_SSID_TYPE_PUBLIC;
-       memcpy(cmd->ap.ssid, wl->ssid, wl->ssid_len);
+
+       if (!bss_conf->hidden_ssid) {
+               /* take the SSID from the beacon for backward compatibility */
+               cmd->ap.ssid_type = WL12XX_SSID_TYPE_PUBLIC;
+               cmd->ap.ssid_len = wl->ssid_len;
+               memcpy(cmd->ap.ssid, wl->ssid, wl->ssid_len);
+       } else {
+               cmd->ap.ssid_type = WL12XX_SSID_TYPE_HIDDEN;
+               cmd->ap.ssid_len = bss_conf->ssid_len;
+               memcpy(cmd->ap.ssid, bss_conf->ssid, bss_conf->ssid_len);
+       }
+
        cmd->ap.local_rates = cpu_to_le32(0xffffffff);
 
        switch (wl->band) {
@@ -1106,6 +1112,7 @@ int wl1271_cmd_build_probe_req(struct wl1271 *wl,
 {
        struct sk_buff *skb;
        int ret;
+       u32 rate;
 
        skb = ieee80211_probereq_get(wl->hw, wl->vif, ssid, ssid_len,
                                     ie, ie_len);
@@ -1116,14 +1123,13 @@ int wl1271_cmd_build_probe_req(struct wl1271 *wl,
 
        wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", skb->data, skb->len);
 
+       rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]);
        if (band == IEEE80211_BAND_2GHZ)
                ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
-                                             skb->data, skb->len, 0,
-                                             wl->conf.tx.basic_rate);
+                                             skb->data, skb->len, 0, rate);
        else
                ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
-                                             skb->data, skb->len, 0,
-                                             wl->conf.tx.basic_rate_5);
+                                             skb->data, skb->len, 0, rate);
 
 out:
        dev_kfree_skb(skb);
@@ -1134,6 +1140,7 @@ struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl,
                                              struct sk_buff *skb)
 {
        int ret;
+       u32 rate;
 
        if (!skb)
                skb = ieee80211_ap_probereq_get(wl->hw, wl->vif);
@@ -1142,14 +1149,13 @@ struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl,
 
        wl1271_dump(DEBUG_SCAN, "AP PROBE REQ: ", skb->data, skb->len);
 
+       rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[wl->band]);
        if (wl->band == IEEE80211_BAND_2GHZ)
                ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
-                                             skb->data, skb->len, 0,
-                                             wl->conf.tx.basic_rate);
+                                             skb->data, skb->len, 0, rate);
        else
                ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
-                                             skb->data, skb->len, 0,
-                                             wl->conf.tx.basic_rate_5);
+                                             skb->data, skb->len, 0, rate);
 
        if (ret < 0)
                wl1271_error("Unable to set ap probe request template.");
@@ -1442,7 +1448,8 @@ int wl12xx_cmd_add_peer(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid)
                sta_rates |= sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET;
 
        cmd->supported_rates =
-               cpu_to_le32(wl1271_tx_enabled_rates_get(wl, sta_rates));
+               cpu_to_le32(wl1271_tx_enabled_rates_get(wl, sta_rates,
+                                                       wl->band));
 
        wl1271_debug(DEBUG_CMD, "new peer rates=0x%x queues=0x%x",
                     cmd->supported_rates, sta->uapsd_queues);
index 45428a21f9e2af980c843726acfeab407c284d55..6a6805c3cc747e732bccec4cab0c69a659d49cc8 100644 (file)
@@ -454,12 +454,10 @@ struct conf_rx_settings {
 #define CONF_TX_AP_DEFAULT_MGMT_RATES  (CONF_HW_BIT_RATE_1MBPS | \
        CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS)
 
-/*
- * Default rates for working as IBSS. use 11b rates
- */
+/* default rates for working as IBSS (11b and OFDM) */
 #define CONF_TX_IBSS_DEFAULT_RATES  (CONF_HW_BIT_RATE_1MBPS |       \
                CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS | \
-               CONF_HW_BIT_RATE_11MBPS);
+               CONF_HW_BIT_RATE_11MBPS | CONF_TX_OFDM_RATES);
 
 struct conf_tx_rate_class {
 
index c73fe4c6b6167652a220ede10dccb31e662613a9..e66db69f8d17e38dd8abd76668fa4aaa06109225 100644 (file)
@@ -181,7 +181,7 @@ static void wl1271_stop_ba_event(struct wl1271 *wl)
        } else {
                int i;
                struct wl1271_link *lnk;
-               for (i = WL1271_AP_STA_HLID_START; i < WL12XX_MAX_LINKS; i++) {
+               for (i = WL1271_AP_STA_HLID_START; i < AP_MAX_LINKS; i++) {
                        lnk = &wl->links[i];
                        if (!wl1271_is_active_sta(wl, i) || !lnk->ba_bitmap)
                                continue;
index 09515f5e5e1dffc30647d19142ab160db5e9d335..04db64c94e9a642fa21885ccdf276d8c3fcc9545 100644 (file)
@@ -103,6 +103,7 @@ static int wl1271_ap_init_deauth_template(struct wl1271 *wl)
 {
        struct wl12xx_disconn_template *tmpl;
        int ret;
+       u32 rate;
 
        tmpl = kzalloc(sizeof(*tmpl), GFP_KERNEL);
        if (!tmpl) {
@@ -113,9 +114,9 @@ static int wl1271_ap_init_deauth_template(struct wl1271 *wl)
        tmpl->header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT |
                                             IEEE80211_STYPE_DEAUTH);
 
+       rate = wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
        ret = wl1271_cmd_template_set(wl, CMD_TEMPL_DEAUTH_AP,
-                                     tmpl, sizeof(*tmpl), 0,
-                                     wl1271_tx_min_rate_get(wl));
+                                     tmpl, sizeof(*tmpl), 0, rate);
 
 out:
        kfree(tmpl);
@@ -126,6 +127,7 @@ static int wl1271_ap_init_null_template(struct wl1271 *wl)
 {
        struct ieee80211_hdr_3addr *nullfunc;
        int ret;
+       u32 rate;
 
        nullfunc = kzalloc(sizeof(*nullfunc), GFP_KERNEL);
        if (!nullfunc) {
@@ -142,9 +144,9 @@ static int wl1271_ap_init_null_template(struct wl1271 *wl)
        memcpy(nullfunc->addr2, wl->mac_addr, ETH_ALEN);
        memcpy(nullfunc->addr3, wl->mac_addr, ETH_ALEN);
 
+       rate = wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
        ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, nullfunc,
-                                     sizeof(*nullfunc), 0,
-                                     wl1271_tx_min_rate_get(wl));
+                                     sizeof(*nullfunc), 0, rate);
 
 out:
        kfree(nullfunc);
@@ -155,6 +157,7 @@ static int wl1271_ap_init_qos_null_template(struct wl1271 *wl)
 {
        struct ieee80211_qos_hdr *qosnull;
        int ret;
+       u32 rate;
 
        qosnull = kzalloc(sizeof(*qosnull), GFP_KERNEL);
        if (!qosnull) {
@@ -171,9 +174,9 @@ static int wl1271_ap_init_qos_null_template(struct wl1271 *wl)
        memcpy(qosnull->addr2, wl->mac_addr, ETH_ALEN);
        memcpy(qosnull->addr3, wl->mac_addr, ETH_ALEN);
 
+       rate = wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
        ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, qosnull,
-                                     sizeof(*qosnull), 0,
-                                     wl1271_tx_min_rate_get(wl));
+                                     sizeof(*qosnull), 0, rate);
 
 out:
        kfree(qosnull);
@@ -498,7 +501,7 @@ int wl1271_init_ap_rates(struct wl1271 *wl)
                return ret;
 
        /* use the min basic rate for AP broadcast/multicast */
-       rc.enabled_rates = wl1271_tx_min_rate_get(wl);
+       rc.enabled_rates = wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
        rc.short_retry_limit = 10;
        rc.long_retry_limit = 10;
        rc.aflags = 0;
index 680f5582618efad8385ca03b9793566970fd4d67..7d409b0f335753406526e7d1e89a0e234b9fcc55 100644 (file)
@@ -2099,6 +2099,8 @@ deinit:
        wl->time_offset = 0;
        wl->session_counter = 0;
        wl->rate_set = CONF_TX_RATE_MASK_BASIC;
+       wl->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
+       wl->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
        wl->vif = NULL;
        wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
        wl1271_free_ap_keys(wl);
@@ -2237,14 +2239,8 @@ out:
 
 static void wl1271_set_band_rate(struct wl1271 *wl)
 {
-       if (wl->band == IEEE80211_BAND_2GHZ) {
-               wl->basic_rate_set = wl->conf.tx.basic_rate;
-               wl->rate_set = wl->conf.tx.basic_rate;
-       } else {
-               wl->basic_rate_set = wl->conf.tx.basic_rate_5;
-               wl->rate_set = wl->conf.tx.basic_rate_5;
-       }
-
+       wl->basic_rate_set = wl->bitrate_masks[wl->band];
+       wl->rate_set = wl->basic_rate_set;
 }
 
 static bool wl12xx_is_roc(struct wl1271 *wl)
@@ -2273,7 +2269,7 @@ static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
                        if (ret < 0)
                                goto out;
                }
-               wl->rate_set = wl1271_tx_min_rate_get(wl);
+               wl->rate_set = wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
                ret = wl1271_acx_sta_rate_policies(wl);
                if (ret < 0)
                        goto out;
@@ -2355,6 +2351,8 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
        if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
            ((wl->band != conf->channel->band) ||
             (wl->channel != channel))) {
+               /* send all pending packets */
+               wl1271_tx_work_locked(wl);
                wl->band = conf->channel->band;
                wl->channel = channel;
 
@@ -2368,7 +2366,8 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
                        if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
                                wl1271_set_band_rate(wl);
 
-                       wl->basic_rate = wl1271_tx_min_rate_get(wl);
+                       wl->basic_rate =
+                               wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
                        ret = wl1271_acx_sta_rate_policies(wl);
                        if (ret < 0)
                                wl1271_warning("rate policy for channel "
@@ -3069,6 +3068,93 @@ static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
        return 0;
 }
 
+static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
+{
+       int len;
+       const u8 *next, *end = skb->data + skb->len;
+       u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
+                                       skb->len - ieoffset);
+       if (!ie)
+               return;
+       len = ie[1] + 2;
+       next = ie + len;
+       memmove(ie, next, end - next);
+       skb_trim(skb, skb->len - len);
+}
+
+static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
+                                           unsigned int oui, u8 oui_type,
+                                           int ieoffset)
+{
+       int len;
+       const u8 *next, *end = skb->data + skb->len;
+       u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
+                                              skb->data + ieoffset,
+                                              skb->len - ieoffset);
+       if (!ie)
+               return;
+       len = ie[1] + 2;
+       next = ie + len;
+       memmove(ie, next, end - next);
+       skb_trim(skb, skb->len - len);
+}
+
+static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl,
+                                        u8 *probe_rsp_data,
+                                        size_t probe_rsp_len,
+                                        u32 rates)
+{
+       struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf;
+       u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
+       int ssid_ie_offset, ie_offset, templ_len;
+       const u8 *ptr;
+
+       /* no need to change probe response if the SSID is set correctly */
+       if (wl->ssid_len > 0)
+               return wl1271_cmd_template_set(wl,
+                                              CMD_TEMPL_AP_PROBE_RESPONSE,
+                                              probe_rsp_data,
+                                              probe_rsp_len, 0,
+                                              rates);
+
+       if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
+               wl1271_error("probe_rsp template too big");
+               return -EINVAL;
+       }
+
+       /* start searching from IE offset */
+       ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
+
+       ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
+                              probe_rsp_len - ie_offset);
+       if (!ptr) {
+               wl1271_error("No SSID in beacon!");
+               return -EINVAL;
+       }
+
+       ssid_ie_offset = ptr - probe_rsp_data;
+       ptr += (ptr[1] + 2);
+
+       memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
+
+       /* insert SSID from bss_conf */
+       probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
+       probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
+       memcpy(probe_rsp_templ + ssid_ie_offset + 2,
+              bss_conf->ssid, bss_conf->ssid_len);
+       templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
+
+       memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
+              ptr, probe_rsp_len - (ptr - probe_rsp_data));
+       templ_len += probe_rsp_len - (ptr - probe_rsp_data);
+
+       return wl1271_cmd_template_set(wl,
+                                      CMD_TEMPL_AP_PROBE_RESPONSE,
+                                      probe_rsp_templ,
+                                      templ_len, 0,
+                                      rates);
+}
+
 static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
                                       struct ieee80211_bss_conf *bss_conf,
                                       u32 changed)
@@ -3125,6 +3211,7 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
 
        if ((changed & BSS_CHANGED_BEACON)) {
                struct ieee80211_hdr *hdr;
+               u32 min_rate;
                int ieoffset = offsetof(struct ieee80211_mgmt,
                                        u.beacon.variable);
                struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
@@ -3140,28 +3227,46 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
                        dev_kfree_skb(beacon);
                        goto out;
                }
+               min_rate = wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
                tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
                                  CMD_TEMPL_BEACON;
                ret = wl1271_cmd_template_set(wl, tmpl_id,
                                              beacon->data,
                                              beacon->len, 0,
-                                             wl1271_tx_min_rate_get(wl));
+                                             min_rate);
                if (ret < 0) {
                        dev_kfree_skb(beacon);
                        goto out;
                }
 
+               /* remove TIM ie from probe response */
+               wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
+
+               /*
+                * remove p2p ie from probe response.
+                * the fw reponds to probe requests that don't include
+                * the p2p ie. probe requests with p2p ie will be passed,
+                * and will be responded by the supplicant (the spec
+                * forbids including the p2p ie when responding to probe
+                * requests that didn't include it).
+                */
+               wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
+                                       WLAN_OUI_TYPE_WFA_P2P, ieoffset);
+
                hdr = (struct ieee80211_hdr *) beacon->data;
                hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
                                                 IEEE80211_STYPE_PROBE_RESP);
-
-               tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
-                                 CMD_TEMPL_PROBE_RESPONSE;
-               ret = wl1271_cmd_template_set(wl,
-                                             tmpl_id,
-                                             beacon->data,
-                                             beacon->len, 0,
-                                             wl1271_tx_min_rate_get(wl));
+               if (is_ap)
+                       ret = wl1271_ap_set_probe_resp_tmpl(wl,
+                                               beacon->data,
+                                               beacon->len,
+                                               min_rate);
+               else
+                       ret = wl1271_cmd_template_set(wl,
+                                               CMD_TEMPL_PROBE_RESPONSE,
+                                               beacon->data,
+                                               beacon->len, 0,
+                                               min_rate);
                dev_kfree_skb(beacon);
                if (ret < 0)
                        goto out;
@@ -3182,8 +3287,10 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
        if ((changed & BSS_CHANGED_BASIC_RATES)) {
                u32 rates = bss_conf->basic_rates;
 
-               wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
-               wl->basic_rate = wl1271_tx_min_rate_get(wl);
+               wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
+                                                                wl->band);
+               wl->basic_rate = wl1271_tx_min_rate_get(wl,
+                                                       wl->basic_rate_set);
 
                ret = wl1271_init_ap_rates(wl);
                if (ret < 0) {
@@ -3365,12 +3472,15 @@ sta_not_found:
                         * to use with control frames.
                         */
                        rates = bss_conf->basic_rates;
-                       wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
-                                                                        rates);
-                       wl->basic_rate = wl1271_tx_min_rate_get(wl);
+                       wl->basic_rate_set =
+                               wl1271_tx_enabled_rates_get(wl, rates,
+                                                           wl->band);
+                       wl->basic_rate =
+                               wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
                        if (sta_rate_set)
                                wl->rate_set = wl1271_tx_enabled_rates_get(wl,
-                                                               sta_rate_set);
+                                                               sta_rate_set,
+                                                               wl->band);
                        ret = wl1271_acx_sta_rate_policies(wl);
                        if (ret < 0)
                                goto out;
@@ -3417,7 +3527,8 @@ sta_not_found:
 
                        /* revert back to minimum rates for the current band */
                        wl1271_set_band_rate(wl);
-                       wl->basic_rate = wl1271_tx_min_rate_get(wl);
+                       wl->basic_rate =
+                               wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
                        ret = wl1271_acx_sta_rate_policies(wl);
                        if (ret < 0)
                                goto out;
@@ -3468,11 +3579,13 @@ sta_not_found:
 
                if (bss_conf->ibss_joined) {
                        u32 rates = bss_conf->basic_rates;
-                       wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
-                                                                        rates);
-                       wl->basic_rate = wl1271_tx_min_rate_get(wl);
+                       wl->basic_rate_set =
+                               wl1271_tx_enabled_rates_get(wl, rates,
+                                                           wl->band);
+                       wl->basic_rate =
+                               wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
 
-                       /* by default, use 11b rates */
+                       /* by default, use 11b + OFDM rates */
                        wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
                        ret = wl1271_acx_sta_rate_policies(wl);
                        if (ret < 0)
@@ -3702,7 +3815,8 @@ out:
        return ret;
 }
 
-static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
+static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
+                            struct ieee80211_vif *vif)
 {
 
        struct wl1271 *wl = hw->priv;
@@ -3992,6 +4106,29 @@ out:
        return ret;
 }
 
+static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
+                                  struct ieee80211_vif *vif,
+                                  const struct cfg80211_bitrate_mask *mask)
+{
+       struct wl1271 *wl = hw->priv;
+       int i;
+
+       wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
+               mask->control[NL80211_BAND_2GHZ].legacy,
+               mask->control[NL80211_BAND_5GHZ].legacy);
+
+       mutex_lock(&wl->mutex);
+
+       for (i = 0; i < IEEE80211_NUM_BANDS; i++)
+               wl->bitrate_masks[i] =
+                       wl1271_tx_enabled_rates_get(wl,
+                                                   mask->control[i].legacy,
+                                                   i);
+       mutex_unlock(&wl->mutex);
+
+       return 0;
+}
+
 static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
 {
        struct wl1271 *wl = hw->priv;
@@ -4267,6 +4404,7 @@ static const struct ieee80211_ops wl1271_ops = {
        .sta_remove = wl1271_op_sta_remove,
        .ampdu_action = wl1271_op_ampdu_action,
        .tx_frames_pending = wl1271_tx_frames_pending,
+       .set_bitrate_mask = wl12xx_set_bitrate_mask,
        CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
 };
 
@@ -4585,6 +4723,8 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
        int i, j, ret;
        unsigned int order;
 
+       BUILD_BUG_ON(AP_MAX_LINKS > WL12XX_MAX_LINKS);
+
        hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
        if (!hw) {
                wl1271_error("could not alloc ieee80211_hw");
@@ -4687,6 +4827,8 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
 
        /* Apply default driver configuration. */
        wl1271_conf_init(wl);
+       wl->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
+       wl->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
 
        order = get_order(WL1271_AGGR_BUFFER_SIZE);
        wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
index eeccc9f095bb28cb5e4ff408b1ea6453e210265d..128ccb79318c86c7e0a8bc4a65c61389b58e959f 100644 (file)
@@ -28,6 +28,7 @@
 #include "scan.h"
 #include "acx.h"
 #include "ps.h"
+#include "tx.h"
 
 void wl1271_scan_complete_work(struct work_struct *work)
 {
@@ -99,14 +100,18 @@ static int wl1271_get_scan_channels(struct wl1271 *wl,
        for (i = 0, j = 0;
             i < req->n_channels && j < WL1271_SCAN_MAX_CHANNELS;
             i++) {
-
                flags = req->channels[i]->flags;
 
                if (!test_bit(i, wl->scan.scanned_ch) &&
                    !(flags & IEEE80211_CHAN_DISABLED) &&
-                   ((!!(flags & IEEE80211_CHAN_PASSIVE_SCAN)) == passive) &&
-                   (req->channels[i]->band == band)) {
-
+                   (req->channels[i]->band == band) &&
+                   /*
+                    * In passive scans, we scan all remaining
+                    * channels, even if not marked as such.
+                    * In active scans, we only scan channels not
+                    * marked as passive.
+                    */
+                   (passive || !(flags & IEEE80211_CHAN_PASSIVE_SCAN))) {
                        wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ",
                                     req->channels[i]->band,
                                     req->channels[i]->center_freq);
@@ -158,6 +163,10 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band,
        int ret;
        u16 scan_options = 0;
 
+       /* skip active scans if we don't have SSIDs */
+       if (!passive && wl->scan.req->n_ssids == 0)
+               return WL1271_NOTHING_TO_SCAN;
+
        cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
        trigger = kzalloc(sizeof(*trigger), GFP_KERNEL);
        if (!cmd || !trigger) {
@@ -165,8 +174,7 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band,
                goto out;
        }
 
-       /* No SSIDs means that we have a forced passive scan */
-       if (passive || wl->scan.req->n_ssids == 0)
+       if (passive)
                scan_options |= WL1271_SCAN_OPT_PASSIVE;
 
        if (WARN_ON(wl->role_id == WL12XX_INVALID_ROLE_ID)) {
@@ -236,14 +244,17 @@ out:
 void wl1271_scan_stm(struct wl1271 *wl)
 {
        int ret = 0;
+       enum ieee80211_band band;
+       u32 rate;
 
        switch (wl->scan.state) {
        case WL1271_SCAN_STATE_IDLE:
                break;
 
        case WL1271_SCAN_STATE_2GHZ_ACTIVE:
-               ret = wl1271_scan_send(wl, IEEE80211_BAND_2GHZ, false,
-                                      wl->conf.tx.basic_rate);
+               band = IEEE80211_BAND_2GHZ;
+               rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]);
+               ret = wl1271_scan_send(wl, band, false, rate);
                if (ret == WL1271_NOTHING_TO_SCAN) {
                        wl->scan.state = WL1271_SCAN_STATE_2GHZ_PASSIVE;
                        wl1271_scan_stm(wl);
@@ -252,8 +263,9 @@ void wl1271_scan_stm(struct wl1271 *wl)
                break;
 
        case WL1271_SCAN_STATE_2GHZ_PASSIVE:
-               ret = wl1271_scan_send(wl, IEEE80211_BAND_2GHZ, true,
-                                      wl->conf.tx.basic_rate);
+               band = IEEE80211_BAND_2GHZ;
+               rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]);
+               ret = wl1271_scan_send(wl, band, true, rate);
                if (ret == WL1271_NOTHING_TO_SCAN) {
                        if (wl->enable_11a)
                                wl->scan.state = WL1271_SCAN_STATE_5GHZ_ACTIVE;
@@ -265,8 +277,9 @@ void wl1271_scan_stm(struct wl1271 *wl)
                break;
 
        case WL1271_SCAN_STATE_5GHZ_ACTIVE:
-               ret = wl1271_scan_send(wl, IEEE80211_BAND_5GHZ, false,
-                                      wl->conf.tx.basic_rate_5);
+               band = IEEE80211_BAND_5GHZ;
+               rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]);
+               ret = wl1271_scan_send(wl, band, false, rate);
                if (ret == WL1271_NOTHING_TO_SCAN) {
                        wl->scan.state = WL1271_SCAN_STATE_5GHZ_PASSIVE;
                        wl1271_scan_stm(wl);
@@ -275,8 +288,9 @@ void wl1271_scan_stm(struct wl1271 *wl)
                break;
 
        case WL1271_SCAN_STATE_5GHZ_PASSIVE:
-               ret = wl1271_scan_send(wl, IEEE80211_BAND_5GHZ, true,
-                                      wl->conf.tx.basic_rate_5);
+               band = IEEE80211_BAND_5GHZ;
+               rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]);
+               ret = wl1271_scan_send(wl, band, true, rate);
                if (ret == WL1271_NOTHING_TO_SCAN) {
                        wl->scan.state = WL1271_SCAN_STATE_DONE;
                        wl1271_scan_stm(wl);
index c3610492852eb3d49e7b8f81e1fa9b19c64d7093..f25d5d9212e79c9a1eb4aa501bfd592bc08865ed 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/mmc/sdio_func.h>
 #include <linux/mmc/sdio_ids.h>
 #include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
 #include <linux/gpio.h>
 #include <linux/wl12xx.h>
 #include <linux/kthread.h>
@@ -142,14 +143,23 @@ static int wl1271_sdio_set_power(struct wl1271 *wl, bool enable)
                ret = pm_runtime_get_sync(&func->dev);
                if (ret < 0)
                        goto out;
+
+               /* Runtime PM might be disabled, power up the card manually */
+               ret = mmc_power_restore_host(func->card->host);
+               if (ret < 0)
+                       goto out;
+
                sdio_claim_host(func);
                sdio_enable_func(func);
-               sdio_release_host(func);
        } else {
-               sdio_claim_host(func);
                sdio_disable_func(func);
                sdio_release_host(func);
 
+               /* Runtime PM might be disabled, power off the card manually */
+               ret = mmc_power_save_host(func->card->host);
+               if (ret < 0)
+                       goto out;
+
                /* Power down the card */
                ret = pm_runtime_put_sync(&func->dev);
        }
@@ -433,7 +443,6 @@ static int __devinit wl1271_probe(struct sdio_func *func,
 
        sdio_set_drvdata(func, wl_test);
 
-
        /* power up the device */
        ret = wl1271_chip_wakeup(wl);
        if (ret) {
index 9d4157ce0950ea0dd964bbb21a8f9c5027f03497..bad9e29d49b0145bd3ec5220be6372cc16840c36 100644 (file)
@@ -81,8 +81,7 @@ static int wl1271_tx_update_filters(struct wl1271 *wl,
        struct ieee80211_hdr *hdr;
        int ret;
 
-       hdr = (struct ieee80211_hdr *)(skb->data +
-                                      sizeof(struct wl1271_tx_hw_descr));
+       hdr = (struct ieee80211_hdr *)skb->data;
 
        /*
         * stop bssid-based filtering before transmitting authentication
@@ -181,14 +180,20 @@ u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct sk_buff *skb)
 
 static u8 wl1271_tx_get_hlid(struct wl1271 *wl, struct sk_buff *skb)
 {
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+
        if (wl12xx_is_dummy_packet(wl, skb))
                return wl->system_hlid;
 
        if (wl->bss_type == BSS_TYPE_AP_BSS)
                return wl12xx_tx_get_hlid_ap(wl, skb);
 
-       if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
-           test_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags))
+       wl1271_tx_update_filters(wl, skb);
+
+       if ((test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
+            test_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags)) &&
+           !ieee80211_is_auth(hdr->frame_control) &&
+           !ieee80211_is_assoc_req(hdr->frame_control))
                return wl->sta_hlid;
        else
                return wl->dev_hlid;
@@ -423,8 +428,6 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
        if (wl->bss_type == BSS_TYPE_AP_BSS) {
                wl1271_tx_ap_update_inconnection_sta(wl, skb);
                wl1271_tx_regulate_link(wl, hlid);
-       } else {
-               wl1271_tx_update_filters(wl, skb);
        }
 
        /*
@@ -447,13 +450,14 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
        return total_len;
 }
 
-u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set)
+u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set,
+                               enum ieee80211_band rate_band)
 {
        struct ieee80211_supported_band *band;
        u32 enabled_rates = 0;
        int bit;
 
-       band = wl->hw->wiphy->bands[wl->band];
+       band = wl->hw->wiphy->bands[rate_band];
        for (bit = 0; bit < band->n_bitrates; bit++) {
                if (rate_set & 0x1)
                        enabled_rates |= band->bitrates[bit].hw_value;
@@ -986,20 +990,10 @@ void wl1271_tx_flush(struct wl1271 *wl)
        wl1271_warning("Unable to flush all TX buffers, timed out.");
 }
 
-u32 wl1271_tx_min_rate_get(struct wl1271 *wl)
+u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set)
 {
-       int i;
-       u32 rate = 0;
-
-       if (!wl->basic_rate_set) {
-               WARN_ON(1);
-               wl->basic_rate_set = wl->conf.tx.basic_rate;
-       }
-
-       for (i = 0; !rate; i++) {
-               if ((wl->basic_rate_set >> i) & 0x1)
-                       rate = 1 << i;
-       }
+       if (WARN_ON(!rate_set))
+               return 0;
 
-       return rate;
+       return BIT(__ffs(rate_set));
 }
index d6fdbf904a09304e6fcdf7c5ace5fad6645c1c8c..dc4f09adf088541b5ae642f84a7cfac960e9b3b7 100644 (file)
@@ -209,8 +209,9 @@ void wl1271_tx_complete(struct wl1271 *wl);
 void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues);
 void wl1271_tx_flush(struct wl1271 *wl);
 u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band);
-u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set);
-u32 wl1271_tx_min_rate_get(struct wl1271 *wl);
+u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set,
+                               enum ieee80211_band rate_band);
+u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set);
 u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct sk_buff *skb);
 void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid);
 void wl1271_handle_tx_low_watermark(struct wl1271 *wl);
index 3ceb20c170bc60f159ede7db9c9d3c3bcb6b48d4..997f532450111577905c055eaacf122b6035b3fb 100644 (file)
@@ -138,7 +138,7 @@ extern u32 wl12xx_debug_level;
 #define WL1271_DEFAULT_DTIM_PERIOD 1
 
 #define WL12XX_MAX_ROLES           4
-#define WL12XX_MAX_LINKS           8
+#define WL12XX_MAX_LINKS           12
 #define WL12XX_INVALID_ROLE_ID     0xff
 #define WL12XX_INVALID_LINK_ID     0xff
 
@@ -279,7 +279,7 @@ struct wl12xx_fw_status {
 
        /* Cumulative counter of released Voice memory blocks */
        u8 tx_voice_released_blks;
-       u8 padding_1[7];
+       u8 padding_1[3];
        __le32 log_start_addr;
 } __packed;
 
@@ -526,6 +526,7 @@ struct wl1271 {
        u32 basic_rate_set;
        u32 basic_rate;
        u32 rate_set;
+       u32 bitrate_masks[IEEE80211_NUM_BANDS];
 
        /* The current band */
        enum ieee80211_band band;
index 6bc7c92fbff73b580c5f0fc334f21407322aebad..98fbf54f6004144e832f713034728a8b302c45ee 100644 (file)
@@ -1781,7 +1781,7 @@ static int wl3501_get_encode(struct net_device *dev,
                                  keys, len_keys);
        if (rc)
                goto out;
-       tocopy = min_t(u8, len_keys, wrqu->encoding.length);
+       tocopy = min_t(u16, len_keys, wrqu->encoding.length);
        tocopy = min_t(u8, tocopy, 100);
        wrqu->encoding.length = tocopy;
        memcpy(extra, keys, tocopy);
index cabfae1e70b14027e5e5d381783590869c23f0d8..0a70149df3fcb8aa39c9bbf7556edc5af7cf2da4 100644 (file)
@@ -1332,7 +1332,7 @@ static void zd_op_bss_info_changed(struct ieee80211_hw *hw,
        }
 }
 
-static u64 zd_op_get_tsf(struct ieee80211_hw *hw)
+static u64 zd_op_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
        struct zd_mac *mac = zd_hw_mac(hw);
        return zd_chip_get_tsf(&mac->chip);
index d6de44e430d32d5f86539692225856252b4691b3..315dd91800b6a7ed09068d8a4f5b03792a8d78bb 100644 (file)
@@ -133,7 +133,8 @@ static int brcms_ops_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
                          bool set);
 static void brcms_ops_sw_scan_start(struct ieee80211_hw *hw);
 static void brcms_ops_sw_scan_complete(struct ieee80211_hw *hw);
-static void brcms_ops_set_tsf(struct ieee80211_hw *hw, u64 tsf);
+static void brcms_ops_set_tsf(struct ieee80211_hw *hw,
+                             struct ieee80211_vif *vif, u64 tsf);
 static int brcms_ops_get_stats(struct ieee80211_hw *hw,
                            struct ieee80211_low_level_stats *stats);
 static void brcms_ops_sta_notify(struct ieee80211_hw *hw,
@@ -142,7 +143,8 @@ static void brcms_ops_sta_notify(struct ieee80211_hw *hw,
                              struct ieee80211_sta *sta);
 static int brcms_ops_conf_tx(struct ieee80211_hw *hw, u16 queue,
                          const struct ieee80211_tx_queue_params *params);
-static u64 brcms_ops_get_tsf(struct ieee80211_hw *hw);
+static u64 brcms_ops_get_tsf(struct ieee80211_hw *hw,
+                            struct ieee80211_vif *vif);
 static int brcms_ops_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                      struct ieee80211_sta *sta);
 static int brcms_ops_sta_remove(struct ieee80211_hw *hw,
@@ -516,7 +518,8 @@ static void brcms_ops_sw_scan_complete(struct ieee80211_hw *hw)
        return;
 }
 
-static void brcms_ops_set_tsf(struct ieee80211_hw *hw, u64 tsf)
+static void brcms_ops_set_tsf(struct ieee80211_hw *hw,
+                             struct ieee80211_vif *vif, u64 tsf)
 {
        wiphy_err(hw->wiphy, "%s: Enter\n", __func__);
        return;
@@ -565,7 +568,8 @@ brcms_ops_conf_tx(struct ieee80211_hw *hw, u16 queue,
        return 0;
 }
 
-static u64 brcms_ops_get_tsf(struct ieee80211_hw *hw)
+static u64 brcms_ops_get_tsf(struct ieee80211_hw *hw,
+                            struct ieee80211_vif *vif)
 {
        wiphy_err(hw->wiphy, "%s: Enter\n", __func__);
        return 0;
index 3724e1e67ec23adfd56d52b0e1cf6a5e0fe9e523..a2e8bd452ed9dfed2ae3f324b19cab9e0672075f 100644 (file)
@@ -277,7 +277,7 @@ static int wbsoft_config(struct ieee80211_hw *dev, u32 changed)
        return 0;
 }
 
-static u64 wbsoft_get_tsf(struct ieee80211_hw *dev)
+static u64 wbsoft_get_tsf(struct ieee80211_hw *dev, struct ieee80211_vif *vif)
 {
        printk("wbsoft_get_tsf called\n");
        return 0;
index b5e0a5c344fd69677507f8e24ed4890d143e6136..48363c3c40f8f6de0e1ebb062a35eef498f6077a 100644 (file)
@@ -759,6 +759,12 @@ struct ieee80211_mgmt {
                                        u8 action;
                                        u8 smps_control;
                                } __attribute__ ((packed)) ht_smps;
+                               struct {
+                                       u8 action_code;
+                                       u8 dialog_token;
+                                       __le16 capability;
+                                       u8 variable[0];
+                               } __packed tdls_discover_resp;
                        } u;
                } __attribute__ ((packed)) action;
        } u;
@@ -805,6 +811,52 @@ struct ieee80211_pspoll {
        u8 ta[6];
 } __attribute__ ((packed));
 
+/* TDLS */
+
+/* Link-id information element */
+struct ieee80211_tdls_lnkie {
+       u8 ie_type; /* Link Identifier IE */
+       u8 ie_len;
+       u8 bssid[6];
+       u8 init_sta[6];
+       u8 resp_sta[6];
+} __packed;
+
+struct ieee80211_tdls_data {
+       u8 da[6];
+       u8 sa[6];
+       __be16 ether_type;
+       u8 payload_type;
+       u8 category;
+       u8 action_code;
+       union {
+               struct {
+                       u8 dialog_token;
+                       __le16 capability;
+                       u8 variable[0];
+               } __packed setup_req;
+               struct {
+                       __le16 status_code;
+                       u8 dialog_token;
+                       __le16 capability;
+                       u8 variable[0];
+               } __packed setup_resp;
+               struct {
+                       __le16 status_code;
+                       u8 dialog_token;
+                       u8 variable[0];
+               } __packed setup_cfm;
+               struct {
+                       __le16 reason_code;
+                       u8 variable[0];
+               } __packed teardown;
+               struct {
+                       u8 dialog_token;
+                       u8 variable[0];
+               } __packed discover_req;
+       } u;
+} __packed;
+
 /**
  * struct ieee80211_bar - HT Block Ack Request
  *
@@ -1196,6 +1248,8 @@ enum ieee80211_eid {
        WLAN_EID_TS_DELAY = 43,
        WLAN_EID_TCLAS_PROCESSING = 44,
        WLAN_EID_QOS_CAPA = 46,
+       /* 802.11z */
+       WLAN_EID_LINK_ID = 101,
        /* 802.11s */
        WLAN_EID_MESH_CONFIG = 113,
        WLAN_EID_MESH_ID = 114,
@@ -1279,6 +1333,7 @@ enum ieee80211_category {
        WLAN_CATEGORY_HT = 7,
        WLAN_CATEGORY_SA_QUERY = 8,
        WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION = 9,
+       WLAN_CATEGORY_TDLS = 12,
        WLAN_CATEGORY_MESH_ACTION = 13,
        WLAN_CATEGORY_MULTIHOP_ACTION = 14,
        WLAN_CATEGORY_SELF_PROTECTED = 15,
@@ -1342,6 +1397,36 @@ enum ieee80211_key_len {
        WLAN_KEY_LEN_AES_CMAC = 16,
 };
 
+/* Public action codes */
+enum ieee80211_pub_actioncode {
+       WLAN_PUB_ACTION_TDLS_DISCOVER_RES = 14,
+};
+
+/* TDLS action codes */
+enum ieee80211_tdls_actioncode {
+       WLAN_TDLS_SETUP_REQUEST = 0,
+       WLAN_TDLS_SETUP_RESPONSE = 1,
+       WLAN_TDLS_SETUP_CONFIRM = 2,
+       WLAN_TDLS_TEARDOWN = 3,
+       WLAN_TDLS_PEER_TRAFFIC_INDICATION = 4,
+       WLAN_TDLS_CHANNEL_SWITCH_REQUEST = 5,
+       WLAN_TDLS_CHANNEL_SWITCH_RESPONSE = 6,
+       WLAN_TDLS_PEER_PSM_REQUEST = 7,
+       WLAN_TDLS_PEER_PSM_RESPONSE = 8,
+       WLAN_TDLS_PEER_TRAFFIC_RESPONSE = 9,
+       WLAN_TDLS_DISCOVERY_REQUEST = 10,
+};
+
+/*
+ * TDLS capabililites to be enabled in the 5th byte of the
+ * @WLAN_EID_EXT_CAPABILITY information element
+ */
+#define WLAN_EXT_CAPA5_TDLS_ENABLED    BIT(5)
+#define WLAN_EXT_CAPA5_TDLS_PROHIBITED BIT(6)
+
+/* TDLS specific payload type in the LLC/SNAP header */
+#define WLAN_TDLS_SNAP_RFTYPE  0x2
+
 /**
  * enum - mesh path selection protocol identifier
  *
index a3d99ff6e3b5c01120f93aa0beadbdfbe9f52c20..49c38fc8dbc382c4ac978cff79e424632d02b1c6 100644 (file)
@@ -83,6 +83,7 @@
 #define ETH_P_8021AH   0x88E7          /* 802.1ah Backbone Service Tag */
 #define ETH_P_1588     0x88F7          /* IEEE 1588 Timesync */
 #define ETH_P_FCOE     0x8906          /* Fibre Channel over Ethernet  */
+#define ETH_P_TDLS     0x890D          /* TDLS */
 #define ETH_P_FIP      0x8914          /* FCoE Initialization Protocol */
 #define ETH_P_QINQ1    0x9100          /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
 #define ETH_P_QINQ2    0x9200          /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
index 460b12a8ef6654f7f45902a28399dbe85126baab..9d797f253d8edbe1b4968a9a0698ae7be84229cb 100644 (file)
  *
  * @NL80211_CMD_GET_SCAN: get scan results
  * @NL80211_CMD_TRIGGER_SCAN: trigger a new scan with the given parameters
+ *     %NL80211_ATTR_TX_NO_CCK_RATE is used to decide whether to send the
+ *     probe requests at CCK rate or not.
  * @NL80211_CMD_NEW_SCAN_RESULTS: scan notification (as a reply to
  *     NL80211_CMD_GET_SCAN and on the "scan" multicast group)
  * @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons,
  *     specified using %NL80211_ATTR_DURATION. When called, this operation
  *     returns a cookie (%NL80211_ATTR_COOKIE) that will be included with the
  *     TX status event pertaining to the TX request.
+ *     %NL80211_ATTR_TX_NO_CCK_RATE is used to decide whether to send the
+ *     management frames at CCK rate or not in 2GHz band.
  * @NL80211_CMD_FRAME_WAIT_CANCEL: When an off-channel TX was requested, this
  *     command may be used with the corresponding cookie to cancel the wait
  *     time if it is known that it is no longer necessary.
  * @NL80211_CMD_PMKSA_CANDIDATE: This is used as an event to inform userspace
  *     of PMKSA caching dandidates.
  *
+ * @NL80211_CMD_TDLS_OPER: Perform a high-level TDLS command (e.g. link setup).
+ * @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -628,6 +635,9 @@ enum nl80211_commands {
 
        NL80211_CMD_PMKSA_CANDIDATE,
 
+       NL80211_CMD_TDLS_OPER,
+       NL80211_CMD_TDLS_MGMT,
+
        /* add new commands above here */
 
        /* used to define NL80211_CMD_MAX below */
@@ -1078,6 +1088,27 @@ enum nl80211_commands {
  * @NL80211_ATTR_PMKSA_CANDIDATE: Nested attribute containing the PMKSA caching
  *     candidate information, see &enum nl80211_pmksa_candidate_attr.
  *
+ * @NL80211_ATTR_TX_NO_CCK_RATE: Indicates whether to use CCK rate or not
+ *     for management frames transmission. In order to avoid p2p probe/action
+ *     frames are being transmitted at CCK rate in 2GHz band, the user space
+ *     applications use this attribute.
+ *     This attribute is used with %NL80211_CMD_TRIGGER_SCAN and
+ *     %NL80211_CMD_FRAME commands.
+ *
+ * @NL80211_ATTR_TDLS_ACTION: Low level TDLS action code (e.g. link setup
+ *     request, link setup confirm, link teardown, etc.). Values are
+ *     described in the TDLS (802.11z) specification.
+ * @NL80211_ATTR_TDLS_DIALOG_TOKEN: Non-zero token for uniquely identifying a
+ *     TDLS conversation between two devices.
+ * @NL80211_ATTR_TDLS_OPERATION: High level TDLS operation; see
+ *     &enum nl80211_tdls_operation, represented as a u8.
+ * @NL80211_ATTR_TDLS_SUPPORT: A flag indicating the device can operate
+ *     as a TDLS peer sta.
+ * @NL80211_ATTR_TDLS_EXTERNAL_SETUP: The TDLS discovery/setup and teardown
+ *     procedures should be performed by sending TDLS packets via
+ *     %NL80211_CMD_TDLS_MGMT. Otherwise %NL80211_CMD_TDLS_OPER should be
+ *     used for asking the driver to perform a TDLS operation.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1298,6 +1329,14 @@ enum nl80211_attrs {
 
        NL80211_ATTR_PMKSA_CANDIDATE,
 
+       NL80211_ATTR_TX_NO_CCK_RATE,
+
+       NL80211_ATTR_TDLS_ACTION,
+       NL80211_ATTR_TDLS_DIALOG_TOKEN,
+       NL80211_ATTR_TDLS_OPERATION,
+       NL80211_ATTR_TDLS_SUPPORT,
+       NL80211_ATTR_TDLS_EXTERNAL_SETUP,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
@@ -1395,6 +1434,7 @@ enum nl80211_iftype {
  * @NL80211_STA_FLAG_WME: station is WME/QoS capable
  * @NL80211_STA_FLAG_MFP: station uses management frame protection
  * @NL80211_STA_FLAG_AUTHENTICATED: station is authenticated
+ * @NL80211_STA_FLAG_TDLS_PEER: station is a TDLS peer
  * @NL80211_STA_FLAG_MAX: highest station flag number currently defined
  * @__NL80211_STA_FLAG_AFTER_LAST: internal use
  */
@@ -1405,6 +1445,7 @@ enum nl80211_sta_flags {
        NL80211_STA_FLAG_WME,
        NL80211_STA_FLAG_MFP,
        NL80211_STA_FLAG_AUTHENTICATED,
+       NL80211_STA_FLAG_TDLS_PEER,
 
        /* keep last */
        __NL80211_STA_FLAG_AFTER_LAST,
@@ -2591,4 +2632,20 @@ enum nl80211_pmksa_candidate_attr {
        MAX_NL80211_PMKSA_CANDIDATE = NUM_NL80211_PMKSA_CANDIDATE - 1
 };
 
+/**
+ * enum nl80211_tdls_operation - values for %NL80211_ATTR_TDLS_OPERATION
+ * @NL80211_TDLS_DISCOVERY_REQ: Send a TDLS discovery request
+ * @NL80211_TDLS_SETUP: Setup TDLS link
+ * @NL80211_TDLS_TEARDOWN: Teardown a TDLS link which is already established
+ * @NL80211_TDLS_ENABLE_LINK: Enable TDLS link
+ * @NL80211_TDLS_DISABLE_LINK: Disable TDLS link
+ */
+enum nl80211_tdls_operation {
+       NL80211_TDLS_DISCOVERY_REQ,
+       NL80211_TDLS_SETUP,
+       NL80211_TDLS_TEARDOWN,
+       NL80211_TDLS_ENABLE_LINK,
+       NL80211_TDLS_DISABLE_LINK,
+};
+
 #endif /* __LINUX_NL80211_H */
index be30aabe7b88b95825eab3e65dc606ae91d3ea83..aaf79af7243262592607924aa1e4dd609da7d2aa 100644 (file)
@@ -716,6 +716,16 @@ struct hci_rp_read_bd_addr {
        bdaddr_t bdaddr;
 } __packed;
 
+#define HCI_OP_WRITE_PAGE_SCAN_ACTIVITY        0x0c1c
+struct hci_cp_write_page_scan_activity {
+       __le16   interval;
+       __le16   window;
+} __packed;
+
+#define HCI_OP_WRITE_PAGE_SCAN_TYPE    0x0c47
+       #define PAGE_SCAN_TYPE_STANDARD         0x00
+       #define PAGE_SCAN_TYPE_INTERLACED       0x01
+
 #define HCI_OP_LE_SET_EVENT_MASK       0x2001
 struct hci_cp_le_set_event_mask {
        __u8     mask[8];
index 8f441b8b2963d685330d8981263b5d8454a0acb5..5b924423cf205ad9e927c7de4045e86160f1a082 100644 (file)
@@ -195,8 +195,6 @@ struct hci_dev {
 
        __u16                   init_last_cmd;
 
-       struct crypto_blkcipher *tfm;
-
        struct inquiry_cache    inq_cache;
        struct hci_conn_hash    conn_hash;
        struct list_head        blacklist;
@@ -348,6 +346,7 @@ enum {
        HCI_CONN_RSWITCH_PEND,
        HCI_CONN_MODE_CHANGE_PEND,
        HCI_CONN_SCO_SETUP_PEND,
+       HCI_CONN_LE_SMP_PEND,
 };
 
 static inline void hci_conn_hash_init(struct hci_dev *hdev)
@@ -395,6 +394,22 @@ static inline void hci_conn_hash_del(struct hci_dev *hdev, struct hci_conn *c)
        }
 }
 
+static inline unsigned int hci_conn_num(struct hci_dev *hdev, __u8 type)
+{
+       struct hci_conn_hash *h = &hdev->conn_hash;
+       switch (type) {
+       case ACL_LINK:
+               return h->acl_num;
+       case LE_LINK:
+               return h->le_num;
+       case SCO_LINK:
+       case ESCO_LINK:
+               return h->sco_num;
+       default:
+               return 0;
+       }
+}
+
 static inline struct hci_conn *hci_conn_hash_lookup_handle(struct hci_dev *hdev,
                                                                __u16 handle)
 {
@@ -475,7 +490,7 @@ static inline void hci_conn_put(struct hci_conn *conn)
 {
        if (atomic_dec_and_test(&conn->refcnt)) {
                unsigned long timeo;
-               if (conn->type == ACL_LINK) {
+               if (conn->type == ACL_LINK || conn->type == LE_LINK) {
                        del_timer(&conn->idle_timer);
                        if (conn->state == BT_CONNECTED) {
                                timeo = msecs_to_jiffies(conn->disc_timeout);
@@ -838,7 +853,7 @@ int mgmt_powered(u16 index, u8 powered);
 int mgmt_discoverable(u16 index, u8 discoverable);
 int mgmt_connectable(u16 index, u8 connectable);
 int mgmt_new_key(u16 index, struct link_key *key, u8 persistent);
-int mgmt_connected(u16 index, bdaddr_t *bdaddr);
+int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 link_type);
 int mgmt_disconnected(u16 index, bdaddr_t *bdaddr);
 int mgmt_disconnect_failed(u16 index);
 int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status);
@@ -858,6 +873,8 @@ int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
                                                                u8 *eir);
 int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name);
 int mgmt_discovering(u16 index, u8 discovering);
+int mgmt_device_blocked(u16 index, bdaddr_t *bdaddr);
+int mgmt_device_unblocked(u16 index, bdaddr_t *bdaddr);
 
 /* HCI info for socket */
 #define hci_pi(sk) ((struct hci_pinfo *) sk)
index 4f34ad25e75c62b3ce2f5c642c79d7c26ecdcf58..7f878b9d5642b4a3cf5a40ae86ee6bd14c58fd94 100644 (file)
@@ -409,14 +409,8 @@ struct l2cap_conn {
 
        __u8            disc_reason;
 
-       __u8            preq[7]; /* SMP Pairing Request */
-       __u8            prsp[7]; /* SMP Pairing Response */
-       __u8            prnd[16]; /* SMP Pairing Random */
-       __u8            pcnf[16]; /* SMP Pairing Confirm */
-       __u8            tk[16]; /* SMP Temporary Key */
-       __u8            smp_key_size;
-
        struct timer_list security_timer;
+       struct smp_chan *smp_chan;
 
        struct list_head chan_l;
        rwlock_t        chan_lock;
index 5428fd32ccec228a4df03c6be87539bcb2985919..d66da0f94f95ae60e4ceb1d2fe713bc90c376e08 100644 (file)
@@ -211,6 +211,11 @@ struct mgmt_cp_unblock_device {
        bdaddr_t bdaddr;
 } __packed;
 
+#define MGMT_OP_SET_FAST_CONNECTABLE   0x001F
+struct mgmt_cp_set_fast_connectable {
+       __u8 enable;
+} __packed;
+
 #define MGMT_EV_CMD_COMPLETE           0x0001
 struct mgmt_ev_cmd_complete {
        __le16 opcode;
@@ -249,6 +254,7 @@ struct mgmt_ev_new_key {
 #define MGMT_EV_CONNECTED              0x000B
 struct mgmt_ev_connected {
        bdaddr_t bdaddr;
+       __u8 link_type;
 } __packed;
 
 #define MGMT_EV_DISCONNECTED           0x000C
@@ -301,3 +307,13 @@ struct mgmt_ev_remote_name {
 } __packed;
 
 #define MGMT_EV_DISCOVERING            0x0014
+
+#define MGMT_EV_DEVICE_BLOCKED         0x0015
+struct mgmt_ev_device_blocked {
+       bdaddr_t bdaddr;
+} __packed;
+
+#define MGMT_EV_DEVICE_UNBLOCKED       0x0016
+struct mgmt_ev_device_unblocked {
+       bdaddr_t bdaddr;
+} __packed;
index 46c457612300c8fcbca5ebdaa3be1f387dd95512..15b97d54944195b19f52d57434a01f5443407d92 100644 (file)
@@ -115,9 +115,26 @@ struct smp_cmd_security_req {
 #define SMP_MIN_ENC_KEY_SIZE           7
 #define SMP_MAX_ENC_KEY_SIZE           16
 
+struct smp_chan {
+       struct l2cap_conn *conn;
+       u8              preq[7]; /* SMP Pairing Request */
+       u8              prsp[7]; /* SMP Pairing Response */
+       u8              prnd[16]; /* SMP Pairing Random (local) */
+       u8              rrnd[16]; /* SMP Pairing Random (remote) */
+       u8              pcnf[16]; /* SMP Pairing Confirm */
+       u8              tk[16]; /* SMP Temporary Key */
+       u8              smp_key_size;
+       struct crypto_blkcipher *tfm;
+       struct work_struct confirm;
+       struct work_struct random;
+
+};
+
 /* SMP Commands */
 int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level);
 int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb);
 int smp_distribute_keys(struct l2cap_conn *conn, __u8 force);
 
+void smp_chan_destroy(struct l2cap_conn *conn);
+
 #endif /* __SMP_H */
index ccfdf3f63ce503fb654c17ca93c2037b9805cc27..74f4f85be32fa41cdaac6859fded9816180fb615 100644 (file)
@@ -423,6 +423,17 @@ enum plink_actions {
        PLINK_ACTION_BLOCK,
 };
 
+/**
+ * enum station_parameters_apply_mask - station parameter values to apply
+ * @STATION_PARAM_APPLY_UAPSD: apply new uAPSD parameters (uapsd_queues, max_sp)
+ *
+ * Not all station parameters have in-band "no change" signalling,
+ * for those that don't these flags will are used.
+ */
+enum station_parameters_apply_mask {
+       STATION_PARAM_APPLY_UAPSD = BIT(0),
+};
+
 /**
  * struct station_parameters - station parameters
  *
@@ -450,6 +461,7 @@ struct station_parameters {
        u8 *supported_rates;
        struct net_device *vlan;
        u32 sta_flags_mask, sta_flags_set;
+       u32 sta_modify_mask;
        int listen_interval;
        u16 aid;
        u8 supported_rates_len;
@@ -860,6 +872,7 @@ struct cfg80211_ssid {
  * @wiphy: the wiphy this was for
  * @dev: the interface
  * @aborted: (internal) scan request was notified as aborted
+ * @no_cck: used to send probe requests at non CCK rate in 2GHz band
  */
 struct cfg80211_scan_request {
        struct cfg80211_ssid *ssids;
@@ -874,6 +887,7 @@ struct cfg80211_scan_request {
        struct wiphy *wiphy;
        struct net_device *dev;
        bool aborted;
+       bool no_cck;
 
        /* keep last */
        struct ieee80211_channel *channels[0];
@@ -1408,6 +1422,9 @@ struct cfg80211_gtk_rekey_data {
  * @set_ringparam: Set tx and rx ring sizes.
  *
  * @get_ringparam: Get tx and rx ring current and maximum sizes.
+ *
+ * @tdls_mgmt: Transmit a TDLS management frame.
+ * @tdls_oper: Perform a high-level TDLS operation (e.g. TDLS link setup).
  */
 struct cfg80211_ops {
        int     (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -1484,7 +1501,7 @@ struct cfg80211_ops {
        int     (*change_bss)(struct wiphy *wiphy, struct net_device *dev,
                              struct bss_parameters *params);
 
-       int     (*set_txq_params)(struct wiphy *wiphy,
+       int     (*set_txq_params)(struct wiphy *wiphy, struct net_device *dev,
                                  struct ieee80211_txq_params *params);
 
        int     (*set_channel)(struct wiphy *wiphy, struct net_device *dev,
@@ -1560,7 +1577,8 @@ struct cfg80211_ops {
                          struct ieee80211_channel *chan, bool offchan,
                          enum nl80211_channel_type channel_type,
                          bool channel_type_valid, unsigned int wait,
-                         const u8 *buf, size_t len, u64 *cookie);
+                         const u8 *buf, size_t len, bool no_cck,
+                         u64 *cookie);
        int     (*mgmt_tx_cancel_wait)(struct wiphy *wiphy,
                                       struct net_device *dev,
                                       u64 cookie);
@@ -1590,6 +1608,12 @@ struct cfg80211_ops {
 
        int     (*set_rekey_data)(struct wiphy *wiphy, struct net_device *dev,
                                  struct cfg80211_gtk_rekey_data *data);
+
+       int     (*tdls_mgmt)(struct wiphy *wiphy, struct net_device *dev,
+                            u8 *peer, u8 action_code,  u8 dialog_token,
+                            u16 status_code, const u8 *buf, size_t len);
+       int     (*tdls_oper)(struct wiphy *wiphy, struct net_device *dev,
+                            u8 *peer, enum nl80211_tdls_operation oper);
 };
 
 /*
@@ -1642,6 +1666,12 @@ struct cfg80211_ops {
  * @WIPHY_FLAG_SUPPORTS_FW_ROAM: The device supports roaming feature in the
  *     firmware.
  * @WIPHY_FLAG_AP_UAPSD: The device supports uapsd on AP.
+ * @WIPHY_FLAG_SUPPORTS_TDLS: The device supports TDLS (802.11z) operation.
+ * @WIPHY_FLAG_TDLS_EXTERNAL_SETUP: The device does not handle TDLS (802.11z)
+ *     link setup/discovery operations internally. Setup, discovery and
+ *     teardown packets should be sent through the @NL80211_CMD_TDLS_MGMT
+ *     command. When this flag is not set, @NL80211_CMD_TDLS_OPER should be
+ *     used for asking the driver/firmware to perform a TDLS operation.
  */
 enum wiphy_flags {
        WIPHY_FLAG_CUSTOM_REGULATORY            = BIT(0),
@@ -1658,6 +1688,8 @@ enum wiphy_flags {
        WIPHY_FLAG_ENFORCE_COMBINATIONS         = BIT(12),
        WIPHY_FLAG_SUPPORTS_FW_ROAM             = BIT(13),
        WIPHY_FLAG_AP_UAPSD                     = BIT(14),
+       WIPHY_FLAG_SUPPORTS_TDLS                = BIT(15),
+       WIPHY_FLAG_TDLS_EXTERNAL_SETUP          = BIT(16),
 };
 
 /**
index c0f63fd0c52b092bb92bbbc020733f275f7688ad..bc799304be71c85d008f6c5c867a65034d04bc85 100644 (file)
@@ -109,6 +109,7 @@ enum ieee80211_ac_numbers {
        IEEE80211_AC_BE         = 2,
        IEEE80211_AC_BK         = 3,
 };
+#define IEEE80211_NUM_ACS      4
 
 /**
  * struct ieee80211_tx_queue_params - transmit queue configuration
@@ -338,9 +339,9 @@ struct ieee80211_bss_conf {
  *     used to indicate that a frame was already retried due to PS
  * @IEEE80211_TX_INTFL_DONT_ENCRYPT: completely internal to mac80211,
  *     used to indicate frame should not be encrypted
- * @IEEE80211_TX_CTL_PSPOLL_RESPONSE: (internal?)
- *     This frame is a response to a PS-poll frame and should be sent
- *     although the station is in powersave mode.
+ * @IEEE80211_TX_CTL_POLL_RESPONSE: This frame is a response to a poll
+ *     frame (PS-Poll or uAPSD) and should be sent although the station
+ *     is in powersave mode.
  * @IEEE80211_TX_CTL_MORE_FRAMES: More frames will be passed to the
  *     transmit function after the current frame, this can be used
  *     by drivers to kick the DMA queue only if unset or when the
@@ -363,6 +364,14 @@ struct ieee80211_bss_conf {
  * @IEEE80211_TX_INTFL_TKIP_MIC_FAILURE: Marks this packet to be used for TKIP
  *     testing. It will be sent out with incorrect Michael MIC key to allow
  *     TKIP countermeasures to be tested.
+ * @IEEE80211_TX_CTL_NO_CCK_RATE: This frame will be sent at non CCK rate.
+ *     This flag is actually used for management frame especially for P2P
+ *     frames not being sent at CCK rate in 2GHz band.
+ * @IEEE80211_TX_STATUS_EOSP: This packet marks the end of service period,
+ *     when its status is reported the service period ends. For frames in
+ *     an SP that mac80211 transmits, it is already set; for driver frames
+ *     the driver may set this flag. It is also used to do the same for
+ *     PS-Poll responses.
  *
  * Note: If you have to add new flags to the enumeration, then don't
  *      forget to update %IEEE80211_TX_TEMPORARY_FLAGS when necessary.
@@ -384,7 +393,7 @@ enum mac80211_tx_control_flags {
        IEEE80211_TX_INTFL_NEED_TXPROCESSING    = BIT(14),
        IEEE80211_TX_INTFL_RETRIED              = BIT(15),
        IEEE80211_TX_INTFL_DONT_ENCRYPT         = BIT(16),
-       IEEE80211_TX_CTL_PSPOLL_RESPONSE        = BIT(17),
+       IEEE80211_TX_CTL_POLL_RESPONSE          = BIT(17),
        IEEE80211_TX_CTL_MORE_FRAMES            = BIT(18),
        IEEE80211_TX_INTFL_RETRANSMISSION       = BIT(19),
        IEEE80211_TX_INTFL_HAS_RADIOTAP         = BIT(20),
@@ -393,6 +402,8 @@ enum mac80211_tx_control_flags {
        IEEE80211_TX_CTL_STBC                   = BIT(23) | BIT(24),
        IEEE80211_TX_CTL_TX_OFFCHAN             = BIT(25),
        IEEE80211_TX_INTFL_TKIP_MIC_FAILURE     = BIT(26),
+       IEEE80211_TX_CTL_NO_CCK_RATE            = BIT(27),
+       IEEE80211_TX_STATUS_EOSP                = BIT(28),
 };
 
 #define IEEE80211_TX_CTL_STBC_SHIFT            23
@@ -406,9 +417,9 @@ enum mac80211_tx_control_flags {
        IEEE80211_TX_CTL_SEND_AFTER_DTIM | IEEE80211_TX_CTL_AMPDU |           \
        IEEE80211_TX_STAT_TX_FILTERED | IEEE80211_TX_STAT_ACK |               \
        IEEE80211_TX_STAT_AMPDU | IEEE80211_TX_STAT_AMPDU_NO_BACK |           \
-       IEEE80211_TX_CTL_RATE_CTRL_PROBE | IEEE80211_TX_CTL_PSPOLL_RESPONSE | \
+       IEEE80211_TX_CTL_RATE_CTRL_PROBE | IEEE80211_TX_CTL_POLL_RESPONSE |   \
        IEEE80211_TX_CTL_MORE_FRAMES | IEEE80211_TX_CTL_LDPC |                \
-       IEEE80211_TX_CTL_STBC)
+       IEEE80211_TX_CTL_STBC | IEEE80211_TX_STATUS_EOSP)
 
 /**
  * enum mac80211_rate_control_flags - per-rate flags set by the
@@ -1527,6 +1538,95 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw,
  * This rule applies to all other FIF flags as well.
  */
 
+/**
+ * DOC: AP support for powersaving clients
+ *
+ * In order to implement AP and P2P GO modes, mac80211 has support for
+ * client powersaving, both "legacy" PS (PS-Poll/null data) and uAPSD.
+ * There currently is no support for sAPSD.
+ *
+ * There is one assumption that mac80211 makes, namely that a client
+ * will not poll with PS-Poll and trigger with uAPSD at the same time.
+ * Both are supported, and both can be used by the same client, but
+ * they can't be used concurrently by the same client. This simplifies
+ * the driver code.
+ *
+ * The first thing to keep in mind is that there is a flag for complete
+ * driver implementation: %IEEE80211_HW_AP_LINK_PS. If this flag is set,
+ * mac80211 expects the driver to handle most of the state machine for
+ * powersaving clients and will ignore the PM bit in incoming frames.
+ * Drivers then use ieee80211_sta_ps_transition() to inform mac80211 of
+ * stations' powersave transitions. In this mode, mac80211 also doesn't
+ * handle PS-Poll/uAPSD.
+ *
+ * In the mode without %IEEE80211_HW_AP_LINK_PS, mac80211 will check the
+ * PM bit in incoming frames for client powersave transitions. When a
+ * station goes to sleep, we will stop transmitting to it. There is,
+ * however, a race condition: a station might go to sleep while there is
+ * data buffered on hardware queues. If the device has support for this
+ * it will reject frames, and the driver should give the frames back to
+ * mac80211 with the %IEEE80211_TX_STAT_TX_FILTERED flag set which will
+ * cause mac80211 to retry the frame when the station wakes up. The
+ * driver is also notified of powersave transitions by calling its
+ * @sta_notify callback.
+ *
+ * When the station is asleep, it has three choices: it can wake up,
+ * it can PS-Poll, or it can possibly start a uAPSD service period.
+ * Waking up is implemented by simply transmitting all buffered (and
+ * filtered) frames to the station. This is the easiest case. When
+ * the station sends a PS-Poll or a uAPSD trigger frame, mac80211
+ * will inform the driver of this with the @allow_buffered_frames
+ * callback; this callback is optional. mac80211 will then transmit
+ * the frames as usual and set the %IEEE80211_TX_CTL_POLL_RESPONSE
+ * on each frame. The last frame in the service period (or the only
+ * response to a PS-Poll) also has %IEEE80211_TX_STATUS_EOSP set to
+ * indicate that it ends the service period; as this frame must have
+ * TX status report it also sets %IEEE80211_TX_CTL_REQ_TX_STATUS.
+ * When TX status is reported for this frame, the service period is
+ * marked has having ended and a new one can be started by the peer.
+ *
+ * Another race condition can happen on some devices like iwlwifi
+ * when there are frames queued for the station and it wakes up
+ * or polls; the frames that are already queued could end up being
+ * transmitted first instead, causing reordering and/or wrong
+ * processing of the EOSP. The cause is that allowing frames to be
+ * transmitted to a certain station is out-of-band communication to
+ * the device. To allow this problem to be solved, the driver can
+ * call ieee80211_sta_block_awake() if frames are buffered when it
+ * is notified that the station went to sleep. When all these frames
+ * have been filtered (see above), it must call the function again
+ * to indicate that the station is no longer blocked.
+ *
+ * If the driver buffers frames in the driver for aggregation in any
+ * way, it must use the ieee80211_sta_set_buffered() call when it is
+ * notified of the station going to sleep to inform mac80211 of any
+ * TIDs that have frames buffered. Note that when a station wakes up
+ * this information is reset (hence the requirement to call it when
+ * informed of the station going to sleep). Then, when a service
+ * period starts for any reason, @release_buffered_frames is called
+ * with the number of frames to be released and which TIDs they are
+ * to come from. In this case, the driver is responsible for setting
+ * the EOSP (for uAPSD) and MORE_DATA bits in the released frames,
+ * to help the @more_data paramter is passed to tell the driver if
+ * there is more data on other TIDs -- the TIDs to release frames
+ * from are ignored since mac80211 doesn't know how many frames the
+ * buffers for those TIDs contain.
+ *
+ * If the driver also implement GO mode, where absence periods may
+ * shorten service periods (or abort PS-Poll responses), it must
+ * filter those response frames except in the case of frames that
+ * are buffered in the driver -- those must remain buffered to avoid
+ * reordering. Because it is possible that no frames are released
+ * in this case, the driver must call ieee80211_sta_eosp_irqsafe()
+ * to indicate to mac80211 that the service period ended anyway.
+ *
+ * Finally, if frames from multiple TIDs are released from mac80211
+ * but the driver might reorder them, it must clear & set the flags
+ * appropriately (only the last frame may have %IEEE80211_TX_STATUS_EOSP)
+ * and also take care of the EOSP and MORE_DATA bits in the frame.
+ * The driver may also use ieee80211_sta_eosp_irqsafe() in this case.
+ */
+
 /**
  * enum ieee80211_filter_flags - hardware filter flags
  *
@@ -1616,6 +1716,17 @@ enum ieee80211_tx_sync_type {
        IEEE80211_TX_SYNC_ACTION,
 };
 
+/**
+ * enum ieee80211_frame_release_type - frame release reason
+ * @IEEE80211_FRAME_RELEASE_PSPOLL: frame released for PS-Poll
+ * @IEEE80211_FRAME_RELEASE_UAPSD: frame(s) released due to
+ *     frame received on trigger-enabled AC
+ */
+enum ieee80211_frame_release_type {
+       IEEE80211_FRAME_RELEASE_PSPOLL,
+       IEEE80211_FRAME_RELEASE_UAPSD,
+};
+
 /**
  * struct ieee80211_ops - callbacks from mac80211 to the driver
  *
@@ -1926,6 +2037,45 @@ enum ieee80211_tx_sync_type {
  *     The callback can sleep.
  * @rssi_callback: Notify driver when the average RSSI goes above/below
  *     thresholds that were registered previously. The callback can sleep.
+ *
+ * @release_buffered_frames: Release buffered frames according to the given
+ *     parameters. In the case where the driver buffers some frames for
+ *     sleeping stations mac80211 will use this callback to tell the driver
+ *     to release some frames, either for PS-poll or uAPSD.
+ *     Note that if the @more_data paramter is %false the driver must check
+ *     if there are more frames on the given TIDs, and if there are more than
+ *     the frames being released then it must still set the more-data bit in
+ *     the frame. If the @more_data parameter is %true, then of course the
+ *     more-data bit must always be set.
+ *     The @tids parameter tells the driver which TIDs to release frames
+ *     from, for PS-poll it will always have only a single bit set.
+ *     In the case this is used for a PS-poll initiated release, the
+ *     @num_frames parameter will always be 1 so code can be shared. In
+ *     this case the driver must also set %IEEE80211_TX_STATUS_EOSP flag
+ *     on the TX status (and must report TX status) so that the PS-poll
+ *     period is properly ended. This is used to avoid sending multiple
+ *     responses for a retried PS-poll frame.
+ *     In the case this is used for uAPSD, the @num_frames parameter may be
+ *     bigger than one, but the driver may send fewer frames (it must send
+ *     at least one, however). In this case it is also responsible for
+ *     setting the EOSP flag in the QoS header of the frames. Also, when the
+ *     service period ends, the driver must set %IEEE80211_TX_STATUS_EOSP
+ *     on the last frame in the SP. Alternatively, it may call the function
+ *     ieee80211_sta_eosp_irqsafe() to inform mac80211 of the end of the SP.
+ *     This callback must be atomic.
+ * @allow_buffered_frames: Prepare device to allow the given number of frames
+ *     to go out to the given station. The frames will be sent by mac80211
+ *     via the usual TX path after this call. The TX information for frames
+ *     released will also have the %IEEE80211_TX_CTL_POLL_RESPONSE flag set
+ *     and the last one will also have %IEEE80211_TX_STATUS_EOSP set. In case
+ *     frames from multiple TIDs are released and the driver might reorder
+ *     them between the TIDs, it must set the %IEEE80211_TX_STATUS_EOSP flag
+ *     on the last frame and clear it on all others and also handle the EOSP
+ *     bit in the QoS header correctly. Alternatively, it can also call the
+ *     ieee80211_sta_eosp_irqsafe() function.
+ *     The @tids parameter is a bitmap and tells the driver which TIDs the
+ *     frames will be on; it will at most have two bits set.
+ *     This callback must be atomic.
  */
 struct ieee80211_ops {
        void (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
@@ -2000,9 +2150,10 @@ struct ieee80211_ops {
                        enum sta_notify_cmd, struct ieee80211_sta *sta);
        int (*conf_tx)(struct ieee80211_hw *hw, u16 queue,
                       const struct ieee80211_tx_queue_params *params);
-       u64 (*get_tsf)(struct ieee80211_hw *hw);
-       void (*set_tsf)(struct ieee80211_hw *hw, u64 tsf);
-       void (*reset_tsf)(struct ieee80211_hw *hw);
+       u64 (*get_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
+       void (*set_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                       u64 tsf);
+       void (*reset_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
        int (*tx_last_beacon)(struct ieee80211_hw *hw);
        int (*ampdu_action)(struct ieee80211_hw *hw,
                            struct ieee80211_vif *vif,
@@ -2039,6 +2190,17 @@ struct ieee80211_ops {
                                const struct cfg80211_bitrate_mask *mask);
        void (*rssi_callback)(struct ieee80211_hw *hw,
                              enum ieee80211_rssi_event rssi_event);
+
+       void (*allow_buffered_frames)(struct ieee80211_hw *hw,
+                                     struct ieee80211_sta *sta,
+                                     u16 tids, int num_frames,
+                                     enum ieee80211_frame_release_type reason,
+                                     bool more_data);
+       void (*release_buffered_frames)(struct ieee80211_hw *hw,
+                                       struct ieee80211_sta *sta,
+                                       u16 tids, int num_frames,
+                                       enum ieee80211_frame_release_type reason,
+                                       bool more_data);
 };
 
 /**
@@ -2356,17 +2518,35 @@ static inline int ieee80211_sta_ps_transition_ni(struct ieee80211_sta *sta,
 #define IEEE80211_TX_STATUS_HEADROOM   13
 
 /**
- * ieee80211_sta_set_tim - set the TIM bit for a sleeping station
+ * ieee80211_sta_set_buffered - inform mac80211 about driver-buffered frames
  * @sta: &struct ieee80211_sta pointer for the sleeping station
+ * @tid: the TID that has buffered frames
+ * @buffered: indicates whether or not frames are buffered for this TID
  *
  * If a driver buffers frames for a powersave station instead of passing
- * them back to mac80211 for retransmission, the station needs to be told
- * to wake up using the TIM bitmap in the beacon.
+ * them back to mac80211 for retransmission, the station may still need
+ * to be told that there are buffered frames via the TIM bit.
  *
- * This function sets the station's TIM bit - it will be cleared when the
- * station wakes up.
+ * This function informs mac80211 whether or not there are frames that are
+ * buffered in the driver for a given TID; mac80211 can then use this data
+ * to set the TIM bit (NOTE: This may call back into the driver's set_tim
+ * call! Beware of the locking!)
+ *
+ * If all frames are released to the station (due to PS-poll or uAPSD)
+ * then the driver needs to inform mac80211 that there no longer are
+ * frames buffered. However, when the station wakes up mac80211 assumes
+ * that all buffered frames will be transmitted and clears this data,
+ * drivers need to make sure they inform mac80211 about all buffered
+ * frames on the sleep transition (sta_notify() with %STA_NOTIFY_SLEEP).
+ *
+ * Note that technically mac80211 only needs to know this per AC, not per
+ * TID, but since driver buffering will inevitably happen per TID (since
+ * it is related to aggregation) it is easier to make mac80211 map the
+ * TID to the AC as required instead of keeping track in all drivers that
+ * use this API.
  */
-void ieee80211_sta_set_tim(struct ieee80211_sta *sta);
+void ieee80211_sta_set_buffered(struct ieee80211_sta *sta,
+                               u8 tid, bool buffered);
 
 /**
  * ieee80211_tx_status - transmit status callback
@@ -3023,6 +3203,24 @@ struct ieee80211_sta *ieee80211_find_sta_by_ifaddr(struct ieee80211_hw *hw,
 void ieee80211_sta_block_awake(struct ieee80211_hw *hw,
                               struct ieee80211_sta *pubsta, bool block);
 
+/**
+ * ieee80211_sta_eosp - notify mac80211 about end of SP
+ * @pubsta: the station
+ *
+ * When a device transmits frames in a way that it can't tell
+ * mac80211 in the TX status about the EOSP, it must clear the
+ * %IEEE80211_TX_STATUS_EOSP bit and call this function instead.
+ * This applies for PS-Poll as well as uAPSD.
+ *
+ * Note that there is no non-_irqsafe version right now as
+ * it wasn't needed, but just like _tx_status() and _rx()
+ * must not be mixed in irqsafe/non-irqsafe versions, this
+ * function must not be mixed with those either. Use the
+ * all irqsafe, or all non-irqsafe, don't mix! If you need
+ * the non-irqsafe version of this, you need to add it.
+ */
+void ieee80211_sta_eosp_irqsafe(struct ieee80211_sta *pubsta);
+
 /**
  * ieee80211_iter_keys - iterate keys programmed into the device
  * @hw: pointer obtained from ieee80211_alloc_hw()
@@ -3439,4 +3637,9 @@ void ieee80211_enable_rssi_reports(struct ieee80211_vif *vif,
                                   int rssi_max_thold);
 
 void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif);
+
+int ieee80211_add_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb);
+
+int ieee80211_add_ext_srates_ie(struct ieee80211_vif *vif,
+                               struct sk_buff *skb);
 #endif /* MAC80211_H */
index 2563f3a95e6712fed32a3392abf1ee91833db6d1..b8b4bbd7e0fc2d6abfa70ae5d2be24b11471bb76 100644 (file)
@@ -40,6 +40,7 @@ enum {
        NCI_UP,
        NCI_DISCOVERY,
        NCI_POLL_ACTIVE,
+       NCI_DATA_EXCHANGE,
 };
 
 /* NCI timeouts */
index ea7f031f3b04607efc65e79ab061dd0c5cb9337c..c2df7bf1d37430f63a24fff7c9e24813c4648ad5 100644 (file)
@@ -218,7 +218,7 @@ void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
        cp.handle = cpu_to_le16(conn->handle);
        memcpy(cp.ltk, ltk, sizeof(cp.ltk));
        cp.ediv = ediv;
-       memcpy(cp.rand, rand, sizeof(rand));
+       memcpy(cp.rand, rand, sizeof(cp.rand));
 
        hci_send_cmd(hdev, HCI_OP_LE_START_ENC, sizeof(cp), &cp);
 }
index 56943add45cc44707167f4877e27fe5630b00c95..b84458dcc2261259d83e1bad2aecef95ed622113 100644 (file)
@@ -1312,59 +1312,41 @@ int hci_blacklist_clear(struct hci_dev *hdev)
 int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr)
 {
        struct bdaddr_list *entry;
-       int err;
 
        if (bacmp(bdaddr, BDADDR_ANY) == 0)
                return -EBADF;
 
-       hci_dev_lock_bh(hdev);
-
-       if (hci_blacklist_lookup(hdev, bdaddr)) {
-               err = -EEXIST;
-               goto err;
-       }
+       if (hci_blacklist_lookup(hdev, bdaddr))
+               return -EEXIST;
 
        entry = kzalloc(sizeof(struct bdaddr_list), GFP_KERNEL);
-       if (!entry) {
-               err = -ENOMEM;
-               goto err;
-       }
+       if (!entry)
+               return -ENOMEM;
 
        bacpy(&entry->bdaddr, bdaddr);
 
        list_add(&entry->list, &hdev->blacklist);
 
-       err = 0;
-
-err:
-       hci_dev_unlock_bh(hdev);
-       return err;
+       return mgmt_device_blocked(hdev->id, bdaddr);
 }
 
 int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr)
 {
        struct bdaddr_list *entry;
-       int err = 0;
-
-       hci_dev_lock_bh(hdev);
 
        if (bacmp(bdaddr, BDADDR_ANY) == 0) {
-               hci_blacklist_clear(hdev);
-               goto done;
+               return hci_blacklist_clear(hdev);
        }
 
        entry = hci_blacklist_lookup(hdev, bdaddr);
        if (!entry) {
-               err = -ENOENT;
-               goto done;
+               return -ENOENT;
        }
 
        list_del(&entry->list);
        kfree(entry);
 
-done:
-       hci_dev_unlock_bh(hdev);
-       return err;
+       return mgmt_device_unblocked(hdev->id, bdaddr);
 }
 
 static void hci_clear_adv_cache(unsigned long arg)
@@ -1523,11 +1505,6 @@ int hci_register_dev(struct hci_dev *hdev)
        if (!hdev->workqueue)
                goto nomem;
 
-       hdev->tfm = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC);
-       if (IS_ERR(hdev->tfm))
-               BT_INFO("Failed to load transform for ecb(aes): %ld",
-                                                       PTR_ERR(hdev->tfm));
-
        hci_register_sysfs(hdev);
 
        hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev,
@@ -1576,9 +1553,6 @@ int hci_unregister_dev(struct hci_dev *hdev)
                                        !test_bit(HCI_SETUP, &hdev->flags))
                mgmt_index_removed(hdev->id);
 
-       if (!IS_ERR(hdev->tfm))
-               crypto_free_blkcipher(hdev->tfm);
-
        hci_notify(hdev, HCI_DEV_UNREG);
 
        if (hdev->rfkill) {
@@ -2074,6 +2048,9 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int
                        min  = c->sent;
                        conn = c;
                }
+
+               if (hci_conn_num(hdev, type) == num)
+                       break;
        }
 
        if (conn) {
@@ -2131,6 +2108,9 @@ static inline void hci_sched_acl(struct hci_dev *hdev)
 
        BT_DBG("%s", hdev->name);
 
+       if (!hci_conn_num(hdev, ACL_LINK))
+               return;
+
        if (!test_bit(HCI_RAW, &hdev->flags)) {
                /* ACL tx timeout must be longer than maximum
                 * link supervision timeout (40.9 seconds) */
@@ -2162,6 +2142,9 @@ static inline void hci_sched_sco(struct hci_dev *hdev)
 
        BT_DBG("%s", hdev->name);
 
+       if (!hci_conn_num(hdev, SCO_LINK))
+               return;
+
        while (hdev->sco_cnt && (conn = hci_low_sent(hdev, SCO_LINK, &quote))) {
                while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
                        BT_DBG("skb %p len %d", skb, skb->len);
@@ -2182,6 +2165,9 @@ static inline void hci_sched_esco(struct hci_dev *hdev)
 
        BT_DBG("%s", hdev->name);
 
+       if (!hci_conn_num(hdev, ESCO_LINK))
+               return;
+
        while (hdev->sco_cnt && (conn = hci_low_sent(hdev, ESCO_LINK, &quote))) {
                while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
                        BT_DBG("skb %p len %d", skb, skb->len);
@@ -2202,6 +2188,9 @@ static inline void hci_sched_le(struct hci_dev *hdev)
 
        BT_DBG("%s", hdev->name);
 
+       if (!hci_conn_num(hdev, LE_LINK))
+               return;
+
        if (!test_bit(HCI_RAW, &hdev->flags)) {
                /* LE tx timeout must be longer than maximum
                 * link supervision timeout (40.9 seconds) */
index 7ef4eb4435fb4444585e9e8c6b54ef1effd486a9..35083f2aa2ea0c0ae23608b4fa421f0646b9b08d 100644 (file)
@@ -898,16 +898,15 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
        if (!cp)
                return;
 
-       hci_dev_lock(hdev);
-
        if (cp->enable == 0x01) {
                del_timer(&hdev->adv_timer);
+
+               hci_dev_lock(hdev);
                hci_adv_entries_clear(hdev);
+               hci_dev_unlock(hdev);
        } else if (cp->enable == 0x00) {
                mod_timer(&hdev->adv_timer, jiffies + ADV_CLEAR_TIMEOUT);
        }
-
-       hci_dev_unlock(hdev);
 }
 
 static void hci_cc_le_ltk_reply(struct hci_dev *hdev, struct sk_buff *skb)
@@ -1103,9 +1102,10 @@ static int hci_outgoing_auth_needed(struct hci_dev *hdev,
                return 0;
 
        /* Only request authentication for SSP connections or non-SSP
-        * devices with sec_level HIGH */
+        * devices with sec_level HIGH or if MITM protection is requested */
        if (!(hdev->ssp_mode > 0 && conn->ssp_mode > 0) &&
-                               conn->pending_sec_level != BT_SECURITY_HIGH)
+                               conn->pending_sec_level != BT_SECURITY_HIGH &&
+                               !(conn->auth_type & 0x01))
                return 0;
 
        return 1;
@@ -1412,7 +1412,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
                        conn->state = BT_CONFIG;
                        hci_conn_hold(conn);
                        conn->disc_timeout = HCI_DISCONN_TIMEOUT;
-                       mgmt_connected(hdev->id, &ev->bdaddr);
+                       mgmt_connected(hdev->id, &ev->bdaddr, conn->type);
                } else
                        conn->state = BT_CONNECTED;
 
@@ -2816,7 +2816,7 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff
                goto unlock;
        }
 
-       mgmt_connected(hdev->id, &ev->bdaddr);
+       mgmt_connected(hdev->id, &ev->bdaddr, conn->type);
 
        conn->sec_level = BT_SECURITY_LOW;
        conn->handle = __le16_to_cpu(ev->handle);
index ff02cf5e77ccdd576d2f42f78f2c4715e3a47d5e..f6afe3d76a668154a3131fe55f78bf3de34ed636 100644 (file)
@@ -183,21 +183,35 @@ static int hci_sock_release(struct socket *sock)
 static int hci_sock_blacklist_add(struct hci_dev *hdev, void __user *arg)
 {
        bdaddr_t bdaddr;
+       int err;
 
        if (copy_from_user(&bdaddr, arg, sizeof(bdaddr)))
                return -EFAULT;
 
-       return hci_blacklist_add(hdev, &bdaddr);
+       hci_dev_lock_bh(hdev);
+
+       err = hci_blacklist_add(hdev, &bdaddr);
+
+       hci_dev_unlock_bh(hdev);
+
+       return err;
 }
 
 static int hci_sock_blacklist_del(struct hci_dev *hdev, void __user *arg)
 {
        bdaddr_t bdaddr;
+       int err;
 
        if (copy_from_user(&bdaddr, arg, sizeof(bdaddr)))
                return -EFAULT;
 
-       return hci_blacklist_del(hdev, &bdaddr);
+       hci_dev_lock_bh(hdev);
+
+       err = hci_blacklist_del(hdev, &bdaddr);
+
+       hci_dev_unlock_bh(hdev);
+
+       return err;
 }
 
 /* Ioctls that require bound socket */
index a6c3aa8be1f79796dbfa051af03b3503f23fbe4e..22f1a6c87035b551c352acf70d53ed369d6e9dcd 100644 (file)
@@ -23,6 +23,8 @@ static inline char *link_typetostr(int type)
                return "SCO";
        case ESCO_LINK:
                return "eSCO";
+       case LE_LINK:
+               return "LE";
        default:
                return "UNKNOWN";
        }
index fb68f344c34a68e5a4334b751196680ac33ffdfe..b83979c548b2ee706908a053430ad94a2df5a82c 100644 (file)
@@ -872,6 +872,9 @@ static int hidp_start(struct hid_device *hid)
        struct hidp_session *session = hid->driver_data;
        struct hid_report *report;
 
+       if (hid->quirks & HID_QUIRK_NO_INIT_REPORTS)
+               return 0;
+
        list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].
                        report_list, list)
                hidp_send_report(session, report);
index b3bdb482bbe6f5fdf2d197fc1035082f495c448b..1611b3544bb1fc7770db9d9333b495a719e17e1c 100644 (file)
@@ -907,6 +907,9 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
        if (!conn->hcon->out && conn->hcon->type == LE_LINK)
                l2cap_le_conn_ready(conn);
 
+       if (conn->hcon->out && conn->hcon->type == LE_LINK)
+               smp_conn_security(conn, conn->hcon->pending_sec_level);
+
        read_lock(&conn->chan_lock);
 
        list_for_each_entry(chan, &conn->chan_l, list) {
@@ -986,8 +989,10 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
        if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
                del_timer_sync(&conn->info_timer);
 
-       if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend))
+       if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend)) {
                del_timer(&conn->security_timer);
+               smp_chan_destroy(conn);
+       }
 
        hcon->l2cap_data = NULL;
        kfree(conn);
@@ -1519,7 +1524,9 @@ struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *m
        return skb;
 }
 
-struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u16 control, u16 sdulen)
+static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
+                                               struct msghdr *msg, size_t len,
+                                               u16 control, u16 sdulen)
 {
        struct sock *sk = chan->sk;
        struct l2cap_conn *conn = chan->conn;
@@ -4093,6 +4100,11 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
 
        BT_DBG("conn %p", conn);
 
+       if (hcon->type == LE_LINK) {
+               smp_distribute_keys(conn, 0);
+               del_timer(&conn->security_timer);
+       }
+
        read_lock(&conn->chan_lock);
 
        list_for_each_entry(chan, &conn->chan_l, list) {
@@ -4105,9 +4117,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
                if (chan->scid == L2CAP_CID_LE_DATA) {
                        if (!status && encrypt) {
                                chan->sec_level = hcon->sec_level;
-                               del_timer(&conn->security_timer);
                                l2cap_chan_ready(sk);
-                               smp_distribute_keys(conn, 0);
                        }
 
                        bh_unlock_sock(sk);
index 53e109eb043e073a22479b479082bdee0a321d6d..5a94eec06caa900f9bb422b5cd7376076d67c63d 100644 (file)
@@ -908,7 +908,7 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
        struct hci_dev *hdev;
        struct mgmt_cp_load_keys *cp;
        u16 key_count, expected_len;
-       int i, err;
+       int i;
 
        cp = (void *) data;
 
@@ -918,9 +918,9 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
        key_count = get_unaligned_le16(&cp->key_count);
 
        expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
-       if (expected_len > len) {
-               BT_ERR("load_keys: expected at least %u bytes, got %u bytes",
-                                                       expected_len, len);
+       if (expected_len != len) {
+               BT_ERR("load_keys: expected %u bytes, got %u bytes",
+                                                       len, expected_len);
                return -EINVAL;
        }
 
@@ -942,36 +942,17 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
        else
                clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
 
-       len -= sizeof(*cp);
-       i = 0;
-
-       while (i < len) {
-               struct mgmt_key_info *key = (void *) cp->keys + i;
-
-               i += sizeof(*key) + key->dlen;
-
-               if (key->type == HCI_LK_SMP_LTK) {
-                       struct key_master_id *id = (void *) key->data;
-
-                       if (key->dlen != sizeof(struct key_master_id))
-                               continue;
-
-                       hci_add_ltk(hdev, 0, &key->bdaddr, key->pin_len,
-                                               id->ediv, id->rand, key->val);
-
-                       continue;
-               }
+       for (i = 0; i < key_count; i++) {
+               struct mgmt_key_info *key = &cp->keys[i];
 
                hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
                                                                key->pin_len);
        }
 
-       err = cmd_complete(sk, index, MGMT_OP_LOAD_KEYS, NULL, 0);
-
        hci_dev_unlock_bh(hdev);
        hci_dev_put(hdev);
 
-       return err;
+       return 0;
 }
 
 static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
@@ -1347,6 +1328,7 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
        struct hci_dev *hdev;
        struct mgmt_cp_pair_device *cp;
        struct pending_cmd *cmd;
+       struct adv_entry *entry;
        u8 sec_level, auth_type;
        struct hci_conn *conn;
        int err;
@@ -1364,15 +1346,20 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
 
        hci_dev_lock_bh(hdev);
 
-       if (cp->io_cap == 0x03) {
-               sec_level = BT_SECURITY_MEDIUM;
+       sec_level = BT_SECURITY_MEDIUM;
+       if (cp->io_cap == 0x03)
                auth_type = HCI_AT_DEDICATED_BONDING;
-       } else {
-               sec_level = BT_SECURITY_HIGH;
+       else
                auth_type = HCI_AT_DEDICATED_BONDING_MITM;
-       }
 
-       conn = hci_connect(hdev, ACL_LINK, &cp->bdaddr, sec_level, auth_type);
+       entry = hci_find_adv_entry(hdev, &cp->bdaddr);
+       if (entry)
+               conn = hci_connect(hdev, LE_LINK, &cp->bdaddr, sec_level,
+                                                               auth_type);
+       else
+               conn = hci_connect(hdev, ACL_LINK, &cp->bdaddr, sec_level,
+                                                               auth_type);
+
        if (IS_ERR(conn)) {
                err = PTR_ERR(conn);
                goto unlock;
@@ -1391,7 +1378,10 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
                goto unlock;
        }
 
-       conn->connect_cfm_cb = pairing_complete_cb;
+       /* For LE, just connecting isn't a proof that the pairing finished */
+       if (!entry)
+               conn->connect_cfm_cb = pairing_complete_cb;
+
        conn->security_cfm_cb = pairing_complete_cb;
        conn->disconn_cfm_cb = pairing_complete_cb;
        conn->io_capability = cp->io_cap;
@@ -1689,13 +1679,12 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data,
                                                                u16 len)
 {
        struct hci_dev *hdev;
-       struct mgmt_cp_block_device *cp;
+       struct pending_cmd *cmd;
+       struct mgmt_cp_block_device *cp = (void *) data;
        int err;
 
        BT_DBG("hci%u", index);
 
-       cp = (void *) data;
-
        if (len != sizeof(*cp))
                return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
                                                        EINVAL);
@@ -1705,6 +1694,14 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data,
                return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
                                                        ENODEV);
 
+       hci_dev_lock_bh(hdev);
+
+       cmd = mgmt_pending_add(sk, MGMT_OP_BLOCK_DEVICE, index, NULL, 0);
+       if (!cmd) {
+               err = -ENOMEM;
+               goto failed;
+       }
+
        err = hci_blacklist_add(hdev, &cp->bdaddr);
 
        if (err < 0)
@@ -1712,6 +1709,11 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data,
        else
                err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
                                                        NULL, 0);
+
+       mgmt_pending_remove(cmd);
+
+failed:
+       hci_dev_unlock_bh(hdev);
        hci_dev_put(hdev);
 
        return err;
@@ -1721,13 +1723,12 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
                                                                u16 len)
 {
        struct hci_dev *hdev;
-       struct mgmt_cp_unblock_device *cp;
+       struct pending_cmd *cmd;
+       struct mgmt_cp_unblock_device *cp = (void *) data;
        int err;
 
        BT_DBG("hci%u", index);
 
-       cp = (void *) data;
-
        if (len != sizeof(*cp))
                return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
                                                                EINVAL);
@@ -1737,6 +1738,14 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
                return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
                                                                ENODEV);
 
+       hci_dev_lock_bh(hdev);
+
+       cmd = mgmt_pending_add(sk, MGMT_OP_UNBLOCK_DEVICE, index, NULL, 0);
+       if (!cmd) {
+               err = -ENOMEM;
+               goto failed;
+       }
+
        err = hci_blacklist_del(hdev, &cp->bdaddr);
 
        if (err < 0)
@@ -1744,6 +1753,67 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
        else
                err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
                                                                NULL, 0);
+
+       mgmt_pending_remove(cmd);
+
+failed:
+       hci_dev_unlock_bh(hdev);
+       hci_dev_put(hdev);
+
+       return err;
+}
+
+static int set_fast_connectable(struct sock *sk, u16 index,
+                                       unsigned char *data, u16 len)
+{
+       struct hci_dev *hdev;
+       struct mgmt_cp_set_fast_connectable *cp = (void *) data;
+       struct hci_cp_write_page_scan_activity acp;
+       u8 type;
+       int err;
+
+       BT_DBG("hci%u", index);
+
+       if (len != sizeof(*cp))
+               return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
+                                                               EINVAL);
+
+       hdev = hci_dev_get(index);
+       if (!hdev)
+               return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
+                                                               ENODEV);
+
+       hci_dev_lock(hdev);
+
+       if (cp->enable) {
+               type = PAGE_SCAN_TYPE_INTERLACED;
+               acp.interval = 0x0024;  /* 22.5 msec page scan interval */
+       } else {
+               type = PAGE_SCAN_TYPE_STANDARD; /* default */
+               acp.interval = 0x0800;  /* default 1.28 sec page scan */
+       }
+
+       acp.window = 0x0012;    /* default 11.25 msec page scan window */
+
+       err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
+                                               sizeof(acp), &acp);
+       if (err < 0) {
+               err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
+                                                               -err);
+               goto done;
+       }
+
+       err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
+       if (err < 0) {
+               err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
+                                                               -err);
+               goto done;
+       }
+
+       err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
+                                                       NULL, 0);
+done:
+       hci_dev_unlock(hdev);
        hci_dev_put(hdev);
 
        return err;
@@ -1869,6 +1939,10 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
        case MGMT_OP_UNBLOCK_DEVICE:
                err = unblock_device(sk, index, buf + sizeof(*hdr), len);
                break;
+       case MGMT_OP_SET_FAST_CONNECTABLE:
+               err = set_fast_connectable(sk, index, buf + sizeof(*hdr),
+                                                               len);
+               break;
        default:
                BT_DBG("Unknown op %u", opcode);
                err = cmd_status(sk, index, opcode, 0x01);
@@ -1977,35 +2051,25 @@ int mgmt_connectable(u16 index, u8 connectable)
 
 int mgmt_new_key(u16 index, struct link_key *key, u8 persistent)
 {
-       struct mgmt_ev_new_key *ev;
-       int err, total;
-
-       total = sizeof(struct mgmt_ev_new_key) + key->dlen;
-       ev = kzalloc(total, GFP_ATOMIC);
-       if (!ev)
-               return -ENOMEM;
-
-       bacpy(&ev->key.bdaddr, &key->bdaddr);
-       ev->key.type = key->type;
-       memcpy(ev->key.val, key->val, 16);
-       ev->key.pin_len = key->pin_len;
-       ev->key.dlen = key->dlen;
-       ev->store_hint = persistent;
+       struct mgmt_ev_new_key ev;
 
-       memcpy(ev->key.data, key->data, key->dlen);
-
-       err = mgmt_event(MGMT_EV_NEW_KEY, index, ev, total, NULL);
+       memset(&ev, 0, sizeof(ev));
 
-       kfree(ev);
+       ev.store_hint = persistent;
+       bacpy(&ev.key.bdaddr, &key->bdaddr);
+       ev.key.type = key->type;
+       memcpy(ev.key.val, key->val, 16);
+       ev.key.pin_len = key->pin_len;
 
-       return err;
+       return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL);
 }
 
-int mgmt_connected(u16 index, bdaddr_t *bdaddr)
+int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 link_type)
 {
        struct mgmt_ev_connected ev;
 
        bacpy(&ev.bdaddr, bdaddr);
+       ev.link_type = link_type;
 
        return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
 }
@@ -2260,12 +2324,14 @@ int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
        memset(&ev, 0, sizeof(ev));
 
        bacpy(&ev.bdaddr, bdaddr);
-       memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
        ev.rssi = rssi;
 
        if (eir)
                memcpy(ev.eir, eir, sizeof(ev.eir));
 
+       if (dev_class)
+               memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
+
        return mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
 }
 
@@ -2286,3 +2352,29 @@ int mgmt_discovering(u16 index, u8 discovering)
        return mgmt_event(MGMT_EV_DISCOVERING, index, &discovering,
                                                sizeof(discovering), NULL);
 }
+
+int mgmt_device_blocked(u16 index, bdaddr_t *bdaddr)
+{
+       struct pending_cmd *cmd;
+       struct mgmt_ev_device_blocked ev;
+
+       cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, index);
+
+       bacpy(&ev.bdaddr, bdaddr);
+
+       return mgmt_event(MGMT_EV_DEVICE_BLOCKED, index, &ev, sizeof(ev),
+                                               cmd ? cmd->sk : NULL);
+}
+
+int mgmt_device_unblocked(u16 index, bdaddr_t *bdaddr)
+{
+       struct pending_cmd *cmd;
+       struct mgmt_ev_device_unblocked ev;
+
+       cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, index);
+
+       bacpy(&ev.bdaddr, bdaddr);
+
+       return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, index, &ev, sizeof(ev),
+                                               cmd ? cmd->sk : NULL);
+}
index 391888b88a929bdcb93166b0d3ed2c1ae1e3d7f3..759b63572641012b4c89fa5f48fcf6c68eee6918 100644 (file)
@@ -182,18 +182,9 @@ static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data)
                return;
 
        hci_send_acl(conn->hcon, skb, 0);
-}
-
-static __u8 seclevel_to_authreq(__u8 level)
-{
-       switch (level) {
-       case BT_SECURITY_HIGH:
-               /* Right now we don't support bonding */
-               return SMP_AUTH_MITM;
 
-       default:
-               return SMP_AUTH_NONE;
-       }
+       mod_timer(&conn->security_timer, jiffies +
+                                       msecs_to_jiffies(SMP_TIMEOUT));
 }
 
 static void build_pairing_cmd(struct l2cap_conn *conn,
@@ -205,7 +196,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
 
        dist_keys = 0;
        if (test_bit(HCI_PAIRABLE, &conn->hcon->hdev->flags)) {
-               dist_keys = SMP_DIST_ENC_KEY | SMP_DIST_ID_KEY | SMP_DIST_SIGN;
+               dist_keys = SMP_DIST_ENC_KEY;
                authreq |= SMP_AUTH_BONDING;
        }
 
@@ -229,24 +220,184 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
 
 static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size)
 {
+       struct smp_chan *smp = conn->smp_chan;
+
        if ((max_key_size > SMP_MAX_ENC_KEY_SIZE) ||
                        (max_key_size < SMP_MIN_ENC_KEY_SIZE))
                return SMP_ENC_KEY_SIZE;
 
-       conn->smp_key_size = max_key_size;
+       smp->smp_key_size = max_key_size;
 
        return 0;
 }
 
+static void confirm_work(struct work_struct *work)
+{
+       struct smp_chan *smp = container_of(work, struct smp_chan, confirm);
+       struct l2cap_conn *conn = smp->conn;
+       struct crypto_blkcipher *tfm;
+       struct smp_cmd_pairing_confirm cp;
+       int ret;
+       u8 res[16], reason;
+
+       BT_DBG("conn %p", conn);
+
+       tfm = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC);
+       if (IS_ERR(tfm)) {
+               reason = SMP_UNSPECIFIED;
+               goto error;
+       }
+
+       smp->tfm = tfm;
+
+       if (conn->hcon->out)
+               ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp, 0,
+                               conn->src, conn->hcon->dst_type, conn->dst,
+                               res);
+       else
+               ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp,
+                               conn->hcon->dst_type, conn->dst, 0, conn->src,
+                               res);
+       if (ret) {
+               reason = SMP_UNSPECIFIED;
+               goto error;
+       }
+
+       swap128(res, cp.confirm_val);
+       smp_send_cmd(smp->conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp);
+
+       return;
+
+error:
+       smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason), &reason);
+       smp_chan_destroy(conn);
+}
+
+static void random_work(struct work_struct *work)
+{
+       struct smp_chan *smp = container_of(work, struct smp_chan, random);
+       struct l2cap_conn *conn = smp->conn;
+       struct hci_conn *hcon = conn->hcon;
+       struct crypto_blkcipher *tfm = smp->tfm;
+       u8 reason, confirm[16], res[16], key[16];
+       int ret;
+
+       if (IS_ERR_OR_NULL(tfm)) {
+               reason = SMP_UNSPECIFIED;
+               goto error;
+       }
+
+       BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");
+
+       if (hcon->out)
+               ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp, 0,
+                               conn->src, hcon->dst_type, conn->dst,
+                               res);
+       else
+               ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp,
+                               hcon->dst_type, conn->dst, 0, conn->src,
+                               res);
+       if (ret) {
+               reason = SMP_UNSPECIFIED;
+               goto error;
+       }
+
+       swap128(res, confirm);
+
+       if (memcmp(smp->pcnf, confirm, sizeof(smp->pcnf)) != 0) {
+               BT_ERR("Pairing failed (confirmation values mismatch)");
+               reason = SMP_CONFIRM_FAILED;
+               goto error;
+       }
+
+       if (hcon->out) {
+               u8 stk[16], rand[8];
+               __le16 ediv;
+
+               memset(rand, 0, sizeof(rand));
+               ediv = 0;
+
+               smp_s1(tfm, smp->tk, smp->rrnd, smp->prnd, key);
+               swap128(key, stk);
+
+               memset(stk + smp->smp_key_size, 0,
+                               SMP_MAX_ENC_KEY_SIZE - smp->smp_key_size);
+
+               if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend)) {
+                       reason = SMP_UNSPECIFIED;
+                       goto error;
+               }
+
+               hci_le_start_enc(hcon, ediv, rand, stk);
+               hcon->enc_key_size = smp->smp_key_size;
+       } else {
+               u8 stk[16], r[16], rand[8];
+               __le16 ediv;
+
+               memset(rand, 0, sizeof(rand));
+               ediv = 0;
+
+               swap128(smp->prnd, r);
+               smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(r), r);
+
+               smp_s1(tfm, smp->tk, smp->prnd, smp->rrnd, key);
+               swap128(key, stk);
+
+               memset(stk + smp->smp_key_size, 0,
+                               SMP_MAX_ENC_KEY_SIZE - smp->smp_key_size);
+
+               hci_add_ltk(hcon->hdev, 0, conn->dst, smp->smp_key_size,
+                                                       ediv, rand, stk);
+       }
+
+       return;
+
+error:
+       smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason), &reason);
+       smp_chan_destroy(conn);
+}
+
+static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
+{
+       struct smp_chan *smp;
+
+       smp = kzalloc(sizeof(struct smp_chan), GFP_ATOMIC);
+       if (!smp)
+               return NULL;
+
+       INIT_WORK(&smp->confirm, confirm_work);
+       INIT_WORK(&smp->random, random_work);
+
+       smp->conn = conn;
+       conn->smp_chan = smp;
+
+       hci_conn_hold(conn->hcon);
+
+       return smp;
+}
+
+void smp_chan_destroy(struct l2cap_conn *conn)
+{
+       kfree(conn->smp_chan);
+       hci_conn_put(conn->hcon);
+}
+
 static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
 {
        struct smp_cmd_pairing rsp, *req = (void *) skb->data;
+       struct smp_chan *smp;
        u8 key_size;
+       int ret;
 
        BT_DBG("conn %p", conn);
 
-       conn->preq[0] = SMP_CMD_PAIRING_REQ;
-       memcpy(&conn->preq[1], req, sizeof(*req));
+       if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend))
+               smp = smp_chan_create(conn);
+
+       smp = conn->smp_chan;
+
+       smp->preq[0] = SMP_CMD_PAIRING_REQ;
+       memcpy(&smp->preq[1], req, sizeof(*req));
        skb_pull(skb, sizeof(*req));
 
        if (req->oob_flag)
@@ -260,32 +411,33 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
                return SMP_ENC_KEY_SIZE;
 
        /* Just works */
-       memset(conn->tk, 0, sizeof(conn->tk));
+       memset(smp->tk, 0, sizeof(smp->tk));
+
+       ret = smp_rand(smp->prnd);
+       if (ret)
+               return SMP_UNSPECIFIED;
 
-       conn->prsp[0] = SMP_CMD_PAIRING_RSP;
-       memcpy(&conn->prsp[1], &rsp, sizeof(rsp));
+       smp->prsp[0] = SMP_CMD_PAIRING_RSP;
+       memcpy(&smp->prsp[1], &rsp, sizeof(rsp));
 
        smp_send_cmd(conn, SMP_CMD_PAIRING_RSP, sizeof(rsp), &rsp);
 
-       mod_timer(&conn->security_timer, jiffies +
-                                       msecs_to_jiffies(SMP_TIMEOUT));
-
        return 0;
 }
 
 static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
 {
        struct smp_cmd_pairing *req, *rsp = (void *) skb->data;
-       struct smp_cmd_pairing_confirm cp;
-       struct crypto_blkcipher *tfm = conn->hcon->hdev->tfm;
+       struct smp_chan *smp = conn->smp_chan;
+       struct hci_dev *hdev = conn->hcon->hdev;
+       u8 key_size;
        int ret;
-       u8 res[16], key_size;
 
        BT_DBG("conn %p", conn);
 
        skb_pull(skb, sizeof(*rsp));
 
-       req = (void *) &conn->preq[1];
+       req = (void *) &smp->preq[1];
 
        key_size = min(req->max_key_size, rsp->max_key_size);
        if (check_enc_key_size(conn, key_size))
@@ -295,222 +447,154 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
                return SMP_OOB_NOT_AVAIL;
 
        /* Just works */
-       memset(conn->tk, 0, sizeof(conn->tk));
-
-       conn->prsp[0] = SMP_CMD_PAIRING_RSP;
-       memcpy(&conn->prsp[1], rsp, sizeof(*rsp));
-
-       ret = smp_rand(conn->prnd);
-       if (ret)
-               return SMP_UNSPECIFIED;
+       memset(smp->tk, 0, sizeof(smp->tk));
 
-       ret = smp_c1(tfm, conn->tk, conn->prnd, conn->preq, conn->prsp, 0,
-                       conn->src, conn->hcon->dst_type, conn->dst, res);
+       ret = smp_rand(smp->prnd);
        if (ret)
                return SMP_UNSPECIFIED;
 
-       swap128(res, cp.confirm_val);
+       smp->prsp[0] = SMP_CMD_PAIRING_RSP;
+       memcpy(&smp->prsp[1], rsp, sizeof(*rsp));
 
-       smp_send_cmd(conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp);
+       queue_work(hdev->workqueue, &smp->confirm);
 
        return 0;
 }
 
 static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb)
 {
-       struct crypto_blkcipher *tfm = conn->hcon->hdev->tfm;
+       struct smp_chan *smp = conn->smp_chan;
+       struct hci_dev *hdev = conn->hcon->hdev;
 
        BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");
 
-       memcpy(conn->pcnf, skb->data, sizeof(conn->pcnf));
-       skb_pull(skb, sizeof(conn->pcnf));
+       memcpy(smp->pcnf, skb->data, sizeof(smp->pcnf));
+       skb_pull(skb, sizeof(smp->pcnf));
 
        if (conn->hcon->out) {
                u8 random[16];
 
-               swap128(conn->prnd, random);
+               swap128(smp->prnd, random);
                smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(random),
                                                                random);
        } else {
-               struct smp_cmd_pairing_confirm cp;
-               int ret;
-               u8 res[16];
-
-               ret = smp_rand(conn->prnd);
-               if (ret)
-                       return SMP_UNSPECIFIED;
-
-               ret = smp_c1(tfm, conn->tk, conn->prnd, conn->preq, conn->prsp,
-                                               conn->hcon->dst_type, conn->dst,
-                                               0, conn->src, res);
-               if (ret)
-                       return SMP_CONFIRM_FAILED;
-
-               swap128(res, cp.confirm_val);
-
-               smp_send_cmd(conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp);
+               queue_work(hdev->workqueue, &smp->confirm);
        }
 
-       mod_timer(&conn->security_timer, jiffies +
-                                       msecs_to_jiffies(SMP_TIMEOUT));
-
        return 0;
 }
 
 static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
 {
-       struct hci_conn *hcon = conn->hcon;
-       struct crypto_blkcipher *tfm = hcon->hdev->tfm;
-       int ret;
-       u8 key[16], res[16], random[16], confirm[16];
+       struct smp_chan *smp = conn->smp_chan;
+       struct hci_dev *hdev = conn->hcon->hdev;
 
-       swap128(skb->data, random);
-       skb_pull(skb, sizeof(random));
-
-       if (conn->hcon->out)
-               ret = smp_c1(tfm, conn->tk, random, conn->preq, conn->prsp, 0,
-                               conn->src, conn->hcon->dst_type, conn->dst,
-                               res);
-       else
-               ret = smp_c1(tfm, conn->tk, random, conn->preq, conn->prsp,
-                               conn->hcon->dst_type, conn->dst, 0, conn->src,
-                               res);
-       if (ret)
-               return SMP_UNSPECIFIED;
-
-       BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");
-
-       swap128(res, confirm);
-
-       if (memcmp(conn->pcnf, confirm, sizeof(conn->pcnf)) != 0) {
-               BT_ERR("Pairing failed (confirmation values mismatch)");
-               return SMP_CONFIRM_FAILED;
-       }
-
-       if (conn->hcon->out) {
-               u8 stk[16], rand[8];
-               __le16 ediv;
-
-               memset(rand, 0, sizeof(rand));
-               ediv = 0;
+       BT_DBG("conn %p", conn);
 
-               smp_s1(tfm, conn->tk, random, conn->prnd, key);
-               swap128(key, stk);
+       swap128(skb->data, smp->rrnd);
+       skb_pull(skb, sizeof(smp->rrnd));
 
-               memset(stk + conn->smp_key_size, 0,
-                               SMP_MAX_ENC_KEY_SIZE - conn->smp_key_size);
+       queue_work(hdev->workqueue, &smp->random);
 
-               hci_le_start_enc(hcon, ediv, rand, stk);
-               hcon->enc_key_size = conn->smp_key_size;
-       } else {
-               u8 stk[16], r[16], rand[8];
-               __le16 ediv;
+       return 0;
+}
 
-               memset(rand, 0, sizeof(rand));
-               ediv = 0;
+static u8 smp_ltk_encrypt(struct l2cap_conn *conn)
+{
+       struct link_key *key;
+       struct key_master_id *master;
+       struct hci_conn *hcon = conn->hcon;
 
-               swap128(conn->prnd, r);
-               smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(r), r);
+       key = hci_find_link_key_type(hcon->hdev, conn->dst,
+                                               HCI_LK_SMP_LTK);
+       if (!key)
+               return 0;
 
-               smp_s1(tfm, conn->tk, conn->prnd, random, key);
-               swap128(key, stk);
+       if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND,
+                                       &hcon->pend))
+               return 1;
 
-               memset(stk + conn->smp_key_size, 0,
-                               SMP_MAX_ENC_KEY_SIZE - conn->smp_key_size);
+       master = (void *) key->data;
+       hci_le_start_enc(hcon, master->ediv, master->rand,
+                                               key->val);
+       hcon->enc_key_size = key->pin_len;
 
-               hci_add_ltk(conn->hcon->hdev, 0, conn->dst, conn->smp_key_size,
-                                                       ediv, rand, stk);
-       }
+       return 1;
 
-       return 0;
 }
-
 static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
 {
        struct smp_cmd_security_req *rp = (void *) skb->data;
        struct smp_cmd_pairing cp;
        struct hci_conn *hcon = conn->hcon;
+       struct smp_chan *smp;
 
        BT_DBG("conn %p", conn);
 
-       if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend))
+       hcon->pending_sec_level = BT_SECURITY_MEDIUM;
+
+       if (smp_ltk_encrypt(conn))
                return 0;
 
+       if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend))
+               return 0;
+
+       smp = smp_chan_create(conn);
+
        skb_pull(skb, sizeof(*rp));
 
        memset(&cp, 0, sizeof(cp));
        build_pairing_cmd(conn, &cp, NULL, rp->auth_req);
 
-       conn->preq[0] = SMP_CMD_PAIRING_REQ;
-       memcpy(&conn->preq[1], &cp, sizeof(cp));
+       smp->preq[0] = SMP_CMD_PAIRING_REQ;
+       memcpy(&smp->preq[1], &cp, sizeof(cp));
 
        smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp);
 
-       mod_timer(&conn->security_timer, jiffies +
-                                       msecs_to_jiffies(SMP_TIMEOUT));
-
-       set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend);
-
        return 0;
 }
 
 int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
 {
        struct hci_conn *hcon = conn->hcon;
-       __u8 authreq;
+       struct smp_chan *smp = conn->smp_chan;
 
        BT_DBG("conn %p hcon %p level 0x%2.2x", conn, hcon, sec_level);
 
        if (!lmp_host_le_capable(hcon->hdev))
                return 1;
 
-       if (IS_ERR(hcon->hdev->tfm))
-               return 1;
-
-       if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend))
-               return 0;
-
        if (sec_level == BT_SECURITY_LOW)
                return 1;
 
        if (hcon->sec_level >= sec_level)
                return 1;
 
-       authreq = seclevel_to_authreq(sec_level);
-
-       if (hcon->link_mode & HCI_LM_MASTER) {
-               struct smp_cmd_pairing cp;
-               struct link_key *key;
+       if (hcon->link_mode & HCI_LM_MASTER)
+               if (smp_ltk_encrypt(conn))
+                       goto done;
 
-               key = hci_find_link_key_type(hcon->hdev, conn->dst,
-                                                       HCI_LK_SMP_LTK);
-               if (key) {
-                       struct key_master_id *master = (void *) key->data;
+       if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend))
+               return 0;
 
-                       hci_le_start_enc(hcon, master->ediv, master->rand,
-                                                               key->val);
-                       hcon->enc_key_size = key->pin_len;
+       smp = smp_chan_create(conn);
 
-                       goto done;
-               }
-
-               build_pairing_cmd(conn, &cp, NULL, authreq);
-               conn->preq[0] = SMP_CMD_PAIRING_REQ;
-               memcpy(&conn->preq[1], &cp, sizeof(cp));
+       if (hcon->link_mode & HCI_LM_MASTER) {
+               struct smp_cmd_pairing cp;
 
-               mod_timer(&conn->security_timer, jiffies +
-                                       msecs_to_jiffies(SMP_TIMEOUT));
+               build_pairing_cmd(conn, &cp, NULL, SMP_AUTH_NONE);
+               smp->preq[0] = SMP_CMD_PAIRING_REQ;
+               memcpy(&smp->preq[1], &cp, sizeof(cp));
 
                smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp);
        } else {
                struct smp_cmd_security_req cp;
-               cp.auth_req = authreq;
+               cp.auth_req = SMP_AUTH_NONE;
                smp_send_cmd(conn, SMP_CMD_SECURITY_REQ, sizeof(cp), &cp);
        }
 
 done:
        hcon->pending_sec_level = sec_level;
-       set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend);
 
        return 0;
 }
@@ -518,10 +602,11 @@ done:
 static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb)
 {
        struct smp_cmd_encrypt_info *rp = (void *) skb->data;
+       struct smp_chan *smp = conn->smp_chan;
 
        skb_pull(skb, sizeof(*rp));
 
-       memcpy(conn->tk, rp->ltk, sizeof(conn->tk));
+       memcpy(smp->tk, rp->ltk, sizeof(smp->tk));
 
        return 0;
 }
@@ -529,11 +614,12 @@ static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb)
 static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
 {
        struct smp_cmd_master_ident *rp = (void *) skb->data;
+       struct smp_chan *smp = conn->smp_chan;
 
        skb_pull(skb, sizeof(*rp));
 
-       hci_add_ltk(conn->hcon->hdev, 1, conn->src, conn->smp_key_size,
-                                               rp->ediv, rp->rand, conn->tk);
+       hci_add_ltk(conn->hcon->hdev, 1, conn->src, smp->smp_key_size,
+                                               rp->ediv, rp->rand, smp->tk);
 
        smp_distribute_keys(conn, 1);
 
@@ -552,12 +638,6 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
                goto done;
        }
 
-       if (IS_ERR(conn->hcon->hdev->tfm)) {
-               err = PTR_ERR(conn->hcon->hdev->tfm);
-               reason = SMP_PAIRING_NOTSUPP;
-               goto done;
-       }
-
        skb_pull(skb, sizeof(code));
 
        switch (code) {
@@ -621,20 +701,21 @@ done:
 int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
 {
        struct smp_cmd_pairing *req, *rsp;
+       struct smp_chan *smp = conn->smp_chan;
        __u8 *keydist;
 
        BT_DBG("conn %p force %d", conn, force);
 
-       if (IS_ERR(conn->hcon->hdev->tfm))
-               return PTR_ERR(conn->hcon->hdev->tfm);
+       if (!test_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend))
+               return 0;
 
-       rsp = (void *) &conn->prsp[1];
+       rsp = (void *) &smp->prsp[1];
 
        /* The responder sends its keys first */
        if (!force && conn->hcon->out && (rsp->resp_key_dist & 0x07))
                return 0;
 
-       req = (void *) &conn->preq[1];
+       req = (void *) &smp->preq[1];
 
        if (conn->hcon->out) {
                keydist = &rsp->init_key_dist;
@@ -658,7 +739,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
 
                smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc);
 
-               hci_add_ltk(conn->hcon->hdev, 1, conn->dst, conn->smp_key_size,
+               hci_add_ltk(conn->hcon->hdev, 1, conn->dst, smp->smp_key_size,
                                                ediv, ident.rand, enc.ltk);
 
                ident.ediv = cpu_to_le16(ediv);
@@ -698,5 +779,11 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
                *keydist &= ~SMP_DIST_SIGN;
        }
 
+       if (conn->hcon->out || force) {
+               clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend);
+               del_timer(&conn->security_timer);
+               smp_chan_destroy(conn);
+       }
+
        return 0;
 }
index d1886b59bec4d451116eb3e5f4cecde5ff2cc4bf..7d3b438755f01d944615ffa03e11f14895591b29 100644 (file)
@@ -225,6 +225,18 @@ config MAC80211_VERBOSE_MHWMP_DEBUG
 
          Do not select this option.
 
+config MAC80211_VERBOSE_TDLS_DEBUG
+       bool "Verbose TDLS debugging"
+       depends on MAC80211_DEBUG_MENU
+       ---help---
+         Selecting this option causes mac80211 to print out very
+         verbose TDLS selection debugging messages (when mac80211
+         is a TDLS STA).
+         It should not be selected on production systems as those
+         messages are remotely triggerable.
+
+         Do not select this option.
+
 config MAC80211_DEBUG_COUNTERS
        bool "Extra statistics for TX/RX debugging"
        depends on MAC80211_DEBUG_MENU
index e6cab51dceb078e43e8a0657f424b03364c82926..0cde8df6828de8658c013df001e002fbfd2b7478 100644 (file)
@@ -223,7 +223,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
 
        status = WLAN_STATUS_REQUEST_DECLINED;
 
-       if (test_sta_flags(sta, WLAN_STA_BLOCK_BA)) {
+       if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
                printk(KERN_DEBUG "Suspend in progress. "
                       "Denying ADDBA request\n");
index 3cef5a7281cb2d5c2db9c3c82a9b5037dbf550b8..2ac033989e016304047dca1ecaacbd9519ae697e 100644 (file)
@@ -382,7 +382,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
            sdata->vif.type != NL80211_IFTYPE_AP)
                return -EINVAL;
 
-       if (test_sta_flags(sta, WLAN_STA_BLOCK_BA)) {
+       if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
                printk(KERN_DEBUG "BA sessions blocked. "
                       "Denying BA session request\n");
index b57ddf941e598a121ea1197fcd857a6e05bb50b0..1309bb9c97be197c90b2b2f454487cb592d2d3a2 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/slab.h>
 #include <net/net_namespace.h>
 #include <linux/rcupdate.h>
+#include <linux/if_ether.h>
 #include <net/cfg80211.h>
 #include "ieee80211_i.h"
 #include "driver-ops.h"
@@ -667,7 +668,6 @@ static void sta_apply_parameters(struct ieee80211_local *local,
                                 struct sta_info *sta,
                                 struct station_parameters *params)
 {
-       unsigned long flags;
        u32 rates;
        int i, j;
        struct ieee80211_supported_band *sband;
@@ -676,46 +676,58 @@ static void sta_apply_parameters(struct ieee80211_local *local,
 
        sband = local->hw.wiphy->bands[local->oper_channel->band];
 
-       spin_lock_irqsave(&sta->flaglock, flags);
        mask = params->sta_flags_mask;
        set = params->sta_flags_set;
 
        if (mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
-               sta->flags &= ~WLAN_STA_AUTHORIZED;
                if (set & BIT(NL80211_STA_FLAG_AUTHORIZED))
-                       sta->flags |= WLAN_STA_AUTHORIZED;
+                       set_sta_flag(sta, WLAN_STA_AUTHORIZED);
+               else
+                       clear_sta_flag(sta, WLAN_STA_AUTHORIZED);
        }
 
        if (mask & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) {
-               sta->flags &= ~WLAN_STA_SHORT_PREAMBLE;
                if (set & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE))
-                       sta->flags |= WLAN_STA_SHORT_PREAMBLE;
+                       set_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE);
+               else
+                       clear_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE);
        }
 
        if (mask & BIT(NL80211_STA_FLAG_WME)) {
-               sta->flags &= ~WLAN_STA_WME;
-               sta->sta.wme = false;
                if (set & BIT(NL80211_STA_FLAG_WME)) {
-                       sta->flags |= WLAN_STA_WME;
+                       set_sta_flag(sta, WLAN_STA_WME);
                        sta->sta.wme = true;
+               } else {
+                       clear_sta_flag(sta, WLAN_STA_WME);
+                       sta->sta.wme = false;
                }
        }
 
        if (mask & BIT(NL80211_STA_FLAG_MFP)) {
-               sta->flags &= ~WLAN_STA_MFP;
                if (set & BIT(NL80211_STA_FLAG_MFP))
-                       sta->flags |= WLAN_STA_MFP;
+                       set_sta_flag(sta, WLAN_STA_MFP);
+               else
+                       clear_sta_flag(sta, WLAN_STA_MFP);
        }
 
        if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED)) {
-               sta->flags &= ~WLAN_STA_AUTH;
                if (set & BIT(NL80211_STA_FLAG_AUTHENTICATED))
-                       sta->flags |= WLAN_STA_AUTH;
+                       set_sta_flag(sta, WLAN_STA_AUTH);
+               else
+                       clear_sta_flag(sta, WLAN_STA_AUTH);
        }
-       spin_unlock_irqrestore(&sta->flaglock, flags);
 
-       sta->sta.uapsd_queues = params->uapsd_queues;
-       sta->sta.max_sp = params->max_sp;
+       if (mask & BIT(NL80211_STA_FLAG_TDLS_PEER)) {
+               if (set & BIT(NL80211_STA_FLAG_TDLS_PEER))
+                       set_sta_flag(sta, WLAN_STA_TDLS_PEER);
+               else
+                       clear_sta_flag(sta, WLAN_STA_TDLS_PEER);
+       }
+
+       if (params->sta_modify_mask & STATION_PARAM_APPLY_UAPSD) {
+               sta->sta.uapsd_queues = params->uapsd_queues;
+               sta->sta.max_sp = params->max_sp;
+       }
 
        /*
         * cfg80211 validates this (1-2007) and allows setting the AID
@@ -806,10 +818,17 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
        if (!sta)
                return -ENOMEM;
 
-       sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC;
+       set_sta_flag(sta, WLAN_STA_AUTH);
+       set_sta_flag(sta, WLAN_STA_ASSOC);
 
        sta_apply_parameters(local, sta, params);
 
+       /* Only TDLS-supporting stations can add TDLS peers */
+       if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) &&
+           !((wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) &&
+             sdata->vif.type == NL80211_IFTYPE_STATION))
+               return -ENOTSUPP;
+
        rate_control_rate_init(sta);
 
        layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
@@ -862,6 +881,14 @@ static int ieee80211_change_station(struct wiphy *wiphy,
                return -ENOENT;
        }
 
+       /* The TDLS bit cannot be toggled after the STA was added */
+       if ((params->sta_flags_mask & BIT(NL80211_STA_FLAG_TDLS_PEER)) &&
+           !!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) !=
+           !!test_sta_flag(sta, WLAN_STA_TDLS_PEER)) {
+               rcu_read_unlock();
+               return -EINVAL;
+       }
+
        if (params->vlan && params->vlan != sta->sdata->dev) {
                vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
 
@@ -1271,9 +1298,11 @@ static int ieee80211_change_bss(struct wiphy *wiphy,
 }
 
 static int ieee80211_set_txq_params(struct wiphy *wiphy,
+                                   struct net_device *dev,
                                    struct ieee80211_txq_params *params)
 {
        struct ieee80211_local *local = wiphy_priv(wiphy);
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_tx_queue_params p;
 
        if (!local->ops->conf_tx)
@@ -1294,8 +1323,8 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy,
        if (params->queue >= local->hw.queues)
                return -EINVAL;
 
-       local->tx_conf[params->queue] = p;
-       if (drv_conf_tx(local, params->queue, &p)) {
+       sdata->tx_conf[params->queue] = p;
+       if (drv_conf_tx(local, sdata, params->queue, &p)) {
                wiphy_debug(local->hw.wiphy,
                            "failed to set TX queue parameters for queue %d\n",
                            params->queue);
@@ -1869,7 +1898,8 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
                             struct ieee80211_channel *chan, bool offchan,
                             enum nl80211_channel_type channel_type,
                             bool channel_type_valid, unsigned int wait,
-                            const u8 *buf, size_t len, u64 *cookie)
+                            const u8 *buf, size_t len, bool no_cck,
+                            u64 *cookie)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = sdata->local;
@@ -1896,6 +1926,9 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
                flags |= IEEE80211_TX_CTL_TX_OFFCHAN;
        }
 
+       if (no_cck)
+               flags |= IEEE80211_TX_CTL_NO_CCK_RATE;
+
        if (is_offchan && !offchan)
                return -EBUSY;
 
@@ -2120,6 +2153,323 @@ static int ieee80211_set_rekey_data(struct wiphy *wiphy,
        return 0;
 }
 
+static void ieee80211_tdls_add_ext_capab(struct sk_buff *skb)
+{
+       u8 *pos = (void *)skb_put(skb, 7);
+
+       *pos++ = WLAN_EID_EXT_CAPABILITY;
+       *pos++ = 5; /* len */
+       *pos++ = 0x0;
+       *pos++ = 0x0;
+       *pos++ = 0x0;
+       *pos++ = 0x0;
+       *pos++ = WLAN_EXT_CAPA5_TDLS_ENABLED;
+}
+
+static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_local *local = sdata->local;
+       u16 capab;
+
+       capab = 0;
+       if (local->oper_channel->band != IEEE80211_BAND_2GHZ)
+               return capab;
+
+       if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE))
+               capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
+       if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE))
+               capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
+
+       return capab;
+}
+
+static void ieee80211_tdls_add_link_ie(struct sk_buff *skb, u8 *src_addr,
+                                      u8 *peer, u8 *bssid)
+{
+       struct ieee80211_tdls_lnkie *lnkid;
+
+       lnkid = (void *)skb_put(skb, sizeof(struct ieee80211_tdls_lnkie));
+
+       lnkid->ie_type = WLAN_EID_LINK_ID;
+       lnkid->ie_len = sizeof(struct ieee80211_tdls_lnkie) - 2;
+
+       memcpy(lnkid->bssid, bssid, ETH_ALEN);
+       memcpy(lnkid->init_sta, src_addr, ETH_ALEN);
+       memcpy(lnkid->resp_sta, peer, ETH_ALEN);
+}
+
+static int
+ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev,
+                              u8 *peer, u8 action_code, u8 dialog_token,
+                              u16 status_code, struct sk_buff *skb)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_tdls_data *tf;
+
+       tf = (void *)skb_put(skb, offsetof(struct ieee80211_tdls_data, u));
+
+       memcpy(tf->da, peer, ETH_ALEN);
+       memcpy(tf->sa, sdata->vif.addr, ETH_ALEN);
+       tf->ether_type = cpu_to_be16(ETH_P_TDLS);
+       tf->payload_type = WLAN_TDLS_SNAP_RFTYPE;
+
+       switch (action_code) {
+       case WLAN_TDLS_SETUP_REQUEST:
+               tf->category = WLAN_CATEGORY_TDLS;
+               tf->action_code = WLAN_TDLS_SETUP_REQUEST;
+
+               skb_put(skb, sizeof(tf->u.setup_req));
+               tf->u.setup_req.dialog_token = dialog_token;
+               tf->u.setup_req.capability =
+                       cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
+
+               ieee80211_add_srates_ie(&sdata->vif, skb);
+               ieee80211_add_ext_srates_ie(&sdata->vif, skb);
+               ieee80211_tdls_add_ext_capab(skb);
+               break;
+       case WLAN_TDLS_SETUP_RESPONSE:
+               tf->category = WLAN_CATEGORY_TDLS;
+               tf->action_code = WLAN_TDLS_SETUP_RESPONSE;
+
+               skb_put(skb, sizeof(tf->u.setup_resp));
+               tf->u.setup_resp.status_code = cpu_to_le16(status_code);
+               tf->u.setup_resp.dialog_token = dialog_token;
+               tf->u.setup_resp.capability =
+                       cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
+
+               ieee80211_add_srates_ie(&sdata->vif, skb);
+               ieee80211_add_ext_srates_ie(&sdata->vif, skb);
+               ieee80211_tdls_add_ext_capab(skb);
+               break;
+       case WLAN_TDLS_SETUP_CONFIRM:
+               tf->category = WLAN_CATEGORY_TDLS;
+               tf->action_code = WLAN_TDLS_SETUP_CONFIRM;
+
+               skb_put(skb, sizeof(tf->u.setup_cfm));
+               tf->u.setup_cfm.status_code = cpu_to_le16(status_code);
+               tf->u.setup_cfm.dialog_token = dialog_token;
+               break;
+       case WLAN_TDLS_TEARDOWN:
+               tf->category = WLAN_CATEGORY_TDLS;
+               tf->action_code = WLAN_TDLS_TEARDOWN;
+
+               skb_put(skb, sizeof(tf->u.teardown));
+               tf->u.teardown.reason_code = cpu_to_le16(status_code);
+               break;
+       case WLAN_TDLS_DISCOVERY_REQUEST:
+               tf->category = WLAN_CATEGORY_TDLS;
+               tf->action_code = WLAN_TDLS_DISCOVERY_REQUEST;
+
+               skb_put(skb, sizeof(tf->u.discover_req));
+               tf->u.discover_req.dialog_token = dialog_token;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int
+ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev,
+                          u8 *peer, u8 action_code, u8 dialog_token,
+                          u16 status_code, struct sk_buff *skb)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_mgmt *mgmt;
+
+       mgmt = (void *)skb_put(skb, 24);
+       memset(mgmt, 0, 24);
+       memcpy(mgmt->da, peer, ETH_ALEN);
+       memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
+       memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
+
+       mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+                                         IEEE80211_STYPE_ACTION);
+
+       switch (action_code) {
+       case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
+               skb_put(skb, 1 + sizeof(mgmt->u.action.u.tdls_discover_resp));
+               mgmt->u.action.category = WLAN_CATEGORY_PUBLIC;
+               mgmt->u.action.u.tdls_discover_resp.action_code =
+                       WLAN_PUB_ACTION_TDLS_DISCOVER_RES;
+               mgmt->u.action.u.tdls_discover_resp.dialog_token =
+                       dialog_token;
+               mgmt->u.action.u.tdls_discover_resp.capability =
+                       cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
+
+               ieee80211_add_srates_ie(&sdata->vif, skb);
+               ieee80211_add_ext_srates_ie(&sdata->vif, skb);
+               ieee80211_tdls_add_ext_capab(skb);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
+                              u8 *peer, u8 action_code, u8 dialog_token,
+                              u16 status_code, const u8 *extra_ies,
+                              size_t extra_ies_len)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_tx_info *info;
+       struct sk_buff *skb = NULL;
+       bool send_direct;
+       int ret;
+
+       if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS))
+               return -ENOTSUPP;
+
+       /* make sure we are in managed mode, and associated */
+       if (sdata->vif.type != NL80211_IFTYPE_STATION ||
+           !sdata->u.mgd.associated)
+               return -EINVAL;
+
+#ifdef CONFIG_MAC80211_VERBOSE_TDLS_DEBUG
+       printk(KERN_DEBUG "TDLS mgmt action %d peer %pM\n", action_code, peer);
+#endif
+
+       skb = dev_alloc_skb(local->hw.extra_tx_headroom +
+                           max(sizeof(struct ieee80211_mgmt),
+                               sizeof(struct ieee80211_tdls_data)) +
+                           50 + /* supported rates */
+                           7 + /* ext capab */
+                           extra_ies_len +
+                           sizeof(struct ieee80211_tdls_lnkie));
+       if (!skb)
+               return -ENOMEM;
+
+       info = IEEE80211_SKB_CB(skb);
+       skb_reserve(skb, local->hw.extra_tx_headroom);
+
+       switch (action_code) {
+       case WLAN_TDLS_SETUP_REQUEST:
+       case WLAN_TDLS_SETUP_RESPONSE:
+       case WLAN_TDLS_SETUP_CONFIRM:
+       case WLAN_TDLS_TEARDOWN:
+       case WLAN_TDLS_DISCOVERY_REQUEST:
+               ret = ieee80211_prep_tdls_encap_data(wiphy, dev, peer,
+                                                    action_code, dialog_token,
+                                                    status_code, skb);
+               send_direct = false;
+               break;
+       case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
+               ret = ieee80211_prep_tdls_direct(wiphy, dev, peer, action_code,
+                                                dialog_token, status_code,
+                                                skb);
+               send_direct = true;
+               break;
+       default:
+               ret = -ENOTSUPP;
+               break;
+       }
+
+       if (ret < 0)
+               goto fail;
+
+       if (extra_ies_len)
+               memcpy(skb_put(skb, extra_ies_len), extra_ies, extra_ies_len);
+
+       /* the TDLS link IE is always added last */
+       switch (action_code) {
+       case WLAN_TDLS_SETUP_REQUEST:
+       case WLAN_TDLS_SETUP_CONFIRM:
+       case WLAN_TDLS_TEARDOWN:
+       case WLAN_TDLS_DISCOVERY_REQUEST:
+               /* we are the initiator */
+               ieee80211_tdls_add_link_ie(skb, sdata->vif.addr, peer,
+                                          sdata->u.mgd.bssid);
+               break;
+       case WLAN_TDLS_SETUP_RESPONSE:
+       case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
+               /* we are the responder */
+               ieee80211_tdls_add_link_ie(skb, peer, sdata->vif.addr,
+                                          sdata->u.mgd.bssid);
+               break;
+       default:
+               ret = -ENOTSUPP;
+               goto fail;
+       }
+
+       if (send_direct) {
+               ieee80211_tx_skb(sdata, skb);
+               return 0;
+       }
+
+       /*
+        * According to 802.11z: Setup req/resp are sent in AC_BK, otherwise
+        * we should default to AC_VI.
+        */
+       switch (action_code) {
+       case WLAN_TDLS_SETUP_REQUEST:
+       case WLAN_TDLS_SETUP_RESPONSE:
+               skb_set_queue_mapping(skb, IEEE80211_AC_BK);
+               skb->priority = 2;
+               break;
+       default:
+               skb_set_queue_mapping(skb, IEEE80211_AC_VI);
+               skb->priority = 5;
+               break;
+       }
+
+       /* disable bottom halves when entering the Tx path */
+       local_bh_disable();
+       ret = ieee80211_subif_start_xmit(skb, dev);
+       local_bh_enable();
+
+       return ret;
+
+fail:
+       dev_kfree_skb(skb);
+       return ret;
+}
+
+static int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
+                              u8 *peer, enum nl80211_tdls_operation oper)
+{
+       struct sta_info *sta;
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+       if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS))
+               return -ENOTSUPP;
+
+       if (sdata->vif.type != NL80211_IFTYPE_STATION)
+               return -EINVAL;
+
+#ifdef CONFIG_MAC80211_VERBOSE_TDLS_DEBUG
+       printk(KERN_DEBUG "TDLS oper %d peer %pM\n", oper, peer);
+#endif
+
+       switch (oper) {
+       case NL80211_TDLS_ENABLE_LINK:
+               rcu_read_lock();
+               sta = sta_info_get(sdata, peer);
+               if (!sta) {
+                       rcu_read_unlock();
+                       return -ENOLINK;
+               }
+
+               set_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH);
+               rcu_read_unlock();
+               break;
+       case NL80211_TDLS_DISABLE_LINK:
+               return sta_info_destroy_addr(sdata, peer);
+       case NL80211_TDLS_TEARDOWN:
+       case NL80211_TDLS_SETUP:
+       case NL80211_TDLS_DISCOVERY_REQ:
+               /* We don't support in-driver setup/teardown/discovery */
+               return -ENOTSUPP;
+       default:
+               return -ENOTSUPP;
+       }
+
+       return 0;
+}
+
 struct cfg80211_ops mac80211_config_ops = {
        .add_virtual_intf = ieee80211_add_iface,
        .del_virtual_intf = ieee80211_del_iface,
@@ -2183,4 +2533,6 @@ struct cfg80211_ops mac80211_config_ops = {
        .set_ringparam = ieee80211_set_ringparam,
        .get_ringparam = ieee80211_get_ringparam,
        .set_rekey_data = ieee80211_set_rekey_data,
+       .tdls_oper = ieee80211_tdls_oper,
+       .tdls_mgmt = ieee80211_tdls_mgmt,
 };
index c9141168fd4343bc562168be5457ba80069fc549..883996b2f99fae26bd21e53d1ce12d7b322a8608 100644 (file)
@@ -78,57 +78,6 @@ DEBUGFS_READONLY_FILE(wep_iv, "%#08x",
 DEBUGFS_READONLY_FILE(rate_ctrl_alg, "%s",
        local->rate_ctrl ? local->rate_ctrl->ops->name : "hw/driver");
 
-static ssize_t tsf_read(struct file *file, char __user *user_buf,
-                            size_t count, loff_t *ppos)
-{
-       struct ieee80211_local *local = file->private_data;
-       u64 tsf;
-
-       tsf = drv_get_tsf(local);
-
-       return mac80211_format_buffer(user_buf, count, ppos, "0x%016llx\n",
-                                     (unsigned long long) tsf);
-}
-
-static ssize_t tsf_write(struct file *file,
-                         const char __user *user_buf,
-                         size_t count, loff_t *ppos)
-{
-       struct ieee80211_local *local = file->private_data;
-       unsigned long long tsf;
-       char buf[100];
-       size_t len;
-
-       len = min(count, sizeof(buf) - 1);
-       if (copy_from_user(buf, user_buf, len))
-               return -EFAULT;
-       buf[len] = '\0';
-
-       if (strncmp(buf, "reset", 5) == 0) {
-               if (local->ops->reset_tsf) {
-                       drv_reset_tsf(local);
-                       wiphy_info(local->hw.wiphy, "debugfs reset TSF\n");
-               }
-       } else {
-               tsf = simple_strtoul(buf, NULL, 0);
-               if (local->ops->set_tsf) {
-                       drv_set_tsf(local, tsf);
-                       wiphy_info(local->hw.wiphy,
-                                  "debugfs set TSF to %#018llx\n", tsf);
-
-               }
-       }
-
-       return count;
-}
-
-static const struct file_operations tsf_ops = {
-       .read = tsf_read,
-       .write = tsf_write,
-       .open = mac80211_open_file_generic,
-       .llseek = default_llseek,
-};
-
 static ssize_t reset_write(struct file *file, const char __user *user_buf,
                           size_t count, loff_t *ppos)
 {
@@ -447,7 +396,6 @@ void debugfs_hw_add(struct ieee80211_local *local)
        DEBUGFS_ADD(frequency);
        DEBUGFS_ADD(total_ps_buffered);
        DEBUGFS_ADD(wep_iv);
-       DEBUGFS_ADD(tsf);
        DEBUGFS_ADD(queues);
        DEBUGFS_ADD_MODE(reset, 0200);
        DEBUGFS_ADD(noack);
index dd046291751852118783b087f81b6dee6a8da253..9352819a986bb48847ae4ef9349ac2f2100ef3d1 100644 (file)
@@ -21,6 +21,7 @@
 #include "rate.h"
 #include "debugfs.h"
 #include "debugfs_netdev.h"
+#include "driver-ops.h"
 
 static ssize_t ieee80211_if_read(
        struct ieee80211_sub_if_data *sdata,
@@ -331,6 +332,46 @@ static ssize_t ieee80211_if_fmt_num_buffered_multicast(
 }
 __IEEE80211_IF_FILE(num_buffered_multicast, NULL);
 
+/* IBSS attributes */
+static ssize_t ieee80211_if_fmt_tsf(
+       const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
+{
+       struct ieee80211_local *local = sdata->local;
+       u64 tsf;
+
+       tsf = drv_get_tsf(local, (struct ieee80211_sub_if_data *)sdata);
+
+       return scnprintf(buf, buflen, "0x%016llx\n", (unsigned long long) tsf);
+}
+
+static ssize_t ieee80211_if_parse_tsf(
+       struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
+{
+       struct ieee80211_local *local = sdata->local;
+       unsigned long long tsf;
+       int ret;
+
+       if (strncmp(buf, "reset", 5) == 0) {
+               if (local->ops->reset_tsf) {
+                       drv_reset_tsf(local, sdata);
+                       wiphy_info(local->hw.wiphy, "debugfs reset TSF\n");
+               }
+       } else {
+               ret = kstrtoull(buf, 10, &tsf);
+               if (ret < 0)
+                       return -EINVAL;
+               if (local->ops->set_tsf) {
+                       drv_set_tsf(local, sdata, tsf);
+                       wiphy_info(local->hw.wiphy,
+                                  "debugfs set TSF to %#018llx\n", tsf);
+               }
+       }
+
+       return buflen;
+}
+__IEEE80211_IF_FILE_W(tsf);
+
+
 /* WDS attributes */
 IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC);
 
@@ -421,6 +462,11 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata)
        DEBUGFS_ADD_MODE(tkip_mic_test, 0200);
 }
 
+static void add_ibss_files(struct ieee80211_sub_if_data *sdata)
+{
+       DEBUGFS_ADD_MODE(tsf, 0600);
+}
+
 static void add_wds_files(struct ieee80211_sub_if_data *sdata)
 {
        DEBUGFS_ADD(drop_unencrypted);
@@ -515,7 +561,7 @@ static void add_files(struct ieee80211_sub_if_data *sdata)
                add_sta_files(sdata);
                break;
        case NL80211_IFTYPE_ADHOC:
-               /* XXX */
+               add_ibss_files(sdata);
                break;
        case NL80211_IFTYPE_AP:
                add_ap_files(sdata);
index a01d2137fddca33f11bc89bda319c5d00937b98d..c5f341798c16769a1e5c5b7f48937e1a15d47f80 100644 (file)
@@ -56,19 +56,22 @@ STA_FILE(last_signal, last_signal, D);
 static ssize_t sta_flags_read(struct file *file, char __user *userbuf,
                              size_t count, loff_t *ppos)
 {
-       char buf[100];
+       char buf[121];
        struct sta_info *sta = file->private_data;
-       u32 staflags = get_sta_flags(sta);
-       int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s",
-               staflags & WLAN_STA_AUTH ? "AUTH\n" : "",
-               staflags & WLAN_STA_ASSOC ? "ASSOC\n" : "",
-               staflags & WLAN_STA_PS_STA ? "PS (sta)\n" : "",
-               staflags & WLAN_STA_PS_DRIVER ? "PS (driver)\n" : "",
-               staflags & WLAN_STA_AUTHORIZED ? "AUTHORIZED\n" : "",
-               staflags & WLAN_STA_SHORT_PREAMBLE ? "SHORT PREAMBLE\n" : "",
-               staflags & WLAN_STA_WME ? "WME\n" : "",
-               staflags & WLAN_STA_WDS ? "WDS\n" : "",
-               staflags & WLAN_STA_MFP ? "MFP\n" : "");
+
+#define TEST(flg) \
+       test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : ""
+
+       int res = scnprintf(buf, sizeof(buf),
+                           "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+                           TEST(AUTH), TEST(ASSOC), TEST(PS_STA),
+                           TEST(PS_DRIVER), TEST(AUTHORIZED),
+                           TEST(SHORT_PREAMBLE), TEST(ASSOC_AP),
+                           TEST(WME), TEST(WDS), TEST(CLEAR_PS_FILT),
+                           TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL),
+                           TEST(UAPSD), TEST(SP), TEST(TDLS_PEER),
+                           TEST(TDLS_PEER_AUTH));
+#undef TEST
        return simple_read_from_buffer(userbuf, count, ppos, buf, res);
 }
 STA_OPS(flags);
@@ -78,8 +81,14 @@ static ssize_t sta_num_ps_buf_frames_read(struct file *file,
                                          size_t count, loff_t *ppos)
 {
        struct sta_info *sta = file->private_data;
-       return mac80211_format_buffer(userbuf, count, ppos, "%u\n",
-                                     skb_queue_len(&sta->ps_tx_buf));
+       char buf[17*IEEE80211_NUM_ACS], *p = buf;
+       int ac;
+
+       for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
+               p += scnprintf(p, sizeof(buf)+buf-p, "AC%d: %d\n", ac,
+                              skb_queue_len(&sta->ps_tx_buf[ac]) +
+                              skb_queue_len(&sta->tx_filtered[ac]));
+       return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
 }
 STA_OPS(num_ps_buf_frames);
 
index 9001ff331f0a6efa6c6e1234a7975e4f255d775e..68721d379fe1adc1173268ae025891d99ef2546b 100644 (file)
@@ -413,50 +413,55 @@ static inline void drv_sta_remove(struct ieee80211_local *local,
        trace_drv_return_void(local);
 }
 
-static inline int drv_conf_tx(struct ieee80211_local *local, u16 queue,
+static inline int drv_conf_tx(struct ieee80211_local *local,
+                             struct ieee80211_sub_if_data *sdata, u16 queue,
                              const struct ieee80211_tx_queue_params *params)
 {
        int ret = -EOPNOTSUPP;
 
        might_sleep();
 
-       trace_drv_conf_tx(local, queue, params);
+       trace_drv_conf_tx(local, sdata, queue, params);
        if (local->ops->conf_tx)
                ret = local->ops->conf_tx(&local->hw, queue, params);
        trace_drv_return_int(local, ret);
        return ret;
 }
 
-static inline u64 drv_get_tsf(struct ieee80211_local *local)
+static inline u64 drv_get_tsf(struct ieee80211_local *local,
+                             struct ieee80211_sub_if_data *sdata)
 {
        u64 ret = -1ULL;
 
        might_sleep();
 
-       trace_drv_get_tsf(local);
+       trace_drv_get_tsf(local, sdata);
        if (local->ops->get_tsf)
-               ret = local->ops->get_tsf(&local->hw);
+               ret = local->ops->get_tsf(&local->hw, &sdata->vif);
        trace_drv_return_u64(local, ret);
        return ret;
 }
 
-static inline void drv_set_tsf(struct ieee80211_local *local, u64 tsf)
+static inline void drv_set_tsf(struct ieee80211_local *local,
+                              struct ieee80211_sub_if_data *sdata,
+                              u64 tsf)
 {
        might_sleep();
 
-       trace_drv_set_tsf(local, tsf);
+       trace_drv_set_tsf(local, sdata, tsf);
        if (local->ops->set_tsf)
-               local->ops->set_tsf(&local->hw, tsf);
+               local->ops->set_tsf(&local->hw, &sdata->vif, tsf);
        trace_drv_return_void(local);
 }
 
-static inline void drv_reset_tsf(struct ieee80211_local *local)
+static inline void drv_reset_tsf(struct ieee80211_local *local,
+                                struct ieee80211_sub_if_data *sdata)
 {
        might_sleep();
 
-       trace_drv_reset_tsf(local);
+       trace_drv_reset_tsf(local, sdata);
        if (local->ops->reset_tsf)
-               local->ops->reset_tsf(&local->hw);
+               local->ops->reset_tsf(&local->hw, &sdata->vif);
        trace_drv_return_void(local);
 }
 
@@ -665,4 +670,34 @@ static inline void drv_rssi_callback(struct ieee80211_local *local,
                local->ops->rssi_callback(&local->hw, event);
        trace_drv_return_void(local);
 }
+
+static inline void
+drv_release_buffered_frames(struct ieee80211_local *local,
+                           struct sta_info *sta, u16 tids, int num_frames,
+                           enum ieee80211_frame_release_type reason,
+                           bool more_data)
+{
+       trace_drv_release_buffered_frames(local, &sta->sta, tids, num_frames,
+                                         reason, more_data);
+       if (local->ops->release_buffered_frames)
+               local->ops->release_buffered_frames(&local->hw, &sta->sta, tids,
+                                                   num_frames, reason,
+                                                   more_data);
+       trace_drv_return_void(local);
+}
+
+static inline void
+drv_allow_buffered_frames(struct ieee80211_local *local,
+                         struct sta_info *sta, u16 tids, int num_frames,
+                         enum ieee80211_frame_release_type reason,
+                         bool more_data)
+{
+       trace_drv_allow_buffered_frames(local, &sta->sta, tids, num_frames,
+                                       reason, more_data);
+       if (local->ops->allow_buffered_frames)
+               local->ops->allow_buffered_frames(&local->hw, &sta->sta,
+                                                 tids, num_frames, reason,
+                                                 more_data);
+       trace_drv_return_void(local);
+}
 #endif /* __MAC80211_DRIVER_OPS */
index f47b00dc7afd839017a4a485b3ced5149dd9e6b9..2af4fca553371f3c4a6a7263ade75f9f6342002a 100644 (file)
@@ -697,64 +697,76 @@ TRACE_EVENT(drv_sta_remove,
 );
 
 TRACE_EVENT(drv_conf_tx,
-       TP_PROTO(struct ieee80211_local *local, u16 queue,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata,
+                u16 queue,
                 const struct ieee80211_tx_queue_params *params),
 
-       TP_ARGS(local, queue, params),
+       TP_ARGS(local, sdata, queue, params),
 
        TP_STRUCT__entry(
                LOCAL_ENTRY
+               VIF_ENTRY
                __field(u16, queue)
                __field(u16, txop)
                __field(u16, cw_min)
                __field(u16, cw_max)
                __field(u8, aifs)
+               __field(bool, uapsd)
        ),
 
        TP_fast_assign(
                LOCAL_ASSIGN;
+               VIF_ASSIGN;
                __entry->queue = queue;
                __entry->txop = params->txop;
                __entry->cw_max = params->cw_max;
                __entry->cw_min = params->cw_min;
                __entry->aifs = params->aifs;
+               __entry->uapsd = params->uapsd;
        ),
 
        TP_printk(
-               LOCAL_PR_FMT " queue:%d",
-               LOCAL_PR_ARG, __entry->queue
+               LOCAL_PR_FMT  VIF_PR_FMT  " queue:%d",
+               LOCAL_PR_ARG, VIF_PR_ARG, __entry->queue
        )
 );
 
-DEFINE_EVENT(local_only_evt, drv_get_tsf,
-       TP_PROTO(struct ieee80211_local *local),
-       TP_ARGS(local)
+DEFINE_EVENT(local_sdata_evt, drv_get_tsf,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata),
+       TP_ARGS(local, sdata)
 );
 
 TRACE_EVENT(drv_set_tsf,
-       TP_PROTO(struct ieee80211_local *local, u64 tsf),
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata,
+                u64 tsf),
 
-       TP_ARGS(local, tsf),
+       TP_ARGS(local, sdata, tsf),
 
        TP_STRUCT__entry(
                LOCAL_ENTRY
+               VIF_ENTRY
                __field(u64, tsf)
        ),
 
        TP_fast_assign(
                LOCAL_ASSIGN;
+               VIF_ASSIGN;
                __entry->tsf = tsf;
        ),
 
        TP_printk(
-               LOCAL_PR_FMT " tsf:%llu",
-               LOCAL_PR_ARG, (unsigned long long)__entry->tsf
+               LOCAL_PR_FMT  VIF_PR_FMT  " tsf:%llu",
+               LOCAL_PR_ARG, VIF_PR_ARG, (unsigned long long)__entry->tsf
        )
 );
 
-DEFINE_EVENT(local_only_evt, drv_reset_tsf,
-       TP_PROTO(struct ieee80211_local *local),
-       TP_ARGS(local)
+DEFINE_EVENT(local_sdata_evt, drv_reset_tsf,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata),
+       TP_ARGS(local, sdata)
 );
 
 DEFINE_EVENT(local_only_evt, drv_tx_last_beacon,
@@ -1117,6 +1129,61 @@ TRACE_EVENT(drv_rssi_callback,
        )
 );
 
+DECLARE_EVENT_CLASS(release_evt,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sta *sta,
+                u16 tids, int num_frames,
+                enum ieee80211_frame_release_type reason,
+                bool more_data),
+
+       TP_ARGS(local, sta, tids, num_frames, reason, more_data),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               STA_ENTRY
+               __field(u16, tids)
+               __field(int, num_frames)
+               __field(int, reason)
+               __field(bool, more_data)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               STA_ASSIGN;
+               __entry->tids = tids;
+               __entry->num_frames = num_frames;
+               __entry->reason = reason;
+               __entry->more_data = more_data;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT STA_PR_FMT
+               " TIDs:0x%.4x frames:%d reason:%d more:%d",
+               LOCAL_PR_ARG, STA_PR_ARG, __entry->tids, __entry->num_frames,
+               __entry->reason, __entry->more_data
+       )
+);
+
+DEFINE_EVENT(release_evt, drv_release_buffered_frames,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sta *sta,
+                u16 tids, int num_frames,
+                enum ieee80211_frame_release_type reason,
+                bool more_data),
+
+       TP_ARGS(local, sta, tids, num_frames, reason, more_data)
+);
+
+DEFINE_EVENT(release_evt, drv_allow_buffered_frames,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sta *sta,
+                u16 tids, int num_frames,
+                enum ieee80211_frame_release_type reason,
+                bool more_data),
+
+       TP_ARGS(local, sta, tids, num_frames, reason, more_data)
+);
+
 /*
  * Tracing for API calls that drivers call.
  */
@@ -1431,6 +1498,28 @@ TRACE_EVENT(api_enable_rssi_reports,
        )
 );
 
+TRACE_EVENT(api_eosp,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sta *sta),
+
+       TP_ARGS(local, sta),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               STA_ENTRY
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               STA_ASSIGN;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT STA_PR_FMT,
+               LOCAL_PR_ARG, STA_PR_FMT
+       )
+);
+
 /*
  * Tracing for internal functions
  * (which may also be called in response to driver calls)
index 2b9b52c69569b29c53756f7eb33fa7cbfb4f8b85..f80a35c0d00020fec66f47839111f418401b4758 100644 (file)
@@ -130,7 +130,7 @@ void ieee80211_ba_session_work(struct work_struct *work)
         * down by the code that set the flag, so this
         * need not run.
         */
-       if (test_sta_flags(sta, WLAN_STA_BLOCK_BA))
+       if (test_sta_flag(sta, WLAN_STA_BLOCK_BA))
                return;
 
        mutex_lock(&sta->ampdu_mlme.mtx);
index 836b2752ecd6f694523263c0cc5ae0475c26af87..2da3040787a7c10d8bf26dc4d217940aa8dc1c1e 100644 (file)
@@ -81,7 +81,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
        lockdep_assert_held(&ifibss->mtx);
 
        /* Reset own TSF to allow time synchronization work. */
-       drv_reset_tsf(local);
+       drv_reset_tsf(local, sdata);
 
        skb = ifibss->skb;
        rcu_assign_pointer(ifibss->presp, NULL);
@@ -314,7 +314,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
                }
 
                if (sta && elems->wmm_info)
-                       set_sta_flags(sta, WLAN_STA_WME);
+                       set_sta_flag(sta, WLAN_STA_WME);
 
                rcu_read_unlock();
        }
@@ -382,7 +382,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
                 * second best option: get current TSF
                 * (will return -1 if not supported)
                 */
-               rx_timestamp = drv_get_tsf(local);
+               rx_timestamp = drv_get_tsf(local, sdata);
        }
 
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
@@ -452,7 +452,7 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
                return NULL;
 
        sta->last_rx = jiffies;
-       set_sta_flags(sta, WLAN_STA_AUTHORIZED);
+       set_sta_flag(sta, WLAN_STA_AUTHORIZED);
 
        /* make sure mandatory rates are always added */
        sta->sta.supp_rates[band] = supp_rates |
index 21186e280ceb11e50f47446f83e203e387ba4dd5..9fa5f8a674bc00ec1b40fe4e58942ef6386912d5 100644 (file)
@@ -609,6 +609,8 @@ struct ieee80211_sub_if_data {
        __be16 control_port_protocol;
        bool control_port_no_encrypt;
 
+       struct ieee80211_tx_queue_params tx_conf[IEEE80211_MAX_QUEUES];
+
        struct work_struct work;
        struct sk_buff_head skb_queue;
 
@@ -662,6 +664,11 @@ enum sdata_queue_type {
 enum {
        IEEE80211_RX_MSG        = 1,
        IEEE80211_TX_STATUS_MSG = 2,
+       IEEE80211_EOSP_MSG      = 3,
+};
+
+struct skb_eosp_msg_data {
+       u8 sta[ETH_ALEN], iface[ETH_ALEN];
 };
 
 enum queue_stop_reason {
@@ -751,7 +758,6 @@ struct ieee80211_local {
        struct workqueue_struct *workqueue;
 
        unsigned long queue_stop_reasons[IEEE80211_MAX_QUEUES];
-       struct ieee80211_tx_queue_params tx_conf[IEEE80211_MAX_QUEUES];
        /* also used to protect ampdu_ac_queue and amdpu_ac_stop_refcnt */
        spinlock_t queue_stop_reason_lock;
 
@@ -1271,6 +1277,7 @@ void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int ke
                                     struct ieee80211_hdr *hdr, const u8 *tsc,
                                     gfp_t gfp);
 void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata);
+void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb);
 void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb);
 void ieee802_11_parse_elems(u8 *start, size_t len,
                            struct ieee802_11_elems *elems);
@@ -1302,11 +1309,11 @@ void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue,
                                    enum queue_stop_reason reason);
 void ieee80211_add_pending_skb(struct ieee80211_local *local,
                               struct sk_buff *skb);
-int ieee80211_add_pending_skbs(struct ieee80211_local *local,
-                              struct sk_buff_head *skbs);
-int ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
-                                 struct sk_buff_head *skbs,
-                                 void (*fn)(void *data), void *data);
+void ieee80211_add_pending_skbs(struct ieee80211_local *local,
+                               struct sk_buff_head *skbs);
+void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
+                                  struct sk_buff_head *skbs,
+                                  void (*fn)(void *data), void *data);
 
 void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
                         u16 transaction, u16 auth_alg,
@@ -1324,7 +1331,7 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
 void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
                              const u8 *ssid, size_t ssid_len,
                              const u8 *ie, size_t ie_len,
-                             u32 ratemask, bool directed);
+                             u32 ratemask, bool directed, bool no_cck);
 
 void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
                                  const size_t supp_rates_len,
index 4116a7542b6b51af584dad4c6a22e264caa6fa18..ef741e8dbedb4b6fc4a9c63ff85d3f088ed1294e 100644 (file)
@@ -299,8 +299,8 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
                        goto err_del_interface;
                }
 
-               /* no locking required since STA is not live yet */
-               sta->flags |= WLAN_STA_AUTHORIZED;
+               /* no atomic bitop required since STA is not live yet */
+               set_sta_flag(sta, WLAN_STA_AUTHORIZED);
 
                res = sta_info_insert(sta);
                if (res) {
index 5150c6d11b57bc728eae5bedfa0897d7c3343ec5..756b157c2edd7a147c9390ec773d173f074117d5 100644 (file)
@@ -464,7 +464,7 @@ int ieee80211_key_link(struct ieee80211_key *key,
                 * some hardware cannot handle TKIP with QoS, so
                 * we indicate whether QoS could be in use.
                 */
-               if (test_sta_flags(sta, WLAN_STA_WME))
+               if (test_sta_flag(sta, WLAN_STA_WME))
                        key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA;
        } else {
                if (sdata->vif.type == NL80211_IFTYPE_STATION) {
@@ -478,7 +478,7 @@ int ieee80211_key_link(struct ieee80211_key *key,
                        /* same here, the AP could be using QoS */
                        ap = sta_info_get(key->sdata, key->sdata->u.mgd.bssid);
                        if (ap) {
-                               if (test_sta_flags(ap, WLAN_STA_WME))
+                               if (test_sta_flag(ap, WLAN_STA_WME))
                                        key->conf.flags |=
                                                IEEE80211_KEY_FLAG_WMM_STA;
                        }
index a5809a1a623988791a1d4d831dff35d16e44d532..17b038aeac9b7c5113082761b3114673d4b202e8 100644 (file)
@@ -325,6 +325,8 @@ u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata)
 static void ieee80211_tasklet_handler(unsigned long data)
 {
        struct ieee80211_local *local = (struct ieee80211_local *) data;
+       struct sta_info *sta, *tmp;
+       struct skb_eosp_msg_data *eosp_data;
        struct sk_buff *skb;
 
        while ((skb = skb_dequeue(&local->skb_queue)) ||
@@ -340,6 +342,18 @@ static void ieee80211_tasklet_handler(unsigned long data)
                        skb->pkt_type = 0;
                        ieee80211_tx_status(local_to_hw(local), skb);
                        break;
+               case IEEE80211_EOSP_MSG:
+                       eosp_data = (void *)skb->cb;
+                       for_each_sta_info(local, eosp_data->sta, sta, tmp) {
+                               /* skip wrong virtual interface */
+                               if (memcmp(eosp_data->iface,
+                                          sta->sdata->vif.addr, ETH_ALEN))
+                                       continue;
+                               clear_sta_flag(sta, WLAN_STA_SP);
+                               break;
+                       }
+                       dev_kfree_skb(skb);
+                       break;
                default:
                        WARN(1, "mac80211: Packet is of unknown type %d\n",
                             skb->pkt_type);
@@ -863,6 +877,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        if (local->ops->sched_scan_start)
                local->hw.wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
 
+       /* mac80211 based drivers don't support internal TDLS setup */
+       if (local->hw.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)
+               local->hw.wiphy->flags |= WIPHY_FLAG_TDLS_EXTERNAL_SETUP;
+
        result = wiphy_register(local->hw.wiphy);
        if (result < 0)
                goto fail_wiphy_register;
index a4225ae69681dbac88d9e664f747526f55c5fb70..a7078fdba8ca7e3cf2a1f047f1f39c57c643f63e 100644 (file)
@@ -320,64 +320,6 @@ mesh_add_rsn_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
        return 0;
 }
 
-int
-mesh_add_srates_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
-{
-       struct ieee80211_local *local = sdata->local;
-       struct ieee80211_supported_band *sband;
-       int rate;
-       u8 i, rates, *pos;
-
-       sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
-       rates = sband->n_bitrates;
-       if (rates > 8)
-               rates = 8;
-
-       if (skb_tailroom(skb) < rates + 2)
-               return -ENOMEM;
-
-       pos = skb_put(skb, rates + 2);
-       *pos++ = WLAN_EID_SUPP_RATES;
-       *pos++ = rates;
-       for (i = 0; i < rates; i++) {
-               rate = sband->bitrates[i].bitrate;
-               *pos++ = (u8) (rate / 5);
-       }
-
-       return 0;
-}
-
-int
-mesh_add_ext_srates_ie(struct sk_buff *skb,
-                      struct ieee80211_sub_if_data *sdata)
-{
-       struct ieee80211_local *local = sdata->local;
-       struct ieee80211_supported_band *sband;
-       int rate;
-       u8 i, exrates, *pos;
-
-       sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
-       exrates = sband->n_bitrates;
-       if (exrates > 8)
-               exrates -= 8;
-       else
-               exrates = 0;
-
-       if (skb_tailroom(skb) < exrates + 2)
-               return -ENOMEM;
-
-       if (exrates) {
-               pos = skb_put(skb, exrates + 2);
-               *pos++ = WLAN_EID_EXT_SUPP_RATES;
-               *pos++ = exrates;
-               for (i = 8; i < sband->n_bitrates; i++) {
-                       rate = sband->bitrates[i].bitrate;
-                       *pos++ = (u8) (rate / 5);
-               }
-       }
-       return 0;
-}
-
 int mesh_add_ds_params_ie(struct sk_buff *skb,
                          struct ieee80211_sub_if_data *sdata)
 {
index 7118e8e8855ce5bbff0b0b98e3a573b3bf3bb3aa..8c00e2d1d63612f3dfd483960805021f79acb204 100644 (file)
@@ -210,10 +210,6 @@ int mesh_add_rsn_ie(struct sk_buff *skb,
                    struct ieee80211_sub_if_data *sdata);
 int mesh_add_vendor_ies(struct sk_buff *skb,
                        struct ieee80211_sub_if_data *sdata);
-int mesh_add_srates_ie(struct sk_buff *skb,
-                      struct ieee80211_sub_if_data *sdata);
-int mesh_add_ext_srates_ie(struct sk_buff *skb,
-                          struct ieee80211_sub_if_data *sdata);
 int mesh_add_ds_params_ie(struct sk_buff *skb,
                          struct ieee80211_sub_if_data *sdata);
 void mesh_rmc_free(struct ieee80211_sub_if_data *sdata);
index 1213a23ff0fa7e28cfb547bbbcb29855891974f2..7e57f5d07f660ad7b19c432f95518952382832b9 100644 (file)
@@ -92,7 +92,9 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
        if (!sta)
                return NULL;
 
-       sta->flags = WLAN_STA_AUTHORIZED | WLAN_STA_AUTH | WLAN_STA_WME;
+       set_sta_flag(sta, WLAN_STA_AUTH);
+       set_sta_flag(sta, WLAN_STA_AUTHORIZED);
+       set_sta_flag(sta, WLAN_STA_WME);
        sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
        rate_control_rate_init(sta);
 
@@ -185,8 +187,8 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
                        pos = skb_put(skb, 2);
                        memcpy(pos + 2, &plid, 2);
                }
-               if (mesh_add_srates_ie(skb, sdata) ||
-                   mesh_add_ext_srates_ie(skb, sdata) ||
+               if (ieee80211_add_srates_ie(&sdata->vif, skb) ||
+                   ieee80211_add_ext_srates_ie(&sdata->vif, skb) ||
                    mesh_add_rsn_ie(skb, sdata) ||
                    mesh_add_meshid_ie(skb, sdata) ||
                    mesh_add_meshconf_ie(skb, sdata))
@@ -383,7 +385,7 @@ int mesh_plink_open(struct sta_info *sta)
        __le16 llid;
        struct ieee80211_sub_if_data *sdata = sta->sdata;
 
-       if (!test_sta_flags(sta, WLAN_STA_AUTH))
+       if (!test_sta_flag(sta, WLAN_STA_AUTH))
                return -EPERM;
 
        spin_lock_bh(&sta->lock);
@@ -503,7 +505,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
                return;
        }
 
-       if (sta && !test_sta_flags(sta, WLAN_STA_AUTH)) {
+       if (sta && !test_sta_flag(sta, WLAN_STA_AUTH)) {
                mpl_dbg("Mesh plink: Action frame from non-authed peer\n");
                rcu_read_unlock();
                return;
index 1a59fb6630d4f063a1e1098a752ca1f4c9a9aff1..c4e8901c96f6476e39bc6a6a91cb500b51a853e6 100644 (file)
@@ -627,7 +627,7 @@ static bool ieee80211_powersave_allowed(struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_if_managed *mgd = &sdata->u.mgd;
        struct sta_info *sta = NULL;
-       u32 sta_flags = 0;
+       bool authorized = false;
 
        if (!mgd->powersave)
                return false;
@@ -645,13 +645,10 @@ static bool ieee80211_powersave_allowed(struct ieee80211_sub_if_data *sdata)
        rcu_read_lock();
        sta = sta_info_get(sdata, mgd->bssid);
        if (sta)
-               sta_flags = get_sta_flags(sta);
+               authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
        rcu_read_unlock();
 
-       if (!(sta_flags & WLAN_STA_AUTHORIZED))
-               return false;
-
-       return true;
+       return authorized;
 }
 
 /* need to hold RTNL or interface lock */
@@ -936,8 +933,8 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
                            params.aifs, params.cw_min, params.cw_max,
                            params.txop, params.uapsd);
 #endif
-               local->tx_conf[queue] = params;
-               if (drv_conf_tx(local, queue, &params))
+               sdata->tx_conf[queue] = params;
+               if (drv_conf_tx(local, sdata, queue, &params))
                        wiphy_debug(local->hw.wiphy,
                                    "failed to set TX queue parameters for queue %d\n",
                                    queue);
@@ -1095,7 +1092,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
        mutex_lock(&local->sta_mtx);
        sta = sta_info_get(sdata, bssid);
        if (sta) {
-               set_sta_flags(sta, WLAN_STA_BLOCK_BA);
+               set_sta_flag(sta, WLAN_STA_BLOCK_BA);
                ieee80211_sta_tear_down_BA_sessions(sta, tx);
        }
        mutex_unlock(&local->sta_mtx);
@@ -1137,8 +1134,9 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
        changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT;
        ieee80211_bss_info_change_notify(sdata, changed);
 
+       /* remove AP and TDLS peers */
        if (remove_sta)
-               sta_info_destroy_addr(sdata, bssid);
+               sta_info_flush(local, sdata);
 
        del_timer_sync(&sdata->u.mgd.conn_mon_timer);
        del_timer_sync(&sdata->u.mgd.bcn_mon_timer);
@@ -1239,7 +1237,7 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata)
        } else {
                ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID);
                ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid[1], NULL, 0,
-                                        (u32) -1, true);
+                                        (u32) -1, true, false);
        }
 
        ifmgd->probe_send_count++;
@@ -1512,10 +1510,11 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk,
                return false;
        }
 
-       set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC |
-                          WLAN_STA_ASSOC_AP);
+       set_sta_flag(sta, WLAN_STA_AUTH);
+       set_sta_flag(sta, WLAN_STA_ASSOC);
+       set_sta_flag(sta, WLAN_STA_ASSOC_AP);
        if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT))
-               set_sta_flags(sta, WLAN_STA_AUTHORIZED);
+               set_sta_flag(sta, WLAN_STA_AUTHORIZED);
 
        rates = 0;
        basic_rates = 0;
@@ -1574,10 +1573,10 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk,
        rate_control_rate_init(sta);
 
        if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED)
-               set_sta_flags(sta, WLAN_STA_MFP);
+               set_sta_flag(sta, WLAN_STA_MFP);
 
        if (elems.wmm_param)
-               set_sta_flags(sta, WLAN_STA_WME);
+               set_sta_flag(sta, WLAN_STA_WME);
 
        /* sta_info_reinsert will also unlock the mutex lock */
        err = sta_info_reinsert(sta);
@@ -2738,7 +2737,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
                                       req->reason_code, cookie,
                                       !req->local_state_change);
        if (assoc_bss)
-               sta_info_destroy_addr(sdata, bssid);
+               sta_info_flush(sdata->local, sdata);
 
        mutex_lock(&sdata->local->mtx);
        ieee80211_recalc_idle(sdata->local);
@@ -2778,7 +2777,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
        ieee80211_send_deauth_disassoc(sdata, req->bss->bssid,
                        IEEE80211_STYPE_DISASSOC, req->reason_code,
                        cookie, !req->local_state_change);
-       sta_info_destroy_addr(sdata, bssid);
+       sta_info_flush(sdata->local, sdata);
 
        mutex_lock(&sdata->local->mtx);
        ieee80211_recalc_idle(sdata->local);
index 6326d3439861e7448dec7a2f1cb08dee8d10988e..9ee7164b207c23017eba9b9fc064eb1ab0248537 100644 (file)
@@ -42,7 +42,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
        if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
                mutex_lock(&local->sta_mtx);
                list_for_each_entry(sta, &local->sta_list, list) {
-                       set_sta_flags(sta, WLAN_STA_BLOCK_BA);
+                       set_sta_flag(sta, WLAN_STA_BLOCK_BA);
                        ieee80211_sta_tear_down_BA_sessions(sta, true);
                }
                mutex_unlock(&local->sta_mtx);
index 3d5a2cb835c4203bb8cc4e768df7f7705594ee21..f61244c0e0a267422109227e3aab63e4be1eba63 100644 (file)
@@ -233,6 +233,27 @@ static void rc_send_low_broadcast(s8 *idx, u32 basic_rates,
        /* could not find a basic rate; use original selection */
 }
 
+static inline s8
+rate_lowest_non_cck_index(struct ieee80211_supported_band *sband,
+                         struct ieee80211_sta *sta)
+{
+       int i;
+
+       for (i = 0; i < sband->n_bitrates; i++) {
+               struct ieee80211_rate *srate = &sband->bitrates[i];
+               if ((srate->bitrate == 10) || (srate->bitrate == 20) ||
+                   (srate->bitrate == 55) || (srate->bitrate == 110))
+                       continue;
+
+               if (rate_supported(sta, sband->band, i))
+                       return i;
+       }
+
+       /* No matching rate found */
+       return 0;
+}
+
+
 bool rate_control_send_low(struct ieee80211_sta *sta,
                           void *priv_sta,
                           struct ieee80211_tx_rate_control *txrc)
@@ -242,7 +263,13 @@ bool rate_control_send_low(struct ieee80211_sta *sta,
        int mcast_rate;
 
        if (!sta || !priv_sta || rc_no_data_or_no_ack(txrc)) {
-               info->control.rates[0].idx = rate_lowest_index(txrc->sband, sta);
+               if ((sband->band != IEEE80211_BAND_2GHZ) ||
+                   !(info->flags & IEEE80211_TX_CTL_NO_CCK_RATE))
+                       info->control.rates[0].idx =
+                               rate_lowest_index(txrc->sband, sta);
+               else
+                       info->control.rates[0].idx =
+                               rate_lowest_non_cck_index(txrc->sband, sta);
                info->control.rates[0].count =
                        (info->flags & IEEE80211_TX_CTL_NO_ACK) ?
                        1 : txrc->hw->max_rate_tries;
index e19249b0f97124697a5d8c64c9c5e70ab397f0a1..cdb28535716b14d907d6423578c10db604d9c43f 100644 (file)
@@ -281,6 +281,8 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
 
                mr = minstrel_get_ratestats(mi, mg->max_tp_rate);
                if (cur_tp < mr->cur_tp) {
+                       mi->max_tp_rate2 = mi->max_tp_rate;
+                       cur_tp2 = cur_tp;
                        mi->max_tp_rate = mg->max_tp_rate;
                        cur_tp = mr->cur_tp;
                }
index db46601e50bfaa4b88b82fa475ed6351beb9014d..b867bd55de7aab4c9e622eaeff88da9c93671417 100644 (file)
@@ -841,7 +841,7 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
                      ieee80211_is_pspoll(hdr->frame_control)) &&
                     rx->sdata->vif.type != NL80211_IFTYPE_ADHOC &&
                     rx->sdata->vif.type != NL80211_IFTYPE_WDS &&
-                    (!rx->sta || !test_sta_flags(rx->sta, WLAN_STA_ASSOC)))) {
+                    (!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_ASSOC)))) {
                if (rx->sta && rx->sta->dummy &&
                    ieee80211_is_data_present(hdr->frame_control)) {
                        u16 ethertype;
@@ -1110,7 +1110,7 @@ static void ap_sta_ps_start(struct sta_info *sta)
        struct ieee80211_local *local = sdata->local;
 
        atomic_inc(&sdata->bss->num_sta_ps);
-       set_sta_flags(sta, WLAN_STA_PS_STA);
+       set_sta_flag(sta, WLAN_STA_PS_STA);
        if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS))
                drv_sta_notify(local, sdata, STA_NOTIFY_SLEEP, &sta->sta);
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
@@ -1130,7 +1130,7 @@ static void ap_sta_ps_end(struct sta_info *sta)
               sdata->name, sta->sta.addr, sta->sta.aid);
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 
-       if (test_sta_flags(sta, WLAN_STA_PS_DRIVER)) {
+       if (test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
                printk(KERN_DEBUG "%s: STA %pM aid %d driver-ps-blocked\n",
                       sdata->name, sta->sta.addr, sta->sta.aid);
@@ -1149,7 +1149,7 @@ int ieee80211_sta_ps_transition(struct ieee80211_sta *sta, bool start)
        WARN_ON(!(sta_inf->local->hw.flags & IEEE80211_HW_AP_LINK_PS));
 
        /* Don't let the same PS state be set twice */
-       in_ps = test_sta_flags(sta_inf, WLAN_STA_PS_STA);
+       in_ps = test_sta_flag(sta_inf, WLAN_STA_PS_STA);
        if ((start && in_ps) || (!start && !in_ps))
                return -EINVAL;
 
@@ -1162,6 +1162,81 @@ int ieee80211_sta_ps_transition(struct ieee80211_sta *sta, bool start)
 }
 EXPORT_SYMBOL(ieee80211_sta_ps_transition);
 
+static ieee80211_rx_result debug_noinline
+ieee80211_rx_h_uapsd_and_pspoll(struct ieee80211_rx_data *rx)
+{
+       struct ieee80211_sub_if_data *sdata = rx->sdata;
+       struct ieee80211_hdr *hdr = (void *)rx->skb->data;
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
+       int tid, ac;
+
+       if (!rx->sta || !(status->rx_flags & IEEE80211_RX_RA_MATCH))
+               return RX_CONTINUE;
+
+       if (sdata->vif.type != NL80211_IFTYPE_AP &&
+           sdata->vif.type != NL80211_IFTYPE_AP_VLAN)
+               return RX_CONTINUE;
+
+       /*
+        * The device handles station powersave, so don't do anything about
+        * uAPSD and PS-Poll frames (the latter shouldn't even come up from
+        * it to mac80211 since they're handled.)
+        */
+       if (sdata->local->hw.flags & IEEE80211_HW_AP_LINK_PS)
+               return RX_CONTINUE;
+
+       /*
+        * Don't do anything if the station isn't already asleep. In
+        * the uAPSD case, the station will probably be marked asleep,
+        * in the PS-Poll case the station must be confused ...
+        */
+       if (!test_sta_flag(rx->sta, WLAN_STA_PS_STA))
+               return RX_CONTINUE;
+
+       if (unlikely(ieee80211_is_pspoll(hdr->frame_control))) {
+               if (!test_sta_flag(rx->sta, WLAN_STA_SP)) {
+                       if (!test_sta_flag(rx->sta, WLAN_STA_PS_DRIVER))
+                               ieee80211_sta_ps_deliver_poll_response(rx->sta);
+                       else
+                               set_sta_flag(rx->sta, WLAN_STA_PSPOLL);
+               }
+
+               /* Free PS Poll skb here instead of returning RX_DROP that would
+                * count as an dropped frame. */
+               dev_kfree_skb(rx->skb);
+
+               return RX_QUEUED;
+       } else if (!ieee80211_has_morefrags(hdr->frame_control) &&
+                  !(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) &&
+                  ieee80211_has_pm(hdr->frame_control) &&
+                  (ieee80211_is_data_qos(hdr->frame_control) ||
+                   ieee80211_is_qos_nullfunc(hdr->frame_control))) {
+               tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
+               ac = ieee802_1d_to_ac[tid & 7];
+
+               /*
+                * If this AC is not trigger-enabled do nothing.
+                *
+                * NB: This could/should check a separate bitmap of trigger-
+                * enabled queues, but for now we only implement uAPSD w/o
+                * TSPEC changes to the ACs, so they're always the same.
+                */
+               if (!(rx->sta->sta.uapsd_queues & BIT(ac)))
+                       return RX_CONTINUE;
+
+               /* if we are in a service period, do nothing */
+               if (test_sta_flag(rx->sta, WLAN_STA_SP))
+                       return RX_CONTINUE;
+
+               if (!test_sta_flag(rx->sta, WLAN_STA_PS_DRIVER))
+                       ieee80211_sta_ps_deliver_uapsd(rx->sta);
+               else
+                       set_sta_flag(rx->sta, WLAN_STA_UAPSD);
+       }
+
+       return RX_CONTINUE;
+}
+
 static ieee80211_rx_result debug_noinline
 ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
 {
@@ -1220,7 +1295,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
            !(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) &&
            (rx->sdata->vif.type == NL80211_IFTYPE_AP ||
             rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) {
-               if (test_sta_flags(sta, WLAN_STA_PS_STA)) {
+               if (test_sta_flag(sta, WLAN_STA_PS_STA)) {
                        /*
                         * Ignore doze->wake transitions that are
                         * indicated by non-data frames, the standard
@@ -1472,33 +1547,6 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
        return RX_CONTINUE;
 }
 
-static ieee80211_rx_result debug_noinline
-ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx)
-{
-       struct ieee80211_sub_if_data *sdata = rx->sdata;
-       __le16 fc = ((struct ieee80211_hdr *)rx->skb->data)->frame_control;
-       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
-
-       if (likely(!rx->sta || !ieee80211_is_pspoll(fc) ||
-                  !(status->rx_flags & IEEE80211_RX_RA_MATCH)))
-               return RX_CONTINUE;
-
-       if ((sdata->vif.type != NL80211_IFTYPE_AP) &&
-           (sdata->vif.type != NL80211_IFTYPE_AP_VLAN))
-               return RX_DROP_UNUSABLE;
-
-       if (!test_sta_flags(rx->sta, WLAN_STA_PS_DRIVER))
-               ieee80211_sta_ps_deliver_poll_response(rx->sta);
-       else
-               set_sta_flags(rx->sta, WLAN_STA_PSPOLL);
-
-       /* Free PS Poll skb here instead of returning RX_DROP that would
-        * count as an dropped frame. */
-       dev_kfree_skb(rx->skb);
-
-       return RX_QUEUED;
-}
-
 static ieee80211_rx_result debug_noinline
 ieee80211_rx_h_remove_qos_control(struct ieee80211_rx_data *rx)
 {
@@ -1522,7 +1570,7 @@ static int
 ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx)
 {
        if (unlikely(!rx->sta ||
-           !test_sta_flags(rx->sta, WLAN_STA_AUTHORIZED)))
+           !test_sta_flag(rx->sta, WLAN_STA_AUTHORIZED)))
                return -EACCES;
 
        return 0;
@@ -1565,7 +1613,7 @@ ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx)
        if (status->flag & RX_FLAG_DECRYPTED)
                return 0;
 
-       if (rx->sta && test_sta_flags(rx->sta, WLAN_STA_MFP)) {
+       if (rx->sta && test_sta_flag(rx->sta, WLAN_STA_MFP)) {
                if (unlikely(!ieee80211_has_protected(fc) &&
                             ieee80211_is_unicast_robust_mgmt_frame(rx->skb) &&
                             rx->key)) {
@@ -2567,9 +2615,9 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx)
 
                CALL_RXH(ieee80211_rx_h_decrypt)
                CALL_RXH(ieee80211_rx_h_check_more_data)
+               CALL_RXH(ieee80211_rx_h_uapsd_and_pspoll)
                CALL_RXH(ieee80211_rx_h_sta_process)
                CALL_RXH(ieee80211_rx_h_defragment)
-               CALL_RXH(ieee80211_rx_h_ps_poll)
                CALL_RXH(ieee80211_rx_h_michael_mic_verify)
                /* must be after MMIC verify so header is counted in MPDU mic */
 #ifdef CONFIG_MAC80211_MESH
index 6f09eca011123de5dac20d3fed5f6712200fd112..830e60f65779670ab8539256d3db3f1814c25a4e 100644 (file)
@@ -660,7 +660,8 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local,
                        local->scan_req->ssids[i].ssid,
                        local->scan_req->ssids[i].ssid_len,
                        local->scan_req->ie, local->scan_req->ie_len,
-                       local->scan_req->rates[band], false);
+                       local->scan_req->rates[band], false,
+                       local->scan_req->no_cck);
 
        /*
         * After sending probe requests, wait for probe responses
index c52e58c0a979a757574334f53061d2e610246fba..076593bffbcfa15778b637bbc0f833099785ad0d 100644 (file)
@@ -24,6 +24,7 @@
 #include "sta_info.h"
 #include "debugfs_sta.h"
 #include "mesh.h"
+#include "wme.h"
 
 /**
  * DOC: STA information lifetime rules
@@ -243,13 +244,22 @@ static void sta_unblock(struct work_struct *wk)
        if (sta->dead)
                return;
 
-       if (!test_sta_flags(sta, WLAN_STA_PS_STA))
+       if (!test_sta_flag(sta, WLAN_STA_PS_STA))
                ieee80211_sta_ps_deliver_wakeup(sta);
-       else if (test_and_clear_sta_flags(sta, WLAN_STA_PSPOLL)) {
-               clear_sta_flags(sta, WLAN_STA_PS_DRIVER);
+       else if (test_and_clear_sta_flag(sta, WLAN_STA_PSPOLL)) {
+               clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
+
+               local_bh_disable();
                ieee80211_sta_ps_deliver_poll_response(sta);
+               local_bh_enable();
+       } else if (test_and_clear_sta_flag(sta, WLAN_STA_UAPSD)) {
+               clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
+
+               local_bh_disable();
+               ieee80211_sta_ps_deliver_uapsd(sta);
+               local_bh_enable();
        } else
-               clear_sta_flags(sta, WLAN_STA_PS_DRIVER);
+               clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
 }
 
 static int sta_prepare_rate_control(struct ieee80211_local *local,
@@ -282,7 +292,6 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
                return NULL;
 
        spin_lock_init(&sta->lock);
-       spin_lock_init(&sta->flaglock);
        INIT_WORK(&sta->drv_unblock_wk, sta_unblock);
        INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work);
        mutex_init(&sta->ampdu_mlme.mtx);
@@ -309,8 +318,10 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
                 */
                sta->timer_to_tid[i] = i;
        }
-       skb_queue_head_init(&sta->ps_tx_buf);
-       skb_queue_head_init(&sta->tx_filtered);
+       for (i = 0; i < IEEE80211_NUM_ACS; i++) {
+               skb_queue_head_init(&sta->ps_tx_buf[i]);
+               skb_queue_head_init(&sta->tx_filtered[i]);
+       }
 
        for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
                sta->last_seq_ctrl[i] = cpu_to_le16(USHRT_MAX);
@@ -641,54 +652,84 @@ static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, u16 aid)
        bss->tim[aid / 8] &= ~(1 << (aid % 8));
 }
 
-static void __sta_info_set_tim_bit(struct ieee80211_if_ap *bss,
-                                  struct sta_info *sta)
+static unsigned long ieee80211_tids_for_ac(int ac)
 {
-       BUG_ON(!bss);
-
-       __bss_tim_set(bss, sta->sta.aid);
-
-       if (sta->local->ops->set_tim) {
-               sta->local->tim_in_locked_section = true;
-               drv_set_tim(sta->local, &sta->sta, true);
-               sta->local->tim_in_locked_section = false;
+       /* If we ever support TIDs > 7, this obviously needs to be adjusted */
+       switch (ac) {
+       case IEEE80211_AC_VO:
+               return BIT(6) | BIT(7);
+       case IEEE80211_AC_VI:
+               return BIT(4) | BIT(5);
+       case IEEE80211_AC_BE:
+               return BIT(0) | BIT(3);
+       case IEEE80211_AC_BK:
+               return BIT(1) | BIT(2);
+       default:
+               WARN_ON(1);
+               return 0;
        }
 }
 
-void sta_info_set_tim_bit(struct sta_info *sta)
+void sta_info_recalc_tim(struct sta_info *sta)
 {
+       struct ieee80211_local *local = sta->local;
+       struct ieee80211_if_ap *bss = sta->sdata->bss;
        unsigned long flags;
+       bool indicate_tim = false;
+       u8 ignore_for_tim = sta->sta.uapsd_queues;
+       int ac;
 
-       BUG_ON(!sta->sdata->bss);
+       if (WARN_ON_ONCE(!sta->sdata->bss))
+               return;
 
-       spin_lock_irqsave(&sta->local->sta_lock, flags);
-       __sta_info_set_tim_bit(sta->sdata->bss, sta);
-       spin_unlock_irqrestore(&sta->local->sta_lock, flags);
-}
+       /* No need to do anything if the driver does all */
+       if (local->hw.flags & IEEE80211_HW_AP_LINK_PS)
+               return;
 
-static void __sta_info_clear_tim_bit(struct ieee80211_if_ap *bss,
-                                    struct sta_info *sta)
-{
-       BUG_ON(!bss);
+       if (sta->dead)
+               goto done;
+
+       /*
+        * If all ACs are delivery-enabled then we should build
+        * the TIM bit for all ACs anyway; if only some are then
+        * we ignore those and build the TIM bit using only the
+        * non-enabled ones.
+        */
+       if (ignore_for_tim == BIT(IEEE80211_NUM_ACS) - 1)
+               ignore_for_tim = 0;
+
+       for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+               unsigned long tids;
 
-       __bss_tim_clear(bss, sta->sta.aid);
+               if (ignore_for_tim & BIT(ac))
+                       continue;
+
+               indicate_tim |= !skb_queue_empty(&sta->tx_filtered[ac]) ||
+                               !skb_queue_empty(&sta->ps_tx_buf[ac]);
+               if (indicate_tim)
+                       break;
 
-       if (sta->local->ops->set_tim) {
-               sta->local->tim_in_locked_section = true;
-               drv_set_tim(sta->local, &sta->sta, false);
-               sta->local->tim_in_locked_section = false;
+               tids = ieee80211_tids_for_ac(ac);
+
+               indicate_tim |=
+                       sta->driver_buffered_tids & tids;
        }
-}
 
-void sta_info_clear_tim_bit(struct sta_info *sta)
-{
-       unsigned long flags;
+ done:
+       spin_lock_irqsave(&local->sta_lock, flags);
 
-       BUG_ON(!sta->sdata->bss);
+       if (indicate_tim)
+               __bss_tim_set(bss, sta->sta.aid);
+       else
+               __bss_tim_clear(bss, sta->sta.aid);
+
+       if (local->ops->set_tim) {
+               local->tim_in_locked_section = true;
+               drv_set_tim(local, &sta->sta, indicate_tim);
+               local->tim_in_locked_section = false;
+       }
 
-       spin_lock_irqsave(&sta->local->sta_lock, flags);
-       __sta_info_clear_tim_bit(sta->sdata->bss, sta);
-       spin_unlock_irqrestore(&sta->local->sta_lock, flags);
+       spin_unlock_irqrestore(&local->sta_lock, flags);
 }
 
 static bool sta_info_buffer_expired(struct sta_info *sta, struct sk_buff *skb)
@@ -711,21 +752,59 @@ static bool sta_info_buffer_expired(struct sta_info *sta, struct sk_buff *skb)
 }
 
 
-static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
-                                            struct sta_info *sta)
+static bool sta_info_cleanup_expire_buffered_ac(struct ieee80211_local *local,
+                                               struct sta_info *sta, int ac)
 {
        unsigned long flags;
        struct sk_buff *skb;
 
+       /*
+        * First check for frames that should expire on the filtered
+        * queue. Frames here were rejected by the driver and are on
+        * a separate queue to avoid reordering with normal PS-buffered
+        * frames. They also aren't accounted for right now in the
+        * total_ps_buffered counter.
+        */
+       for (;;) {
+               spin_lock_irqsave(&sta->tx_filtered[ac].lock, flags);
+               skb = skb_peek(&sta->tx_filtered[ac]);
+               if (sta_info_buffer_expired(sta, skb))
+                       skb = __skb_dequeue(&sta->tx_filtered[ac]);
+               else
+                       skb = NULL;
+               spin_unlock_irqrestore(&sta->tx_filtered[ac].lock, flags);
+
+               /*
+                * Frames are queued in order, so if this one
+                * hasn't expired yet we can stop testing. If
+                * we actually reached the end of the queue we
+                * also need to stop, of course.
+                */
+               if (!skb)
+                       break;
+               dev_kfree_skb(skb);
+       }
+
+       /*
+        * Now also check the normal PS-buffered queue, this will
+        * only find something if the filtered queue was emptied
+        * since the filtered frames are all before the normal PS
+        * buffered frames.
+        */
        for (;;) {
-               spin_lock_irqsave(&sta->ps_tx_buf.lock, flags);
-               skb = skb_peek(&sta->ps_tx_buf);
+               spin_lock_irqsave(&sta->ps_tx_buf[ac].lock, flags);
+               skb = skb_peek(&sta->ps_tx_buf[ac]);
                if (sta_info_buffer_expired(sta, skb))
-                       skb = __skb_dequeue(&sta->ps_tx_buf);
+                       skb = __skb_dequeue(&sta->ps_tx_buf[ac]);
                else
                        skb = NULL;
-               spin_unlock_irqrestore(&sta->ps_tx_buf.lock, flags);
+               spin_unlock_irqrestore(&sta->ps_tx_buf[ac].lock, flags);
 
+               /*
+                * frames are queued in order, so if this one
+                * hasn't expired yet (or we reached the end of
+                * the queue) we can stop testing
+                */
                if (!skb)
                        break;
 
@@ -735,22 +814,47 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
                       sta->sta.addr);
 #endif
                dev_kfree_skb(skb);
-
-               if (skb_queue_empty(&sta->ps_tx_buf) &&
-                   !test_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF))
-                       sta_info_clear_tim_bit(sta);
        }
 
-       return !skb_queue_empty(&sta->ps_tx_buf);
+       /*
+        * Finally, recalculate the TIM bit for this station -- it might
+        * now be clear because the station was too slow to retrieve its
+        * frames.
+        */
+       sta_info_recalc_tim(sta);
+
+       /*
+        * Return whether there are any frames still buffered, this is
+        * used to check whether the cleanup timer still needs to run,
+        * if there are no frames we don't need to rearm the timer.
+        */
+       return !(skb_queue_empty(&sta->ps_tx_buf[ac]) &&
+                skb_queue_empty(&sta->tx_filtered[ac]));
+}
+
+static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
+                                            struct sta_info *sta)
+{
+       bool have_buffered = false;
+       int ac;
+
+       /* This is only necessary for stations on BSS interfaces */
+       if (!sta->sdata->bss)
+               return false;
+
+       for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
+               have_buffered |=
+                       sta_info_cleanup_expire_buffered_ac(local, sta, ac);
+
+       return have_buffered;
 }
 
 static int __must_check __sta_info_destroy(struct sta_info *sta)
 {
        struct ieee80211_local *local;
        struct ieee80211_sub_if_data *sdata;
-       struct sk_buff *skb;
        unsigned long flags;
-       int ret, i;
+       int ret, i, ac;
 
        might_sleep();
 
@@ -766,7 +870,7 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
         * sessions -- block that to make sure the tear-down
         * will be sufficient.
         */
-       set_sta_flags(sta, WLAN_STA_BLOCK_BA);
+       set_sta_flag(sta, WLAN_STA_BLOCK_BA);
        ieee80211_sta_tear_down_BA_sessions(sta, true);
 
        spin_lock_irqsave(&local->sta_lock, flags);
@@ -787,12 +891,15 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
 
        sta->dead = true;
 
-       if (test_and_clear_sta_flags(sta,
-                               WLAN_STA_PS_STA | WLAN_STA_PS_DRIVER)) {
+       if (test_sta_flag(sta, WLAN_STA_PS_STA) ||
+           test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
                BUG_ON(!sdata->bss);
 
+               clear_sta_flag(sta, WLAN_STA_PS_STA);
+               clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
+
                atomic_dec(&sdata->bss->num_sta_ps);
-               sta_info_clear_tim_bit(sta);
+               sta_info_recalc_tim(sta);
        }
 
        local->num_sta--;
@@ -818,6 +925,12 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
         */
        synchronize_rcu();
 
+       for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+               local->total_ps_buffered -= skb_queue_len(&sta->ps_tx_buf[ac]);
+               __skb_queue_purge(&sta->ps_tx_buf[ac]);
+               __skb_queue_purge(&sta->tx_filtered[ac]);
+       }
+
 #ifdef CONFIG_MAC80211_MESH
        if (ieee80211_vif_is_mesh(&sdata->vif))
                mesh_accept_plinks_update(sdata);
@@ -840,14 +953,6 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
        }
 #endif
 
-       while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) {
-               local->total_ps_buffered--;
-               dev_kfree_skb_any(skb);
-       }
-
-       while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL)
-               dev_kfree_skb_any(skb);
-
        __sta_info_free(local, sta);
 
        return 0;
@@ -1013,7 +1118,8 @@ static void clear_sta_ps_flags(void *_sta)
 {
        struct sta_info *sta = _sta;
 
-       clear_sta_flags(sta, WLAN_STA_PS_DRIVER | WLAN_STA_PS_STA);
+       clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
+       clear_sta_flag(sta, WLAN_STA_PS_STA);
 }
 
 /* powersave support code */
@@ -1021,88 +1127,343 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
 {
        struct ieee80211_sub_if_data *sdata = sta->sdata;
        struct ieee80211_local *local = sdata->local;
-       int sent, buffered;
+       struct sk_buff_head pending;
+       int filtered = 0, buffered = 0, ac;
+
+       clear_sta_flag(sta, WLAN_STA_SP);
+
+       BUILD_BUG_ON(BITS_TO_LONGS(STA_TID_NUM) > 1);
+       sta->driver_buffered_tids = 0;
 
-       clear_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF);
        if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS))
                drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta);
 
-       if (!skb_queue_empty(&sta->ps_tx_buf))
-               sta_info_clear_tim_bit(sta);
+       skb_queue_head_init(&pending);
 
        /* Send all buffered frames to the station */
-       sent = ieee80211_add_pending_skbs(local, &sta->tx_filtered);
-       buffered = ieee80211_add_pending_skbs_fn(local, &sta->ps_tx_buf,
-                                                clear_sta_ps_flags, sta);
-       sent += buffered;
+       for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+               int count = skb_queue_len(&pending), tmp;
+
+               skb_queue_splice_tail_init(&sta->tx_filtered[ac], &pending);
+               tmp = skb_queue_len(&pending);
+               filtered += tmp - count;
+               count = tmp;
+
+               skb_queue_splice_tail_init(&sta->ps_tx_buf[ac], &pending);
+               tmp = skb_queue_len(&pending);
+               buffered += tmp - count;
+       }
+
+       ieee80211_add_pending_skbs_fn(local, &pending, clear_sta_ps_flags, sta);
+
        local->total_ps_buffered -= buffered;
 
+       sta_info_recalc_tim(sta);
+
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
        printk(KERN_DEBUG "%s: STA %pM aid %d sending %d filtered/%d PS frames "
               "since STA not sleeping anymore\n", sdata->name,
-              sta->sta.addr, sta->sta.aid, sent - buffered, buffered);
+              sta->sta.addr, sta->sta.aid, filtered, buffered);
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 }
 
-void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta)
+static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata,
+                                        struct sta_info *sta, int tid,
+                                        enum ieee80211_frame_release_type reason)
 {
-       struct ieee80211_sub_if_data *sdata = sta->sdata;
        struct ieee80211_local *local = sdata->local;
+       struct ieee80211_qos_hdr *nullfunc;
        struct sk_buff *skb;
-       int no_pending_pkts;
+       int size = sizeof(*nullfunc);
+       __le16 fc;
+       bool qos = test_sta_flag(sta, WLAN_STA_WME);
+       struct ieee80211_tx_info *info;
 
-       skb = skb_dequeue(&sta->tx_filtered);
-       if (!skb) {
-               skb = skb_dequeue(&sta->ps_tx_buf);
-               if (skb)
-                       local->total_ps_buffered--;
+       if (qos) {
+               fc = cpu_to_le16(IEEE80211_FTYPE_DATA |
+                                IEEE80211_STYPE_QOS_NULLFUNC |
+                                IEEE80211_FCTL_FROMDS);
+       } else {
+               size -= 2;
+               fc = cpu_to_le16(IEEE80211_FTYPE_DATA |
+                                IEEE80211_STYPE_NULLFUNC |
+                                IEEE80211_FCTL_FROMDS);
        }
-       no_pending_pkts = skb_queue_empty(&sta->tx_filtered) &&
-               skb_queue_empty(&sta->ps_tx_buf);
 
-       if (skb) {
-               struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-               struct ieee80211_hdr *hdr =
-                       (struct ieee80211_hdr *) skb->data;
+       skb = dev_alloc_skb(local->hw.extra_tx_headroom + size);
+       if (!skb)
+               return;
+
+       skb_reserve(skb, local->hw.extra_tx_headroom);
+
+       nullfunc = (void *) skb_put(skb, size);
+       nullfunc->frame_control = fc;
+       nullfunc->duration_id = 0;
+       memcpy(nullfunc->addr1, sta->sta.addr, ETH_ALEN);
+       memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN);
+       memcpy(nullfunc->addr3, sdata->vif.addr, ETH_ALEN);
+
+       if (qos) {
+               skb->priority = tid;
+
+               skb_set_queue_mapping(skb, ieee802_1d_to_ac[tid]);
+
+               nullfunc->qos_ctrl = cpu_to_le16(tid);
+
+               if (reason == IEEE80211_FRAME_RELEASE_UAPSD)
+                       nullfunc->qos_ctrl |=
+                               cpu_to_le16(IEEE80211_QOS_CTL_EOSP);
+       }
+
+       info = IEEE80211_SKB_CB(skb);
+
+       /*
+        * Tell TX path to send this frame even though the
+        * STA may still remain is PS mode after this frame
+        * exchange. Also set EOSP to indicate this packet
+        * ends the poll/service period.
+        */
+       info->flags |= IEEE80211_TX_CTL_POLL_RESPONSE |
+                      IEEE80211_TX_STATUS_EOSP |
+                      IEEE80211_TX_CTL_REQ_TX_STATUS;
+
+       drv_allow_buffered_frames(local, sta, BIT(tid), 1, reason, false);
+
+       ieee80211_xmit(sdata, skb);
+}
+
+static void
+ieee80211_sta_ps_deliver_response(struct sta_info *sta,
+                                 int n_frames, u8 ignored_acs,
+                                 enum ieee80211_frame_release_type reason)
+{
+       struct ieee80211_sub_if_data *sdata = sta->sdata;
+       struct ieee80211_local *local = sdata->local;
+       bool found = false;
+       bool more_data = false;
+       int ac;
+       unsigned long driver_release_tids = 0;
+       struct sk_buff_head frames;
+
+       /* Service or PS-Poll period starts */
+       set_sta_flag(sta, WLAN_STA_SP);
+
+       __skb_queue_head_init(&frames);
+
+       /*
+        * Get response frame(s) and more data bit for it.
+        */
+       for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+               unsigned long tids;
+
+               if (ignored_acs & BIT(ac))
+                       continue;
+
+               tids = ieee80211_tids_for_ac(ac);
+
+               if (!found) {
+                       driver_release_tids = sta->driver_buffered_tids & tids;
+                       if (driver_release_tids) {
+                               found = true;
+                       } else {
+                               struct sk_buff *skb;
+
+                               while (n_frames > 0) {
+                                       skb = skb_dequeue(&sta->tx_filtered[ac]);
+                                       if (!skb) {
+                                               skb = skb_dequeue(
+                                                       &sta->ps_tx_buf[ac]);
+                                               if (skb)
+                                                       local->total_ps_buffered--;
+                                       }
+                                       if (!skb)
+                                               break;
+                                       n_frames--;
+                                       found = true;
+                                       __skb_queue_tail(&frames, skb);
+                               }
+                       }
+
+                       /*
+                        * If the driver has data on more than one TID then
+                        * certainly there's more data if we release just a
+                        * single frame now (from a single TID).
+                        */
+                       if (reason == IEEE80211_FRAME_RELEASE_PSPOLL &&
+                           hweight16(driver_release_tids) > 1) {
+                               more_data = true;
+                               driver_release_tids =
+                                       BIT(ffs(driver_release_tids) - 1);
+                               break;
+                       }
+               }
+
+               if (!skb_queue_empty(&sta->tx_filtered[ac]) ||
+                   !skb_queue_empty(&sta->ps_tx_buf[ac])) {
+                       more_data = true;
+                       break;
+               }
+       }
+
+       if (!found) {
+               int tid;
 
                /*
-                * Tell TX path to send this frame even though the STA may
-                * still remain is PS mode after this frame exchange.
+                * For PS-Poll, this can only happen due to a race condition
+                * when we set the TIM bit and the station notices it, but
+                * before it can poll for the frame we expire it.
+                *
+                * For uAPSD, this is said in the standard (11.2.1.5 h):
+                *      At each unscheduled SP for a non-AP STA, the AP shall
+                *      attempt to transmit at least one MSDU or MMPDU, but no
+                *      more than the value specified in the Max SP Length field
+                *      in the QoS Capability element from delivery-enabled ACs,
+                *      that are destined for the non-AP STA.
+                *
+                * Since we have no other MSDU/MMPDU, transmit a QoS null frame.
                 */
-               info->flags |= IEEE80211_TX_CTL_PSPOLL_RESPONSE;
 
-#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-               printk(KERN_DEBUG "STA %pM aid %d: PS Poll (entries after %d)\n",
-                      sta->sta.addr, sta->sta.aid,
-                      skb_queue_len(&sta->ps_tx_buf));
-#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
+               /* This will evaluate to 1, 3, 5 or 7. */
+               tid = 7 - ((ffs(~ignored_acs) - 1) << 1);
 
-               /* Use MoreData flag to indicate whether there are more
-                * buffered frames for this STA */
-               if (no_pending_pkts)
-                       hdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREDATA);
-               else
-                       hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
+               ieee80211_send_null_response(sdata, sta, tid, reason);
+               return;
+       }
 
-               ieee80211_add_pending_skb(local, skb);
+       if (!driver_release_tids) {
+               struct sk_buff_head pending;
+               struct sk_buff *skb;
+               int num = 0;
+               u16 tids = 0;
+
+               skb_queue_head_init(&pending);
+
+               while ((skb = __skb_dequeue(&frames))) {
+                       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+                       struct ieee80211_hdr *hdr = (void *) skb->data;
+                       u8 *qoshdr = NULL;
+
+                       num++;
+
+                       /*
+                        * Tell TX path to send this frame even though the
+                        * STA may still remain is PS mode after this frame
+                        * exchange.
+                        */
+                       info->flags |= IEEE80211_TX_CTL_POLL_RESPONSE;
+
+                       /*
+                        * Use MoreData flag to indicate whether there are
+                        * more buffered frames for this STA
+                        */
+                       if (!more_data)
+                               hdr->frame_control &=
+                                       cpu_to_le16(~IEEE80211_FCTL_MOREDATA);
+                       else
+                               hdr->frame_control |=
+                                       cpu_to_le16(IEEE80211_FCTL_MOREDATA);
+
+                       if (ieee80211_is_data_qos(hdr->frame_control) ||
+                           ieee80211_is_qos_nullfunc(hdr->frame_control))
+                               qoshdr = ieee80211_get_qos_ctl(hdr);
+
+                       /* set EOSP for the frame */
+                       if (reason == IEEE80211_FRAME_RELEASE_UAPSD &&
+                           qoshdr && skb_queue_empty(&frames))
+                               *qoshdr |= IEEE80211_QOS_CTL_EOSP;
+
+                       info->flags |= IEEE80211_TX_STATUS_EOSP |
+                                      IEEE80211_TX_CTL_REQ_TX_STATUS;
+
+                       if (qoshdr)
+                               tids |= BIT(*qoshdr & IEEE80211_QOS_CTL_TID_MASK);
+                       else
+                               tids |= BIT(0);
+
+                       __skb_queue_tail(&pending, skb);
+               }
 
-               if (no_pending_pkts)
-                       sta_info_clear_tim_bit(sta);
-#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
+               drv_allow_buffered_frames(local, sta, tids, num,
+                                         reason, more_data);
+
+               ieee80211_add_pending_skbs(local, &pending);
+
+               sta_info_recalc_tim(sta);
        } else {
                /*
-                * FIXME: This can be the result of a race condition between
-                *        us expiring a frame and the station polling for it.
-                *        Should we send it a null-func frame indicating we
-                *        have nothing buffered for it?
+                * We need to release a frame that is buffered somewhere in the
+                * driver ... it'll have to handle that.
+                * Note that, as per the comment above, it'll also have to see
+                * if there is more than just one frame on the specific TID that
+                * we're releasing from, and it needs to set the more-data bit
+                * accordingly if we tell it that there's no more data. If we do
+                * tell it there's more data, then of course the more-data bit
+                * needs to be set anyway.
+                */
+               drv_release_buffered_frames(local, sta, driver_release_tids,
+                                           n_frames, reason, more_data);
+
+               /*
+                * Note that we don't recalculate the TIM bit here as it would
+                * most likely have no effect at all unless the driver told us
+                * that the TID became empty before returning here from the
+                * release function.
+                * Either way, however, when the driver tells us that the TID
+                * became empty we'll do the TIM recalculation.
                 */
-               printk(KERN_DEBUG "%s: STA %pM sent PS Poll even "
-                      "though there are no buffered frames for it\n",
-                      sdata->name, sta->sta.addr);
-#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
        }
 }
 
+void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta)
+{
+       u8 ignore_for_response = sta->sta.uapsd_queues;
+
+       /*
+        * If all ACs are delivery-enabled then we should reply
+        * from any of them, if only some are enabled we reply
+        * only from the non-enabled ones.
+        */
+       if (ignore_for_response == BIT(IEEE80211_NUM_ACS) - 1)
+               ignore_for_response = 0;
+
+       ieee80211_sta_ps_deliver_response(sta, 1, ignore_for_response,
+                                         IEEE80211_FRAME_RELEASE_PSPOLL);
+}
+
+void ieee80211_sta_ps_deliver_uapsd(struct sta_info *sta)
+{
+       int n_frames = sta->sta.max_sp;
+       u8 delivery_enabled = sta->sta.uapsd_queues;
+
+       /*
+        * If we ever grow support for TSPEC this might happen if
+        * the TSPEC update from hostapd comes in between a trigger
+        * frame setting WLAN_STA_UAPSD in the RX path and this
+        * actually getting called.
+        */
+       if (!delivery_enabled)
+               return;
+
+       switch (sta->sta.max_sp) {
+       case 1:
+               n_frames = 2;
+               break;
+       case 2:
+               n_frames = 4;
+               break;
+       case 3:
+               n_frames = 6;
+               break;
+       case 0:
+               /* XXX: what is a good value? */
+               n_frames = 8;
+               break;
+       }
+
+       ieee80211_sta_ps_deliver_response(sta, n_frames, ~delivery_enabled,
+                                         IEEE80211_FRAME_RELEASE_UAPSD);
+}
+
 void ieee80211_sta_block_awake(struct ieee80211_hw *hw,
                               struct ieee80211_sta *pubsta, bool block)
 {
@@ -1111,17 +1472,50 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw,
        trace_api_sta_block_awake(sta->local, pubsta, block);
 
        if (block)
-               set_sta_flags(sta, WLAN_STA_PS_DRIVER);
-       else if (test_sta_flags(sta, WLAN_STA_PS_DRIVER))
+               set_sta_flag(sta, WLAN_STA_PS_DRIVER);
+       else if (test_sta_flag(sta, WLAN_STA_PS_DRIVER))
                ieee80211_queue_work(hw, &sta->drv_unblock_wk);
 }
 EXPORT_SYMBOL(ieee80211_sta_block_awake);
 
-void ieee80211_sta_set_tim(struct ieee80211_sta *pubsta)
+void ieee80211_sta_eosp_irqsafe(struct ieee80211_sta *pubsta)
+{
+       struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
+       struct ieee80211_local *local = sta->local;
+       struct sk_buff *skb;
+       struct skb_eosp_msg_data *data;
+
+       trace_api_eosp(local, pubsta);
+
+       skb = alloc_skb(0, GFP_ATOMIC);
+       if (!skb) {
+               /* too bad ... but race is better than loss */
+               clear_sta_flag(sta, WLAN_STA_SP);
+               return;
+       }
+
+       data = (void *)skb->cb;
+       memcpy(data->sta, pubsta->addr, ETH_ALEN);
+       memcpy(data->iface, sta->sdata->vif.addr, ETH_ALEN);
+       skb->pkt_type = IEEE80211_EOSP_MSG;
+       skb_queue_tail(&local->skb_queue, skb);
+       tasklet_schedule(&local->tasklet);
+}
+EXPORT_SYMBOL(ieee80211_sta_eosp_irqsafe);
+
+void ieee80211_sta_set_buffered(struct ieee80211_sta *pubsta,
+                               u8 tid, bool buffered)
 {
        struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
 
-       set_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF);
-       sta_info_set_tim_bit(sta);
+       if (WARN_ON(tid >= STA_TID_NUM))
+               return;
+
+       if (buffered)
+               set_bit(tid, &sta->driver_buffered_tids);
+       else
+               clear_bit(tid, &sta->driver_buffered_tids);
+
+       sta_info_recalc_tim(sta);
 }
-EXPORT_SYMBOL(ieee80211_sta_set_tim);
+EXPORT_SYMBOL(ieee80211_sta_set_buffered);
index 56a3d38a2cd19479520f875d080d53127a37a73d..8c8ce05ad26fd0090d0b08eb41809b25bd89a6db 100644 (file)
@@ -19,7 +19,8 @@
 /**
  * enum ieee80211_sta_info_flags - Stations flags
  *
- * These flags are used with &struct sta_info's @flags member.
+ * These flags are used with &struct sta_info's @flags member, but
+ * only indirectly with set_sta_flag() and friends.
  *
  * @WLAN_STA_AUTH: Station is authenticated.
  * @WLAN_STA_ASSOC: Station is associated.
  *     be in the queues
  * @WLAN_STA_PSPOLL: Station sent PS-poll while driver was keeping
  *     station in power-save mode, reply when the driver unblocks.
- * @WLAN_STA_PS_DRIVER_BUF: Station has frames pending in driver internal
- *     buffers. Automatically cleared on station wake-up.
+ * @WLAN_STA_TDLS_PEER: Station is a TDLS peer.
+ * @WLAN_STA_TDLS_PEER_AUTH: This TDLS peer is authorized to send direct
+ *     packets. This means the link is enabled.
+ * @WLAN_STA_UAPSD: Station requested unscheduled SP while driver was
+ *     keeping station in power-save mode, reply when the driver
+ *     unblocks the station.
+ * @WLAN_STA_SP: Station is in a service period, so don't try to
+ *     reply to other uAPSD trigger frames or PS-Poll.
  */
 enum ieee80211_sta_info_flags {
-       WLAN_STA_AUTH           = 1<<0,
-       WLAN_STA_ASSOC          = 1<<1,
-       WLAN_STA_PS_STA         = 1<<2,
-       WLAN_STA_AUTHORIZED     = 1<<3,
-       WLAN_STA_SHORT_PREAMBLE = 1<<4,
-       WLAN_STA_ASSOC_AP       = 1<<5,
-       WLAN_STA_WME            = 1<<6,
-       WLAN_STA_WDS            = 1<<7,
-       WLAN_STA_CLEAR_PS_FILT  = 1<<9,
-       WLAN_STA_MFP            = 1<<10,
-       WLAN_STA_BLOCK_BA       = 1<<11,
-       WLAN_STA_PS_DRIVER      = 1<<12,
-       WLAN_STA_PSPOLL         = 1<<13,
-       WLAN_STA_PS_DRIVER_BUF  = 1<<14,
+       WLAN_STA_AUTH,
+       WLAN_STA_ASSOC,
+       WLAN_STA_PS_STA,
+       WLAN_STA_AUTHORIZED,
+       WLAN_STA_SHORT_PREAMBLE,
+       WLAN_STA_ASSOC_AP,
+       WLAN_STA_WME,
+       WLAN_STA_WDS,
+       WLAN_STA_CLEAR_PS_FILT,
+       WLAN_STA_MFP,
+       WLAN_STA_BLOCK_BA,
+       WLAN_STA_PS_DRIVER,
+       WLAN_STA_PSPOLL,
+       WLAN_STA_TDLS_PEER,
+       WLAN_STA_TDLS_PEER_AUTH,
+       WLAN_STA_UAPSD,
+       WLAN_STA_SP,
 };
 
 #define STA_TID_NUM 16
@@ -203,15 +213,16 @@ struct sta_ampdu_mlme {
  * @last_rx_rate_flag: rx status flag of the last data packet
  * @lock: used for locking all fields that require locking, see comments
  *     in the header file.
- * @flaglock: spinlock for flags accesses
  * @drv_unblock_wk: used for driver PS unblocking
  * @listen_interval: listen interval of this station, when we're acting as AP
- * @flags: STA flags, see &enum ieee80211_sta_info_flags
- * @ps_tx_buf: buffer of frames to transmit to this station
- *     when it leaves power saving state
- * @tx_filtered: buffer of frames we already tried to transmit
- *     but were filtered by hardware due to STA having entered
- *     power saving state
+ * @_flags: STA flags, see &enum ieee80211_sta_info_flags, do not use directly
+ * @ps_tx_buf: buffers (per AC) of frames to transmit to this station
+ *     when it leaves power saving state or polls
+ * @tx_filtered: buffers (per AC) of frames we already tried to
+ *     transmit but were filtered by hardware due to STA having
+ *     entered power saving state, these are also delivered to
+ *     the station when it leaves powersave or polls for frames
+ * @driver_buffered_tids: bitmap of TIDs the driver has data buffered on
  * @rx_packets: Number of MSDUs received from this STA
  * @rx_bytes: Number of bytes received from this STA
  * @wep_weak_iv_count: number of weak WEP IVs received from this station
@@ -261,7 +272,6 @@ struct sta_info {
        struct rate_control_ref *rate_ctrl;
        void *rate_ctrl_priv;
        spinlock_t lock;
-       spinlock_t flaglock;
 
        struct work_struct drv_unblock_wk;
 
@@ -271,18 +281,16 @@ struct sta_info {
 
        bool uploaded;
 
-       /*
-        * frequently updated, locked with own spinlock (flaglock),
-        * use the accessors defined below
-        */
-       u32 flags;
+       /* use the accessors defined below */
+       unsigned long _flags;
 
        /*
         * STA powersave frame queues, no more than the internal
         * locking required.
         */
-       struct sk_buff_head ps_tx_buf;
-       struct sk_buff_head tx_filtered;
+       struct sk_buff_head ps_tx_buf[IEEE80211_NUM_ACS];
+       struct sk_buff_head tx_filtered[IEEE80211_NUM_ACS];
+       unsigned long driver_buffered_tids;
 
        /* Updated from RX path only, no locking requirements */
        unsigned long rx_packets, rx_bytes;
@@ -358,60 +366,28 @@ static inline enum nl80211_plink_state sta_plink_state(struct sta_info *sta)
        return NL80211_PLINK_LISTEN;
 }
 
-static inline void set_sta_flags(struct sta_info *sta, const u32 flags)
+static inline void set_sta_flag(struct sta_info *sta,
+                               enum ieee80211_sta_info_flags flag)
 {
-       unsigned long irqfl;
-
-       spin_lock_irqsave(&sta->flaglock, irqfl);
-       sta->flags |= flags;
-       spin_unlock_irqrestore(&sta->flaglock, irqfl);
+       set_bit(flag, &sta->_flags);
 }
 
-static inline void clear_sta_flags(struct sta_info *sta, const u32 flags)
+static inline void clear_sta_flag(struct sta_info *sta,
+                                 enum ieee80211_sta_info_flags flag)
 {
-       unsigned long irqfl;
-
-       spin_lock_irqsave(&sta->flaglock, irqfl);
-       sta->flags &= ~flags;
-       spin_unlock_irqrestore(&sta->flaglock, irqfl);
+       clear_bit(flag, &sta->_flags);
 }
 
-static inline u32 test_sta_flags(struct sta_info *sta, const u32 flags)
+static inline int test_sta_flag(struct sta_info *sta,
+                               enum ieee80211_sta_info_flags flag)
 {
-       u32 ret;
-       unsigned long irqfl;
-
-       spin_lock_irqsave(&sta->flaglock, irqfl);
-       ret = sta->flags & flags;
-       spin_unlock_irqrestore(&sta->flaglock, irqfl);
-
-       return ret;
+       return test_bit(flag, &sta->_flags);
 }
 
-static inline u32 test_and_clear_sta_flags(struct sta_info *sta,
-                                          const u32 flags)
+static inline int test_and_clear_sta_flag(struct sta_info *sta,
+                                         enum ieee80211_sta_info_flags flag)
 {
-       u32 ret;
-       unsigned long irqfl;
-
-       spin_lock_irqsave(&sta->flaglock, irqfl);
-       ret = sta->flags & flags;
-       sta->flags &= ~flags;
-       spin_unlock_irqrestore(&sta->flaglock, irqfl);
-
-       return ret;
-}
-
-static inline u32 get_sta_flags(struct sta_info *sta)
-{
-       u32 ret;
-       unsigned long irqfl;
-
-       spin_lock_irqsave(&sta->flaglock, irqfl);
-       ret = sta->flags;
-       spin_unlock_irqrestore(&sta->flaglock, irqfl);
-
-       return ret;
+       return test_and_clear_bit(flag, &sta->_flags);
 }
 
 void ieee80211_assign_tid_tx(struct sta_info *sta, int tid,
@@ -429,8 +405,8 @@ rcu_dereference_protected_tid_tx(struct sta_info *sta, int tid)
 #define STA_HASH(sta) (sta[5])
 
 
-/* Maximum number of frames to buffer per power saving station */
-#define STA_MAX_TX_BUFFER 128
+/* Maximum number of frames to buffer per power saving station per AC */
+#define STA_MAX_TX_BUFFER      64
 
 /* Minimum buffered frame expiry time. If STA uses listen interval that is
  * smaller than this value, the minimum value here is used instead. */
@@ -523,8 +499,7 @@ int sta_info_destroy_addr(struct ieee80211_sub_if_data *sdata,
 int sta_info_destroy_addr_bss(struct ieee80211_sub_if_data *sdata,
                              const u8 *addr);
 
-void sta_info_set_tim_bit(struct sta_info *sta);
-void sta_info_clear_tim_bit(struct sta_info *sta);
+void sta_info_recalc_tim(struct sta_info *sta);
 
 void sta_info_init(struct ieee80211_local *local);
 void sta_info_stop(struct ieee80211_local *local);
@@ -535,5 +510,6 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
 
 void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta);
 void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta);
+void ieee80211_sta_ps_deliver_uapsd(struct sta_info *sta);
 
 #endif /* STA_INFO_H */
index d50358c45ab079bd6a023a1a2a764042bfd17cfc..864a9c3bcf4688b08cb25993b9f5f808080cc040 100644 (file)
@@ -14,6 +14,7 @@
 #include "rate.h"
 #include "mesh.h"
 #include "led.h"
+#include "wme.h"
 
 
 void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
@@ -43,6 +44,8 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
                                            struct sk_buff *skb)
 {
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_hdr *hdr = (void *)skb->data;
+       int ac;
 
        /*
         * This skb 'survived' a round-trip through the driver, and
@@ -62,12 +65,38 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
 
        sta->tx_filtered_count++;
 
+       /*
+        * Clear more-data bit on filtered frames, it might be set
+        * but later frames might time out so it might have to be
+        * clear again ... It's all rather unlikely (this frame
+        * should time out first, right?) but let's not confuse
+        * peers unnecessarily.
+        */
+       if (hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_MOREDATA))
+               hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_MOREDATA);
+
+       if (ieee80211_is_data_qos(hdr->frame_control)) {
+               u8 *p = ieee80211_get_qos_ctl(hdr);
+               int tid = *p & IEEE80211_QOS_CTL_TID_MASK;
+
+               /*
+                * Clear EOSP if set, this could happen e.g.
+                * if an absence period (us being a P2P GO)
+                * shortens the SP.
+                */
+               if (*p & IEEE80211_QOS_CTL_EOSP)
+                       *p &= ~IEEE80211_QOS_CTL_EOSP;
+               ac = ieee802_1d_to_ac[tid & 7];
+       } else {
+               ac = IEEE80211_AC_BE;
+       }
+
        /*
         * Clear the TX filter mask for this STA when sending the next
         * packet. If the STA went to power save mode, this will happen
         * when it wakes up for the next time.
         */
-       set_sta_flags(sta, WLAN_STA_CLEAR_PS_FILT);
+       set_sta_flag(sta, WLAN_STA_CLEAR_PS_FILT);
 
        /*
         * This code races in the following way:
@@ -103,13 +132,19 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
         *      changes before calling TX status events if ordering can be
         *      unknown.
         */
-       if (test_sta_flags(sta, WLAN_STA_PS_STA) &&
-           skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) {
-               skb_queue_tail(&sta->tx_filtered, skb);
+       if (test_sta_flag(sta, WLAN_STA_PS_STA) &&
+           skb_queue_len(&sta->tx_filtered[ac]) < STA_MAX_TX_BUFFER) {
+               skb_queue_tail(&sta->tx_filtered[ac], skb);
+               sta_info_recalc_tim(sta);
+
+               if (!timer_pending(&local->sta_cleanup))
+                       mod_timer(&local->sta_cleanup,
+                                 round_jiffies(jiffies +
+                                               STA_INFO_CLEANUP_INTERVAL));
                return;
        }
 
-       if (!test_sta_flags(sta, WLAN_STA_PS_STA) &&
+       if (!test_sta_flag(sta, WLAN_STA_PS_STA) &&
            !(info->flags & IEEE80211_TX_INTFL_RETRIED)) {
                /* Software retry the packet once */
                info->flags |= IEEE80211_TX_INTFL_RETRIED;
@@ -121,8 +156,8 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
        if (net_ratelimit())
                wiphy_debug(local->hw.wiphy,
                            "dropped TX filtered frame, queue_len=%d PS=%d @%lu\n",
-                           skb_queue_len(&sta->tx_filtered),
-                           !!test_sta_flags(sta, WLAN_STA_PS_STA), jiffies);
+                           skb_queue_len(&sta->tx_filtered[ac]),
+                           !!test_sta_flag(sta, WLAN_STA_PS_STA), jiffies);
 #endif
        dev_kfree_skb(skb);
 }
@@ -249,8 +284,11 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
                if (memcmp(hdr->addr2, sta->sdata->vif.addr, ETH_ALEN))
                        continue;
 
+               if (info->flags & IEEE80211_TX_STATUS_EOSP)
+                       clear_sta_flag(sta, WLAN_STA_SP);
+
                acked = !!(info->flags & IEEE80211_TX_STAT_ACK);
-               if (!acked && test_sta_flags(sta, WLAN_STA_PS_STA)) {
+               if (!acked && test_sta_flag(sta, WLAN_STA_PS_STA)) {
                        /*
                         * The STA is in power save mode, so assume
                         * that this TX packet failed because of that.
index 7cd6c28968b282763fa4739fd13296ed3ad99550..ae5dd85f1e93a1aac1a221baa1b516b60f3eead9 100644 (file)
@@ -253,7 +253,7 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
 
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
-       u32 sta_flags;
+       bool assoc = false;
 
        if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED))
                return TX_CONTINUE;
@@ -284,10 +284,11 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
        if (tx->flags & IEEE80211_TX_PS_BUFFERED)
                return TX_CONTINUE;
 
-       sta_flags = tx->sta ? get_sta_flags(tx->sta) : 0;
+       if (tx->sta)
+               assoc = test_sta_flag(tx->sta, WLAN_STA_ASSOC);
 
        if (likely(tx->flags & IEEE80211_TX_UNICAST)) {
-               if (unlikely(!(sta_flags & WLAN_STA_ASSOC) &&
+               if (unlikely(!assoc &&
                             tx->sdata->vif.type != NL80211_IFTYPE_ADHOC &&
                             ieee80211_is_data(hdr->frame_control))) {
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
@@ -343,13 +344,22 @@ static void purge_old_ps_buffers(struct ieee80211_local *local)
                total += skb_queue_len(&ap->ps_bc_buf);
        }
 
+       /*
+        * Drop one frame from each station from the lowest-priority
+        * AC that has frames at all.
+        */
        list_for_each_entry_rcu(sta, &local->sta_list, list) {
-               skb = skb_dequeue(&sta->ps_tx_buf);
-               if (skb) {
-                       purged++;
-                       dev_kfree_skb(skb);
+               int ac;
+
+               for (ac = IEEE80211_AC_BK; ac >= IEEE80211_AC_VO; ac--) {
+                       skb = skb_dequeue(&sta->ps_tx_buf[ac]);
+                       total += skb_queue_len(&sta->ps_tx_buf[ac]);
+                       if (skb) {
+                               purged++;
+                               dev_kfree_skb(skb);
+                               break;
+                       }
                }
-               total += skb_queue_len(&sta->ps_tx_buf);
        }
 
        rcu_read_unlock();
@@ -418,7 +428,7 @@ static int ieee80211_use_mfp(__le16 fc, struct sta_info *sta,
        if (!ieee80211_is_mgmt(fc))
                return 0;
 
-       if (sta == NULL || !test_sta_flags(sta, WLAN_STA_MFP))
+       if (sta == NULL || !test_sta_flag(sta, WLAN_STA_MFP))
                return 0;
 
        if (!ieee80211_is_robust_mgmt_frame((struct ieee80211_hdr *)
@@ -435,7 +445,6 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
        struct ieee80211_local *local = tx->local;
-       u32 staflags;
 
        if (unlikely(!sta ||
                     ieee80211_is_probe_resp(hdr->frame_control) ||
@@ -444,57 +453,52 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
                     ieee80211_is_reassoc_resp(hdr->frame_control)))
                return TX_CONTINUE;
 
-       staflags = get_sta_flags(sta);
+       if (unlikely((test_sta_flag(sta, WLAN_STA_PS_STA) ||
+                     test_sta_flag(sta, WLAN_STA_PS_DRIVER)) &&
+                    !(info->flags & IEEE80211_TX_CTL_POLL_RESPONSE))) {
+               int ac = skb_get_queue_mapping(tx->skb);
 
-       if (unlikely((staflags & (WLAN_STA_PS_STA | WLAN_STA_PS_DRIVER)) &&
-                    !(info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE))) {
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-               printk(KERN_DEBUG "STA %pM aid %d: PS buffer (entries "
-                      "before %d)\n",
-                      sta->sta.addr, sta->sta.aid,
-                      skb_queue_len(&sta->ps_tx_buf));
+               printk(KERN_DEBUG "STA %pM aid %d: PS buffer for AC %d\n",
+                      sta->sta.addr, sta->sta.aid, ac);
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
                if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
                        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);
+               if (skb_queue_len(&sta->ps_tx_buf[ac]) >= STA_MAX_TX_BUFFER) {
+                       struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf[ac]);
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-                       if (net_ratelimit()) {
-                               printk(KERN_DEBUG "%s: STA %pM TX "
-                                      "buffer full - dropping oldest frame\n",
-                                      tx->sdata->name, sta->sta.addr);
-                       }
+                       if (net_ratelimit())
+                               printk(KERN_DEBUG "%s: STA %pM TX buffer for "
+                                      "AC %d full - dropping oldest frame\n",
+                                      tx->sdata->name, sta->sta.addr, ac);
 #endif
                        dev_kfree_skb(old);
                } else
                        tx->local->total_ps_buffered++;
 
-               /*
-                * Queue frame to be sent after STA wakes up/polls,
-                * but don't set the TIM bit if the driver is blocking
-                * wakeup or poll response transmissions anyway.
-                */
-               if (skb_queue_empty(&sta->ps_tx_buf) &&
-                   !(staflags & WLAN_STA_PS_DRIVER))
-                       sta_info_set_tim_bit(sta);
-
                info->control.jiffies = jiffies;
                info->control.vif = &tx->sdata->vif;
                info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
-               skb_queue_tail(&sta->ps_tx_buf, tx->skb);
+               skb_queue_tail(&sta->ps_tx_buf[ac], tx->skb);
 
                if (!timer_pending(&local->sta_cleanup))
                        mod_timer(&local->sta_cleanup,
                                  round_jiffies(jiffies +
                                                STA_INFO_CLEANUP_INTERVAL));
 
+               /*
+                * We queued up some frames, so the TIM bit might
+                * need to be set, recalculate it.
+                */
+               sta_info_recalc_tim(sta);
+
                return TX_QUEUED;
        }
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-       else if (unlikely(staflags & WLAN_STA_PS_STA)) {
-               printk(KERN_DEBUG "%s: STA %pM in PS mode, but pspoll "
-                      "set -> send frame\n", tx->sdata->name,
-                      sta->sta.addr);
+       else if (unlikely(test_sta_flag(sta, WLAN_STA_PS_STA))) {
+               printk(KERN_DEBUG
+                      "%s: STA %pM in PS mode, but polling/in SP -> send frame\n",
+                      tx->sdata->name, sta->sta.addr);
        }
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 
@@ -552,7 +556,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
                 !(info->flags & IEEE80211_TX_CTL_INJECTED) &&
                 (!ieee80211_is_robust_mgmt_frame(hdr) ||
                  (ieee80211_is_action(hdr->frame_control) &&
-                  tx->sta && test_sta_flags(tx->sta, WLAN_STA_MFP)))) {
+                  tx->sta && test_sta_flag(tx->sta, WLAN_STA_MFP)))) {
                I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted);
                return TX_DROP;
        } else
@@ -611,7 +615,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
        u32 len;
        bool inval = false, rts = false, short_preamble = false;
        struct ieee80211_tx_rate_control txrc;
-       u32 sta_flags;
+       bool assoc = false;
 
        memset(&txrc, 0, sizeof(txrc));
 
@@ -647,17 +651,17 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
         */
        if (tx->sdata->vif.bss_conf.use_short_preamble &&
            (ieee80211_is_data(hdr->frame_control) ||
-            (tx->sta && test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE))))
+            (tx->sta && test_sta_flag(tx->sta, WLAN_STA_SHORT_PREAMBLE))))
                txrc.short_preamble = short_preamble = true;
 
-       sta_flags = tx->sta ? get_sta_flags(tx->sta) : 0;
+       if (tx->sta)
+               assoc = test_sta_flag(tx->sta, WLAN_STA_ASSOC);
 
        /*
         * Lets not bother rate control if we're associated and cannot
         * talk to the sta. This should not happen.
         */
-       if (WARN(test_bit(SCAN_SW_SCANNING, &tx->local->scanning) &&
-                (sta_flags & WLAN_STA_ASSOC) &&
+       if (WARN(test_bit(SCAN_SW_SCANNING, &tx->local->scanning) && assoc &&
                 !rate_usable_index_exists(sband, &tx->sta->sta),
                 "%s: Dropped data frame as no usable bitrate found while "
                 "scanning and associated. Target station: "
@@ -800,6 +804,9 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx)
        if (ieee80211_hdrlen(hdr->frame_control) < 24)
                return TX_CONTINUE;
 
+       if (ieee80211_is_qos_nullfunc(hdr->frame_control))
+               return TX_CONTINUE;
+
        /*
         * Anything but QoS data that has a sequence number field
         * (is long enough) gets a sequence number from the global
@@ -1232,6 +1239,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
                tx->sta = sta_info_get(sdata, hdr->addr1);
 
        if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) &&
+           !ieee80211_is_qos_nullfunc(hdr->frame_control) &&
            (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION) &&
            !(local->hw.flags & IEEE80211_HW_TX_AMPDU_SETUP_IN_HW)) {
                struct tid_ampdu_tx *tid_tx;
@@ -1273,7 +1281,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
 
        if (!tx->sta)
                info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
-       else if (test_and_clear_sta_flags(tx->sta, WLAN_STA_CLEAR_PS_FILT))
+       else if (test_and_clear_sta_flag(tx->sta, WLAN_STA_CLEAR_PS_FILT))
                info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
 
        hdrlen = ieee80211_hdrlen(hdr->frame_control);
@@ -1515,8 +1523,7 @@ static int ieee80211_skb_resize(struct ieee80211_sub_if_data *sdata,
        return 0;
 }
 
-static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
-                          struct sk_buff *skb)
+void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@ -1724,8 +1731,9 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
        int encaps_len, skip_header_bytes;
        int nh_pos, h_pos;
        struct sta_info *sta = NULL;
-       u32 sta_flags = 0;
+       bool wme_sta = false, authorized = false, tdls_auth = false;
        struct sk_buff *tmp_skb;
+       bool tdls_direct = false;
 
        if (unlikely(skb->len < ETH_HLEN)) {
                ret = NETDEV_TX_OK;
@@ -1749,7 +1757,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                        memcpy(hdr.addr3, skb->data, ETH_ALEN);
                        memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
                        hdrlen = 30;
-                       sta_flags = get_sta_flags(sta);
+                       authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
+                       wme_sta = test_sta_flag(sta, WLAN_STA_WME);
                }
                rcu_read_unlock();
                if (sta)
@@ -1837,11 +1846,50 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                break;
 #endif
        case NL80211_IFTYPE_STATION:
-               memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN);
-               if (sdata->u.mgd.use_4addr &&
-                   cpu_to_be16(ethertype) != sdata->control_port_protocol) {
-                       fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
+               if (sdata->wdev.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) {
+                       bool tdls_peer = false;
+
+                       rcu_read_lock();
+                       sta = sta_info_get(sdata, skb->data);
+                       if (sta) {
+                               authorized = test_sta_flag(sta,
+                                                       WLAN_STA_AUTHORIZED);
+                               wme_sta = test_sta_flag(sta, WLAN_STA_WME);
+                               tdls_peer = test_sta_flag(sta,
+                                                        WLAN_STA_TDLS_PEER);
+                               tdls_auth = test_sta_flag(sta,
+                                               WLAN_STA_TDLS_PEER_AUTH);
+                       }
+                       rcu_read_unlock();
+
+                       /*
+                        * If the TDLS link is enabled, send everything
+                        * directly. Otherwise, allow TDLS setup frames
+                        * to be transmitted indirectly.
+                        */
+                       tdls_direct = tdls_peer && (tdls_auth ||
+                                !(ethertype == ETH_P_TDLS && skb->len > 14 &&
+                                  skb->data[14] == WLAN_TDLS_SNAP_RFTYPE));
+               }
+
+               if (tdls_direct) {
+                       /* link during setup - throw out frames to peer */
+                       if (!tdls_auth) {
+                               ret = NETDEV_TX_OK;
+                               goto fail;
+                       }
+
+                       /* DA SA BSSID */
+                       memcpy(hdr.addr1, skb->data, ETH_ALEN);
+                       memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
+                       memcpy(hdr.addr3, sdata->u.mgd.bssid, ETH_ALEN);
+                       hdrlen = 24;
+               }  else if (sdata->u.mgd.use_4addr &&
+                           cpu_to_be16(ethertype) != sdata->control_port_protocol) {
+                       fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS |
+                                         IEEE80211_FCTL_TODS);
                        /* RA TA DA SA */
+                       memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN);
                        memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN);
                        memcpy(hdr.addr3, skb->data, ETH_ALEN);
                        memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
@@ -1849,6 +1897,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                } else {
                        fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
                        /* BSSID SA DA */
+                       memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN);
                        memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
                        memcpy(hdr.addr3, skb->data, ETH_ALEN);
                        hdrlen = 24;
@@ -1874,17 +1923,19 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
        if (!is_multicast_ether_addr(hdr.addr1)) {
                rcu_read_lock();
                sta = sta_info_get(sdata, hdr.addr1);
-               if (sta)
-                       sta_flags = get_sta_flags(sta);
+               if (sta) {
+                       authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
+                       wme_sta = test_sta_flag(sta, WLAN_STA_WME);
+               }
                rcu_read_unlock();
        }
 
        /* For mesh, the use of the QoS header is mandatory */
        if (ieee80211_vif_is_mesh(&sdata->vif))
-               sta_flags |= WLAN_STA_WME;
+               wme_sta = true;
 
        /* receiver and we are QoS enabled, use a QoS type frame */
-       if ((sta_flags & WLAN_STA_WME) && local->hw.queues >= 4) {
+       if (wme_sta && local->hw.queues >= 4) {
                fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
                hdrlen += 2;
        }
@@ -1894,8 +1945,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
         * EAPOL frames from the local station.
         */
        if (!ieee80211_vif_is_mesh(&sdata->vif) &&
-               unlikely(!is_multicast_ether_addr(hdr.addr1) &&
-                     !(sta_flags & WLAN_STA_AUTHORIZED) &&
+               unlikely(!is_multicast_ether_addr(hdr.addr1) && !authorized &&
                      !(cpu_to_be16(ethertype) == sdata->control_port_protocol &&
                       compare_ether_addr(sdata->vif.addr,
                                          skb->data + ETH_ALEN) == 0))) {
@@ -2307,9 +2357,9 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
                *pos++ = WLAN_EID_SSID;
                *pos++ = 0x0;
 
-               if (mesh_add_srates_ie(skb, sdata) ||
+               if (ieee80211_add_srates_ie(&sdata->vif, skb) ||
                    mesh_add_ds_params_ie(skb, sdata) ||
-                   mesh_add_ext_srates_ie(skb, sdata) ||
+                   ieee80211_add_ext_srates_ie(&sdata->vif, skb) ||
                    mesh_add_rsn_ie(skb, sdata) ||
                    mesh_add_meshid_ie(skb, sdata) ||
                    mesh_add_meshconf_ie(skb, sdata) ||
index 4b1466d5b6a1da6bbbe286765c805d445c6465b8..7439d26bf5f9e281f66cb9e47e05a80a825d7d37 100644 (file)
@@ -367,14 +367,14 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local,
        spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
 }
 
-int ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
-                                 struct sk_buff_head *skbs,
-                                 void (*fn)(void *data), void *data)
+void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
+                                  struct sk_buff_head *skbs,
+                                  void (*fn)(void *data), void *data)
 {
        struct ieee80211_hw *hw = &local->hw;
        struct sk_buff *skb;
        unsigned long flags;
-       int queue, ret = 0, i;
+       int queue, i;
 
        spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
        for (i = 0; i < hw->queues; i++)
@@ -389,7 +389,6 @@ int ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
                        continue;
                }
 
-               ret++;
                queue = skb_get_queue_mapping(skb);
                __skb_queue_tail(&local->pending[queue], skb);
        }
@@ -401,14 +400,12 @@ int ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
                __ieee80211_wake_queue(hw, i,
                        IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
        spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
-
-       return ret;
 }
 
-int ieee80211_add_pending_skbs(struct ieee80211_local *local,
-                              struct sk_buff_head *skbs)
+void ieee80211_add_pending_skbs(struct ieee80211_local *local,
+                               struct sk_buff_head *skbs)
 {
-       return ieee80211_add_pending_skbs_fn(local, skbs, NULL, NULL);
+       ieee80211_add_pending_skbs_fn(local, skbs, NULL, NULL);
 }
 
 void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw,
@@ -632,8 +629,8 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata)
 
                qparam.uapsd = false;
 
-               local->tx_conf[queue] = qparam;
-               drv_conf_tx(local, queue, &qparam);
+               sdata->tx_conf[queue] = qparam;
+               drv_conf_tx(local, sdata, queue, &qparam);
        }
 
        /* after reinitialize QoS TX queues setting to default,
@@ -899,14 +896,18 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
 void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
                              const u8 *ssid, size_t ssid_len,
                              const u8 *ie, size_t ie_len,
-                             u32 ratemask, bool directed)
+                             u32 ratemask, bool directed, bool no_cck)
 {
        struct sk_buff *skb;
 
        skb = ieee80211_build_probe_req(sdata, dst, ratemask, ssid, ssid_len,
                                        ie, ie_len, directed);
-       if (skb)
+       if (skb) {
+               if (no_cck)
+                       IEEE80211_SKB_CB(skb)->flags |=
+                               IEEE80211_TX_CTL_NO_CCK_RATE;
                ieee80211_tx_skb(sdata, skb);
+       }
 }
 
 u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
@@ -1040,8 +1041,15 @@ int ieee80211_reconfig(struct ieee80211_local *local)
        mutex_unlock(&local->sta_mtx);
 
        /* reconfigure tx conf */
-       for (i = 0; i < hw->queues; i++)
-               drv_conf_tx(local, i, &local->tx_conf[i]);
+       list_for_each_entry(sdata, &local->interfaces, list) {
+               if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
+                   sdata->vif.type == NL80211_IFTYPE_MONITOR ||
+                   !ieee80211_sdata_running(sdata))
+                       continue;
+
+               for (i = 0; i < hw->queues; i++)
+                       drv_conf_tx(local, sdata, i, &sdata->tx_conf[i]);
+       }
 
        /* reconfigure hardware */
        ieee80211_hw_config(local, ~0);
@@ -1114,7 +1122,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
 
                list_for_each_entry(sta, &local->sta_list, list) {
                        ieee80211_sta_tear_down_BA_sessions(sta, true);
-                       clear_sta_flags(sta, WLAN_STA_BLOCK_BA);
+                       clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
                }
 
                mutex_unlock(&local->sta_mtx);
@@ -1353,3 +1361,60 @@ void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif)
        _ieee80211_enable_rssi_reports(sdata, 0, 0);
 }
 EXPORT_SYMBOL(ieee80211_disable_rssi_reports);
+
+int ieee80211_add_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb)
+{
+       struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_supported_band *sband;
+       int rate;
+       u8 i, rates, *pos;
+
+       sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+       rates = sband->n_bitrates;
+       if (rates > 8)
+               rates = 8;
+
+       if (skb_tailroom(skb) < rates + 2)
+               return -ENOMEM;
+
+       pos = skb_put(skb, rates + 2);
+       *pos++ = WLAN_EID_SUPP_RATES;
+       *pos++ = rates;
+       for (i = 0; i < rates; i++) {
+               rate = sband->bitrates[i].bitrate;
+               *pos++ = (u8) (rate / 5);
+       }
+
+       return 0;
+}
+
+int ieee80211_add_ext_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb)
+{
+       struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_supported_band *sband;
+       int rate;
+       u8 i, exrates, *pos;
+
+       sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+       exrates = sband->n_bitrates;
+       if (exrates > 8)
+               exrates -= 8;
+       else
+               exrates = 0;
+
+       if (skb_tailroom(skb) < exrates + 2)
+               return -ENOMEM;
+
+       if (exrates) {
+               pos = skb_put(skb, exrates + 2);
+               *pos++ = WLAN_EID_EXT_SUPP_RATES;
+               *pos++ = exrates;
+               for (i = 8; i < sband->n_bitrates; i++) {
+                       rate = sband->bitrates[i].bitrate;
+                       *pos++ = (u8) (rate / 5);
+               }
+       }
+       return 0;
+}
index 971004c9b04f62b6c59557966b2985591e6d63e6..fd52e695c071082b4b51bc3cbc20e535a9f47630 100644 (file)
@@ -72,7 +72,7 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
        case NL80211_IFTYPE_AP_VLAN:
                sta = rcu_dereference(sdata->u.vlan.sta);
                if (sta) {
-                       qos = get_sta_flags(sta) & WLAN_STA_WME;
+                       qos = test_sta_flag(sta, WLAN_STA_WME);
                        break;
                }
        case NL80211_IFTYPE_AP:
@@ -99,7 +99,7 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
        if (!sta && ra && !is_multicast_ether_addr(ra)) {
                sta = sta_info_get(sdata, ra);
                if (sta)
-                       qos = get_sta_flags(sta) & WLAN_STA_WME;
+                       qos = test_sta_flag(sta, WLAN_STA_WME);
        }
        rcu_read_unlock();
 
index bac34394c05ef9262e41df4bc1ce2bda6dcb188f..af374fab1a12b247ccd40dea0c2a8994dd2dc732 100644 (file)
@@ -458,7 +458,7 @@ ieee80211_direct_probe(struct ieee80211_work *wk)
         */
        ieee80211_send_probe_req(sdata, NULL, wk->probe_auth.ssid,
                                 wk->probe_auth.ssid_len, NULL, 0,
-                                (u32) -1, true);
+                                (u32) -1, true, false);
 
        wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
        run_again(local, wk->timeout);
index 895e5fdf464a384914e2194ef154a9f3c259d79a..4047e29acb3b0f1eeac3d030c8ae7642399d80f1 100644 (file)
@@ -135,8 +135,10 @@ static void nci_init_req(struct nci_dev *ndev, unsigned long opt)
 
 static void nci_init_complete_req(struct nci_dev *ndev, unsigned long opt)
 {
-       struct nci_rf_disc_map_cmd cmd;
        struct nci_core_conn_create_cmd conn_cmd;
+       struct nci_rf_disc_map_cmd cmd;
+       struct disc_map_config *cfg = cmd.mapping_configs;
+       __u8 *num = &cmd.num_mapping_configs;
        int i;
 
        /* create static rf connection */
@@ -145,36 +147,30 @@ static void nci_init_complete_req(struct nci_dev *ndev, unsigned long opt)
        nci_send_cmd(ndev, NCI_OP_CORE_CONN_CREATE_CMD, 2, &conn_cmd);
 
        /* set rf mapping configurations */
-       cmd.num_mapping_configs = 0;
+       *num = 0;
 
        /* by default mapping is set to NCI_RF_INTERFACE_FRAME */
        for (i = 0; i < ndev->num_supported_rf_interfaces; i++) {
                if (ndev->supported_rf_interfaces[i] ==
                        NCI_RF_INTERFACE_ISO_DEP) {
-                       cmd.mapping_configs[cmd.num_mapping_configs]
-                       .rf_protocol = NCI_RF_PROTOCOL_ISO_DEP;
-                       cmd.mapping_configs[cmd.num_mapping_configs]
-                       .mode = NCI_DISC_MAP_MODE_BOTH;
-                       cmd.mapping_configs[cmd.num_mapping_configs]
-                       .rf_interface_type = NCI_RF_INTERFACE_ISO_DEP;
-                       cmd.num_mapping_configs++;
+                       cfg[*num].rf_protocol = NCI_RF_PROTOCOL_ISO_DEP;
+                       cfg[*num].mode = NCI_DISC_MAP_MODE_BOTH;
+                       cfg[*num].rf_interface_type = NCI_RF_INTERFACE_ISO_DEP;
+                       (*num)++;
                } else if (ndev->supported_rf_interfaces[i] ==
                        NCI_RF_INTERFACE_NFC_DEP) {
-                       cmd.mapping_configs[cmd.num_mapping_configs]
-                       .rf_protocol = NCI_RF_PROTOCOL_NFC_DEP;
-                       cmd.mapping_configs[cmd.num_mapping_configs]
-                       .mode = NCI_DISC_MAP_MODE_BOTH;
-                       cmd.mapping_configs[cmd.num_mapping_configs]
-                       .rf_interface_type = NCI_RF_INTERFACE_NFC_DEP;
-                       cmd.num_mapping_configs++;
+                       cfg[*num].rf_protocol = NCI_RF_PROTOCOL_NFC_DEP;
+                       cfg[*num].mode = NCI_DISC_MAP_MODE_BOTH;
+                       cfg[*num].rf_interface_type = NCI_RF_INTERFACE_NFC_DEP;
+                       (*num)++;
                }
 
-               if (cmd.num_mapping_configs == NCI_MAX_NUM_MAPPING_CONFIGS)
+               if (*num == NCI_MAX_NUM_MAPPING_CONFIGS)
                        break;
        }
 
        nci_send_cmd(ndev, NCI_OP_RF_DISCOVER_MAP_CMD,
-               (1 + (cmd.num_mapping_configs*sizeof(struct disc_map_config))),
+               (1 + ((*num)*sizeof(struct disc_map_config))),
                &cmd);
 }
 
@@ -365,8 +361,13 @@ static int nci_start_poll(struct nfc_dev *nfc_dev, __u32 protocols)
                return -EBUSY;
        }
 
+       if (ndev->target_active_prot) {
+               nfc_err("there is an active target");
+               return -EBUSY;
+       }
+
        if (test_bit(NCI_POLL_ACTIVE, &ndev->flags)) {
-               nfc_dbg("target already active, first deactivate...");
+               nfc_dbg("target is active, implicitly deactivate...");
 
                rc = nci_request(ndev, nci_rf_deactivate_req, 0,
                        msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT));
@@ -452,6 +453,7 @@ static int nci_data_exchange(struct nfc_dev *nfc_dev, __u32 target_idx,
                                                void *cb_context)
 {
        struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
+       int rc;
 
        nfc_dbg("entry, target_idx %d, len %d", target_idx, skb->len);
 
@@ -460,11 +462,18 @@ static int nci_data_exchange(struct nfc_dev *nfc_dev, __u32 target_idx,
                return -EINVAL;
        }
 
+       if (test_and_set_bit(NCI_DATA_EXCHANGE, &ndev->flags))
+               return -EBUSY;
+
        /* store cb and context to be used on receiving data */
        ndev->data_exchange_cb = cb;
        ndev->data_exchange_cb_context = cb_context;
 
-       return nci_send_data(ndev, ndev->conn_id, skb);
+       rc = nci_send_data(ndev, ndev->conn_id, skb);
+       if (rc)
+               clear_bit(NCI_DATA_EXCHANGE, &ndev->flags);
+
+       return rc;
 }
 
 static struct nfc_ops nci_nfc_ops = {
@@ -490,19 +499,19 @@ struct nci_dev *nci_allocate_device(struct nci_ops *ops,
                                        int tx_headroom,
                                        int tx_tailroom)
 {
-       struct nci_dev *ndev = NULL;
+       struct nci_dev *ndev;
 
        nfc_dbg("entry, supported_protocols 0x%x", supported_protocols);
 
        if (!ops->open || !ops->close || !ops->send)
-               goto exit;
+               return NULL;
 
        if (!supported_protocols)
-               goto exit;
+               return NULL;
 
        ndev = kzalloc(sizeof(struct nci_dev), GFP_KERNEL);
        if (!ndev)
-               goto exit;
+               return NULL;
 
        ndev->ops = ops;
        ndev->tx_headroom = tx_headroom;
@@ -517,13 +526,11 @@ struct nci_dev *nci_allocate_device(struct nci_ops *ops,
 
        nfc_set_drvdata(ndev->nfc_dev, ndev);
 
-       goto exit;
+       return ndev;
 
 free_exit:
        kfree(ndev);
-
-exit:
-       return ndev;
+       return NULL;
 }
 EXPORT_SYMBOL(nci_allocate_device);
 
index 141790ada4aa9e7f0269dc96c0f327998416fd1d..e5ed90fc1a9cf1bf6024e22bb2989644a48ed837 100644 (file)
@@ -54,6 +54,8 @@ void nci_data_exchange_complete(struct nci_dev *ndev,
                /* no waiting callback, free skb */
                kfree_skb(skb);
        }
+
+       clear_bit(NCI_DATA_EXCHANGE, &ndev->flags);
 }
 
 /* ----------------- NCI TX Data ----------------- */
index 8dd75352ab6cd851f8485f223908fc41e44c9671..96633f5cda4f790d3bae4ecdfa4f3a6435c5797c 100644 (file)
@@ -215,7 +215,7 @@ static void nci_rf_deactivate_ntf_packet(struct nci_dev *ndev,
        }
 
        /* complete the data exchange transaction, if exists */
-       if (ndev->data_exchange_cb)
+       if (test_bit(NCI_DATA_EXCHANGE, &ndev->flags))
                nci_data_exchange_complete(ndev, NULL, -EIO);
 }
 
index 796a4bdf8b0d8901f571cc81436ab0719abbab17..b9ec3061ed722c4dc58b526d0c545ce64ad5f163 100644 (file)
@@ -375,7 +375,8 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
                          struct ieee80211_channel *chan, bool offchan,
                          enum nl80211_channel_type channel_type,
                          bool channel_type_valid, unsigned int wait,
-                         const u8 *buf, size_t len, u64 *cookie);
+                         const u8 *buf, size_t len, bool no_cck,
+                         u64 *cookie);
 
 /* SME */
 int __cfg80211_connect(struct cfg80211_registered_device *rdev,
@@ -406,6 +407,7 @@ void cfg80211_sme_failed_assoc(struct wireless_dev *wdev);
 bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev);
 
 /* internal helpers */
+bool cfg80211_supported_cipher_suite(struct wiphy *wiphy, u32 cipher);
 int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
                                   struct key_params *params, int key_idx,
                                   bool pairwise, const u8 *mac_addr);
index 61adea540e02c0243869204322837a907a6f9204..21fc9702f81c355a772803f507aa8496801adb0e 100644 (file)
@@ -900,7 +900,8 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
                          struct ieee80211_channel *chan, bool offchan,
                          enum nl80211_channel_type channel_type,
                          bool channel_type_valid, unsigned int wait,
-                         const u8 *buf, size_t len, u64 *cookie)
+                         const u8 *buf, size_t len, bool no_cck,
+                         u64 *cookie)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        const struct ieee80211_mgmt *mgmt;
@@ -991,7 +992,7 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
        /* Transmit the Action frame as requested by user space */
        return rdev->ops->mgmt_tx(&rdev->wiphy, dev, chan, offchan,
                                  channel_type, channel_type_valid,
-                                 wait, buf, len, cookie);
+                                 wait, buf, len, no_cck, cookie);
 }
 
 bool cfg80211_rx_mgmt(struct net_device *dev, int freq, const u8 *buf,
index 3c6427abdf3425f353d929168218b076b711b6da..edf655aeea0015513f7fc79290b3f5cecd02bc81 100644 (file)
@@ -191,6 +191,12 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
                                         .len = IEEE80211_MAX_DATA_LEN },
        [NL80211_ATTR_ROAM_SUPPORT] = { .type = NLA_FLAG },
        [NL80211_ATTR_SCHED_SCAN_MATCH] = { .type = NLA_NESTED },
+       [NL80211_ATTR_TX_NO_CCK_RATE] = { .type = NLA_FLAG },
+       [NL80211_ATTR_TDLS_ACTION] = { .type = NLA_U8 },
+       [NL80211_ATTR_TDLS_DIALOG_TOKEN] = { .type = NLA_U8 },
+       [NL80211_ATTR_TDLS_OPERATION] = { .type = NLA_U8 },
+       [NL80211_ATTR_TDLS_SUPPORT] = { .type = NLA_FLAG },
+       [NL80211_ATTR_TDLS_EXTERNAL_SETUP] = { .type = NLA_FLAG },
 };
 
 /* policy for the key attributes */
@@ -731,9 +737,12 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
                NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_MESH_AUTH);
        if (dev->wiphy.flags & WIPHY_FLAG_AP_UAPSD)
                NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_AP_UAPSD);
-
        if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_FW_ROAM)
                NLA_PUT_FLAG(msg, NL80211_ATTR_ROAM_SUPPORT);
+       if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS)
+               NLA_PUT_FLAG(msg, NL80211_ATTR_TDLS_SUPPORT);
+       if (dev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP)
+               NLA_PUT_FLAG(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP);
 
        NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES,
                sizeof(u32) * dev->wiphy.n_cipher_suites,
@@ -876,6 +885,10 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
        }
        CMD(set_channel, SET_CHANNEL);
        CMD(set_wds_peer, SET_WDS_PEER);
+       if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) {
+               CMD(tdls_mgmt, TDLS_MGMT);
+               CMD(tdls_oper, TDLS_OPER);
+       }
        if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
                CMD(sched_scan_start, START_SCHED_SCAN);
 
@@ -1235,6 +1248,11 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
                        goto bad_res;
                }
 
+               if (!netdev) {
+                       result = -EINVAL;
+                       goto bad_res;
+               }
+
                nla_for_each_nested(nl_txq_params,
                                    info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS],
                                    rem_txq_params) {
@@ -1247,6 +1265,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
                                goto bad_res;
 
                        result = rdev->ops->set_txq_params(&rdev->wiphy,
+                                                          netdev,
                                                           &txq_params);
                        if (result)
                                goto bad_res;
@@ -2511,18 +2530,25 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
                break;
        case NL80211_IFTYPE_P2P_CLIENT:
        case NL80211_IFTYPE_STATION:
-               /* disallow everything but AUTHORIZED flag */
+               /* disallow things sta doesn't support */
                if (params.plink_action)
                        err = -EINVAL;
                if (params.vlan)
                        err = -EINVAL;
-               if (params.supported_rates)
+               if (params.supported_rates &&
+                   !(params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)))
                        err = -EINVAL;
                if (params.ht_capa)
                        err = -EINVAL;
                if (params.listen_interval >= 0)
                        err = -EINVAL;
-               if (params.sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED))
+               if (params.sta_flags_mask &
+                               ~(BIT(NL80211_STA_FLAG_AUTHORIZED) |
+                                 BIT(NL80211_STA_FLAG_TDLS_PEER)))
+                       err = -EINVAL;
+               /* can't change the TDLS bit */
+               if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) &&
+                   (params.sta_flags_mask & BIT(NL80211_STA_FLAG_TDLS_PEER)))
                        err = -EINVAL;
                break;
        case NL80211_IFTYPE_MESH_POINT:
@@ -2613,7 +2639,7 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
 
        /* parse WME attributes if sta is WME capable */
        if ((rdev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) &&
-           (params.sta_flags_set & NL80211_STA_FLAG_WME) &&
+           (params.sta_flags_set & BIT(NL80211_STA_FLAG_WME)) &&
            info->attrs[NL80211_ATTR_STA_WME]) {
                struct nlattr *tb[NL80211_STA_WME_MAX + 1];
                struct nlattr *nla;
@@ -2636,12 +2662,25 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
 
                if (params.max_sp & ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK)
                        return -EINVAL;
+
+               params.sta_modify_mask |= STATION_PARAM_APPLY_UAPSD;
        }
 
        if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
            dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
            dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT &&
-           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO &&
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION)
+               return -EINVAL;
+
+       /*
+        * Only managed stations can add TDLS peers, and only when the
+        * wiphy supports external TDLS setup.
+        */
+       if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION &&
+           !((params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) &&
+             (rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) &&
+             (rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP)))
                return -EINVAL;
 
        err = get_vlan(info, rdev, &params.vlan);
@@ -3620,6 +3659,9 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
                }
        }
 
+       request->no_cck =
+               nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
+
        request->dev = dev;
        request->wiphy = &rdev->wiphy;
 
@@ -4126,22 +4168,6 @@ static bool nl80211_valid_wpa_versions(u32 wpa_versions)
                                  NL80211_WPA_VERSION_2));
 }
 
-static bool nl80211_valid_akm_suite(u32 akm)
-{
-       return akm == WLAN_AKM_SUITE_8021X ||
-               akm == WLAN_AKM_SUITE_PSK;
-}
-
-static bool nl80211_valid_cipher_suite(u32 cipher)
-{
-       return cipher == WLAN_CIPHER_SUITE_WEP40 ||
-               cipher == WLAN_CIPHER_SUITE_WEP104 ||
-               cipher == WLAN_CIPHER_SUITE_TKIP ||
-               cipher == WLAN_CIPHER_SUITE_CCMP ||
-               cipher == WLAN_CIPHER_SUITE_AES_CMAC;
-}
-
-
 static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *rdev = info->user_ptr[0];
@@ -4274,7 +4300,8 @@ static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
                memcpy(settings->ciphers_pairwise, data, len);
 
                for (i = 0; i < settings->n_ciphers_pairwise; i++)
-                       if (!nl80211_valid_cipher_suite(
+                       if (!cfg80211_supported_cipher_suite(
+                                       &rdev->wiphy,
                                        settings->ciphers_pairwise[i]))
                                return -EINVAL;
        }
@@ -4282,7 +4309,8 @@ static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
        if (info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]) {
                settings->cipher_group =
                        nla_get_u32(info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]);
-               if (!nl80211_valid_cipher_suite(settings->cipher_group))
+               if (!cfg80211_supported_cipher_suite(&rdev->wiphy,
+                                                    settings->cipher_group))
                        return -EINVAL;
        }
 
@@ -4295,7 +4323,7 @@ static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
 
        if (info->attrs[NL80211_ATTR_AKM_SUITES]) {
                void *data;
-               int len, i;
+               int len;
 
                data = nla_data(info->attrs[NL80211_ATTR_AKM_SUITES]);
                len = nla_len(info->attrs[NL80211_ATTR_AKM_SUITES]);
@@ -4304,11 +4332,10 @@ static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
                if (len % sizeof(u32))
                        return -EINVAL;
 
-               memcpy(settings->akm_suites, data, len);
+               if (settings->n_akm_suites > NL80211_MAX_NR_AKM_SUITES)
+                       return -EINVAL;
 
-               for (i = 0; i < settings->n_ciphers_pairwise; i++)
-                       if (!nl80211_valid_akm_suite(settings->akm_suites[i]))
-                               return -EINVAL;
+               memcpy(settings->akm_suites, data, len);
        }
 
        return 0;
@@ -4969,6 +4996,57 @@ static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info)
        return rdev->ops->flush_pmksa(&rdev->wiphy, dev);
 }
 
+static int nl80211_tdls_mgmt(struct sk_buff *skb, struct genl_info *info)
+{
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
+       u8 action_code, dialog_token;
+       u16 status_code;
+       u8 *peer;
+
+       if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) ||
+           !rdev->ops->tdls_mgmt)
+               return -EOPNOTSUPP;
+
+       if (!info->attrs[NL80211_ATTR_TDLS_ACTION] ||
+           !info->attrs[NL80211_ATTR_STATUS_CODE] ||
+           !info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN] ||
+           !info->attrs[NL80211_ATTR_IE] ||
+           !info->attrs[NL80211_ATTR_MAC])
+               return -EINVAL;
+
+       peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
+       action_code = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_ACTION]);
+       status_code = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]);
+       dialog_token = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN]);
+
+       return rdev->ops->tdls_mgmt(&rdev->wiphy, dev, peer, action_code,
+                                   dialog_token, status_code,
+                                   nla_data(info->attrs[NL80211_ATTR_IE]),
+                                   nla_len(info->attrs[NL80211_ATTR_IE]));
+}
+
+static int nl80211_tdls_oper(struct sk_buff *skb, struct genl_info *info)
+{
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
+       enum nl80211_tdls_operation operation;
+       u8 *peer;
+
+       if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) ||
+           !rdev->ops->tdls_oper)
+               return -EOPNOTSUPP;
+
+       if (!info->attrs[NL80211_ATTR_TDLS_OPERATION] ||
+           !info->attrs[NL80211_ATTR_MAC])
+               return -EINVAL;
+
+       operation = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_OPERATION]);
+       peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+       return rdev->ops->tdls_oper(&rdev->wiphy, dev, peer, operation);
+}
+
 static int nl80211_remain_on_channel(struct sk_buff *skb,
                                     struct genl_info *info)
 {
@@ -5189,6 +5267,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
        struct sk_buff *msg;
        unsigned int wait = 0;
        bool offchan;
+       bool no_cck;
 
        if (!info->attrs[NL80211_ATTR_FRAME] ||
            !info->attrs[NL80211_ATTR_WIPHY_FREQ])
@@ -5225,6 +5304,8 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
 
        offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK];
 
+       no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
+
        freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
        chan = rdev_freq_to_chan(rdev, freq, channel_type);
        if (chan == NULL)
@@ -5245,7 +5326,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
                                    channel_type_valid, wait,
                                    nla_data(info->attrs[NL80211_ATTR_FRAME]),
                                    nla_len(info->attrs[NL80211_ATTR_FRAME]),
-                                   &cookie);
+                                   no_cck, &cookie);
        if (err)
                goto free_msg;
 
@@ -6281,6 +6362,22 @@ static struct genl_ops nl80211_ops[] = {
                .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
                                  NL80211_FLAG_NEED_RTNL,
        },
+       {
+               .cmd = NL80211_CMD_TDLS_MGMT,
+               .doit = nl80211_tdls_mgmt,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
+       },
+       {
+               .cmd = NL80211_CMD_TDLS_OPER,
+               .doit = nl80211_tdls_oper,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
+       },
 };
 
 static struct genl_multicast_group nl80211_mlme_mcgrp = {
index 39dbf4ad7ca17cdca7581355b5a5b0aaa6221b48..2f178f73943f5b3aa85e469add4884a1a1fb4ee0 100644 (file)
@@ -151,12 +151,19 @@ void ieee80211_set_bitrate_flags(struct wiphy *wiphy)
                        set_mandatory_flags_band(wiphy->bands[band], band);
 }
 
+bool cfg80211_supported_cipher_suite(struct wiphy *wiphy, u32 cipher)
+{
+       int i;
+       for (i = 0; i < wiphy->n_cipher_suites; i++)
+               if (cipher == wiphy->cipher_suites[i])
+                       return true;
+       return false;
+}
+
 int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
                                   struct key_params *params, int key_idx,
                                   bool pairwise, const u8 *mac_addr)
 {
-       int i;
-
        if (key_idx > 5)
                return -EINVAL;
 
@@ -226,10 +233,7 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
                }
        }
 
-       for (i = 0; i < rdev->wiphy.n_cipher_suites; i++)
-               if (params->cipher == rdev->wiphy.cipher_suites[i])
-                       break;
-       if (i == rdev->wiphy.n_cipher_suites)
+       if (!cfg80211_supported_cipher_suite(&rdev->wiphy, params->cipher))
                return -EINVAL;
 
        return 0;
@@ -392,8 +396,9 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
                }
                break;
        case cpu_to_le16(0):
-               if (iftype != NL80211_IFTYPE_ADHOC)
-                       return -1;
+               if (iftype != NL80211_IFTYPE_ADHOC &&
+                   iftype != NL80211_IFTYPE_STATION)
+                               return -1;
                break;
        }
 
This page took 0.181513 seconds and 5 git commands to generate.