Return-path: Received: from smtp.nokia.com ([192.100.105.134]:55134 "EHLO mgw-mx09.nokia.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750837Ab0CSEhz (ORCPT ); Fri, 19 Mar 2010 00:37:55 -0400 Subject: Re: [RFC PATCHv4 1/1] mac80211: Add support connection monitor in hardware From: Juuso Oikarinen To: ext Johannes Berg Cc: "linux-wireless@vger.kernel.org" , "Coelho Luciano (Nokia-D/Helsinki)" In-Reply-To: <1268929437.4005.10.camel@jlt3.sipsolutions.net> References: <1268896346-15397-1-git-send-email-juuso.oikarinen@nokia.com> <1268896346-15397-2-git-send-email-juuso.oikarinen@nokia.com> <1268929437.4005.10.camel@jlt3.sipsolutions.net> Content-Type: text/plain; charset="UTF-8" Date: Fri, 19 Mar 2010 06:34:57 +0200 Message-ID: <1268973297.10120.683.camel@wimaxnb.nmp.nokia.com> Mime-Version: 1.0 Sender: linux-wireless-owner@vger.kernel.org List-ID: On Thu, 2010-03-18 at 17:23 +0100, ext Johannes Berg wrote: > 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 > Thank you! -Juuso > > > Cc: Kalle Valo > > Signed-off-by: Juuso Oikarinen > > --- > > 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, > >