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

Commit 04de8381 authored by Kalle Valo's avatar Kalle Valo Committed by John W. Linville
Browse files

mac80211: add beacon filtering support



Add IEEE80211_HW_BEACON_FILTERING flag so that driver inform that it supports
beacon filtering. Drivers need to call the new function
ieee80211_beacon_loss() to notify about beacon loss.

Signed-off-by: default avatarKalle Valo <kalle.valo@nokia.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent a08c1c1a
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -227,6 +227,12 @@ usage should require reading the full document.
!Pinclude/net/mac80211.h Powersave support
    </chapter>

    <chapter id="beacon-filter">
      <title>Beacon filter support</title>
!Pinclude/net/mac80211.h Beacon filter support
!Finclude/net/mac80211.h ieee80211_beacon_loss
    </chapter>

    <chapter id="qos">
      <title>Multiple queues and QoS support</title>
      <para>TBD</para>
+33 −0
Original line number Diff line number Diff line
@@ -882,6 +882,10 @@ enum ieee80211_tkip_key_type {
 *
 * @IEEE80211_HW_MFP_CAPABLE:
 *	Hardware supports management frame protection (MFP, IEEE 802.11w).
 *
 * @IEEE80211_HW_BEACON_FILTER:
 *	Hardware supports dropping of irrelevant beacon frames to
 *	avoid waking up cpu.
 */
enum ieee80211_hw_flags {
	IEEE80211_HW_RX_INCLUDES_FCS			= 1<<1,
@@ -897,6 +901,7 @@ enum ieee80211_hw_flags {
	IEEE80211_HW_PS_NULLFUNC_STACK			= 1<<11,
	IEEE80211_HW_SUPPORTS_DYNAMIC_PS		= 1<<12,
	IEEE80211_HW_MFP_CAPABLE			= 1<<13,
	IEEE80211_HW_BEACON_FILTER			= 1<<14,
};

/**
@@ -1120,6 +1125,24 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw,
 * value, or by the stack if all nullfunc handling is in the stack.
 */

/**
 * DOC: Beacon filter support
 *
 * Some hardware have beacon filter support to reduce host cpu wakeups
 * which will reduce system power consumption. It usuallly works so that
 * the firmware creates a checksum of the beacon but omits all constantly
 * changing elements (TSF, TIM etc). Whenever the checksum changes the
 * beacon is forwarded to the host, otherwise it will be just dropped. That
 * way the host will only receive beacons where some relevant information
 * (for example ERP protection or WMM settings) have changed.
 *
 * Beacon filter support is informed with %IEEE80211_HW_BEACON_FILTER flag.
 * The driver needs to enable beacon filter support whenever power save is
 * enabled, that is %IEEE80211_CONF_PS is set. When power save is enabled,
 * the stack will not check for beacon miss at all and the driver needs to
 * notify about complete loss of beacons with ieee80211_beacon_loss().
 */

/**
 * DOC: Frame filtering
 *
@@ -1970,6 +1993,16 @@ void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra,
struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_hw *hw,
					 const u8 *addr);

/**
 * ieee80211_beacon_loss - inform hardware does not receive beacons
 *
 * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
 *
 * When beacon filtering is enabled with IEEE80211_HW_BEACON_FILTERING and
 * IEEE80211_CONF_PS is set, the driver needs to inform whenever the
 * hardware is not receiving beacons with this function.
 */
void ieee80211_beacon_loss(struct ieee80211_vif *vif);

/* Rate control API */

+2 −0
Original line number Diff line number Diff line
@@ -275,6 +275,7 @@ struct ieee80211_if_managed {
	struct timer_list chswitch_timer;
	struct work_struct work;
	struct work_struct chswitch_work;
	struct work_struct beacon_loss_work;

	u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN];

@@ -1086,6 +1087,7 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local,
			     int powersave);
void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
			     struct ieee80211_hdr *hdr);
void ieee80211_beacon_loss_work(struct work_struct *work);

void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
				     enum queue_stop_reason reason);
+3 −0
Original line number Diff line number Diff line
@@ -477,6 +477,9 @@ static int ieee80211_stop(struct net_device *dev)
		 */
		cancel_work_sync(&sdata->u.mgd.work);
		cancel_work_sync(&sdata->u.mgd.chswitch_work);

		cancel_work_sync(&sdata->u.mgd.beacon_loss_work);

		/*
		 * When we get here, the interface is marked down.
		 * Call synchronize_rcu() to wait for the RX path
+48 −1
Original line number Diff line number Diff line
@@ -610,6 +610,8 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
		bss_info_changed |= ieee80211_handle_bss_capability(sdata,
			bss->cbss.capability, bss->has_erp_value, bss->erp_value);

		cfg80211_hold_bss(&bss->cbss);

		ieee80211_rx_bss_put(local, bss);
	}

@@ -751,6 +753,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
{
	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
	struct ieee80211_local *local = sdata->local;
	struct ieee80211_conf *conf = &local_to_hw(local)->conf;
	struct ieee80211_bss *bss;
	struct sta_info *sta;
	u32 changed = 0, config_changed = 0;

@@ -774,6 +778,15 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,

	ieee80211_sta_tear_down_BA_sessions(sta);

	bss = ieee80211_rx_bss_get(local, ifmgd->bssid,
				   conf->channel->center_freq,
				   ifmgd->ssid, ifmgd->ssid_len);

	if (bss) {
		cfg80211_unhold_bss(&bss->cbss);
		ieee80211_rx_bss_put(local, bss);
	}

	if (self_disconnected) {
		if (deauth)
			ieee80211_send_deauth_disassoc(sdata,
@@ -925,6 +938,33 @@ void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
			  jiffies + IEEE80211_MONITORING_INTERVAL);
}

void ieee80211_beacon_loss_work(struct work_struct *work)
{
	struct ieee80211_sub_if_data *sdata =
		container_of(work, struct ieee80211_sub_if_data,
			     u.mgd.beacon_loss_work);
	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;

	printk(KERN_DEBUG "%s: driver reports beacon loss from AP %pM "
	       "- sending probe request\n", sdata->dev->name,
	       sdata->u.mgd.bssid);

	ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL;
	ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid,
				 ifmgd->ssid_len, NULL, 0);

	mod_timer(&ifmgd->timer, jiffies + IEEE80211_MONITORING_INTERVAL);
}

void ieee80211_beacon_loss(struct ieee80211_vif *vif)
{
	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);

	queue_work(sdata->local->hw.workqueue,
		   &sdata->u.mgd.beacon_loss_work);
}
EXPORT_SYMBOL(ieee80211_beacon_loss);

static void ieee80211_associated(struct ieee80211_sub_if_data *sdata)
{
	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
@@ -959,7 +999,13 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata)
		goto unlock;
	}

	if (time_after(jiffies,
	/*
	 * Beacon filtering is only enabled with power save and then the
	 * stack should not check for beacon loss.
	 */
	if (!((local->hw.flags & IEEE80211_HW_BEACON_FILTER) &&
	      (local->hw.conf.flags & IEEE80211_CONF_PS)) &&
	    time_after(jiffies,
		       ifmgd->last_beacon + IEEE80211_MONITORING_INTERVAL)) {
		printk(KERN_DEBUG "%s: beacon loss from AP %pM "
		       "- sending probe request\n",
@@ -1869,6 +1915,7 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
	ifmgd = &sdata->u.mgd;
	INIT_WORK(&ifmgd->work, ieee80211_sta_work);
	INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work);
	INIT_WORK(&ifmgd->beacon_loss_work, ieee80211_beacon_loss_work);
	setup_timer(&ifmgd->timer, ieee80211_sta_timer,
		    (unsigned long) sdata);
	setup_timer(&ifmgd->chswitch_timer, ieee80211_chswitch_timer,