diff options
author | Johannes Berg <johannes.berg@intel.com> | 2012-10-19 15:44:42 +0200 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2012-10-26 12:57:06 +0200 |
commit | 1041638f2bba0f1de75e66086d50fb1251d64dcf (patch) | |
tree | 95d5ea3a83302d27887dcdc2d425682216937f3f /net | |
parent | 7b20b8e8d70a0f4f18c254b42e5b157f93731e9f (diff) | |
download | linux-stable-1041638f2bba0f1de75e66086d50fb1251d64dcf.tar.gz linux-stable-1041638f2bba0f1de75e66086d50fb1251d64dcf.tar.bz2 linux-stable-1041638f2bba0f1de75e66086d50fb1251d64dcf.zip |
mac80211: add explicit AP/GO driver operations
Depending on the driver, a lot of setup may be
necessary to start operating as an AP, some of
which may fail. Add an explicit AP start driver
method to make such failures easier to handle,
and add an AP stop driver method for symmetry.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/cfg.c | 11 | ||||
-rw-r--r-- | net/mac80211/driver-ops.h | 25 | ||||
-rw-r--r-- | net/mac80211/pm.c | 4 | ||||
-rw-r--r-- | net/mac80211/trace.h | 37 | ||||
-rw-r--r-- | net/mac80211/util.c | 6 |
5 files changed, 82 insertions, 1 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 95bf3d5d009f..34fd3eba3090 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -922,6 +922,15 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, return err; changed |= err; + err = drv_start_ap(sdata->local, sdata); + if (err) { + old = rtnl_dereference(sdata->u.ap.beacon); + if (old) + kfree_rcu(old, rcu_head); + RCU_INIT_POINTER(sdata->u.ap.beacon, NULL); + return err; + } + ieee80211_bss_info_change_notify(sdata, changed); netif_carrier_on(dev); @@ -979,6 +988,8 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) sta_info_flush(local, sdata); ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); + drv_stop_ap(sdata->local, sdata); + /* free all potentially still buffered bcast frames */ local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps.bc_buf); skb_queue_purge(&sdata->u.ap.ps.bc_buf); diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 77407b31e1ff..1701ad7013a4 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -936,4 +936,29 @@ static inline void drv_unassign_vif_chanctx(struct ieee80211_local *local, trace_drv_return_void(local); } +static inline int drv_start_ap(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata) +{ + int ret = 0; + + check_sdata_in_driver(sdata); + + trace_drv_start_ap(local, sdata, &sdata->vif.bss_conf); + if (local->ops->start_ap) + ret = local->ops->start_ap(&local->hw, &sdata->vif); + trace_drv_return_int(local, ret); + return ret; +} + +static inline void drv_stop_ap(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata) +{ + check_sdata_in_driver(sdata); + + trace_drv_stop_ap(local, sdata); + if (local->ops->stop_ap) + local->ops->stop_ap(&local->hw, &sdata->vif); + trace_drv_return_void(local); +} + #endif /* __MAC80211_DRIVER_OPS */ diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 9f404ac901ab..0f1c434638bc 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -135,6 +135,10 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); + if (sdata->vif.type == NL80211_IFTYPE_AP && + rcu_access_pointer(sdata->u.ap.beacon)) + drv_stop_ap(local, sdata); + /* the interface is leaving the channel and is removed */ ieee80211_vif_release_channel(sdata); drv_remove_interface(local, sdata); diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 0638541b625f..5e74e77cba9a 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -1396,6 +1396,43 @@ DEFINE_EVENT(local_sdata_chanctx, drv_unassign_vif_chanctx, TP_ARGS(local, sdata, ctx) ); +TRACE_EVENT(drv_start_ap, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct ieee80211_bss_conf *info), + + TP_ARGS(local, sdata, info), + + TP_STRUCT__entry( + LOCAL_ENTRY + VIF_ENTRY + __field(u8, dtimper) + __field(u16, bcnint) + __dynamic_array(u8, ssid, info->ssid_len); + __field(bool, hidden_ssid); + ), + + TP_fast_assign( + LOCAL_ASSIGN; + VIF_ASSIGN; + __entry->dtimper = info->dtim_period; + __entry->bcnint = info->beacon_int; + memcpy(__get_dynamic_array(ssid), info->ssid, info->ssid_len); + __entry->hidden_ssid = info->hidden_ssid; + ), + + TP_printk( + LOCAL_PR_FMT VIF_PR_FMT, + LOCAL_PR_ARG, VIF_PR_ARG + ) +); + +DEFINE_EVENT(local_sdata_evt, drv_stop_ap, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata), + TP_ARGS(local, sdata) +); + /* * Tracing for API calls that drivers call. */ diff --git a/net/mac80211/util.c b/net/mac80211/util.c index ea8a6744a9db..dd0e6f20fc51 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1467,9 +1467,13 @@ int ieee80211_reconfig(struct ieee80211_local *local) case NL80211_IFTYPE_AP: changed |= BSS_CHANGED_SSID; - if (sdata->vif.type == NL80211_IFTYPE_AP) + if (sdata->vif.type == NL80211_IFTYPE_AP) { changed |= BSS_CHANGED_AP_PROBE_RESP; + if (rcu_access_pointer(sdata->u.ap.beacon)) + drv_start_ap(local, sdata); + } + /* fall through */ case NL80211_IFTYPE_MESH_POINT: changed |= BSS_CHANGED_BEACON | |