Search Linux Wireless

Re: [RFC PATCHv4 1/1] mac80211: Add support connection monitor in hardware

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, 2010-03-18 at 09:12 +0200, Juuso Oikarinen wrote:
> This patch is based on a RFC patch by Kalle Valo.
> 
> The wl1271 has a feature which handles the connection monitor logic
> in hardware, basically sending periodically nullfunc frames and reporting
> to the host if AP is lost, after attempting to recover by sending
> probe-requests to the AP.
> 
> Add support to mac80211 by adding a new flag IEEE80211_HW_CONNECTION_MONITOR
> which prevents conn_mon_timer from triggering during idle periods, and
> prevents sending probe-requests to the AP if beacon-loss is indicated by the
> hardware.

Reviewed-by: Johannes Berg <johannes@xxxxxxxxxxxxxxxx>


> Cc: Kalle Valo <kalle.valo@xxxxxxxxx>
> Signed-off-by: Juuso Oikarinen <juuso.oikarinen@xxxxxxxxx>
> ---
>  include/net/mac80211.h     |   24 +++++++++++++++-
>  net/mac80211/ieee80211_i.h |    4 +-
>  net/mac80211/iface.c       |    2 +-
>  net/mac80211/mlme.c        |   64 +++++++++++++++++++++++++++++++++++++++-----
>  4 files changed, 82 insertions(+), 12 deletions(-)
> 
> diff --git a/include/net/mac80211.h b/include/net/mac80211.h
> index 936bc41..d14226f 100644
> --- a/include/net/mac80211.h
> +++ b/include/net/mac80211.h
> @@ -954,6 +954,11 @@ enum ieee80211_tkip_key_type {
>   *	Hardware can provide ack status reports of Tx frames to
>   *	the stack.
>   *
> + * @IEEE80211_HW_CONNECTION_MONITOR:
> + *      The hardware performs its own connection monitoring, including
> + *      periodic keep-alives to the AP and probing the AP on beacon loss.
> + *      When this flag is set, signaling beacon-loss will cause an immediate
> + *      change to disassociated state.
>   */
>  enum ieee80211_hw_flags {
>  	IEEE80211_HW_HAS_RATE_CONTROL			= 1<<0,
> @@ -975,6 +980,7 @@ enum ieee80211_hw_flags {
>  	IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS		= 1<<16,
>  	IEEE80211_HW_SUPPORTS_UAPSD			= 1<<17,
>  	IEEE80211_HW_REPORTS_TX_ACK_STATUS		= 1<<18,
> +	IEEE80211_HW_CONNECTION_MONITOR			= 1<<19,
>  };
>  
>  /**
> @@ -2364,12 +2370,26 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw,
>   *
>   * @vif: &struct ieee80211_vif pointer from the add_interface callback.
>   *
> - * When beacon filtering is enabled with IEEE80211_HW_BEACON_FILTERING and
> - * IEEE80211_CONF_PS is set, the driver needs to inform whenever the
> + * 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);
>  
> +/**
> + * ieee80211_connection_loss - inform hardware has lost connection to the AP
> + *
> + * @vif: &struct ieee80211_vif pointer from the add_interface callback.
> + *
> + * When beacon filtering is enabled with %IEEE80211_HW_BEACON_FILTERING, and
> + * %IEEE80211_CONF_PS and %IEEE80211_HW_CONNECTION_MONITOR are set, the driver
> + * needs to inform if the connection to the AP has been lost.
> + *
> + * This function will cause immediate change to disassociated state,
> + * without connection recovery attempts.
> + */
> +void ieee80211_connection_loss(struct ieee80211_vif *vif);
> +
>  /* Rate control API */
>  
>  /**
> diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
> index b841264..ab369e2 100644
> --- a/net/mac80211/ieee80211_i.h
> +++ b/net/mac80211/ieee80211_i.h
> @@ -327,7 +327,7 @@ struct ieee80211_if_managed {
>  	struct work_struct work;
>  	struct work_struct monitor_work;
>  	struct work_struct chswitch_work;
> -	struct work_struct beacon_loss_work;
> +	struct work_struct beacon_connection_loss_work;
>  
>  	unsigned long probe_timeout;
>  	int probe_send_count;
> @@ -1156,7 +1156,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_beacon_connection_loss_work(struct work_struct *work);
>  
>  void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
>  				     enum queue_stop_reason reason);
> diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
> index d5571b9..b4ec59a 100644
> --- a/net/mac80211/iface.c
> +++ b/net/mac80211/iface.c
> @@ -486,7 +486,7 @@ 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.monitor_work);
> -		cancel_work_sync(&sdata->u.mgd.beacon_loss_work);
> +		cancel_work_sync(&sdata->u.mgd.beacon_connection_loss_work);
>  
>  		/*
>  		 * When we get here, the interface is marked down.
> diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
> index be5f723..6b43a0a 100644
> --- a/net/mac80211/mlme.c
> +++ b/net/mac80211/mlme.c
> @@ -854,6 +854,9 @@ void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
>  	if (is_multicast_ether_addr(hdr->addr1))
>  		return;
>  
> +	if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR)
> +		return;
> +
>  	mod_timer(&sdata->u.mgd.conn_mon_timer,
>  		  round_jiffies_up(jiffies + IEEE80211_CONNECTION_IDLE_TIME));
>  }
> @@ -931,23 +934,68 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
>  	mutex_unlock(&ifmgd->mtx);
>  }
>  
> -void ieee80211_beacon_loss_work(struct work_struct *work)
> +static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata)
> +{
> +	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
> +	struct ieee80211_local *local = sdata->local;
> +	u8 bssid[ETH_ALEN];
> +
> +	mutex_lock(&ifmgd->mtx);
> +	if (!ifmgd->associated) {
> +		mutex_unlock(&ifmgd->mtx);
> +		return;
> +	}
> +
> +	memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN);
> +
> +	printk(KERN_DEBUG "Connection to AP %pM lost.\n", bssid);
> +
> +	ieee80211_set_disassoc(sdata);
> +	ieee80211_recalc_idle(local);
> +	mutex_unlock(&ifmgd->mtx);
> +	/*
> +	 * must be outside lock due to cfg80211,
> +	 * but that's not a problem.
> +	 */
> +	ieee80211_send_deauth_disassoc(sdata, bssid,
> +				       IEEE80211_STYPE_DEAUTH,
> +				       WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
> +				       NULL);
> +}
> +
> +void ieee80211_beacon_connection_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);
> +			     u.mgd.beacon_connection_loss_work);
>  
> -	ieee80211_mgd_probe_ap(sdata, true);
> +	if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR)
> +		__ieee80211_connection_loss(sdata);
> +	else
> +		ieee80211_mgd_probe_ap(sdata, true);
>  }
>  
>  void ieee80211_beacon_loss(struct ieee80211_vif *vif)
>  {
>  	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
> +	struct ieee80211_hw *hw = &sdata->local->hw;
>  
> -	ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.beacon_loss_work);
> +	WARN_ON(hw->flags & IEEE80211_HW_CONNECTION_MONITOR);
> +	ieee80211_queue_work(hw, &sdata->u.mgd.beacon_connection_loss_work);
>  }
>  EXPORT_SYMBOL(ieee80211_beacon_loss);
>  
> +void ieee80211_connection_loss(struct ieee80211_vif *vif)
> +{
> +	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
> +	struct ieee80211_hw *hw = &sdata->local->hw;
> +
> +	WARN_ON(!(hw->flags & IEEE80211_HW_CONNECTION_MONITOR));
> +	ieee80211_queue_work(hw, &sdata->u.mgd.beacon_connection_loss_work);
> +}
> +EXPORT_SYMBOL(ieee80211_connection_loss);
> +
> +
>  static enum rx_mgmt_action __must_check
>  ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
>  			 struct ieee80211_mgmt *mgmt, size_t len)
> @@ -1637,7 +1685,8 @@ static void ieee80211_sta_bcn_mon_timer(unsigned long data)
>  	if (local->quiescing)
>  		return;
>  
> -	ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.beacon_loss_work);
> +	ieee80211_queue_work(&sdata->local->hw,
> +			     &sdata->u.mgd.beacon_connection_loss_work);
>  }
>  
>  static void ieee80211_sta_conn_mon_timer(unsigned long data)
> @@ -1689,7 +1738,7 @@ void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata)
>  	 */
>  
>  	cancel_work_sync(&ifmgd->work);
> -	cancel_work_sync(&ifmgd->beacon_loss_work);
> +	cancel_work_sync(&ifmgd->beacon_connection_loss_work);
>  	if (del_timer_sync(&ifmgd->timer))
>  		set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running);
>  
> @@ -1723,7 +1772,8 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
>  	INIT_WORK(&ifmgd->work, ieee80211_sta_work);
>  	INIT_WORK(&ifmgd->monitor_work, ieee80211_sta_monitor_work);
>  	INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work);
> -	INIT_WORK(&ifmgd->beacon_loss_work, ieee80211_beacon_loss_work);
> +	INIT_WORK(&ifmgd->beacon_connection_loss_work,
> +		  ieee80211_beacon_connection_loss_work);
>  	setup_timer(&ifmgd->timer, ieee80211_sta_timer,
>  		    (unsigned long) sdata);
>  	setup_timer(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer,


--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]
  Powered by Linux