Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9d139c81 authored by Johannes Berg's avatar Johannes Berg Committed by John W. Linville
Browse files

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: default avatarJohannes Berg <johannes@sipsolutions.net>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent f3947e2d
Loading
Loading
Loading
Loading
+12 −1
Original line number Diff line number Diff line
@@ -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);
+20 −28
Original line number Diff line number Diff line
@@ -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_WARN_ON(vif->type != wl->if_type);
			if (conf->changed & IEEE80211_IFCC_SSID)
				b43_set_ssid(dev, conf->ssid, conf->ssid_len);
			if (conf->beacon)
				b43_update_templates(wl, conf->beacon);
			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,
};

+17 −28
Original line number Diff line number Diff line
@@ -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.
+16 −3
Original line number Diff line number Diff line
@@ -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
};

+15 −3
Original line number Diff line number Diff line
@@ -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
Loading