} __attribute__ ((packed));
-/* must be called under mdev tx lock */
void ieee80211_configure_filter(struct ieee80211_local *local)
{
+ u64 mc;
unsigned int changed_flags;
unsigned int new_flags = 0;
if (atomic_read(&local->iff_allmultis))
new_flags |= FIF_ALLMULTI;
- if (local->monitors)
+ if (local->monitors || local->scanning)
new_flags |= FIF_BCN_PRBRESP_PROMISC;
if (local->fif_fcsfail)
if (local->fif_other_bss)
new_flags |= FIF_OTHER_BSS;
+ if (local->fif_pspoll)
+ new_flags |= FIF_PSPOLL;
+
+ spin_lock_bh(&local->filter_lock);
changed_flags = local->filter_flags ^ new_flags;
+ mc = drv_prepare_multicast(local, local->mc_count, local->mc_list);
+ spin_unlock_bh(&local->filter_lock);
+
/* be a bit nasty */
new_flags |= (1<<31);
- drv_configure_filter(local, changed_flags, &new_flags,
- local->mc_count,
- local->mc_list);
+ drv_configure_filter(local, changed_flags, &new_flags, mc);
WARN_ON(new_flags & (1<<31));
local->filter_flags = new_flags & ~(1<<31);
}
+static void ieee80211_reconfig_filter(struct work_struct *work)
+{
+ struct ieee80211_local *local =
+ container_of(work, struct ieee80211_local, reconfig_filter);
+
+ ieee80211_configure_filter(local);
+}
+
int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
{
struct ieee80211_channel *chan, *scan_chan;
}
if (changed & BSS_CHANGED_BEACON_ENABLED) {
- if (local->sw_scanning) {
+ if (local->quiescing || !netif_running(sdata->dev) ||
+ test_bit(SCAN_SW_SCANNING, &local->scanning)) {
sdata->vif.bss_conf.enable_beacon = false;
} else {
/*
drv_bss_info_changed(local, &sdata->vif,
&sdata->vif.bss_conf, changed);
-
- /* DEPRECATED */
- local->hw.conf.beacon_int = sdata->vif.bss_conf.beacon_int;
}
u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ /*
+ * XXX: This is temporary!
+ *
+ * The problem here is that when we get here, the driver will
+ * quite likely have pretty much overwritten info->control by
+ * using info->driver_data or info->rate_driver_data. Thus,
+ * when passing out the frame to the driver again, we would be
+ * passing completely bogus data since the driver would then
+ * expect a properly filled info->control. In mac80211 itself
+ * the same problem occurs, since we need info->control.vif
+ * internally.
+ *
+ * To fix this, we should send the frame through TX processing
+ * again. However, it's not that simple, since the frame will
+ * have been software-encrypted (if applicable) already, and
+ * encrypting it again doesn't do much good. So to properly do
+ * that, we not only have to skip the actual 'raw' encryption
+ * (key selection etc. still has to be done!) but also the
+ * sequence number assignment since that impacts the crypto
+ * encapsulation, of course.
+ *
+ * Hence, for now, fix the bug by just dropping the frame.
+ */
+ goto drop;
+
sta->tx_filtered_count++;
/*
* can be unknown, for example with different interrupt status
* bits.
*/
- if (test_sta_flags(sta, WLAN_STA_PS) &&
+ if (test_sta_flags(sta, WLAN_STA_PS_STA) &&
skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) {
skb_queue_tail(&sta->tx_filtered, skb);
return;
}
- if (!test_sta_flags(sta, WLAN_STA_PS) &&
+ if (!test_sta_flags(sta, WLAN_STA_PS_STA) &&
!(info->flags & IEEE80211_TX_INTFL_RETRIED)) {
/* Software retry the packet once */
info->flags |= IEEE80211_TX_INTFL_RETRIED;
return;
}
+ drop:
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
if (net_ratelimit())
printk(KERN_DEBUG "%s: dropped TX filtered frame, "
"queue_len=%d PS=%d @%lu\n",
wiphy_name(local->hw.wiphy),
skb_queue_len(&sta->tx_filtered),
- !!test_sta_flags(sta, WLAN_STA_PS), jiffies);
+ !!test_sta_flags(sta, WLAN_STA_PS_STA), jiffies);
#endif
dev_kfree_skb(skb);
}
if (sta) {
if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
- test_sta_flags(sta, WLAN_STA_PS)) {
+ test_sta_flags(sta, WLAN_STA_PS_STA)) {
/*
* The STA is in power save mode, so assume
* that this TX packet failed because of that.
}
rate_control_tx_status(local, sband, sta, skb);
+ if (ieee80211_vif_is_mesh(&sta->sdata->vif))
+ ieee80211s_update_metric(local, sta, skb);
}
rcu_read_unlock();
if (!wiphy)
return NULL;
+ wiphy->netnsok = true;
wiphy->privid = mac80211_wiphy_privid;
/* Yes, putting cfg80211_bss into ieee80211_bss is a hack */
local->hw.max_rates = 1;
local->hw.conf.long_frame_max_tx_count = wiphy->retry_long;
local->hw.conf.short_frame_max_tx_count = wiphy->retry_short;
- local->hw.conf.radio_enabled = true;
local->user_power_level = -1;
INIT_LIST_HEAD(&local->interfaces);
INIT_WORK(&local->restart_work, ieee80211_restart_work);
+ INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter);
+
INIT_WORK(&local->dynamic_ps_enable_work,
ieee80211_dynamic_ps_enable_work);
INIT_WORK(&local->dynamic_ps_disable_work,
skb_queue_head_init(&local->pending[i]);
tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending,
(unsigned long)local);
- tasklet_disable(&local->tx_pending_tasklet);
tasklet_init(&local->tasklet,
ieee80211_tasklet_handler,
(unsigned long) local);
- tasklet_disable(&local->tasklet);
skb_queue_head_init(&local->skb_queue);
skb_queue_head_init(&local->skb_queue_unreliable);
supp_ht = supp_ht || sband->ht_cap.ht_supported;
}
- local->int_scan_req.n_channels = channels;
- local->int_scan_req.channels = kzalloc(sizeof(void *) * channels, GFP_KERNEL);
- if (!local->int_scan_req.channels)
+ local->int_scan_req = kzalloc(sizeof(*local->int_scan_req) +
+ sizeof(void *) * channels, GFP_KERNEL);
+ if (!local->int_scan_req)
return -ENOMEM;
/* if low-level driver supports AP, we also support VLAN */
if (hw->queues > IEEE80211_MAX_QUEUES)
hw->queues = IEEE80211_MAX_QUEUES;
- local->hw.workqueue =
+ local->workqueue =
create_singlethread_workqueue(wiphy_name(local->hw.wiphy));
- if (!local->hw.workqueue) {
+ if (!local->workqueue) {
result = -ENOMEM;
goto fail_workqueue;
}
/* alloc internal scan request */
i = 0;
- local->int_scan_req.ssids = &local->scan_ssid;
- local->int_scan_req.n_ssids = 1;
+ local->int_scan_req->ssids = &local->scan_ssid;
+ local->int_scan_req->n_ssids = 1;
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
if (!hw->wiphy->bands[band])
continue;
for (j = 0; j < hw->wiphy->bands[band]->n_channels; j++) {
- local->int_scan_req.channels[i] =
+ local->int_scan_req->channels[i] =
&hw->wiphy->bands[band]->channels[j];
i++;
}
}
+ local->int_scan_req->n_channels = i;
local->network_latency_notifier.notifier_call =
ieee80211_max_network_latency;
fail_wep:
sta_info_stop(local);
fail_sta_info:
- debugfs_hw_del(local);
- destroy_workqueue(local->hw.workqueue);
+ destroy_workqueue(local->workqueue);
fail_workqueue:
wiphy_unregister(local->hw.wiphy);
fail_wiphy_register:
- kfree(local->int_scan_req.channels);
+ kfree(local->int_scan_req);
return result;
}
EXPORT_SYMBOL(ieee80211_register_hw);
rtnl_unlock();
+ cancel_work_sync(&local->reconfig_filter);
+
ieee80211_clear_tx_pending(local);
sta_info_stop(local);
rate_control_deinitialize(local);
- debugfs_hw_del(local);
if (skb_queue_len(&local->skb_queue)
|| skb_queue_len(&local->skb_queue_unreliable))
skb_queue_purge(&local->skb_queue);
skb_queue_purge(&local->skb_queue_unreliable);
- destroy_workqueue(local->hw.workqueue);
+ destroy_workqueue(local->workqueue);
wiphy_unregister(local->hw.wiphy);
ieee80211_wep_free(local);
ieee80211_led_exit(local);
- kfree(local->int_scan_req.channels);
+ kfree(local->int_scan_req);
}
EXPORT_SYMBOL(ieee80211_unregister_hw);