mac80211: revamp beacon configuration
authorJohannes Berg <johannes@sipsolutions.net>
Wed, 9 Jul 2008 12:40:37 +0000 (14:40 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 14 Jul 2008 18:30:07 +0000 (14:30 -0400)
This patch changes mac80211's beacon configuration handling
to never pass skbs to the driver directly but rather always
require the driver to use ieee80211_beacon_get(). Additionally,
it introduces "change flags" on the config_interface() call
to enable drivers to figure out what is changing. Finally, it
removes the beacon_update() driver callback in favour of
having IBSS beacon delivered by ieee80211_beacon_get() as well.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
21 files changed:
drivers/net/wireless/ath5k/base.c
drivers/net/wireless/b43/main.c
drivers/net/wireless/b43legacy/main.c
drivers/net/wireless/iwlwifi/iwl3945-base.c
drivers/net/wireless/iwlwifi/iwl4965-base.c
drivers/net/wireless/rt2x00/rt2400pci.c
drivers/net/wireless/rt2x00/rt2500pci.c
drivers/net/wireless/rt2x00/rt2500usb.c
drivers/net/wireless/rt2x00/rt2x00.h
drivers/net/wireless/rt2x00/rt2x00dev.c
drivers/net/wireless/rt2x00/rt2x00mac.c
drivers/net/wireless/rt2x00/rt61pci.c
drivers/net/wireless/rt2x00/rt73usb.c
drivers/net/wireless/zd1211rw/zd_mac.c
include/net/mac80211.h
net/mac80211/cfg.c
net/mac80211/ieee80211_i.h
net/mac80211/main.c
net/mac80211/mlme.c
net/mac80211/tx.c
net/mac80211/wext.c

index a43e9b2..217d506 100644 (file)
@@ -207,7 +207,6 @@ static struct ieee80211_ops ath5k_hw_ops = {
        .get_tx_stats   = ath5k_get_tx_stats,
        .get_tsf        = ath5k_get_tsf,
        .reset_tsf      = ath5k_reset_tsf,
-       .beacon_update  = ath5k_beacon_update,
 };
 
 /*
@@ -2785,6 +2784,18 @@ ath5k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                 * a clean way of letting us retrieve this yet. */
                ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
        }
+
+       if (conf->changed & IEEE80211_IFCC_BEACON &&
+           vif->type == IEEE80211_IF_TYPE_IBSS) {
+               struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
+               if (!beacon) {
+                       ret = -ENOMEM;
+                       goto unlock;
+               }
+               /* call old handler for now */
+               ath5k_beacon_update(hw, beacon);
+       }
+
        mutex_unlock(&sc->lock);
 
        return ath5k_reset(hw);
index 9d2eb27..381dbd3 100644 (file)
@@ -1675,14 +1675,24 @@ static void b43_beacon_update_trigger_work(struct work_struct *work)
 
 /* Asynchronously update the packet templates in template RAM.
  * Locking: Requires wl->irq_lock to be locked. */
-static void b43_update_templates(struct b43_wl *wl, struct sk_buff *beacon)
+static void b43_update_templates(struct b43_wl *wl)
 {
+       struct sk_buff *beacon;
+
        /* This is the top half of the ansynchronous beacon update.
         * The bottom half is the beacon IRQ.
         * Beacon update must be asynchronous to avoid sending an
         * invalid beacon. This can happen for example, if the firmware
         * transmits a beacon while we are updating it. */
 
+       /* We could modify the existing beacon and set the aid bit in
+        * the TIM field, but that would probably require resizing and
+        * moving of data within the beacon template.
+        * Simply request a new beacon and let mac80211 do the hard work. */
+       beacon = ieee80211_beacon_get(wl->hw, wl->vif);
+       if (unlikely(!beacon))
+               return;
+
        if (wl->current_beacon)
                dev_kfree_skb_any(wl->current_beacon);
        wl->current_beacon = beacon;
@@ -3645,10 +3655,14 @@ static int b43_op_config_interface(struct ieee80211_hw *hw,
        if (b43_status(dev) >= B43_STAT_INITIALIZED) {
                if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) ||
                    b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT)) {
-                       B43_WARN_ON(conf->type != wl->if_type);
-                       b43_set_ssid(dev, conf->ssid, conf->ssid_len);
-                       if (conf->beacon)
-                               b43_update_templates(wl, conf->beacon);
+                       B43_WARN_ON(vif->type != wl->if_type);
+                       if (conf->changed & IEEE80211_IFCC_SSID)
+                               b43_set_ssid(dev, conf->ssid, conf->ssid_len);
+                       if (conf->changed & IEEE80211_IFCC_BEACON)
+                               b43_update_templates(wl);
+               } else if (b43_is_mode(wl, IEEE80211_IF_TYPE_IBSS)) {
+                       if (conf->changed & IEEE80211_IFCC_BEACON)
+                               b43_update_templates(wl);
                }
                b43_write_mac_bssid_templates(dev);
        }
@@ -4336,31 +4350,10 @@ out_unlock:
 static int b43_op_beacon_set_tim(struct ieee80211_hw *hw, int aid, int set)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
-       struct sk_buff *beacon;
-       unsigned long flags;
-
-       /* We could modify the existing beacon and set the aid bit in
-        * the TIM field, but that would probably require resizing and
-        * moving of data within the beacon template.
-        * Simply request a new beacon and let mac80211 do the hard work. */
-       beacon = ieee80211_beacon_get(hw, wl->vif);
-       if (unlikely(!beacon))
-               return -ENOMEM;
-       spin_lock_irqsave(&wl->irq_lock, flags);
-       b43_update_templates(wl, beacon);
-       spin_unlock_irqrestore(&wl->irq_lock, flags);
-
-       return 0;
-}
-
-static int b43_op_ibss_beacon_update(struct ieee80211_hw *hw,
-                                    struct sk_buff *beacon)
-{
-       struct b43_wl *wl = hw_to_b43_wl(hw);
        unsigned long flags;
 
        spin_lock_irqsave(&wl->irq_lock, flags);
-       b43_update_templates(wl, beacon);
+       b43_update_templates(wl);
        spin_unlock_irqrestore(&wl->irq_lock, flags);
 
        return 0;
@@ -4391,7 +4384,6 @@ static const struct ieee80211_ops b43_hw_ops = {
        .stop                   = b43_op_stop,
        .set_retry_limit        = b43_op_set_retry_limit,
        .set_tim                = b43_op_beacon_set_tim,
-       .beacon_update          = b43_op_ibss_beacon_update,
        .sta_notify             = b43_op_sta_notify,
 };
 
index 069157e..a1b8bf3 100644 (file)
@@ -1138,14 +1138,22 @@ static void b43legacy_write_probe_resp_template(struct b43legacy_wldev *dev,
 
 /* Asynchronously update the packet templates in template RAM.
  * Locking: Requires wl->irq_lock to be locked. */
-static void b43legacy_update_templates(struct b43legacy_wl *wl,
-                                      struct sk_buff *beacon)
+static void b43legacy_update_templates(struct b43legacy_wl *wl)
 {
+       struct sk_buff *beacon;
        /* This is the top half of the ansynchronous beacon update. The bottom
         * half is the beacon IRQ. Beacon update must be asynchronous to avoid
         * sending an invalid beacon. This can happen for example, if the
         * firmware transmits a beacon while we are updating it. */
 
+       /* We could modify the existing beacon and set the aid bit in the TIM
+        * field, but that would probably require resizing and moving of data
+        * within the beacon template. Simply request a new beacon and let
+        * mac80211 do the hard work. */
+       beacon = ieee80211_beacon_get(wl->hw, wl->vif);
+       if (unlikely(!beacon))
+               return;
+
        if (wl->current_beacon)
                dev_kfree_skb_any(wl->current_beacon);
        wl->current_beacon = beacon;
@@ -2727,10 +2735,13 @@ static int b43legacy_op_config_interface(struct ieee80211_hw *hw,
                memset(wl->bssid, 0, ETH_ALEN);
        if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) {
                if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP)) {
-                       B43legacy_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP);
+                       B43legacy_WARN_ON(vif->type != IEEE80211_IF_TYPE_AP);
                        b43legacy_set_ssid(dev, conf->ssid, conf->ssid_len);
-                       if (conf->beacon)
-                               b43legacy_update_templates(wl, conf->beacon);
+                       if (conf->changed & IEEE80211_IFCC_BEACON)
+                               b43legacy_update_templates(wl);
+               } else if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_IBSS)) {
+                       if (conf->changed & IEEE80211_IFCC_BEACON)
+                               b43legacy_update_templates(wl);
                }
                b43legacy_write_mac_bssid_templates(dev);
        }
@@ -3396,31 +3407,10 @@ static int b43legacy_op_beacon_set_tim(struct ieee80211_hw *hw,
                                       int aid, int set)
 {
        struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
-       struct sk_buff *beacon;
-       unsigned long flags;
-
-       /* We could modify the existing beacon and set the aid bit in the TIM
-        * field, but that would probably require resizing and moving of data
-        * within the beacon template. Simply request a new beacon and let
-        * mac80211 do the hard work. */
-       beacon = ieee80211_beacon_get(hw, wl->vif);
-       if (unlikely(!beacon))
-               return -ENOMEM;
-       spin_lock_irqsave(&wl->irq_lock, flags);
-       b43legacy_update_templates(wl, beacon);
-       spin_unlock_irqrestore(&wl->irq_lock, flags);
-
-       return 0;
-}
-
-static int b43legacy_op_ibss_beacon_update(struct ieee80211_hw *hw,
-                                          struct sk_buff *beacon)
-{
-       struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
        unsigned long flags;
 
        spin_lock_irqsave(&wl->irq_lock, flags);
-       b43legacy_update_templates(wl, beacon);
+       b43legacy_update_templates(wl);
        spin_unlock_irqrestore(&wl->irq_lock, flags);
 
        return 0;
@@ -3440,7 +3430,6 @@ static const struct ieee80211_ops b43legacy_hw_ops = {
        .stop                   = b43legacy_op_stop,
        .set_retry_limit        = b43legacy_op_set_retry_limit,
        .set_tim                = b43legacy_op_beacon_set_tim,
-       .beacon_update          = b43legacy_op_ibss_beacon_update,
 };
 
 /* Hard-reset the chip. Do not call this directly.
index 1a7d18f..7d015f8 100644 (file)
@@ -6907,6 +6907,9 @@ static void iwl3945_config_ap(struct iwl3945_priv *priv)
         * clear sta table, add BCAST sta... */
 }
 
+/* temporary */
+static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb);
+
 static int iwl3945_mac_config_interface(struct ieee80211_hw *hw,
                                        struct ieee80211_vif *vif,
                                    struct ieee80211_if_conf *conf)
@@ -6924,10 +6927,21 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw,
                return 0;
        }
 
+       /* handle this temporarily here */
+       if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS &&
+           conf->changed & IEEE80211_IFCC_BEACON) {
+               struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
+               if (!beacon)
+                       return -ENOMEM;
+               rc = iwl3945_mac_beacon_update(hw, beacon);
+               if (rc)
+                       return rc;
+       }
+
        /* XXX: this MUST use conf->mac_addr */
 
        if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) &&
-           (!conf->beacon || !conf->ssid_len)) {
+           (!conf->ssid_len)) {
                IWL_DEBUG_MAC80211
                    ("Leaving in AP mode because HostAPD is not ready.\n");
                return 0;
@@ -6959,7 +6973,7 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw,
                if (priv->ibss_beacon)
                        dev_kfree_skb(priv->ibss_beacon);
 
-               priv->ibss_beacon = conf->beacon;
+               priv->ibss_beacon = ieee80211_beacon_get(hw, vif);
        }
 
        if (iwl3945_is_rfkill(priv))
@@ -7940,7 +7954,6 @@ static struct ieee80211_ops iwl3945_hw_ops = {
        .conf_tx = iwl3945_mac_conf_tx,
        .get_tsf = iwl3945_mac_get_tsf,
        .reset_tsf = iwl3945_mac_reset_tsf,
-       .beacon_update = iwl3945_mac_beacon_update,
        .hw_scan = iwl3945_mac_hw_scan
 };
 
index 7f65d91..d6fe0de 100644 (file)
@@ -2912,6 +2912,9 @@ static void iwl4965_config_ap(struct iwl_priv *priv)
         * clear sta table, add BCAST sta... */
 }
 
+/* temporary */
+static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb);
+
 static int iwl4965_mac_config_interface(struct ieee80211_hw *hw,
                                        struct ieee80211_vif *vif,
                                    struct ieee80211_if_conf *conf)
@@ -2929,8 +2932,18 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw,
                return 0;
        }
 
+       if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS &&
+           conf->changed & IEEE80211_IFCC_BEACON) {
+               struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
+               if (!beacon)
+                       return -ENOMEM;
+               rc = iwl4965_mac_beacon_update(hw, beacon);
+               if (rc)
+                       return rc;
+       }
+
        if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) &&
-           (!conf->beacon || !conf->ssid_len)) {
+           (!conf->ssid_len)) {
                IWL_DEBUG_MAC80211
                    ("Leaving in AP mode because HostAPD is not ready.\n");
                return 0;
@@ -2962,7 +2975,7 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw,
                if (priv->ibss_beacon)
                        dev_kfree_skb(priv->ibss_beacon);
 
-               priv->ibss_beacon = conf->beacon;
+               priv->ibss_beacon = ieee80211_beacon_get(hw, vif);
        }
 
        if (iwl_is_rfkill(priv))
@@ -4090,7 +4103,6 @@ static struct ieee80211_ops iwl4965_hw_ops = {
        .get_tx_stats = iwl4965_mac_get_tx_stats,
        .conf_tx = iwl4965_mac_conf_tx,
        .reset_tsf = iwl4965_mac_reset_tsf,
-       .beacon_update = iwl4965_mac_beacon_update,
        .bss_info_changed = iwl4965_bss_info_changed,
        .ampdu_action = iwl4965_mac_ampdu_action,
        .hw_scan = iwl4965_mac_hw_scan
index ee953ca..89b874c 100644 (file)
@@ -1581,7 +1581,6 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = {
        .conf_tx                = rt2400pci_conf_tx,
        .get_tx_stats           = rt2x00mac_get_tx_stats,
        .get_tsf                = rt2400pci_get_tsf,
-       .beacon_update          = rt2400pci_beacon_update,
        .tx_last_beacon         = rt2400pci_tx_last_beacon,
 };
 
@@ -1601,6 +1600,7 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
        .write_tx_data          = rt2x00pci_write_tx_data,
        .kick_tx_queue          = rt2400pci_kick_tx_queue,
        .fill_rxdone            = rt2400pci_fill_rxdone,
+       .beacon_update          = rt2400pci_beacon_update,
        .config_filter          = rt2400pci_config_filter,
        .config_intf            = rt2400pci_config_intf,
        .config_erp             = rt2400pci_config_erp,
index 0423c25..a64bb18 100644 (file)
@@ -1875,7 +1875,6 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = {
        .conf_tx                = rt2x00mac_conf_tx,
        .get_tx_stats           = rt2x00mac_get_tx_stats,
        .get_tsf                = rt2500pci_get_tsf,
-       .beacon_update          = rt2500pci_beacon_update,
        .tx_last_beacon         = rt2500pci_tx_last_beacon,
 };
 
@@ -1895,6 +1894,7 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {
        .write_tx_data          = rt2x00pci_write_tx_data,
        .kick_tx_queue          = rt2500pci_kick_tx_queue,
        .fill_rxdone            = rt2500pci_fill_rxdone,
+       .beacon_update          = rt2500pci_beacon_update,
        .config_filter          = rt2500pci_config_filter,
        .config_intf            = rt2500pci_config_intf,
        .config_erp             = rt2500pci_config_erp,
index 0dd1cb5..8ce1726 100644 (file)
@@ -1775,7 +1775,6 @@ static const struct ieee80211_ops rt2500usb_mac80211_ops = {
        .bss_info_changed       = rt2x00mac_bss_info_changed,
        .conf_tx                = rt2x00mac_conf_tx,
        .get_tx_stats           = rt2x00mac_get_tx_stats,
-       .beacon_update          = rt2500usb_beacon_update,
 };
 
 static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
@@ -1793,6 +1792,7 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
        .get_tx_data_len        = rt2500usb_get_tx_data_len,
        .kick_tx_queue          = rt2500usb_kick_tx_queue,
        .fill_rxdone            = rt2500usb_fill_rxdone,
+       .beacon_update          = rt2500usb_beacon_update,
        .config_filter          = rt2500usb_config_filter,
        .config_intf            = rt2500usb_config_intf,
        .config_erp             = rt2500usb_config_erp,
index c07d9ef..9ad3ce4 100644 (file)
@@ -534,6 +534,8 @@ struct rt2x00lib_ops {
        /*
         * Configuration handlers.
         */
+       int (*beacon_update) (struct ieee80211_hw *hw, struct sk_buff *bcn);
+
        void (*config_filter) (struct rt2x00_dev *rt2x00dev,
                               const unsigned int filter_flags);
        void (*config_intf) (struct rt2x00_dev *rt2x00dev,
index b48c04e..1b7f877 100644 (file)
@@ -409,7 +409,6 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
 {
        struct rt2x00_dev *rt2x00dev = data;
        struct rt2x00_intf *intf = vif_to_intf(vif);
-       struct sk_buff *skb;
        struct ieee80211_bss_conf conf;
        int delayed_flags;
 
@@ -436,10 +435,11 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
                return;
 
        if (delayed_flags & DELAYED_UPDATE_BEACON) {
-               skb = ieee80211_beacon_get(rt2x00dev->hw, vif);
-               if (skb &&
-                   rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, skb))
-                       dev_kfree_skb(skb);
+               struct ieee80211_if_conf conf;
+               conf.bssid = conf.ssid = NULL;
+               conf.ssid_len = 0;
+               conf.changed = IEEE80211_IFCC_BEACON;
+               rt2x00dev->ops->hw->config_interface(rt2x00dev->hw, vif, &conf);
        }
 
        if (delayed_flags & DELAYED_CONFIG_ERP)
index 3a1fb6d..84b51f4 100644 (file)
@@ -348,6 +348,7 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw,
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
        struct rt2x00_intf *intf = vif_to_intf(vif);
+       struct sk_buff *beacon;
        int status;
 
        /*
@@ -363,8 +364,11 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw,
         * If the interface does not work in master mode,
         * then the bssid value in the interface structure
         * should now be set.
+        *
+        * conf->bssid can be NULL if coming from the internal
+        * beacon update routine.
         */
-       if (conf->type != IEEE80211_IF_TYPE_AP)
+       if (conf->bssid && vif->type != IEEE80211_IF_TYPE_AP)
                memcpy(&intf->bssid, conf->bssid, ETH_ALEN);
 
        spin_unlock(&intf->lock);
@@ -375,17 +379,23 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw,
         * values as arguments we make keep access to rt2x00_intf thread safe
         * even without the lock.
         */
-       rt2x00lib_config_intf(rt2x00dev, intf, conf->type, NULL, conf->bssid);
+       rt2x00lib_config_intf(rt2x00dev, intf, vif->type, NULL, conf->bssid);
 
        /*
-        * We only need to initialize the beacon when master mode is enabled.
+        * We only need to initialize the beacon when in master/ibss mode.
         */
-       if (conf->type != IEEE80211_IF_TYPE_AP || !conf->beacon)
+       if ((vif->type != IEEE80211_IF_TYPE_AP &&
+            vif->type != IEEE80211_IF_TYPE_IBSS) ||
+           !(conf->changed & IEEE80211_IFCC_BEACON))
                return 0;
 
-       status = rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, conf->beacon);
+       beacon = ieee80211_beacon_get(rt2x00dev->hw, vif);
+       if (!beacon)
+               return -ENOMEM;
+
+       status = rt2x00dev->ops->lib->beacon_update(rt2x00dev->hw, beacon);
        if (status)
-               dev_kfree_skb(conf->beacon);
+               dev_kfree_skb(beacon);
 
        return status;
 }
index bbf1048..852d193 100644 (file)
@@ -2427,7 +2427,6 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = {
        .conf_tx                = rt2x00mac_conf_tx,
        .get_tx_stats           = rt2x00mac_get_tx_stats,
        .get_tsf                = rt61pci_get_tsf,
-       .beacon_update          = rt61pci_beacon_update,
 };
 
 static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
@@ -2449,6 +2448,7 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
        .write_tx_data          = rt2x00pci_write_tx_data,
        .kick_tx_queue          = rt61pci_kick_tx_queue,
        .fill_rxdone            = rt61pci_fill_rxdone,
+       .beacon_update          = rt61pci_beacon_update,
        .config_filter          = rt61pci_config_filter,
        .config_intf            = rt61pci_config_intf,
        .config_erp             = rt61pci_config_erp,
index 3ef318e..6572009 100644 (file)
@@ -2031,7 +2031,6 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = {
        .conf_tx                = rt2x00mac_conf_tx,
        .get_tx_stats           = rt2x00mac_get_tx_stats,
        .get_tsf                = rt73usb_get_tsf,
-       .beacon_update          = rt73usb_beacon_update,
 };
 
 static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
@@ -2052,6 +2051,7 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
        .get_tx_data_len        = rt73usb_get_tx_data_len,
        .kick_tx_queue          = rt73usb_kick_tx_queue,
        .fill_rxdone            = rt73usb_fill_rxdone,
+       .beacon_update          = rt73usb_beacon_update,
        .config_filter          = rt73usb_config_filter,
        .config_intf            = rt73usb_config_intf,
        .config_erp             = rt73usb_config_erp,
index 665f76a..68e2749 100644 (file)
@@ -727,15 +727,19 @@ static int zd_op_config_interface(struct ieee80211_hw *hw,
        if (mac->type == IEEE80211_IF_TYPE_MESH_POINT ||
            mac->type == IEEE80211_IF_TYPE_IBSS) {
                associated = true;
-               if (conf->beacon) {
-                       r = zd_mac_config_beacon(hw, conf->beacon);
+               if (conf->changed & IEEE80211_IFCC_BEACON) {
+                       struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
+
+                       if (!beacon)
+                               return -ENOMEM;
+                       r = zd_mac_config_beacon(hw, beacon);
                        if (r < 0)
                                return r;
                        r = zd_set_beacon_interval(&mac->chip, BCN_MODE_IBSS |
                                        hw->conf.beacon_int);
                        if (r < 0)
                                return r;
-                       kfree_skb(conf->beacon);
+                       kfree_skb(beacon);
                }
        } else
                associated = is_valid_ether_addr(conf->bssid);
@@ -889,17 +893,6 @@ static void zd_op_bss_info_changed(struct ieee80211_hw *hw,
        }
 }
 
-static int zd_op_beacon_update(struct ieee80211_hw *hw,
-                              struct sk_buff *skb)
-{
-       struct zd_mac *mac = zd_hw_mac(hw);
-       zd_mac_config_beacon(hw, skb);
-       kfree_skb(skb);
-       zd_set_beacon_interval(&mac->chip, BCN_MODE_IBSS |
-                                       hw->conf.beacon_int);
-       return 0;
-}
-
 static const struct ieee80211_ops zd_ops = {
        .tx                     = zd_op_tx,
        .start                  = zd_op_start,
@@ -910,7 +903,6 @@ static const struct ieee80211_ops zd_ops = {
        .config_interface       = zd_op_config_interface,
        .configure_filter       = zd_op_configure_filter,
        .bss_info_changed       = zd_op_bss_info_changed,
-       .beacon_update          = zd_op_beacon_update,
 };
 
 struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf)
index 9672a04..47c072e 100644 (file)
@@ -529,33 +529,38 @@ struct ieee80211_if_init_conf {
 };
 
 /**
+ * enum ieee80211_if_conf_change - interface config change flags
+ *
+ * @IEEE80211_IFCC_BSSID: The BSSID changed.
+ * @IEEE80211_IFCC_SSID: The SSID changed.
+ * @IEEE80211_IFCC_BEACON: The beacon for this interface changed
+ *     (currently AP and MESH only), use ieee80211_beacon_get().
+ */
+enum ieee80211_if_conf_change {
+       IEEE80211_IFCC_BSSID    = BIT(0),
+       IEEE80211_IFCC_SSID     = BIT(1),
+       IEEE80211_IFCC_BEACON   = BIT(2),
+};
+
+/**
  * struct ieee80211_if_conf - configuration of an interface
  *
- * @type: type of the interface. This is always the same as was specified in
- *     &struct ieee80211_if_init_conf. The type of an interface never changes
- *     during the life of the interface; this field is present only for
- *     convenience.
+ * @changed: parameters that have changed, see &enum ieee80211_if_conf_change.
  * @bssid: BSSID of the network we are associated to/creating.
  * @ssid: used (together with @ssid_len) by drivers for hardware that
  *     generate beacons independently. The pointer is valid only during the
  *     config_interface() call, so copy the value somewhere if you need
  *     it.
  * @ssid_len: length of the @ssid field.
- * @beacon: beacon template. Valid only if @host_gen_beacon_template in
- *     &struct ieee80211_hw is set. The driver is responsible of freeing
- *     the sk_buff.
- * @beacon_control: tx_control for the beacon template, this field is only
- *     valid when the @beacon field was set.
  *
  * This structure is passed to the config_interface() callback of
  * &struct ieee80211_hw.
  */
 struct ieee80211_if_conf {
-       int type;
+       u32 changed;
        u8 *bssid;
        u8 *ssid;
        size_t ssid_len;
-       struct sk_buff *beacon;
 };
 
 /**
@@ -683,15 +688,6 @@ enum ieee80211_tkip_key_type {
  * any particular flags. There are some exceptions to this rule,
  * however, so you are advised to review these flags carefully.
  *
- * @IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE:
- *     The device only needs to be supplied with a beacon template.
- *     If you need the host to generate each beacon then don't use
- *     this flag and call ieee80211_beacon_get() when you need the
- *     next beacon frame. Note that if you set this flag, you must
- *     implement the set_tim() callback for powersave mode to work
- *     properly.
- *     This flag is only relevant for access-point mode.
- *
  * @IEEE80211_HW_RX_INCLUDES_FCS:
  *     Indicates that received frames passed to the stack include
  *     the FCS at the end.
@@ -1151,17 +1147,6 @@ enum ieee80211_ampdu_mlme_action {
  *     function is optional if the firmware/hardware takes full care of
  *     TSF synchronization.
  *
- * @beacon_update: Setup beacon data for IBSS beacons. Unlike access point,
- *     IBSS uses a fixed beacon frame which is configured using this
- *     function.
- *     If the driver returns success (0) from this callback, it owns
- *     the skb. That means the driver is responsible to kfree_skb() it.
- *     The control structure is not dynamically allocated. That means the
- *     driver does not own the pointer and if it needs it somewhere
- *     outside of the context of this function, it must copy it
- *     somewhere else.
- *     This handler is required only for IBSS mode.
- *
  * @tx_last_beacon: Determine whether the last IBSS beacon was sent by us.
  *     This is needed only for IBSS mode and the result of this function is
  *     used to determine whether to reply to Probe Requests.
@@ -1219,8 +1204,6 @@ struct ieee80211_ops {
                            struct ieee80211_tx_queue_stats *stats);
        u64 (*get_tsf)(struct ieee80211_hw *hw);
        void (*reset_tsf)(struct ieee80211_hw *hw);
-       int (*beacon_update)(struct ieee80211_hw *hw,
-                            struct sk_buff *skb);
        int (*tx_last_beacon)(struct ieee80211_hw *hw);
        int (*ampdu_action)(struct ieee80211_hw *hw,
                            enum ieee80211_ampdu_mlme_action action,
index ea03010..8e7ba0e 100644 (file)
@@ -469,7 +469,7 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
 
        kfree(old);
 
-       return ieee80211_if_config_beacon(sdata->dev);
+       return ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON);
 }
 
 static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
@@ -523,7 +523,7 @@ static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
        synchronize_rcu();
        kfree(old);
 
-       return ieee80211_if_config_beacon(dev);
+       return ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON);
 }
 
 /* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */
index 2146c0c..934c3ef 100644 (file)
@@ -854,8 +854,7 @@ static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr)
 
 /* ieee80211.c */
 int ieee80211_hw_config(struct ieee80211_local *local);
-int ieee80211_if_config(struct net_device *dev);
-int ieee80211_if_config_beacon(struct net_device *dev);
+int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed);
 void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx);
 u32 ieee80211_handle_ht(struct ieee80211_local *local, int enable_ht,
                        struct ieee80211_ht_info *req_ht_cap,
index 0759ab2..36859e7 100644 (file)
@@ -307,7 +307,8 @@ static int ieee80211_open(struct net_device *dev)
                if (res)
                        goto err_stop;
 
-               ieee80211_if_config(dev);
+               if (ieee80211_vif_is_mesh(&sdata->vif))
+                       ieee80211_start_mesh(sdata->dev);
                changed |= ieee80211_reset_erp_info(dev);
                ieee80211_bss_info_change_notify(sdata, changed);
                ieee80211_enable_keys(sdata);
@@ -985,57 +986,47 @@ void ieee80211_if_setup(struct net_device *dev)
 
 /* everything else */
 
-static int __ieee80211_if_config(struct net_device *dev,
-                                struct sk_buff *beacon)
+int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed)
 {
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct ieee80211_local *local = sdata->local;
        struct ieee80211_if_conf conf;
 
-       if (!local->ops->config_interface || !netif_running(dev))
+       if (WARN_ON(!netif_running(sdata->dev)))
+               return 0;
+
+       if (!local->ops->config_interface)
                return 0;
 
        memset(&conf, 0, sizeof(conf));
-       conf.type = sdata->vif.type;
+       conf.changed = changed;
+
        if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
            sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
                conf.bssid = sdata->u.sta.bssid;
                conf.ssid = sdata->u.sta.ssid;
                conf.ssid_len = sdata->u.sta.ssid_len;
-       } else if (ieee80211_vif_is_mesh(&sdata->vif)) {
-               conf.beacon = beacon;
-               ieee80211_start_mesh(dev);
        } else if (sdata->vif.type == IEEE80211_IF_TYPE_AP) {
+               conf.bssid = sdata->dev->dev_addr;
                conf.ssid = sdata->u.ap.ssid;
                conf.ssid_len = sdata->u.ap.ssid_len;
-               conf.beacon = beacon;
+       } 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;
        }
-       return local->ops->config_interface(local_to_hw(local),
-                                           &sdata->vif, &conf);
-}
 
-int ieee80211_if_config(struct net_device *dev)
-{
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT &&
-           (local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE))
-               return ieee80211_if_config_beacon(dev);
-       return __ieee80211_if_config(dev, NULL);
-}
+       if (WARN_ON(!conf.bssid && (changed & IEEE80211_IFCC_BSSID)))
+               return -EINVAL;
 
-int ieee80211_if_config_beacon(struct net_device *dev)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       struct sk_buff *skb;
+       if (WARN_ON(!conf.ssid && (changed & IEEE80211_IFCC_SSID)))
+               return -EINVAL;
 
-       if (!(local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE))
-               return 0;
-       skb = ieee80211_beacon_get(local_to_hw(local), &sdata->vif);
-       if (!skb)
-               return -ENOMEM;
-       return __ieee80211_if_config(dev, skb);
+       return local->ops->config_interface(local_to_hw(local),
+                                           &sdata->vif, &conf);
 }
 
 int ieee80211_hw_config(struct ieee80211_local *local)
index 64d710a..61d7f81 100644 (file)
@@ -2406,8 +2406,6 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
        int res, rates, i, j;
        struct sk_buff *skb;
        struct ieee80211_mgmt *mgmt;
-       struct ieee80211_tx_info *control;
-       struct rate_selection ratesel;
        u8 *pos;
        struct ieee80211_sub_if_data *sdata;
        struct ieee80211_supported_band *sband;
@@ -2425,7 +2423,7 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
                local->ops->reset_tsf(local_to_hw(local));
        }
        memcpy(ifsta->bssid, bss->bssid, ETH_ALEN);
-       res = ieee80211_if_config(dev);
+       res = ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID);
        if (res)
                return res;
 
@@ -2439,19 +2437,16 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
        if (res)
                return res;
 
-       /* Set beacon template */
+       /* Build IBSS probe response */
        skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
-       do {
-               if (!skb)
-                       break;
-
+       if (skb) {
                skb_reserve(skb, local->hw.extra_tx_headroom);
 
                mgmt = (struct ieee80211_mgmt *)
                        skb_put(skb, 24 + sizeof(mgmt->u.beacon));
                memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
                mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
-                                                  IEEE80211_STYPE_BEACON);
+                                                  IEEE80211_STYPE_PROBE_RESP);
                memset(mgmt->da, 0xff, ETH_ALEN);
                memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
                memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
@@ -2495,61 +2490,22 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
                        memcpy(pos, &bss->supp_rates[8], rates);
                }
 
-               control = IEEE80211_SKB_CB(skb);
-
-               rate_control_get_rate(dev, sband, skb, &ratesel);
-               if (ratesel.rate_idx < 0) {
-                       printk(KERN_DEBUG "%s: Failed to determine TX rate "
-                              "for IBSS beacon\n", dev->name);
-                       break;
-               }
-               control->control.vif = &sdata->vif;
-               control->tx_rate_idx = ratesel.rate_idx;
-               if (sdata->bss_conf.use_short_preamble &&
-                   sband->bitrates[ratesel.rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE)
-                       control->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE;
-               control->antenna_sel_tx = local->hw.conf.antenna_sel_tx;
-               control->flags |= IEEE80211_TX_CTL_NO_ACK;
-               control->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT;
-               control->control.retry_limit = 1;
-
-               ifsta->probe_resp = skb_copy(skb, GFP_ATOMIC);
-               if (ifsta->probe_resp) {
-                       mgmt = (struct ieee80211_mgmt *)
-                               ifsta->probe_resp->data;
-                       mgmt->frame_control =
-                               IEEE80211_FC(IEEE80211_FTYPE_MGMT,
-                                            IEEE80211_STYPE_PROBE_RESP);
-               } else {
-                       printk(KERN_DEBUG "%s: Could not allocate ProbeResp "
-                              "template for IBSS\n", dev->name);
-               }
-
-               if (local->ops->beacon_update &&
-                   local->ops->beacon_update(local_to_hw(local), skb) == 0) {
-                       printk(KERN_DEBUG "%s: Configured IBSS beacon "
-                              "template\n", dev->name);
-                       skb = NULL;
-               }
-
-               rates = 0;
-               sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
-               for (i = 0; i < bss->supp_rates_len; i++) {
-                       int bitrate = (bss->supp_rates[i] & 0x7f) * 5;
-                       for (j = 0; j < sband->n_bitrates; j++)
-                               if (sband->bitrates[j].bitrate == bitrate)
-                                       rates |= BIT(j);
-               }
-               ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates;
+               ifsta->probe_resp = skb;
 
-               ieee80211_sta_def_wmm_params(dev, bss, 1);
-       } while (0);
+               ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON);
+       }
 
-       if (skb) {
-               printk(KERN_DEBUG "%s: Failed to configure IBSS beacon "
-                      "template\n", dev->name);
-               dev_kfree_skb(skb);
+       rates = 0;
+       sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+       for (i = 0; i < bss->supp_rates_len; i++) {
+               int bitrate = (bss->supp_rates[i] & 0x7f) * 5;
+               for (j = 0; j < sband->n_bitrates; j++)
+                       if (sband->bitrates[j].bitrate == bitrate)
+                               rates |= BIT(j);
        }
+       ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates;
+
+       ieee80211_sta_def_wmm_params(dev, bss, 1);
 
        ifsta->state = IEEE80211_IBSS_JOINED;
        mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);
@@ -3333,7 +3289,7 @@ static void ieee80211_mesh_housekeeping(struct net_device *dev,
 
        free_plinks = mesh_plink_availables(sdata);
        if (free_plinks != sdata->u.sta.accepting_plinks)
-               ieee80211_if_config_beacon(dev);
+               ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON);
 
        mod_timer(&ifsta->timer, jiffies +
                        IEEE80211_MESH_HOUSEKEEPING_INTERVAL);
@@ -3757,28 +3713,45 @@ int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_if_sta *ifsta;
+       int res;
 
        if (len > IEEE80211_MAX_SSID_LEN)
                return -EINVAL;
 
        ifsta = &sdata->u.sta;
 
-       if (ifsta->ssid_len != len || memcmp(ifsta->ssid, ssid, len) != 0)
+       if (ifsta->ssid_len != len || memcmp(ifsta->ssid, ssid, len) != 0) {
+               memset(ifsta->ssid, 0, sizeof(ifsta->ssid));
+               memcpy(ifsta->ssid, ssid, len);
+               ifsta->ssid_len = len;
                ifsta->flags &= ~IEEE80211_STA_PREV_BSSID_SET;
-       memcpy(ifsta->ssid, ssid, len);
-       memset(ifsta->ssid + len, 0, IEEE80211_MAX_SSID_LEN - len);
-       ifsta->ssid_len = len;
+
+               res = 0;
+               /*
+                * Hack! MLME code needs to be cleaned up to have different
+                * entry points for configuration and internal selection change
+                */
+               if (netif_running(sdata->dev))
+                       res = ieee80211_if_config(sdata, IEEE80211_IFCC_SSID);
+               if (res) {
+                       printk(KERN_DEBUG "%s: Failed to config new SSID to "
+                              "the low-level driver\n", dev->name);
+                       return res;
+               }
+       }
 
        if (len)
                ifsta->flags |= IEEE80211_STA_SSID_SET;
        else
                ifsta->flags &= ~IEEE80211_STA_SSID_SET;
+
        if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS &&
            !(ifsta->flags & IEEE80211_STA_BSSID_SET)) {
                ifsta->ibss_join_req = jiffies;
                ifsta->state = IEEE80211_IBSS_SEARCH;
                return ieee80211_sta_find_ibss(dev, ifsta);
        }
+
        return 0;
 }
 
@@ -3804,7 +3777,12 @@ int ieee80211_sta_set_bssid(struct net_device *dev, u8 *bssid)
 
        if (memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0) {
                memcpy(ifsta->bssid, bssid, ETH_ALEN);
-               res = ieee80211_if_config(dev);
+               res = 0;
+               /*
+                * Hack! See also ieee80211_sta_set_ssid.
+                */
+               if (netif_running(sdata->dev))
+                       res = ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID);
                if (res) {
                        printk(KERN_DEBUG "%s: Failed to config new BSSID to "
                               "the low-level driver\n", dev->name);
index a757dcc..8843416 100644 (file)
@@ -1788,17 +1788,17 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
                                     struct ieee80211_vif *vif)
 {
        struct ieee80211_local *local = hw_to_local(hw);
-       struct sk_buff *skb;
+       struct sk_buff *skb = NULL;
        struct ieee80211_tx_info *info;
        struct net_device *bdev;
        struct ieee80211_sub_if_data *sdata = NULL;
        struct ieee80211_if_ap *ap = NULL;
+       struct ieee80211_if_sta *ifsta = NULL;
        struct rate_selection rsel;
        struct beacon_data *beacon;
        struct ieee80211_supported_band *sband;
        struct ieee80211_mgmt *mgmt;
        int *num_beacons;
-       bool err = true;
        enum ieee80211_band band = local->hw.conf.channel->band;
        u8 *pos;
 
@@ -1852,9 +1852,24 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
                                       beacon->tail, beacon->tail_len);
 
                        num_beacons = &ap->num_beacons;
+               } else
+                       goto out;
+       } else if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
+               struct ieee80211_hdr *hdr;
+               ifsta = &sdata->u.sta;
 
-                       err = false;
-               }
+               if (!ifsta->probe_resp)
+                       goto out;
+
+               skb = skb_copy(ifsta->probe_resp, GFP_ATOMIC);
+               if (!skb)
+                       goto out;
+
+               hdr = (struct ieee80211_hdr *) skb->data;
+               hdr->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+                                                 IEEE80211_STYPE_BEACON);
+
+               num_beacons = &ifsta->num_beacons;
        } else if (ieee80211_vif_is_mesh(&sdata->vif)) {
                /* headroom, head length, tail length and maximum TIM length */
                skb = dev_alloc_skb(local->tx_headroom + 400);
@@ -1881,17 +1896,8 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
                mesh_mgmt_ies_add(skb, sdata->dev);
 
                num_beacons = &sdata->u.sta.num_beacons;
-
-               err = false;
-       }
-
-       if (err) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-               if (net_ratelimit())
-                       printk(KERN_DEBUG "no beacon data avail for %s\n",
-                              bdev->name);
-#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
-               skb = NULL;
+       } else {
+               WARN_ON(1);
                goto out;
        }
 
index c041db9..34fa8ed 100644 (file)
@@ -444,7 +444,7 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev,
                memset(sdata->u.ap.ssid + len, 0,
                       IEEE80211_MAX_SSID_LEN - len);
                sdata->u.ap.ssid_len = len;
-               return ieee80211_if_config(dev);
+               return ieee80211_if_config(sdata, IEEE80211_IFCC_SSID);
        }
        return -EOPNOTSUPP;
 }