Skip to content

Commit

Permalink
mac80211: add explicit AP/GO driver operations
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Johannes Berg committed Oct 26, 2012
1 parent 7b20b8e commit 1041638
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 1 deletion.
10 changes: 10 additions & 0 deletions include/net/mac80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -2381,6 +2381,13 @@ enum ieee80211_rate_control_changed {
* to vif. Possible use is for hw queue remapping.
* @unassign_vif_chanctx: Notifies device driver about channel context being
* unbound from vif.
* @start_ap: Start operation on the AP interface, this is called after all the
* information in bss_conf is set and beacon can be retrieved. A channel
* context is bound before this is called. Note that if the driver uses
* software scan or ROC, this (and @stop_ap) isn't called when the AP is
* just "paused" for scanning/ROC, which is indicated by the beacon being
* disabled/enabled via @bss_info_changed.
* @stop_ap: Stop operation on the AP interface.
*/
struct ieee80211_ops {
void (*tx)(struct ieee80211_hw *hw,
Expand All @@ -2406,6 +2413,9 @@ struct ieee80211_ops {
struct ieee80211_bss_conf *info,
u32 changed);

int (*start_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
void (*stop_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);

u64 (*prepare_multicast)(struct ieee80211_hw *hw,
struct netdev_hw_addr_list *mc_list);
void (*configure_filter)(struct ieee80211_hw *hw,
Expand Down
11 changes: 11 additions & 0 deletions net/mac80211/cfg.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
25 changes: 25 additions & 0 deletions net/mac80211/driver-ops.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
4 changes: 4 additions & 0 deletions net/mac80211/pm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
37 changes: 37 additions & 0 deletions net/mac80211/trace.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down
6 changes: 5 additions & 1 deletion net/mac80211/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down

0 comments on commit 1041638

Please sign in to comment.