/* we hold the RTNL here so can safely walk the list */
list_for_each_entry(sdata, &local->interfaces, list) {
- if (sdata->dev != dev && netif_running(sdata->dev)) {
+ if (netif_running(sdata->dev)) {
res = 0;
break;
}
if (res)
return res;
- netif_start_queue(local->mdev);
+ netif_tx_start_all_queues(local->mdev);
return 0;
}
/* we hold the RTNL here so can safely walk the list */
list_for_each_entry(sdata, &local->interfaces, list)
- if (sdata->dev != dev && netif_running(sdata->dev))
+ if (netif_running(sdata->dev))
dev_close(sdata->dev);
return 0;
list_for_each_entry(nsdata, &local->interfaces, list) {
struct net_device *ndev = nsdata->dev;
- if (ndev != dev && ndev != local->mdev && netif_running(ndev)) {
+ if (ndev != dev && netif_running(ndev)) {
/*
* Allow only a single IBSS interface to be up at any
* time. This is restricted because beacon distribution
nsdata->vif.type == IEEE80211_IF_TYPE_IBSS)
return -EBUSY;
- /*
- * Disallow multiple IBSS/STA mode interfaces.
- *
- * This is a technical restriction, it is possible although
- * most likely not IEEE 802.11 compliant to have multiple
- * STAs with just a single hardware (the TSF timer will not
- * be adjusted properly.)
- *
- * However, because mac80211 uses the master device's BSS
- * information for each STA/IBSS interface, doing this will
- * currently corrupt that BSS information completely, unless,
- * a not very useful case, both STAs are associated to the
- * same BSS.
- *
- * To remove this restriction, the BSS information needs to
- * be embedded in the STA/IBSS mode sdata instead of using
- * the master device's BSS structure.
- */
- if ((sdata->vif.type == IEEE80211_IF_TYPE_STA ||
- sdata->vif.type == IEEE80211_IF_TYPE_IBSS) &&
- (nsdata->vif.type == IEEE80211_IF_TYPE_STA ||
- nsdata->vif.type == IEEE80211_IF_TYPE_IBSS))
- return -EBUSY;
-
/*
* The remaining checks are only performed for interfaces
* with the same MAC address.
*/
if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN &&
nsdata->vif.type == IEEE80211_IF_TYPE_AP)
- sdata->u.vlan.ap = nsdata;
+ sdata->bss = &nsdata->u.ap;
}
}
return -ENOLINK;
break;
case IEEE80211_IF_TYPE_VLAN:
- if (!sdata->u.vlan.ap)
+ if (!sdata->bss)
return -ENOLINK;
+ list_add(&sdata->u.vlan.list, &sdata->bss->vlans);
break;
case IEEE80211_IF_TYPE_AP:
+ sdata->bss = &sdata->u.ap;
+ break;
case IEEE80211_IF_TYPE_STA:
case IEEE80211_IF_TYPE_MNTR:
case IEEE80211_IF_TYPE_IBSS:
if (local->ops->start)
res = local->ops->start(local_to_hw(local));
if (res)
- return res;
+ goto err_del_bss;
need_hw_reconfig = 1;
ieee80211_led_radio(local, local->hw.conf.radio_enabled);
}
switch (sdata->vif.type) {
case IEEE80211_IF_TYPE_VLAN:
- list_add(&sdata->u.vlan.list, &sdata->u.vlan.ap->u.ap.vlans);
/* no need to tell driver */
break;
case IEEE80211_IF_TYPE_MNTR:
if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
local->fif_other_bss++;
- netif_tx_lock_bh(local->mdev);
+ netif_addr_lock_bh(local->mdev);
ieee80211_configure_filter(local);
- netif_tx_unlock_bh(local->mdev);
+ netif_addr_unlock_bh(local->mdev);
break;
case IEEE80211_IF_TYPE_STA:
case IEEE80211_IF_TYPE_IBSS:
if (res)
goto err_stop;
- ieee80211_if_config(dev);
+ if (ieee80211_vif_is_mesh(&sdata->vif))
+ ieee80211_start_mesh(sdata->dev);
changed |= ieee80211_reset_erp_info(dev);
ieee80211_bss_info_change_notify(sdata, changed);
ieee80211_enable_keys(sdata);
queue_work(local->hw.workqueue, &ifsta->work);
}
- netif_start_queue(dev);
+ netif_tx_start_all_queues(dev);
return 0;
err_del_interface:
err_stop:
if (!local->open_count && local->ops->stop)
local->ops->stop(local_to_hw(local));
+ err_del_bss:
+ sdata->bss = NULL;
+ if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
+ list_del(&sdata->u.vlan.list);
return res;
}
/*
* Stop TX on this interface first.
*/
- netif_stop_queue(dev);
+ netif_tx_stop_all_queues(dev);
/*
* Now delete all active aggregation sessions.
switch (sdata->vif.type) {
case IEEE80211_IF_TYPE_VLAN:
list_del(&sdata->u.vlan.list);
- sdata->u.vlan.ap = NULL;
/* no need to tell driver */
break;
case IEEE80211_IF_TYPE_MNTR:
if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
local->fif_other_bss--;
- netif_tx_lock_bh(local->mdev);
+ netif_addr_lock_bh(local->mdev);
ieee80211_configure_filter(local);
- netif_tx_unlock_bh(local->mdev);
+ netif_addr_unlock_bh(local->mdev);
break;
case IEEE80211_IF_TYPE_MESH_POINT:
case IEEE80211_IF_TYPE_STA:
local->sta_hw_scanning = 0;
}
- flush_workqueue(local->hw.workqueue);
-
sdata->u.sta.flags &= ~IEEE80211_STA_PRIVACY_INVOKED;
kfree(sdata->u.sta.extra_ie);
sdata->u.sta.extra_ie = NULL;
local->ops->remove_interface(local_to_hw(local), &conf);
}
+ sdata->bss = NULL;
+
if (local->open_count == 0) {
if (netif_running(local->mdev))
dev_close(local->mdev);
ieee80211_led_radio(local, 0);
+ flush_workqueue(local->hw.workqueue);
+
tasklet_disable(&local->tx_pending_tasklet);
tasklet_disable(&local->tasklet);
}
(unsigned long)&sta->timer_to_tid[tid];
init_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
- /* ensure that TX flow won't interrupt us
- * until the end of the call to requeue function */
- spin_lock_bh(&local->mdev->queue_lock);
-
/* create a new queue for this aggregation */
ret = ieee80211_ht_agg_queue_add(local, sta, tid);
/* No need to requeue the packets in the agg queue, since we
* held the tx lock: no packet could be enqueued to the newly
* allocated queue */
- ieee80211_ht_agg_queue_remove(local, sta, tid, 0);
+ ieee80211_ht_agg_queue_remove(local, sta, tid, 0);
#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "BA request denied - HW unavailable for"
" tid %d\n", tid);
/* Will put all the packets in the new SW queue */
ieee80211_requeue(local, ieee802_1d_to_ac[tid]);
- spin_unlock_bh(&local->mdev->queue_lock);
spin_unlock_bh(&sta->lock);
/* send an addBA request */
err_unlock_queue:
kfree(sta->ampdu_mlme.tid_tx[tid]);
sta->ampdu_mlme.tid_tx[tid] = NULL;
- spin_unlock_bh(&local->mdev->queue_lock);
ret = -EBUSY;
err_unlock_sta:
spin_unlock_bh(&sta->lock);
state = &sta->ampdu_mlme.tid_state_tx[tid];
/* NOTE: no need to use sta->lock in this state check, as
- * ieee80211_stop_tx_ba_session will let only
- * one stop call to pass through per sta/tid */
+ * ieee80211_stop_tx_ba_session will let only one stop call to
+ * pass through per sta/tid
+ */
if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) {
#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n");
agg_queue = sta->tid_to_tx_q[tid];
- /* avoid ordering issues: we are the only one that can modify
- * the content of the qdiscs */
- spin_lock_bh(&local->mdev->queue_lock);
- /* remove the queue for this aggregation */
ieee80211_ht_agg_queue_remove(local, sta, tid, 1);
- spin_unlock_bh(&local->mdev->queue_lock);
- /* we just requeued the all the frames that were in the removed
- * queue, and since we might miss a softirq we do netif_schedule.
- * ieee80211_wake_queue is not used here as this queue is not
- * necessarily stopped */
- netif_schedule(local->mdev);
+ /* We just requeued the all the frames that were in the
+ * removed queue, and since we might miss a softirq we do
+ * netif_schedule_queue. ieee80211_wake_queue is not used
+ * here as this queue is not necessarily stopped
+ */
+ netif_schedule_queue(netdev_get_tx_queue(local->mdev, agg_queue));
spin_lock_bh(&sta->lock);
*state = HT_AGG_STATE_IDLE;
sta->ampdu_mlme.addba_req_num[tid] = 0;
.cache_update = eth_header_cache_update,
};
-/* Must not be called for mdev */
void ieee80211_if_setup(struct net_device *dev)
{
ether_setup(dev);
dev->change_mtu = ieee80211_change_mtu;
dev->open = ieee80211_open;
dev->stop = ieee80211_stop;
- dev->destructor = ieee80211_if_free;
+ dev->destructor = free_netdev;
}
/* everything else */
-static int __ieee80211_if_config(struct net_device *dev,
- struct sk_buff *beacon)
+int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed)
{
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_local *local = sdata->local;
struct ieee80211_if_conf conf;
- if (!local->ops->config_interface || !netif_running(dev))
+ if (WARN_ON(!netif_running(sdata->dev)))
+ return 0;
+
+ if (!local->ops->config_interface)
return 0;
memset(&conf, 0, sizeof(conf));
- conf.type = sdata->vif.type;
+ conf.changed = changed;
+
if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
conf.bssid = sdata->u.sta.bssid;
conf.ssid = sdata->u.sta.ssid;
conf.ssid_len = sdata->u.sta.ssid_len;
- } else if (ieee80211_vif_is_mesh(&sdata->vif)) {
- conf.beacon = beacon;
- ieee80211_start_mesh(dev);
} else if (sdata->vif.type == IEEE80211_IF_TYPE_AP) {
+ conf.bssid = sdata->dev->dev_addr;
conf.ssid = sdata->u.ap.ssid;
conf.ssid_len = sdata->u.ap.ssid_len;
- conf.beacon = beacon;
+ } else if (ieee80211_vif_is_mesh(&sdata->vif)) {
+ u8 zero[ETH_ALEN] = { 0 };
+ conf.bssid = zero;
+ conf.ssid = zero;
+ conf.ssid_len = 0;
+ } else {
+ WARN_ON(1);
+ return -EINVAL;
}
- return local->ops->config_interface(local_to_hw(local),
- &sdata->vif, &conf);
-}
-int ieee80211_if_config(struct net_device *dev)
-{
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT &&
- (local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE))
- return ieee80211_if_config_beacon(dev);
- return __ieee80211_if_config(dev, NULL);
-}
+ if (WARN_ON(!conf.bssid && (changed & IEEE80211_IFCC_BSSID)))
+ return -EINVAL;
-int ieee80211_if_config_beacon(struct net_device *dev)
-{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- struct sk_buff *skb;
+ if (WARN_ON(!conf.ssid && (changed & IEEE80211_IFCC_SSID)))
+ return -EINVAL;
- if (!(local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE))
- return 0;
- skb = ieee80211_beacon_get(local_to_hw(local), &sdata->vif);
- if (!skb)
- return -ENOMEM;
- return __ieee80211_if_config(dev, skb);
+ return local->ops->config_interface(local_to_hw(local),
+ &sdata->vif, &conf);
}
int ieee80211_hw_config(struct ieee80211_local *local)
int result;
enum ieee80211_band band;
struct net_device *mdev;
- struct ieee80211_sub_if_data *sdata;
+ struct wireless_dev *mwdev;
/*
* generic code guarantees at least one band,
* We use the number of queues for feature tests (QoS, HT) internally
* so restrict them appropriately.
*/
-#ifdef CONFIG_MAC80211_QOS
if (hw->queues > IEEE80211_MAX_QUEUES)
hw->queues = IEEE80211_MAX_QUEUES;
if (hw->ampdu_queues > IEEE80211_MAX_AMPDU_QUEUES)
hw->ampdu_queues = IEEE80211_MAX_AMPDU_QUEUES;
if (hw->queues < 4)
hw->ampdu_queues = 0;
-#else
- hw->queues = 1;
- hw->ampdu_queues = 0;
-#endif
- /* for now, mdev needs sub_if_data :/ */
- mdev = alloc_netdev_mq(sizeof(struct ieee80211_sub_if_data),
+ mdev = alloc_netdev_mq(sizeof(struct wireless_dev),
"wmaster%d", ether_setup,
ieee80211_num_queues(hw));
if (!mdev)
goto fail_mdev_alloc;
- if (ieee80211_num_queues(hw) > 1)
- mdev->features |= NETIF_F_MULTI_QUEUE;
-
- sdata = IEEE80211_DEV_TO_SUB_IF(mdev);
- mdev->ieee80211_ptr = &sdata->wdev;
- sdata->wdev.wiphy = local->hw.wiphy;
+ mwdev = netdev_priv(mdev);
+ mdev->ieee80211_ptr = mwdev;
+ mwdev->wiphy = local->hw.wiphy;
local->mdev = mdev;
- ieee80211_rx_bss_list_init(mdev);
+ ieee80211_rx_bss_list_init(local);
mdev->hard_start_xmit = ieee80211_master_start_xmit;
mdev->open = ieee80211_master_open;
mdev->header_ops = &ieee80211_header_ops;
mdev->set_multicast_list = ieee80211_master_set_multicast_list;
- sdata->vif.type = IEEE80211_IF_TYPE_AP;
- sdata->dev = mdev;
- sdata->local = local;
- sdata->u.ap.force_unicast_rateidx = -1;
- sdata->u.ap.max_ratectrl_rateidx = -1;
- ieee80211_if_sdata_init(sdata);
-
- /* no RCU needed since we're still during init phase */
- list_add_tail(&sdata->list, &local->interfaces);
-
name = wiphy_dev(local->hw.wiphy)->driver->name;
local->hw.workqueue = create_freezeable_workqueue(name);
if (!local->hw.workqueue) {
if (result < 0)
goto fail_dev;
- ieee80211_debugfs_add_netdev(IEEE80211_DEV_TO_SUB_IF(local->mdev));
- ieee80211_if_set_type(local->mdev, IEEE80211_IF_TYPE_AP);
-
result = ieee80211_init_rate_ctrl_alg(local,
hw->rate_control_algorithm);
if (result < 0) {
goto fail_wep;
}
- ieee80211_install_qdisc(local->mdev);
+ local->mdev->select_queue = ieee80211_select_queue;
/* add one default STA interface */
- result = ieee80211_if_add(local->mdev, "wlan%d", NULL,
+ result = ieee80211_if_add(local, "wlan%d", NULL,
IEEE80211_IF_TYPE_STA, NULL);
if (result)
printk(KERN_WARNING "%s: Failed to add default virtual iface\n",
wiphy_name(local->hw.wiphy));
- local->reg_state = IEEE80211_DEV_REGISTERED;
rtnl_unlock();
ieee80211_led_init(local);
fail_wep:
rate_control_deinitialize(local);
fail_rate:
- ieee80211_debugfs_remove_netdev(IEEE80211_DEV_TO_SUB_IF(local->mdev));
unregister_netdevice(local->mdev);
local->mdev = NULL;
fail_dev:
debugfs_hw_del(local);
destroy_workqueue(local->hw.workqueue);
fail_workqueue:
- if (local->mdev != NULL) {
- ieee80211_if_free(local->mdev);
- local->mdev = NULL;
- }
+ if (local->mdev)
+ free_netdev(local->mdev);
fail_mdev_alloc:
wiphy_unregister(local->hw.wiphy);
return result;
void ieee80211_unregister_hw(struct ieee80211_hw *hw)
{
struct ieee80211_local *local = hw_to_local(hw);
- struct ieee80211_sub_if_data *sdata, *tmp;
tasklet_kill(&local->tx_pending_tasklet);
tasklet_kill(&local->tasklet);
rtnl_lock();
- BUG_ON(local->reg_state != IEEE80211_DEV_REGISTERED);
-
- local->reg_state = IEEE80211_DEV_UNREGISTERED;
-
/*
* At this point, interface list manipulations are fine
* because the driver cannot be handing us frames any
* more and the tasklet is killed.
*/
- /*
- * First, we remove all non-master interfaces. Do this because they
- * may have bss pointer dependency on the master, and when we free
- * the master these would be freed as well, breaking our list
- * iteration completely.
- */
- list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) {
- if (sdata->dev == local->mdev)
- continue;
- list_del(&sdata->list);
- __ieee80211_if_del(local, sdata);
- }
+ /* First, we remove all virtual interfaces. */
+ ieee80211_remove_interfaces(local);
/* then, finally, remove the master interface */
- __ieee80211_if_del(local, IEEE80211_DEV_TO_SUB_IF(local->mdev));
+ unregister_netdevice(local->mdev);
rtnl_unlock();
- ieee80211_rx_bss_list_deinit(local->mdev);
+ ieee80211_rx_bss_list_deinit(local);
ieee80211_clear_tx_pending(local);
sta_info_stop(local);
rate_control_deinitialize(local);
wiphy_unregister(local->hw.wiphy);
ieee80211_wep_free(local);
ieee80211_led_exit(local);
- ieee80211_if_free(local->mdev);
- local->mdev = NULL;
+ free_netdev(local->mdev);
}
EXPORT_SYMBOL(ieee80211_unregister_hw);
ret = rc80211_pid_init();
if (ret)
- goto out;
-
- ret = ieee80211_wme_register();
- if (ret) {
- printk(KERN_DEBUG "ieee80211_init: failed to "
- "initialize WME (err=%d)\n", ret);
- goto out_cleanup_pid;
- }
+ return ret;
ieee80211_debugfs_netdev_init();
return 0;
-
- out_cleanup_pid:
- rc80211_pid_exit();
- out:
- return ret;
}
static void __exit ieee80211_exit(void)
if (mesh_allocated)
ieee80211s_stop();
- ieee80211_wme_unregister();
ieee80211_debugfs_netdev_exit();
}