Skip to content

Commit

Permalink
Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/…
Browse files Browse the repository at this point in the history
…git/jberg/mac80211
  • Loading branch information
John W. Linville committed Mar 25, 2013
2 parents 36ef0b4 + 370bd00 commit fae1721
Show file tree
Hide file tree
Showing 12 changed files with 154 additions and 76 deletions.
35 changes: 19 additions & 16 deletions net/mac80211/iface.c
Original file line number Diff line number Diff line change
Expand Up @@ -349,21 +349,19 @@ static void ieee80211_set_default_queues(struct ieee80211_sub_if_data *sdata)
static int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
{
struct ieee80211_sub_if_data *sdata;
int ret = 0;
int ret;

if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF))
return 0;

mutex_lock(&local->iflist_mtx);
ASSERT_RTNL();

if (local->monitor_sdata)
goto out_unlock;
return 0;

sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size, GFP_KERNEL);
if (!sdata) {
ret = -ENOMEM;
goto out_unlock;
}
if (!sdata)
return -ENOMEM;

/* set up data */
sdata->local = local;
Expand All @@ -377,27 +375,28 @@ static int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
if (WARN_ON(ret)) {
/* ok .. stupid driver, it asked for this! */
kfree(sdata);
goto out_unlock;
return ret;
}

ret = ieee80211_check_queues(sdata);
if (ret) {
kfree(sdata);
goto out_unlock;
return ret;
}

ret = ieee80211_vif_use_channel(sdata, &local->monitor_chandef,
IEEE80211_CHANCTX_EXCLUSIVE);
if (ret) {
drv_remove_interface(local, sdata);
kfree(sdata);
goto out_unlock;
return ret;
}

mutex_lock(&local->iflist_mtx);
rcu_assign_pointer(local->monitor_sdata, sdata);
out_unlock:
mutex_unlock(&local->iflist_mtx);
return ret;

return 0;
}

static void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
Expand All @@ -407,23 +406,27 @@ static void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF))
return;

ASSERT_RTNL();

mutex_lock(&local->iflist_mtx);

sdata = rcu_dereference_protected(local->monitor_sdata,
lockdep_is_held(&local->iflist_mtx));
if (!sdata)
goto out_unlock;
if (!sdata) {
mutex_unlock(&local->iflist_mtx);
return;
}

rcu_assign_pointer(local->monitor_sdata, NULL);
mutex_unlock(&local->iflist_mtx);

synchronize_net();

ieee80211_vif_release_channel(sdata);

drv_remove_interface(local, sdata);

kfree(sdata);
out_unlock:
mutex_unlock(&local->iflist_mtx);
}

/*
Expand Down
3 changes: 2 additions & 1 deletion net/mac80211/mesh.c
Original file line number Diff line number Diff line change
Expand Up @@ -1060,7 +1060,8 @@ void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local)

rcu_read_lock();
list_for_each_entry_rcu(sdata, &local->interfaces, list)
if (ieee80211_vif_is_mesh(&sdata->vif))
if (ieee80211_vif_is_mesh(&sdata->vif) &&
ieee80211_sdata_running(sdata))
ieee80211_queue_work(&local->hw, &sdata->work);
rcu_read_unlock();
}
Expand Down
6 changes: 4 additions & 2 deletions net/mac80211/mlme.c
Original file line number Diff line number Diff line change
Expand Up @@ -3608,8 +3608,10 @@ void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local)

/* Restart STA timers */
rcu_read_lock();
list_for_each_entry_rcu(sdata, &local->interfaces, list)
ieee80211_restart_sta_timer(sdata);
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
if (ieee80211_sdata_running(sdata))
ieee80211_restart_sta_timer(sdata);
}
rcu_read_unlock();
}

Expand Down
14 changes: 13 additions & 1 deletion net/mac80211/rx.c
Original file line number Diff line number Diff line change
Expand Up @@ -2675,7 +2675,19 @@ ieee80211_rx_h_action_return(struct ieee80211_rx_data *rx)

memset(nskb->cb, 0, sizeof(nskb->cb));

ieee80211_tx_skb(rx->sdata, nskb);
if (rx->sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) {
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(nskb);

info->flags = IEEE80211_TX_CTL_TX_OFFCHAN |
IEEE80211_TX_INTFL_OFFCHAN_TX_OK |
IEEE80211_TX_CTL_NO_CCK_RATE;
if (local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)
info->hw_queue =
local->hw.offchannel_tx_hw_queue;
}

__ieee80211_tx_skb_tid_band(rx->sdata, nskb, 7,
status->band);
}
dev_kfree_skb(rx->skb);
return RX_QUEUED;
Expand Down
12 changes: 10 additions & 2 deletions net/mac80211/sta_info.c
Original file line number Diff line number Diff line change
Expand Up @@ -766,6 +766,7 @@ int __must_check __sta_info_destroy(struct sta_info *sta)
struct ieee80211_local *local;
struct ieee80211_sub_if_data *sdata;
int ret, i;
bool have_key = false;

might_sleep();

Expand Down Expand Up @@ -793,12 +794,19 @@ int __must_check __sta_info_destroy(struct sta_info *sta)
list_del_rcu(&sta->list);

mutex_lock(&local->key_mtx);
for (i = 0; i < NUM_DEFAULT_KEYS; i++)
for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
__ieee80211_key_free(key_mtx_dereference(local, sta->gtk[i]));
if (sta->ptk)
have_key = true;
}
if (sta->ptk) {
__ieee80211_key_free(key_mtx_dereference(local, sta->ptk));
have_key = true;
}
mutex_unlock(&local->key_mtx);

if (!have_key)
synchronize_net();

sta->dead = true;

local->num_sta--;
Expand Down
64 changes: 47 additions & 17 deletions net/wireless/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,39 @@ static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data)
rdev_rfkill_poll(rdev);
}

void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev)
{
lockdep_assert_held(&rdev->devlist_mtx);
lockdep_assert_held(&rdev->sched_scan_mtx);

if (WARN_ON(wdev->iftype != NL80211_IFTYPE_P2P_DEVICE))
return;

if (!wdev->p2p_started)
return;

rdev_stop_p2p_device(rdev, wdev);
wdev->p2p_started = false;

rdev->opencount--;

if (rdev->scan_req && rdev->scan_req->wdev == wdev) {
bool busy = work_busy(&rdev->scan_done_wk);

/*
* If the work isn't pending or running (in which case it would
* be waiting for the lock we hold) the driver didn't properly
* cancel the scan when the interface was removed. In this case
* warn and leak the scan request object to not crash later.
*/
WARN_ON(!busy);

rdev->scan_req->aborted = true;
___cfg80211_scan_done(rdev, !busy);
}
}

static int cfg80211_rfkill_set_block(void *data, bool blocked)
{
struct cfg80211_registered_device *rdev = data;
Expand All @@ -221,7 +254,8 @@ static int cfg80211_rfkill_set_block(void *data, bool blocked)
return 0;

rtnl_lock();
mutex_lock(&rdev->devlist_mtx);

/* read-only iteration need not hold the devlist_mtx */

list_for_each_entry(wdev, &rdev->wdev_list, list) {
if (wdev->netdev) {
Expand All @@ -231,18 +265,18 @@ static int cfg80211_rfkill_set_block(void *data, bool blocked)
/* otherwise, check iftype */
switch (wdev->iftype) {
case NL80211_IFTYPE_P2P_DEVICE:
if (!wdev->p2p_started)
break;
rdev_stop_p2p_device(rdev, wdev);
wdev->p2p_started = false;
rdev->opencount--;
/* but this requires it */
mutex_lock(&rdev->devlist_mtx);
mutex_lock(&rdev->sched_scan_mtx);
cfg80211_stop_p2p_device(rdev, wdev);
mutex_unlock(&rdev->sched_scan_mtx);
mutex_unlock(&rdev->devlist_mtx);
break;
default:
break;
}
}

mutex_unlock(&rdev->devlist_mtx);
rtnl_unlock();

return 0;
Expand Down Expand Up @@ -745,17 +779,13 @@ static void wdev_cleanup_work(struct work_struct *work)
wdev = container_of(work, struct wireless_dev, cleanup_work);
rdev = wiphy_to_dev(wdev->wiphy);

cfg80211_lock_rdev(rdev);
mutex_lock(&rdev->sched_scan_mtx);

if (WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev)) {
rdev->scan_req->aborted = true;
___cfg80211_scan_done(rdev, true);
}

cfg80211_unlock_rdev(rdev);

mutex_lock(&rdev->sched_scan_mtx);

if (WARN_ON(rdev->sched_scan_req &&
rdev->sched_scan_req->dev == wdev->netdev)) {
__cfg80211_stop_sched_scan(rdev, false);
Expand All @@ -781,21 +811,19 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev)
return;

mutex_lock(&rdev->devlist_mtx);
mutex_lock(&rdev->sched_scan_mtx);
list_del_rcu(&wdev->list);
rdev->devlist_generation++;

switch (wdev->iftype) {
case NL80211_IFTYPE_P2P_DEVICE:
if (!wdev->p2p_started)
break;
rdev_stop_p2p_device(rdev, wdev);
wdev->p2p_started = false;
rdev->opencount--;
cfg80211_stop_p2p_device(rdev, wdev);
break;
default:
WARN_ON_ONCE(1);
break;
}
mutex_unlock(&rdev->sched_scan_mtx);
mutex_unlock(&rdev->devlist_mtx);
}
EXPORT_SYMBOL(cfg80211_unregister_wdev);
Expand Down Expand Up @@ -936,6 +964,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
cfg80211_update_iface_num(rdev, wdev->iftype, 1);
cfg80211_lock_rdev(rdev);
mutex_lock(&rdev->devlist_mtx);
mutex_lock(&rdev->sched_scan_mtx);
wdev_lock(wdev);
switch (wdev->iftype) {
#ifdef CONFIG_CFG80211_WEXT
Expand Down Expand Up @@ -967,6 +996,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
break;
}
wdev_unlock(wdev);
mutex_unlock(&rdev->sched_scan_mtx);
rdev->opencount++;
mutex_unlock(&rdev->devlist_mtx);
cfg80211_unlock_rdev(rdev);
Expand Down
3 changes: 3 additions & 0 deletions net/wireless/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,9 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
enum nl80211_iftype iftype, int num);

void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev);

#define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10

#ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS
Expand Down
Loading

0 comments on commit fae1721

Please sign in to comment.