|
@@ -953,26 +953,36 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev,
|
|
|
|
|
|
static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
|
|
|
{
|
|
|
- struct ieee80211_sub_if_data *sdata, *vlan;
|
|
|
- struct beacon_data *old;
|
|
|
-
|
|
|
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
|
|
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
|
|
+ struct ieee80211_sub_if_data *vlan;
|
|
|
+ struct ieee80211_local *local = sdata->local;
|
|
|
+ struct beacon_data *old_beacon;
|
|
|
+ struct probe_resp *old_probe_resp;
|
|
|
|
|
|
- old = rtnl_dereference(sdata->u.ap.beacon);
|
|
|
- if (!old)
|
|
|
+ old_beacon = rtnl_dereference(sdata->u.ap.beacon);
|
|
|
+ if (!old_beacon)
|
|
|
return -ENOENT;
|
|
|
+ old_probe_resp = rtnl_dereference(sdata->u.ap.probe_resp);
|
|
|
|
|
|
+ /* turn off carrier for this interface and dependent VLANs */
|
|
|
list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
|
|
|
netif_carrier_off(vlan->dev);
|
|
|
netif_carrier_off(dev);
|
|
|
|
|
|
+ /* remove beacon and probe response */
|
|
|
RCU_INIT_POINTER(sdata->u.ap.beacon, NULL);
|
|
|
+ RCU_INIT_POINTER(sdata->u.ap.probe_resp, NULL);
|
|
|
+ kfree_rcu(old_beacon, rcu_head);
|
|
|
+ if (old_probe_resp)
|
|
|
+ kfree_rcu(old_probe_resp, rcu_head);
|
|
|
|
|
|
- kfree_rcu(old, rcu_head);
|
|
|
-
|
|
|
- sta_info_flush(sdata->local, sdata);
|
|
|
+ sta_info_flush(local, sdata);
|
|
|
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
|
|
|
|
|
|
+ /* 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);
|
|
|
+
|
|
|
ieee80211_vif_release_channel(sdata);
|
|
|
|
|
|
return 0;
|