]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - net/mac80211/main.c
mac80211: Add capability to enable/disable beaconing
[linux-2.6-omap-h63xx.git] / net / mac80211 / main.c
index 6d8710327d144a298aabe7350cbd72e97a19d327..8d5c19e4a1bcb04ad734cbde093f1bb134d06b05 100644 (file)
@@ -168,7 +168,6 @@ int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed)
                return 0;
 
        memset(&conf, 0, sizeof(conf));
-       conf.changed = changed;
 
        if (sdata->vif.type == NL80211_IFTYPE_STATION ||
            sdata->vif.type == NL80211_IFTYPE_ADHOC)
@@ -176,16 +175,57 @@ int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed)
        else if (sdata->vif.type == NL80211_IFTYPE_AP)
                conf.bssid = sdata->dev->dev_addr;
        else if (ieee80211_vif_is_mesh(&sdata->vif)) {
-               u8 zero[ETH_ALEN] = { 0 };
+               static const u8 zero[ETH_ALEN] = { 0 };
                conf.bssid = zero;
        } else {
                WARN_ON(1);
                return -EINVAL;
        }
 
+       switch (sdata->vif.type) {
+       case NL80211_IFTYPE_AP:
+       case NL80211_IFTYPE_ADHOC:
+       case NL80211_IFTYPE_MESH_POINT:
+               break;
+       default:
+               /* do not warn to simplify caller in scan.c */
+               changed &= ~IEEE80211_IFCC_BEACON_ENABLED;
+               if (WARN_ON(changed & IEEE80211_IFCC_BEACON))
+                       return -EINVAL;
+               changed &= ~IEEE80211_IFCC_BEACON;
+               break;
+       }
+
+       if (changed & IEEE80211_IFCC_BEACON_ENABLED) {
+               if (local->sw_scanning) {
+                       conf.enable_beacon = false;
+               } else {
+                       /*
+                        * Beacon should be enabled, but AP mode must
+                        * check whether there is a beacon configured.
+                        */
+                       switch (sdata->vif.type) {
+                       case NL80211_IFTYPE_AP:
+                               conf.enable_beacon =
+                                       !!rcu_dereference(sdata->u.ap.beacon);
+                               break;
+                       case NL80211_IFTYPE_ADHOC:
+                       case NL80211_IFTYPE_MESH_POINT:
+                               conf.enable_beacon = true;
+                               break;
+                       default:
+                               /* not reached */
+                               WARN_ON(1);
+                               break;
+                       }
+               }
+       }
+
        if (WARN_ON(!conf.bssid && (changed & IEEE80211_IFCC_BSSID)))
                return -EINVAL;
 
+       conf.changed = changed;
+
        return local->ops->config_interface(local_to_hw(local),
                                            &sdata->vif, &conf);
 }
@@ -195,46 +235,35 @@ 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;
+       enum nl80211_channel_type channel_type;
 
        might_sleep();
 
        if (local->sw_scanning) {
                chan = local->scan_channel;
-               sec_chan_offset = NL80211_SEC_CHAN_NO_HT;
+               channel_type = NL80211_CHAN_NO_HT;
        } else {
                chan = local->oper_channel;
-               sec_chan_offset = local->oper_sec_chan_offset;
+               channel_type = local->oper_channel_type;
        }
 
        if (chan != local->hw.conf.channel ||
-           sec_chan_offset != local->hw.conf.ht.sec_chan_offset) {
+           channel_type != local->hw.conf.channel_type) {
                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;
-               }
+               local->hw.conf.channel_type = channel_type;
                changed |= IEEE80211_CONF_CHANGE_CHANNEL;
        }
 
-       if (!local->hw.conf.power_level)
+       if (local->sw_scanning)
                power = chan->max_power;
        else
-               power = min(chan->max_power, local->hw.conf.power_level);
+               power = local->power_constr_level ?
+                       (chan->max_power - local->power_constr_level) :
+                       chan->max_power;
+
+       if (local->user_power_level)
+               power = min(power, local->user_power_level);
+
        if (local->hw.conf.power_level != power) {
                changed |= IEEE80211_CONF_CHANGE_POWER;
                local->hw.conf.power_level = power;
@@ -348,7 +377,8 @@ static void ieee80211_tasklet_handler(unsigned long data)
                        dev_kfree_skb(skb);
                        break ;
                default:
-                       WARN_ON(1);
+                       WARN(1, "mac80211: Packet is of unknown type %d\n",
+                            skb->pkt_type);
                        dev_kfree_skb(skb);
                        break;
                }
@@ -731,8 +761,17 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 
        spin_lock_init(&local->key_lock);
 
+       spin_lock_init(&local->queue_stop_reason_lock);
+
        INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work);
 
+       INIT_WORK(&local->dynamic_ps_enable_work,
+                 ieee80211_dynamic_ps_enable_work);
+       INIT_WORK(&local->dynamic_ps_disable_work,
+                 ieee80211_dynamic_ps_disable_work);
+       setup_timer(&local->dynamic_ps_timer,
+                   ieee80211_dynamic_ps_timer, (unsigned long) local);
+
        sta_info_init(local);
 
        tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending,