]> 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 24b14363d6e70c77766c06946ba5407de122dc89..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);
 }
@@ -208,26 +248,22 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
        }
 
        if (chan != local->hw.conf.channel ||
-           channel_type != local->hw.conf.ht.channel_type) {
+           channel_type != local->hw.conf.channel_type) {
                local->hw.conf.channel = chan;
-               local->hw.conf.ht.channel_type = channel_type;
-               switch (channel_type) {
-               case NL80211_CHAN_NO_HT:
-                       local->hw.conf.ht.enabled = false;
-                       break;
-               case NL80211_CHAN_HT20:
-               case NL80211_CHAN_HT40MINUS:
-               case NL80211_CHAN_HT40PLUS:
-                       local->hw.conf.ht.enabled = true;
-                       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;