mac80211: remove WARN_ON() from ieee80211_hw_config
[pandora-kernel.git] / net / mac80211 / main.c
index ae62ad4..df7e9a8 100644 (file)
@@ -41,6 +41,8 @@
  */
 struct ieee80211_tx_status_rtap_hdr {
        struct ieee80211_radiotap_header hdr;
+       u8 rate;
+       u8 padding_for_rate;
        __le16 tx_flags;
        u8 data_retries;
 } __attribute__ ((packed));
@@ -169,19 +171,13 @@ int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed)
        conf.changed = changed;
 
        if (sdata->vif.type == NL80211_IFTYPE_STATION ||
-           sdata->vif.type == NL80211_IFTYPE_ADHOC) {
+           sdata->vif.type == NL80211_IFTYPE_ADHOC)
                conf.bssid = sdata->u.sta.bssid;
-               conf.ssid = sdata->u.sta.ssid;
-               conf.ssid_len = sdata->u.sta.ssid_len;
-       } else if (sdata->vif.type == NL80211_IFTYPE_AP) {
+       else if (sdata->vif.type == NL80211_IFTYPE_AP)
                conf.bssid = sdata->dev->dev_addr;
-               conf.ssid = sdata->u.ap.ssid;
-               conf.ssid_len = sdata->u.ap.ssid_len;
-       } else if (ieee80211_vif_is_mesh(&sdata->vif)) {
+       else if (ieee80211_vif_is_mesh(&sdata->vif)) {
                u8 zero[ETH_ALEN] = { 0 };
                conf.bssid = zero;
-               conf.ssid = zero;
-               conf.ssid_len = 0;
        } else {
                WARN_ON(1);
                return -EINVAL;
@@ -190,136 +186,80 @@ int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed)
        if (WARN_ON(!conf.bssid && (changed & IEEE80211_IFCC_BSSID)))
                return -EINVAL;
 
-       if (WARN_ON(!conf.ssid && (changed & IEEE80211_IFCC_SSID)))
-               return -EINVAL;
-
        return local->ops->config_interface(local_to_hw(local),
                                            &sdata->vif, &conf);
 }
 
-int ieee80211_hw_config(struct ieee80211_local *local)
+int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
 {
        struct ieee80211_channel *chan;
        int ret = 0;
+       int power;
+       enum nl80211_sec_chan_offset sec_chan_offset;
+
+       might_sleep();
 
-       if (local->sw_scanning)
+       if (local->sw_scanning) {
                chan = local->scan_channel;
-       else
+               sec_chan_offset = NL80211_SEC_CHAN_NO_HT;
+       } else {
                chan = local->oper_channel;
+               sec_chan_offset = local->oper_sec_chan_offset;
+       }
 
-       local->hw.conf.channel = chan;
+       if (chan != local->hw.conf.channel ||
+           sec_chan_offset != local->hw.conf.ht.sec_chan_offset) {
+               local->hw.conf.channel = chan;
+               switch (sec_chan_offset) {
+               case NL80211_SEC_CHAN_NO_HT:
+                       local->hw.conf.ht.enabled = false;
+                       local->hw.conf.ht.sec_chan_offset = 0;
+                       break;
+               case NL80211_SEC_CHAN_DISABLED:
+                       local->hw.conf.ht.enabled = true;
+                       local->hw.conf.ht.sec_chan_offset = 0;
+                       break;
+               case NL80211_SEC_CHAN_BELOW:
+                       local->hw.conf.ht.enabled = true;
+                       local->hw.conf.ht.sec_chan_offset = -1;
+                       break;
+               case NL80211_SEC_CHAN_ABOVE:
+                       local->hw.conf.ht.enabled = true;
+                       local->hw.conf.ht.sec_chan_offset = 1;
+                       break;
+               }
+               changed |= IEEE80211_CONF_CHANGE_CHANNEL;
+       }
 
        if (!local->hw.conf.power_level)
-               local->hw.conf.power_level = chan->max_power;
+               power = chan->max_power;
        else
-               local->hw.conf.power_level = min(chan->max_power,
-                                              local->hw.conf.power_level);
-
-       local->hw.conf.max_antenna_gain = chan->max_antenna_gain;
-
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       printk(KERN_DEBUG "%s: HW CONFIG: freq=%d\n",
-              wiphy_name(local->hw.wiphy), chan->center_freq);
-#endif
-
-       if (local->open_count)
-               ret = local->ops->config(local_to_hw(local), &local->hw.conf);
-
-       return ret;
-}
-
-/**
- * ieee80211_handle_ht should be used only after legacy configuration
- * has been determined namely band, as ht configuration depends upon
- * the hardware's HT abilities for a _specific_ band.
- */
-u32 ieee80211_handle_ht(struct ieee80211_local *local, int enable_ht,
-                          struct ieee80211_ht_info *req_ht_cap,
-                          struct ieee80211_ht_bss_info *req_bss_cap)
-{
-       struct ieee80211_conf *conf = &local->hw.conf;
-       struct ieee80211_supported_band *sband;
-       struct ieee80211_ht_info ht_conf;
-       struct ieee80211_ht_bss_info ht_bss_conf;
-       u32 changed = 0;
-       int i;
-       u8 max_tx_streams = IEEE80211_HT_CAP_MAX_STREAMS;
-       u8 tx_mcs_set_cap;
-
-       sband = local->hw.wiphy->bands[conf->channel->band];
-
-       memset(&ht_conf, 0, sizeof(struct ieee80211_ht_info));
-       memset(&ht_bss_conf, 0, sizeof(struct ieee80211_ht_bss_info));
-
-       /* HT is not supported */
-       if (!sband->ht_info.ht_supported) {
-               conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
-               goto out;
+               power = min(chan->max_power, local->hw.conf.power_level);
+       if (local->hw.conf.power_level != power) {
+               changed |= IEEE80211_CONF_CHANGE_POWER;
+               local->hw.conf.power_level = power;
        }
 
-       /* disable HT */
-       if (!enable_ht) {
-               if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)
-                       changed |= BSS_CHANGED_HT;
-               conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
-               conf->ht_conf.ht_supported = 0;
-               goto out;
+       if (changed && local->open_count) {
+               ret = local->ops->config(local_to_hw(local), changed);
+               /*
+                * Goal:
+                * HW reconfiguration should never fail, the driver has told
+                * us what it can support so it should live up to that promise.
+                *
+                * Current status:
+                * rfkill is not integrated with mac80211 and a
+                * configuration command can thus fail if hardware rfkill
+                * is enabled
+                *
+                * FIXME: integrate rfkill with mac80211 and then add this
+                * WARN_ON() back
+                *
+                */
+               /* WARN_ON(ret); */
        }
 
-
-       if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE))
-               changed |= BSS_CHANGED_HT;
-
-       conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE;
-       ht_conf.ht_supported = 1;
-
-       ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap;
-       ht_conf.cap &= ~(IEEE80211_HT_CAP_SM_PS);
-       ht_conf.cap |= sband->ht_info.cap & IEEE80211_HT_CAP_SM_PS;
-       ht_bss_conf.primary_channel = req_bss_cap->primary_channel;
-       ht_bss_conf.bss_cap = req_bss_cap->bss_cap;
-       ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode;
-
-       ht_conf.ampdu_factor = req_ht_cap->ampdu_factor;
-       ht_conf.ampdu_density = req_ht_cap->ampdu_density;
-
-       /* Bits 96-100 */
-       tx_mcs_set_cap = sband->ht_info.supp_mcs_set[12];
-
-       /* configure suppoerted Tx MCS according to requested MCS
-        * (based in most cases on Rx capabilities of peer) and self
-        * Tx MCS capabilities (as defined by low level driver HW
-        * Tx capabilities) */
-       if (!(tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_DEFINED))
-               goto check_changed;
-
-       /* Counting from 0 therfore + 1 */
-       if (tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_RX_DIFF)
-               max_tx_streams = ((tx_mcs_set_cap &
-                               IEEE80211_HT_CAP_MCS_TX_STREAMS) >> 2) + 1;
-
-       for (i = 0; i < max_tx_streams; i++)
-               ht_conf.supp_mcs_set[i] =
-                       sband->ht_info.supp_mcs_set[i] &
-                                       req_ht_cap->supp_mcs_set[i];
-
-       if (tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_UEQM)
-               for (i = IEEE80211_SUPP_MCS_SET_UEQM;
-                    i < IEEE80211_SUPP_MCS_SET_LEN; i++)
-                       ht_conf.supp_mcs_set[i] =
-                               sband->ht_info.supp_mcs_set[i] &
-                                       req_ht_cap->supp_mcs_set[i];
-
-check_changed:
-       /* if bss configuration changed store the new one */
-       if (memcmp(&conf->ht_conf, &ht_conf, sizeof(ht_conf)) ||
-           memcmp(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf))) {
-               changed |= BSS_CHANGED_HT;
-               memcpy(&conf->ht_conf, &ht_conf, sizeof(ht_conf));
-               memcpy(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf));
-       }
-out:
-       return changed;
+       return ret;
 }
 
 void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
@@ -336,15 +276,18 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
        if (local->ops->bss_info_changed)
                local->ops->bss_info_changed(local_to_hw(local),
                                             &sdata->vif,
-                                            &sdata->bss_conf,
+                                            &sdata->vif.bss_conf,
                                             changed);
 }
 
 u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata)
 {
-       sdata->bss_conf.use_cts_prot = 0;
-       sdata->bss_conf.use_short_preamble = 0;
-       return BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_ERP_PREAMBLE;
+       sdata->vif.bss_conf.use_cts_prot = false;
+       sdata->vif.bss_conf.use_short_preamble = false;
+       sdata->vif.bss_conf.use_short_slot = false;
+       return BSS_CHANGED_ERP_CTS_PROT |
+              BSS_CHANGED_ERP_PREAMBLE |
+              BSS_CHANGED_ERP_SLOT;
 }
 
 void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
@@ -466,8 +409,6 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
                                            struct sta_info *sta,
                                            struct sk_buff *skb)
 {
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-
        sta->tx_filtered_count++;
 
        /*
@@ -514,10 +455,9 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
                return;
        }
 
-       if (!test_sta_flags(sta, WLAN_STA_PS) &&
-           !(info->flags & IEEE80211_TX_CTL_REQUEUE)) {
+       if (!test_sta_flags(sta, WLAN_STA_PS) && !skb->requeue) {
                /* Software retry the packet once */
-               info->flags |= IEEE80211_TX_CTL_REQUEUE;
+               skb->requeue = 1;
                ieee80211_remove_tx_extra(local, sta->key, skb);
                dev_queue_xmit(skb);
                return;
@@ -547,13 +487,28 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
        struct ieee80211_sub_if_data *sdata;
        struct net_device *prev_dev = NULL;
        struct sta_info *sta;
+       int retry_count = -1, i;
+
+       for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
+               /* the HW cannot have attempted that rate */
+               if (i >= hw->max_rates) {
+                       info->status.rates[i].idx = -1;
+                       info->status.rates[i].count = 0;
+               }
+
+               retry_count += info->status.rates[i].count;
+       }
+       if (retry_count < 0)
+               retry_count = 0;
 
        rcu_read_lock();
 
+       sband = local->hw.wiphy->bands[info->band];
+
        sta = sta_info_get(local, hdr->addr1);
 
        if (sta) {
-               if (info->status.excessive_retries &&
+               if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
                    test_sta_flags(sta, WLAN_STA_PS)) {
                        /*
                         * The STA is in power save mode, so assume
@@ -584,12 +539,11 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
                        rcu_read_unlock();
                        return;
                } else {
-                       if (info->status.excessive_retries)
+                       if (!(info->flags & IEEE80211_TX_STAT_ACK))
                                sta->tx_retry_failed++;
-                       sta->tx_retry_count += info->status.retry_count;
+                       sta->tx_retry_count += retry_count;
                }
 
-               sband = local->hw.wiphy->bands[info->band];
                rate_control_tx_status(local, sband, sta, skb);
        }
 
@@ -610,9 +564,9 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
                        local->dot11TransmittedFrameCount++;
                        if (is_multicast_ether_addr(hdr->addr1))
                                local->dot11MulticastTransmittedFrameCount++;
-                       if (info->status.retry_count > 0)
+                       if (retry_count > 0)
                                local->dot11RetryCount++;
-                       if (info->status.retry_count > 1)
+                       if (retry_count > 1)
                                local->dot11MultipleRetryCount++;
                }
 
@@ -656,19 +610,30 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
        rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr));
        rthdr->hdr.it_present =
                cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) |
-                           (1 << IEEE80211_RADIOTAP_DATA_RETRIES));
+                           (1 << IEEE80211_RADIOTAP_DATA_RETRIES) |
+                           (1 << IEEE80211_RADIOTAP_RATE));
 
        if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
            !is_multicast_ether_addr(hdr->addr1))
                rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL);
 
-       if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) &&
-           (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT))
+       /*
+        * XXX: Once radiotap gets the bitmap reset thing the vendor
+        *      extensions proposal contains, we can actually report
+        *      the whole set of tries we did.
+        */
+       if ((info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
+           (info->status.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT))
                rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS);
-       else if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
+       else if (info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
                rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS);
+       if (info->status.rates[0].idx >= 0 &&
+           !(info->status.rates[0].flags & IEEE80211_TX_RC_MCS))
+               rthdr->rate = sband->bitrates[
+                               info->status.rates[0].idx].bitrate / 5;
 
-       rthdr->data_retries = info->status.retry_count;
+       /* for now report the total retry_count */
+       rthdr->data_retries = retry_count;
 
        /* XXX: is this sufficient for BPF? */
        skb_set_mac_header(skb, 0);
@@ -753,13 +718,14 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        BUG_ON(!ops->configure_filter);
        local->ops = ops;
 
-       local->hw.queues = 1; /* default */
-
+       /* set up some defaults */
+       local->hw.queues = 1;
+       local->hw.max_rates = 1;
        local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
        local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD;
-       local->short_retry_limit = 7;
-       local->long_retry_limit = 4;
-       local->hw.conf.radio_enabled = 1;
+       local->hw.conf.long_frame_max_tx_count = 4;
+       local->hw.conf.short_frame_max_tx_count = 7;
+       local->hw.conf.radio_enabled = true;
 
        INIT_LIST_HEAD(&local->interfaces);
 
@@ -788,7 +754,6 @@ EXPORT_SYMBOL(ieee80211_alloc_hw);
 int ieee80211_register_hw(struct ieee80211_hw *hw)
 {
        struct ieee80211_local *local = hw_to_local(hw);
-       const char *name;
        int result;
        enum ieee80211_band band;
        struct net_device *mdev;
@@ -853,8 +818,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        mdev->header_ops = &ieee80211_header_ops;
        mdev->set_multicast_list = ieee80211_master_set_multicast_list;
 
-       name = wiphy_dev(local->hw.wiphy)->driver->name;
-       local->hw.workqueue = create_freezeable_workqueue(name);
+       local->hw.workqueue =
+               create_freezeable_workqueue(wiphy_name(local->hw.wiphy));
        if (!local->hw.workqueue) {
                result = -ENOMEM;
                goto fail_workqueue;
@@ -1013,7 +978,7 @@ static int __init ieee80211_init(void)
 
        BUILD_BUG_ON(sizeof(struct ieee80211_tx_info) > sizeof(skb->cb));
        BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, driver_data) +
-                    IEEE80211_TX_INFO_DRIVER_DATA_SIZE > sizeof(skb->cb));
+                    IEEE80211_TX_INFO_DRIVER_DATA_SIZE > sizeof(skb->cb));
 
        ret = rc80211_minstrel_init();
        if (ret)