Commit 199160bb authored by John W. Linville's avatar John W. Linville
parents 4cfe9a8d fab57a6c
...@@ -1021,8 +1021,10 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, ...@@ -1021,8 +1021,10 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
IEEE80211_P2P_OPPPS_ENABLE_BIT; IEEE80211_P2P_OPPPS_ENABLE_BIT;
err = ieee80211_assign_beacon(sdata, &params->beacon); err = ieee80211_assign_beacon(sdata, &params->beacon);
if (err < 0) if (err < 0) {
ieee80211_vif_release_channel(sdata);
return err; return err;
}
changed |= err; changed |= err;
err = drv_start_ap(sdata->local, sdata); err = drv_start_ap(sdata->local, sdata);
...@@ -1032,6 +1034,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, ...@@ -1032,6 +1034,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
if (old) if (old)
kfree_rcu(old, rcu_head); kfree_rcu(old, rcu_head);
RCU_INIT_POINTER(sdata->u.ap.beacon, NULL); RCU_INIT_POINTER(sdata->u.ap.beacon, NULL);
ieee80211_vif_release_channel(sdata);
return err; return err;
} }
...@@ -1090,8 +1093,6 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) ...@@ -1090,8 +1093,6 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
kfree(sdata->u.ap.next_beacon); kfree(sdata->u.ap.next_beacon);
sdata->u.ap.next_beacon = NULL; sdata->u.ap.next_beacon = NULL;
cancel_work_sync(&sdata->u.ap.request_smps_work);
/* turn off carrier for this interface and dependent VLANs */ /* turn off carrier for this interface and dependent VLANs */
list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
netif_carrier_off(vlan->dev); netif_carrier_off(vlan->dev);
...@@ -1103,6 +1104,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) ...@@ -1103,6 +1104,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
kfree_rcu(old_beacon, rcu_head); kfree_rcu(old_beacon, rcu_head);
if (old_probe_resp) if (old_probe_resp)
kfree_rcu(old_probe_resp, rcu_head); kfree_rcu(old_probe_resp, rcu_head);
sdata->u.ap.driver_smps_mode = IEEE80211_SMPS_OFF;
__sta_info_flush(sdata, true); __sta_info_flush(sdata, true);
ieee80211_free_keys(sdata, true); ieee80211_free_keys(sdata, true);
...@@ -2638,6 +2640,24 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, ...@@ -2638,6 +2640,24 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
INIT_DELAYED_WORK(&roc->work, ieee80211_sw_roc_work); INIT_DELAYED_WORK(&roc->work, ieee80211_sw_roc_work);
INIT_LIST_HEAD(&roc->dependents); INIT_LIST_HEAD(&roc->dependents);
/*
* cookie is either the roc cookie (for normal roc)
* or the SKB (for mgmt TX)
*/
if (!txskb) {
/* local->mtx protects this */
local->roc_cookie_counter++;
roc->cookie = local->roc_cookie_counter;
/* wow, you wrapped 64 bits ... more likely a bug */
if (WARN_ON(roc->cookie == 0)) {
roc->cookie = 1;
local->roc_cookie_counter++;
}
*cookie = roc->cookie;
} else {
*cookie = (unsigned long)txskb;
}
/* if there's one pending or we're scanning, queue this one */ /* if there's one pending or we're scanning, queue this one */
if (!list_empty(&local->roc_list) || if (!list_empty(&local->roc_list) ||
local->scanning || local->radar_detect_enabled) local->scanning || local->radar_detect_enabled)
...@@ -2772,24 +2792,6 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, ...@@ -2772,24 +2792,6 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
if (!queued) if (!queued)
list_add_tail(&roc->list, &local->roc_list); list_add_tail(&roc->list, &local->roc_list);
/*
* cookie is either the roc cookie (for normal roc)
* or the SKB (for mgmt TX)
*/
if (!txskb) {
/* local->mtx protects this */
local->roc_cookie_counter++;
roc->cookie = local->roc_cookie_counter;
/* wow, you wrapped 64 bits ... more likely a bug */
if (WARN_ON(roc->cookie == 0)) {
roc->cookie = 1;
local->roc_cookie_counter++;
}
*cookie = roc->cookie;
} else {
*cookie = (unsigned long)txskb;
}
return 0; return 0;
} }
......
...@@ -466,7 +466,9 @@ void ieee80211_request_smps_ap_work(struct work_struct *work) ...@@ -466,7 +466,9 @@ void ieee80211_request_smps_ap_work(struct work_struct *work)
u.ap.request_smps_work); u.ap.request_smps_work);
sdata_lock(sdata); sdata_lock(sdata);
__ieee80211_request_smps_ap(sdata, sdata->u.ap.driver_smps_mode); if (sdata_dereference(sdata->u.ap.beacon, sdata))
__ieee80211_request_smps_ap(sdata,
sdata->u.ap.driver_smps_mode);
sdata_unlock(sdata); sdata_unlock(sdata);
} }
......
...@@ -695,12 +695,9 @@ static void ieee80211_ibss_disconnect(struct ieee80211_sub_if_data *sdata) ...@@ -695,12 +695,9 @@ static void ieee80211_ibss_disconnect(struct ieee80211_sub_if_data *sdata)
struct cfg80211_bss *cbss; struct cfg80211_bss *cbss;
struct beacon_data *presp; struct beacon_data *presp;
struct sta_info *sta; struct sta_info *sta;
int active_ibss;
u16 capability; u16 capability;
active_ibss = ieee80211_sta_active_ibss(sdata); if (!is_zero_ether_addr(ifibss->bssid)) {
if (!active_ibss && !is_zero_ether_addr(ifibss->bssid)) {
capability = WLAN_CAPABILITY_IBSS; capability = WLAN_CAPABILITY_IBSS;
if (ifibss->privacy) if (ifibss->privacy)
......
...@@ -418,20 +418,24 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local) ...@@ -418,20 +418,24 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
return ret; return ret;
} }
mutex_lock(&local->iflist_mtx);
rcu_assign_pointer(local->monitor_sdata, sdata);
mutex_unlock(&local->iflist_mtx);
mutex_lock(&local->mtx); mutex_lock(&local->mtx);
ret = ieee80211_vif_use_channel(sdata, &local->monitor_chandef, ret = ieee80211_vif_use_channel(sdata, &local->monitor_chandef,
IEEE80211_CHANCTX_EXCLUSIVE); IEEE80211_CHANCTX_EXCLUSIVE);
mutex_unlock(&local->mtx); mutex_unlock(&local->mtx);
if (ret) { if (ret) {
mutex_lock(&local->iflist_mtx);
rcu_assign_pointer(local->monitor_sdata, NULL);
mutex_unlock(&local->iflist_mtx);
synchronize_net();
drv_remove_interface(local, sdata); drv_remove_interface(local, sdata);
kfree(sdata); kfree(sdata);
return ret; return ret;
} }
mutex_lock(&local->iflist_mtx);
rcu_assign_pointer(local->monitor_sdata, sdata);
mutex_unlock(&local->iflist_mtx);
return 0; return 0;
} }
...@@ -770,12 +774,19 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, ...@@ -770,12 +774,19 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
ieee80211_roc_purge(local, sdata); ieee80211_roc_purge(local, sdata);
if (sdata->vif.type == NL80211_IFTYPE_STATION) switch (sdata->vif.type) {
case NL80211_IFTYPE_STATION:
ieee80211_mgd_stop(sdata); ieee80211_mgd_stop(sdata);
break;
if (sdata->vif.type == NL80211_IFTYPE_ADHOC) case NL80211_IFTYPE_ADHOC:
ieee80211_ibss_stop(sdata); ieee80211_ibss_stop(sdata);
break;
case NL80211_IFTYPE_AP:
cancel_work_sync(&sdata->u.ap.request_smps_work);
break;
default:
break;
}
/* /*
* Remove all stations associated with this interface. * Remove all stations associated with this interface.
......
...@@ -878,7 +878,7 @@ static int ieee80211_fragment(struct ieee80211_tx_data *tx, ...@@ -878,7 +878,7 @@ static int ieee80211_fragment(struct ieee80211_tx_data *tx,
} }
/* adjust first fragment's length */ /* adjust first fragment's length */
skb->len = hdrlen + per_fragm; skb_trim(skb, hdrlen + per_fragm);
return 0; return 0;
} }
......
...@@ -203,8 +203,11 @@ void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev, ...@@ -203,8 +203,11 @@ void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev,
rdev->opencount--; rdev->opencount--;
WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev && if (rdev->scan_req && rdev->scan_req->wdev == wdev) {
!rdev->scan_req->notified); if (WARN_ON(!rdev->scan_req->notified))
rdev->scan_req->aborted = true;
___cfg80211_scan_done(rdev, false);
}
} }
static int cfg80211_rfkill_set_block(void *data, bool blocked) static int cfg80211_rfkill_set_block(void *data, bool blocked)
...@@ -440,9 +443,6 @@ int wiphy_register(struct wiphy *wiphy) ...@@ -440,9 +443,6 @@ int wiphy_register(struct wiphy *wiphy)
int i; int i;
u16 ifmodes = wiphy->interface_modes; u16 ifmodes = wiphy->interface_modes;
/* support for 5/10 MHz is broken due to nl80211 API mess - disable */
wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_5_10_MHZ;
/* /*
* There are major locking problems in nl80211/mac80211 for CSA, * There are major locking problems in nl80211/mac80211 for CSA,
* disable for all drivers until this has been reworked. * disable for all drivers until this has been reworked.
...@@ -859,8 +859,11 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, ...@@ -859,8 +859,11 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
break; break;
case NETDEV_DOWN: case NETDEV_DOWN:
cfg80211_update_iface_num(rdev, wdev->iftype, -1); cfg80211_update_iface_num(rdev, wdev->iftype, -1);
WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev && if (rdev->scan_req && rdev->scan_req->wdev == wdev) {
!rdev->scan_req->notified); if (WARN_ON(!rdev->scan_req->notified))
rdev->scan_req->aborted = true;
___cfg80211_scan_done(rdev, false);
}
if (WARN_ON(rdev->sched_scan_req && if (WARN_ON(rdev->sched_scan_req &&
rdev->sched_scan_req->dev == wdev->netdev)) { rdev->sched_scan_req->dev == wdev->netdev)) {
......
...@@ -62,6 +62,7 @@ struct cfg80211_registered_device { ...@@ -62,6 +62,7 @@ struct cfg80211_registered_device {
struct rb_root bss_tree; struct rb_root bss_tree;
u32 bss_generation; u32 bss_generation;
struct cfg80211_scan_request *scan_req; /* protected by RTNL */ struct cfg80211_scan_request *scan_req; /* protected by RTNL */
struct sk_buff *scan_msg;
struct cfg80211_sched_scan_request *sched_scan_req; struct cfg80211_sched_scan_request *sched_scan_req;
unsigned long suspend_at; unsigned long suspend_at;
struct work_struct scan_done_wk; struct work_struct scan_done_wk;
...@@ -361,7 +362,8 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, ...@@ -361,7 +362,8 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
struct key_params *params, int key_idx, struct key_params *params, int key_idx,
bool pairwise, const u8 *mac_addr); bool pairwise, const u8 *mac_addr);
void __cfg80211_scan_done(struct work_struct *wk); void __cfg80211_scan_done(struct work_struct *wk);
void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev); void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev,
bool send_message);
void __cfg80211_sched_scan_results(struct work_struct *wk); void __cfg80211_sched_scan_results(struct work_struct *wk);
int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev, int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
bool driver_initiated); bool driver_initiated);
......
...@@ -1719,9 +1719,10 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -1719,9 +1719,10 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
* We can then retry with the larger buffer. * We can then retry with the larger buffer.
*/ */
if ((ret == -ENOBUFS || ret == -EMSGSIZE) && if ((ret == -ENOBUFS || ret == -EMSGSIZE) &&
!skb->len && !skb->len && !state->split &&
cb->min_dump_alloc < 4096) { cb->min_dump_alloc < 4096) {
cb->min_dump_alloc = 4096; cb->min_dump_alloc = 4096;
state->split_start = 0;
rtnl_unlock(); rtnl_unlock();
return 1; return 1;
} }
...@@ -5244,7 +5245,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) ...@@ -5244,7 +5245,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
if (!rdev->ops->scan) if (!rdev->ops->scan)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (rdev->scan_req) { if (rdev->scan_req || rdev->scan_msg) {
err = -EBUSY; err = -EBUSY;
goto unlock; goto unlock;
} }
...@@ -10011,40 +10012,31 @@ void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, ...@@ -10011,40 +10012,31 @@ void nl80211_send_scan_start(struct cfg80211_registered_device *rdev,
NL80211_MCGRP_SCAN, GFP_KERNEL); NL80211_MCGRP_SCAN, GFP_KERNEL);
} }
void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, struct sk_buff *nl80211_build_scan_msg(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev) struct wireless_dev *wdev, bool aborted)
{ {
struct sk_buff *msg; struct sk_buff *msg;
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg) if (!msg)
return; return NULL;
if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0, if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0,
aborted ? NL80211_CMD_SCAN_ABORTED :
NL80211_CMD_NEW_SCAN_RESULTS) < 0) { NL80211_CMD_NEW_SCAN_RESULTS) < 0) {
nlmsg_free(msg); nlmsg_free(msg);
return; return NULL;
} }
genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, return msg;
NL80211_MCGRP_SCAN, GFP_KERNEL);
} }
void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, void nl80211_send_scan_result(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev) struct sk_buff *msg)
{ {
struct sk_buff *msg;
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg) if (!msg)
return; return;
if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0,
NL80211_CMD_SCAN_ABORTED) < 0) {
nlmsg_free(msg);
return;
}
genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
NL80211_MCGRP_SCAN, GFP_KERNEL); NL80211_MCGRP_SCAN, GFP_KERNEL);
} }
......
...@@ -8,10 +8,10 @@ void nl80211_exit(void); ...@@ -8,10 +8,10 @@ void nl80211_exit(void);
void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev); void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev);
void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, void nl80211_send_scan_start(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev); struct wireless_dev *wdev);
void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, struct sk_buff *nl80211_build_scan_msg(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev); struct wireless_dev *wdev, bool aborted);
void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, void nl80211_send_scan_result(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev); struct sk_buff *msg);
void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev, void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
struct net_device *netdev, u32 cmd); struct net_device *netdev, u32 cmd);
void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev, void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev,
......
...@@ -161,18 +161,25 @@ static void __cfg80211_bss_expire(struct cfg80211_registered_device *dev, ...@@ -161,18 +161,25 @@ static void __cfg80211_bss_expire(struct cfg80211_registered_device *dev,
dev->bss_generation++; dev->bss_generation++;
} }
void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev) void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev,
bool send_message)
{ {
struct cfg80211_scan_request *request; struct cfg80211_scan_request *request;
struct wireless_dev *wdev; struct wireless_dev *wdev;
struct sk_buff *msg;
#ifdef CONFIG_CFG80211_WEXT #ifdef CONFIG_CFG80211_WEXT
union iwreq_data wrqu; union iwreq_data wrqu;
#endif #endif
ASSERT_RTNL(); ASSERT_RTNL();
request = rdev->scan_req; if (rdev->scan_msg) {
nl80211_send_scan_result(rdev, rdev->scan_msg);
rdev->scan_msg = NULL;
return;
}
request = rdev->scan_req;
if (!request) if (!request)
return; return;
...@@ -186,17 +193,15 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev) ...@@ -186,17 +193,15 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev)
if (wdev->netdev) if (wdev->netdev)
cfg80211_sme_scan_done(wdev->netdev); cfg80211_sme_scan_done(wdev->netdev);
if (request->aborted) { if (!request->aborted &&
nl80211_send_scan_aborted(rdev, wdev); request->flags & NL80211_SCAN_FLAG_FLUSH) {
} else {
if (request->flags & NL80211_SCAN_FLAG_FLUSH) {
/* flush entries from previous scans */ /* flush entries from previous scans */
spin_lock_bh(&rdev->bss_lock); spin_lock_bh(&rdev->bss_lock);
__cfg80211_bss_expire(rdev, request->scan_start); __cfg80211_bss_expire(rdev, request->scan_start);
spin_unlock_bh(&rdev->bss_lock); spin_unlock_bh(&rdev->bss_lock);
} }
nl80211_send_scan_done(rdev, wdev);
} msg = nl80211_build_scan_msg(rdev, wdev, request->aborted);
#ifdef CONFIG_CFG80211_WEXT #ifdef CONFIG_CFG80211_WEXT
if (wdev->netdev && !request->aborted) { if (wdev->netdev && !request->aborted) {
...@@ -211,6 +216,11 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev) ...@@ -211,6 +216,11 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev)
rdev->scan_req = NULL; rdev->scan_req = NULL;
kfree(request); kfree(request);
if (!send_message)
rdev->scan_msg = msg;
else
nl80211_send_scan_result(rdev, msg);
} }
void __cfg80211_scan_done(struct work_struct *wk) void __cfg80211_scan_done(struct work_struct *wk)
...@@ -221,7 +231,7 @@ void __cfg80211_scan_done(struct work_struct *wk) ...@@ -221,7 +231,7 @@ void __cfg80211_scan_done(struct work_struct *wk)
scan_done_wk); scan_done_wk);
rtnl_lock(); rtnl_lock();
___cfg80211_scan_done(rdev); ___cfg80211_scan_done(rdev, true);
rtnl_unlock(); rtnl_unlock();
} }
...@@ -1079,7 +1089,7 @@ int cfg80211_wext_siwscan(struct net_device *dev, ...@@ -1079,7 +1089,7 @@ int cfg80211_wext_siwscan(struct net_device *dev,
if (IS_ERR(rdev)) if (IS_ERR(rdev))
return PTR_ERR(rdev); return PTR_ERR(rdev);
if (rdev->scan_req) { if (rdev->scan_req || rdev->scan_msg) {
err = -EBUSY; err = -EBUSY;
goto out; goto out;
} }
...@@ -1481,7 +1491,7 @@ int cfg80211_wext_giwscan(struct net_device *dev, ...@@ -1481,7 +1491,7 @@ int cfg80211_wext_giwscan(struct net_device *dev,
if (IS_ERR(rdev)) if (IS_ERR(rdev))
return PTR_ERR(rdev); return PTR_ERR(rdev);
if (rdev->scan_req) if (rdev->scan_req || rdev->scan_msg)
return -EAGAIN; return -EAGAIN;
res = ieee80211_scan_results(rdev, info, extra, data->length); res = ieee80211_scan_results(rdev, info, extra, data->length);
......
...@@ -67,7 +67,7 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev) ...@@ -67,7 +67,7 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev)
ASSERT_RDEV_LOCK(rdev); ASSERT_RDEV_LOCK(rdev);
ASSERT_WDEV_LOCK(wdev); ASSERT_WDEV_LOCK(wdev);
if (rdev->scan_req) if (rdev->scan_req || rdev->scan_msg)
return -EBUSY; return -EBUSY;
if (wdev->conn->params.channel) if (wdev->conn->params.channel)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment