From 9d139c810a2aa17365cc548d0cd2a189d8433c65 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 9 Jul 2008 14:40:37 +0200 Subject: [PATCH] mac80211: revamp beacon configuration 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 Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/base.c | 13 ++- drivers/net/wireless/b43/main.c | 48 ++++----- drivers/net/wireless/b43legacy/main.c | 45 +++----- drivers/net/wireless/iwlwifi/iwl3945-base.c | 19 +++- drivers/net/wireless/iwlwifi/iwl4965-base.c | 18 +++- drivers/net/wireless/rt2x00/rt2400pci.c | 2 +- drivers/net/wireless/rt2x00/rt2500pci.c | 2 +- drivers/net/wireless/rt2x00/rt2500usb.c | 2 +- drivers/net/wireless/rt2x00/rt2x00.h | 2 + drivers/net/wireless/rt2x00/rt2x00dev.c | 10 +- drivers/net/wireless/rt2x00/rt2x00mac.c | 22 ++-- drivers/net/wireless/rt2x00/rt61pci.c | 2 +- drivers/net/wireless/rt2x00/rt73usb.c | 2 +- drivers/net/wireless/zd1211rw/zd_mac.c | 22 ++-- include/net/mac80211.h | 49 +++------ net/mac80211/cfg.c | 4 +- net/mac80211/ieee80211_i.h | 3 +- net/mac80211/main.c | 59 +++++------ net/mac80211/mlme.c | 112 ++++++++------------ net/mac80211/tx.c | 36 ++++--- net/mac80211/wext.c | 2 +- 21 files changed, 226 insertions(+), 248 deletions(-) diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index a43e9b25169b..217d506527a9 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -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); diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 9d2eb273b726..381dbd33dfc2 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -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); } @@ -4334,33 +4348,12 @@ 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, }; diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 069157eea05c..a1b8bf3ee732 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -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); } @@ -3394,33 +3405,12 @@ out_unlock: 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. diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 1a7d18fea89d..7d015f86ee8c 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -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 }; diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 7f65d9123b2a..d6fe0ded59d7 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -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 diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index ee953ca0c6a3..89b874ca6107 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -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, diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 0423c251c78e..a64bb18322e9 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -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, diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 0dd1cb537b92..8ce1726d7508 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -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, diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index c07d9ef383f0..9ad3ce43e6cd 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -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, diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index b48c04e80a38..1b7f87799a7e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -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) diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 3a1fb6d47e5d..84b51f49175e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -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; } diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index bbf1048f6400..852d193a11a9 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -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, diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 3ef318e098e7..657200972424 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -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, diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 665f76af2fec..68e2749b2ce8 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -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) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 9672a04c4f7b..47c072eab42c 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -528,34 +528,39 @@ struct ieee80211_if_init_conf { void *mac_addr; }; +/** + * 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, diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index ea0301025c15..8e7ba0e62cf5 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -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) */ diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 2146c0c436d2..934c3ef4f0bc 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -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, diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 0759ab2ca3ff..36859e794928 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -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) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 64d710a88b86..61d7f81bf45e 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -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); diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index a757dcc1208d..8843416e1460 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -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; } diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index c041db9556c7..34fa8ed1e784 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c @@ -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; } -- 2.39.5