Commit 630a216d authored by John W. Linville's avatar John W. Linville

Merge branch 'master' of...

Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless into for-davem
parents 91c57464 2e1253d6
......@@ -5059,9 +5059,8 @@ S: Maintained
F: drivers/net/ethernet/marvell/sk*
MARVELL LIBERTAS WIRELESS DRIVER
M: Dan Williams <dcbw@redhat.com>
L: libertas-dev@lists.infradead.org
S: Maintained
S: Orphan
F: drivers/net/wireless/libertas/
MARVELL MV643XX ETHERNET DRIVER
......
......@@ -170,7 +170,8 @@ void ath_rx_poll(unsigned long data)
{
struct ath_softc *sc = (struct ath_softc *)data;
ieee80211_queue_work(sc->hw, &sc->hw_check_work);
if (!test_bit(SC_OP_INVALID, &sc->sc_flags))
ieee80211_queue_work(sc->hw, &sc->hw_check_work);
}
/*
......
......@@ -1487,8 +1487,12 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
const struct b43_dma_ops *ops;
struct b43_dmaring *ring;
struct b43_dmadesc_meta *meta;
static const struct b43_txstatus fake; /* filled with 0 */
const struct b43_txstatus *txstat;
int slot, firstused;
bool frame_succeed;
int skip;
static u8 err_out1, err_out2;
ring = parse_cookie(dev, status->cookie, &slot);
if (unlikely(!ring))
......@@ -1501,13 +1505,36 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
firstused = ring->current_slot - ring->used_slots + 1;
if (firstused < 0)
firstused = ring->nr_slots + firstused;
skip = 0;
if (unlikely(slot != firstused)) {
/* This possibly is a firmware bug and will result in
* malfunction, memory leaks and/or stall of DMA functionality. */
b43dbg(dev->wl, "Out of order TX status report on DMA ring %d. "
"Expected %d, but got %d\n",
ring->index, firstused, slot);
return;
* malfunction, memory leaks and/or stall of DMA functionality.
*/
if (slot == next_slot(ring, next_slot(ring, firstused))) {
/* If a single header/data pair was missed, skip over
* the first two slots in an attempt to recover.
*/
slot = firstused;
skip = 2;
if (!err_out1) {
/* Report the error once. */
b43dbg(dev->wl,
"Skip on DMA ring %d slot %d.\n",
ring->index, slot);
err_out1 = 1;
}
} else {
/* More than a single header/data pair were missed.
* Report this error once.
*/
if (!err_out2)
b43dbg(dev->wl,
"Out of order TX status report on DMA ring %d. Expected %d, but got %d\n",
ring->index, firstused, slot);
err_out2 = 1;
return;
}
}
ops = ring->ops;
......@@ -1522,11 +1549,13 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
slot, firstused, ring->index);
break;
}
if (meta->skb) {
struct b43_private_tx_info *priv_info =
b43_get_priv_tx_info(IEEE80211_SKB_CB(meta->skb));
b43_get_priv_tx_info(IEEE80211_SKB_CB(meta->skb));
unmap_descbuffer(ring, meta->dmaaddr, meta->skb->len, 1);
unmap_descbuffer(ring, meta->dmaaddr,
meta->skb->len, 1);
kfree(priv_info->bouncebuffer);
priv_info->bouncebuffer = NULL;
} else {
......@@ -1538,8 +1567,9 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
struct ieee80211_tx_info *info;
if (unlikely(!meta->skb)) {
/* This is a scatter-gather fragment of a frame, so
* the skb pointer must not be NULL. */
/* This is a scatter-gather fragment of a frame,
* so the skb pointer must not be NULL.
*/
b43dbg(dev->wl, "TX status unexpected NULL skb "
"at slot %d (first=%d) on ring %d\n",
slot, firstused, ring->index);
......@@ -1550,9 +1580,18 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
/*
* Call back to inform the ieee80211 subsystem about
* the status of the transmission.
* the status of the transmission. When skipping over
* a missed TX status report, use a status structure
* filled with zeros to indicate that the frame was not
* sent (frame_count 0) and not acknowledged
*/
frame_succeed = b43_fill_txstatus_report(dev, info, status);
if (unlikely(skip))
txstat = &fake;
else
txstat = status;
frame_succeed = b43_fill_txstatus_report(dev, info,
txstat);
#ifdef CONFIG_B43_DEBUG
if (frame_succeed)
ring->nr_succeed_tx_packets++;
......@@ -1580,12 +1619,14 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
/* Everything unmapped and free'd. So it's not used anymore. */
ring->used_slots--;
if (meta->is_last_fragment) {
if (meta->is_last_fragment && !skip) {
/* This is the last scatter-gather
* fragment of the frame. We are done. */
break;
}
slot = next_slot(ring, slot);
if (skip > 0)
--skip;
}
if (ring->stopped) {
B43_WARN_ON(free_slots(ring) < TX_SLOTS_PER_FRAME);
......
......@@ -1564,7 +1564,7 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev)
u16 clip_off[2] = { 0xFFFF, 0xFFFF };
u8 vcm_final = 0;
s8 offset[4];
s32 offset[4];
s32 results[8][4] = { };
s32 results_min[4] = { };
s32 poll_results[4] = { };
......@@ -1615,7 +1615,7 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev)
}
for (i = 0; i < 4; i += 2) {
s32 curr;
s32 mind = 40;
s32 mind = 0x100000;
s32 minpoll = 249;
u8 minvcm = 0;
if (2 * core != i)
......@@ -1732,7 +1732,7 @@ static void b43_nphy_rev2_rssi_cal(struct b43_wldev *dev, u8 type)
u8 regs_save_radio[2];
u16 regs_save_phy[2];
s8 offset[4];
s32 offset[4];
u8 core;
u8 rail;
......@@ -1799,7 +1799,7 @@ static void b43_nphy_rev2_rssi_cal(struct b43_wldev *dev, u8 type)
}
for (i = 0; i < 4; i++) {
s32 mind = 40;
s32 mind = 0x100000;
u8 minvcm = 0;
s32 minpoll = 249;
s32 curr;
......
......@@ -1992,70 +1992,70 @@ static const u16 dot11lcn_sw_ctrl_tbl_4313_epa_rev0[] = {
};
static const u16 dot11lcn_sw_ctrl_tbl_4313_rev0[] = {
0x0009,
0x000a,
0x0005,
0x0006,
0x0009,
0x000a,
0x0005,
0x0006,
0x0009,
0x000a,
0x0005,
0x0006,
0x0009,
0x000a,
0x0005,
0x0006,
0x0009,
0x000a,
0x0005,
0x0006,
0x0009,
0x000a,
0x0005,
0x0006,
0x0009,
0x000a,
0x0005,
0x0006,
0x0009,
0x000a,
0x0005,
0x0006,
0x0009,
0x000a,
0x0005,
0x0006,
0x0009,
0x000a,
0x0005,
0x0006,
0x0009,
0x000a,
0x0005,
0x0006,
0x0009,
0x000a,
0x0005,
0x0006,
0x000a,
0x0009,
0x0006,
0x0005,
0x000a,
0x0009,
0x0006,
0x0005,
0x000a,
0x0009,
0x0006,
0x0005,
0x000a,
0x0009,
0x0006,
0x0005,
0x000a,
0x0009,
0x0006,
0x0005,
0x000a,
0x0009,
0x0006,
0x0005,
0x000a,
0x0009,
0x0006,
0x0005,
0x000a,
0x0009,
0x0006,
0x0005,
0x000a,
0x0009,
0x0006,
0x0005,
0x000a,
0x0009,
0x0006,
0x0005,
0x000a,
0x0009,
0x0006,
0x0005,
0x000a,
0x0009,
0x0006,
0x0005,
};
static const u16 dot11lcn_sw_ctrl_tbl_rev0[] = {
......
......@@ -2152,7 +2152,7 @@ il4965_rs_initialize_lq(struct il_priv *il, struct ieee80211_conf *conf,
int rate_idx;
int i;
u32 rate;
u8 use_green = il4965_rs_use_green(il, sta);
u8 use_green;
u8 active_tbl = 0;
u8 valid_tx_ant;
struct il_station_priv *sta_priv;
......@@ -2160,6 +2160,7 @@ il4965_rs_initialize_lq(struct il_priv *il, struct ieee80211_conf *conf,
if (!sta || !lq_sta)
return;
use_green = il4965_rs_use_green(il, sta);
sta_priv = (void *)sta->drv_priv;
i = lq_sta->last_txrate_idx;
......
......@@ -1261,6 +1261,15 @@ int iwl_dvm_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
return -EIO;
}
/*
* This can happen upon FW ASSERT: we clear the STATUS_FW_ERROR flag
* in iwl_down but cancel the workers only later.
*/
if (!priv->ucode_loaded) {
IWL_ERR(priv, "Fw not loaded - dropping CMD: %x\n", cmd->id);
return -EIO;
}
/*
* Synchronous commands from this op-mode must hold
* the mutex, this ensures we don't try to send two
......
......@@ -367,6 +367,8 @@ int iwl_load_ucode_wait_alive(struct iwl_priv *priv,
return -EIO;
}
priv->ucode_loaded = true;
if (ucode_type != IWL_UCODE_WOWLAN) {
/* delay a bit to give rfkill time to run */
msleep(5);
......@@ -380,8 +382,6 @@ int iwl_load_ucode_wait_alive(struct iwl_priv *priv,
return ret;
}
priv->ucode_loaded = true;
return 0;
}
......
......@@ -475,6 +475,10 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
/* If platform's RF_KILL switch is NOT set to KILL */
hw_rfkill = iwl_is_rfkill_set(trans);
if (hw_rfkill)
set_bit(STATUS_RFKILL, &trans_pcie->status);
else
clear_bit(STATUS_RFKILL, &trans_pcie->status);
iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
if (hw_rfkill && !run_in_rfkill)
return -ERFKILL;
......@@ -641,6 +645,7 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
bool hw_rfkill;
int err;
......@@ -656,6 +661,10 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
iwl_enable_rfkill_int(trans);
hw_rfkill = iwl_is_rfkill_set(trans);
if (hw_rfkill)
set_bit(STATUS_RFKILL, &trans_pcie->status);
else
clear_bit(STATUS_RFKILL, &trans_pcie->status);
iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
return 0;
......@@ -694,6 +703,10 @@ static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans,
* op_mode.
*/
hw_rfkill = iwl_is_rfkill_set(trans);
if (hw_rfkill)
set_bit(STATUS_RFKILL, &trans_pcie->status);
else
clear_bit(STATUS_RFKILL, &trans_pcie->status);
iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
}
}
......
......@@ -1264,7 +1264,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
for (i = 0; i < IWL_MAX_CMD_TBS_PER_TFD; i++) {
int copy = 0;
if (!cmd->len)
if (!cmd->len[i])
continue;
/* need at least IWL_HCMD_SCRATCHBUF_SIZE copied */
......
......@@ -1508,6 +1508,7 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter)
}
memcpy(adapter->upld_buf, skb->data,
min_t(u32, MWIFIEX_SIZE_OF_CMD_BUFFER, skb->len));
skb_push(skb, INTF_HEADER_LEN);
if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE,
PCI_DMA_FROMDEVICE))
return -1;
......
......@@ -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;
......@@ -377,13 +375,13 @@ 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,
......@@ -391,13 +389,14 @@ static int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
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)
......@@ -407,14 +406,20 @@ 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);
......@@ -422,8 +427,6 @@ static void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
drv_remove_interface(local, sdata);
kfree(sdata);
out_unlock:
mutex_unlock(&local->iflist_mtx);
}
/*
......
......@@ -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();
}
......
......@@ -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();
}
......
......@@ -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;
......
......@@ -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();
......@@ -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--;
......
......@@ -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;
......@@ -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) {
......@@ -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;
......@@ -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);
......@@ -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);
......@@ -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
......@@ -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);
......
......@@ -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
......
......@@ -4702,14 +4702,19 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
if (!rdev->ops->scan)
return -EOPNOTSUPP;
if (rdev->scan_req)
return -EBUSY;
mutex_lock(&rdev->sched_scan_mtx);
if (rdev->scan_req) {
err = -EBUSY;
goto unlock;
}
if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
n_channels = validate_scan_freqs(
info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]);
if (!n_channels)
return -EINVAL;
if (!n_channels) {
err = -EINVAL;
goto unlock;
}
} else {
enum ieee80211_band band;
n_channels = 0;
......@@ -4723,23 +4728,29 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp)
n_ssids++;
if (n_ssids > wiphy->max_scan_ssids)
return -EINVAL;
if (n_ssids > wiphy->max_scan_ssids) {
err = -EINVAL;
goto unlock;
}
if (info->attrs[NL80211_ATTR_IE])
ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
else
ie_len = 0;
if (ie_len > wiphy->max_scan_ie_len)
return -EINVAL;
if (ie_len > wiphy->max_scan_ie_len) {
err = -EINVAL;
goto unlock;
}
request = kzalloc(sizeof(*request)
+ sizeof(*request->ssids) * n_ssids
+ sizeof(*request->channels) * n_channels
+ ie_len, GFP_KERNEL);
if (!request)
return -ENOMEM;
if (!request) {
err = -ENOMEM;
goto unlock;
}
if (n_ssids)
request->ssids = (void *)&request->channels[n_channels];
......@@ -4876,6 +4887,8 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
kfree(request);
}
unlock:
mutex_unlock(&rdev->sched_scan_mtx);
return err;
}
......@@ -7749,20 +7762,9 @@ static int nl80211_stop_p2p_device(struct sk_buff *skb, struct genl_info *info)
if (!rdev->ops->stop_p2p_device)
return -EOPNOTSUPP;
if (!wdev->p2p_started)
return 0;
rdev_stop_p2p_device(rdev, wdev);
wdev->p2p_started = false;
mutex_lock(&rdev->devlist_mtx);
rdev->opencount--;
mutex_unlock(&rdev->devlist_mtx);
if (WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev)) {
rdev->scan_req->aborted = true;
___cfg80211_scan_done(rdev, true);
}
mutex_lock(&rdev->sched_scan_mtx);
cfg80211_stop_p2p_device(rdev, wdev);
mutex_unlock(&rdev->sched_scan_mtx);
return 0;
}
......@@ -8486,7 +8488,7 @@ static int nl80211_add_scan_req(struct sk_buff *msg,
struct nlattr *nest;
int i;
ASSERT_RDEV_LOCK(rdev);
lockdep_assert_held(&rdev->sched_scan_mtx);
if (WARN_ON(!req))
return 0;
......
......@@ -169,7 +169,7 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
union iwreq_data wrqu;
#endif
ASSERT_RDEV_LOCK(rdev);
lockdep_assert_held(&rdev->sched_scan_mtx);
request = rdev->scan_req;
......@@ -230,9 +230,9 @@ void __cfg80211_scan_done(struct work_struct *wk)
rdev = container_of(wk, struct cfg80211_registered_device,
scan_done_wk);
cfg80211_lock_rdev(rdev);
mutex_lock(&rdev->sched_scan_mtx);
___cfg80211_scan_done(rdev, false);
cfg80211_unlock_rdev(rdev);
mutex_unlock(&rdev->sched_scan_mtx);
}
void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
......@@ -698,11 +698,6 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
found = rb_find_bss(dev, tmp, BSS_CMP_REGULAR);
if (found) {
found->pub.beacon_interval = tmp->pub.beacon_interval;
found->pub.signal = tmp->pub.signal;
found->pub.capability = tmp->pub.capability;
found->ts = tmp->ts;
/* Update IEs */
if (rcu_access_pointer(tmp->pub.proberesp_ies)) {
const struct cfg80211_bss_ies *old;
......@@ -723,6 +718,8 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
if (found->pub.hidden_beacon_bss &&
!list_empty(&found->hidden_list)) {
const struct cfg80211_bss_ies *f;
/*
* The found BSS struct is one of the probe
* response members of a group, but we're
......@@ -732,6 +729,10 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
* SSID to showing it, which is confusing so
* drop this information.
*/
f = rcu_access_pointer(tmp->pub.beacon_ies);
kfree_rcu((struct cfg80211_bss_ies *)f,
rcu_head);
goto drop;
}
......@@ -761,6 +762,11 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
kfree_rcu((struct cfg80211_bss_ies *)old,
rcu_head);
}
found->pub.beacon_interval = tmp->pub.beacon_interval;
found->pub.signal = tmp->pub.signal;
found->pub.capability = tmp->pub.capability;
found->ts = tmp->ts;
} else {
struct cfg80211_internal_bss *new;
struct cfg80211_internal_bss *hidden;
......@@ -1056,6 +1062,7 @@ int cfg80211_wext_siwscan(struct net_device *dev,
if (IS_ERR(rdev))
return PTR_ERR(rdev);
mutex_lock(&rdev->sched_scan_mtx);
if (rdev->scan_req) {
err = -EBUSY;
goto out;
......@@ -1162,6 +1169,7 @@ int cfg80211_wext_siwscan(struct net_device *dev,
dev_hold(dev);
}
out:
mutex_unlock(&rdev->sched_scan_mtx);
kfree(creq);
cfg80211_unlock_rdev(rdev);
return err;
......
......@@ -85,6 +85,7 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev)
ASSERT_RTNL();
ASSERT_RDEV_LOCK(rdev);
ASSERT_WDEV_LOCK(wdev);
lockdep_assert_held(&rdev->sched_scan_mtx);
if (rdev->scan_req)
return -EBUSY;
......@@ -320,11 +321,9 @@ void cfg80211_sme_scan_done(struct net_device *dev)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
mutex_lock(&wiphy_to_dev(wdev->wiphy)->devlist_mtx);
wdev_lock(wdev);
__cfg80211_sme_scan_done(dev);
wdev_unlock(wdev);
mutex_unlock(&wiphy_to_dev(wdev->wiphy)->devlist_mtx);
}
void cfg80211_sme_rx_auth(struct net_device *dev,
......@@ -924,9 +923,12 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev,
int err;
mutex_lock(&rdev->devlist_mtx);
/* might request scan - scan_mtx -> wdev_mtx dependency */
mutex_lock(&rdev->sched_scan_mtx);
wdev_lock(dev->ieee80211_ptr);
err = __cfg80211_connect(rdev, dev, connect, connkeys, NULL);
wdev_unlock(dev->ieee80211_ptr);
mutex_unlock(&rdev->sched_scan_mtx);
mutex_unlock(&rdev->devlist_mtx);
return err;
......
......@@ -27,7 +27,8 @@
#define WIPHY_PR_ARG __entry->wiphy_name
#define WDEV_ENTRY __field(u32, id)
#define WDEV_ASSIGN (__entry->id) = (wdev ? wdev->identifier : 0)
#define WDEV_ASSIGN (__entry->id) = (!IS_ERR_OR_NULL(wdev) \
? wdev->identifier : 0)
#define WDEV_PR_FMT "wdev(%u)"
#define WDEV_PR_ARG (__entry->id)
......@@ -1778,7 +1779,7 @@ TRACE_EVENT(rdev_set_mac_acl,
),
TP_fast_assign(
WIPHY_ASSIGN;
WIPHY_ASSIGN;
NETDEV_ASSIGN;
__entry->acl_policy = params->acl_policy;
),
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", acl policy: %d",
......
......@@ -89,6 +89,7 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
cfg80211_lock_rdev(rdev);
mutex_lock(&rdev->devlist_mtx);
mutex_lock(&rdev->sched_scan_mtx);
wdev_lock(wdev);
if (wdev->sme_state != CFG80211_SME_IDLE) {
......@@ -135,6 +136,7 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
err = cfg80211_mgd_wext_connect(rdev, wdev);
out:
wdev_unlock(wdev);
mutex_unlock(&rdev->sched_scan_mtx);
mutex_unlock(&rdev->devlist_mtx);
cfg80211_unlock_rdev(rdev);
return err;
......@@ -190,6 +192,7 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev,
cfg80211_lock_rdev(rdev);
mutex_lock(&rdev->devlist_mtx);
mutex_lock(&rdev->sched_scan_mtx);
wdev_lock(wdev);
err = 0;
......@@ -223,6 +226,7 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev,
err = cfg80211_mgd_wext_connect(rdev, wdev);
out:
wdev_unlock(wdev);
mutex_unlock(&rdev->sched_scan_mtx);
mutex_unlock(&rdev->devlist_mtx);
cfg80211_unlock_rdev(rdev);
return err;
......@@ -285,6 +289,7 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev,
cfg80211_lock_rdev(rdev);
mutex_lock(&rdev->devlist_mtx);
mutex_lock(&rdev->sched_scan_mtx);
wdev_lock(wdev);
if (wdev->sme_state != CFG80211_SME_IDLE) {
......@@ -313,6 +318,7 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev,
err = cfg80211_mgd_wext_connect(rdev, wdev);
out:
wdev_unlock(wdev);
mutex_unlock(&rdev->sched_scan_mtx);
mutex_unlock(&rdev->devlist_mtx);
cfg80211_unlock_rdev(rdev);
return err;
......
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