X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=net%2Fmac80211%2Fmain.c;h=0759ab2ca3ff5d8dfbf567ec3585520f16017697;hb=75636525fbfa78fa33fd754c89785cfde750acd3;hp=f18cfd7278726a53e9cd261b6bb91a4777ae4153;hpb=ea2aca084ba82aaf7c148d04914ceed8758ce08a;p=linux-2.6 diff --git a/net/mac80211/main.c b/net/mac80211/main.c index f18cfd7278..0759ab2ca3 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -105,7 +105,7 @@ static int ieee80211_master_open(struct net_device *dev) /* 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; } @@ -126,7 +126,7 @@ static int ieee80211_master_stop(struct net_device *dev) /* 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; @@ -182,10 +182,11 @@ static int ieee80211_open(struct net_device *dev) { struct ieee80211_sub_if_data *sdata, *nsdata; struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct sta_info *sta; struct ieee80211_if_init_conf conf; + u32 changed = 0; int res; bool need_hw_reconfig = 0; - struct sta_info *sta; sdata = IEEE80211_DEV_TO_SUB_IF(dev); @@ -193,7 +194,7 @@ static int ieee80211_open(struct net_device *dev) 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 @@ -208,30 +209,6 @@ static int ieee80211_open(struct net_device *dev) 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. @@ -251,7 +228,7 @@ static int ieee80211_open(struct net_device *dev) */ 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; } } @@ -261,10 +238,13 @@ static int ieee80211_open(struct net_device *dev) 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: @@ -282,14 +262,13 @@ static int ieee80211_open(struct net_device *dev) 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: @@ -329,7 +308,8 @@ static int ieee80211_open(struct net_device *dev) goto err_stop; ieee80211_if_config(dev); - ieee80211_reset_erp_info(dev); + changed |= ieee80211_reset_erp_info(dev); + ieee80211_bss_info_change_notify(sdata, changed); ieee80211_enable_keys(sdata); if (sdata->vif.type == IEEE80211_IF_TYPE_STA && @@ -402,6 +382,10 @@ static int ieee80211_open(struct net_device *dev) 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; } @@ -484,7 +468,6 @@ static int ieee80211_stop(struct net_device *dev) 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: @@ -533,8 +516,6 @@ static int ieee80211_stop(struct net_device *dev) 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; @@ -549,6 +530,8 @@ static int ieee80211_stop(struct net_device *dev) 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); @@ -558,6 +541,8 @@ static int ieee80211_stop(struct net_device *dev) ieee80211_led_radio(local, 0); + flush_workqueue(local->hw.workqueue); + tasklet_disable(&local->tx_pending_tasklet); tasklet_disable(&local->tasklet); } @@ -568,6 +553,7 @@ static int ieee80211_stop(struct net_device *dev) int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) { struct ieee80211_local *local = hw_to_local(hw); + struct netdev_queue *txq; struct sta_info *sta; struct ieee80211_sub_if_data *sdata; u16 start_seq_num = 0; @@ -634,7 +620,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) /* ensure that TX flow won't interrupt us * until the end of the call to requeue function */ - spin_lock_bh(&local->mdev->queue_lock); + txq = &local->mdev->tx_queue; + spin_lock_bh(&txq->lock); /* create a new queue for this aggregation */ ret = ieee80211_ht_agg_queue_add(local, sta, tid); @@ -673,7 +660,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 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(&txq->lock); spin_unlock_bh(&sta->lock); /* send an addBA request */ @@ -699,7 +686,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) err_unlock_queue: kfree(sta->ampdu_mlme.tid_tx[tid]); sta->ampdu_mlme.tid_tx[tid] = NULL; - spin_unlock_bh(&local->mdev->queue_lock); + spin_unlock_bh(&txq->lock); ret = -EBUSY; err_unlock_sta: spin_unlock_bh(&sta->lock); @@ -824,6 +811,7 @@ EXPORT_SYMBOL(ieee80211_start_tx_ba_cb); void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) { struct ieee80211_local *local = hw_to_local(hw); + struct netdev_queue *txq; struct sta_info *sta; u8 *state; int agg_queue; @@ -873,16 +861,17 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) /* avoid ordering issues: we are the only one that can modify * the content of the qdiscs */ - spin_lock_bh(&local->mdev->queue_lock); + txq = &local->mdev->tx_queue; + spin_lock_bh(&txq->lock); /* remove the queue for this aggregation */ ieee80211_ht_agg_queue_remove(local, sta, tid, 1); - spin_unlock_bh(&local->mdev->queue_lock); + spin_unlock_bh(&txq->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. + * 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(local->mdev); + netif_schedule_queue(txq); spin_lock_bh(&sta->lock); *state = HT_AGG_STATE_IDLE; sta->ampdu_mlme.addba_req_num[tid] = 0; @@ -982,7 +971,6 @@ static const struct header_ops ieee80211_header_ops = { .cache_update = eth_header_cache_update, }; -/* Must not be called for mdev */ void ieee80211_if_setup(struct net_device *dev) { ether_setup(dev); @@ -992,7 +980,7 @@ void ieee80211_if_setup(struct net_device *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 */ @@ -1190,15 +1178,13 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, changed); } -void ieee80211_reset_erp_info(struct net_device *dev) +u32 ieee80211_reset_erp_info(struct net_device *dev) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); sdata->bss_conf.use_cts_prot = 0; sdata->bss_conf.use_short_preamble = 0; - ieee80211_bss_info_change_notify(sdata, - BSS_CHANGED_ERP_CTS_PROT | - BSS_CHANGED_ERP_PREAMBLE); + return BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_ERP_PREAMBLE; } void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, @@ -1404,14 +1390,15 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); u16 frag, type; + __le16 fc; struct ieee80211_tx_status_rtap_hdr *rthdr; struct ieee80211_sub_if_data *sdata; struct net_device *prev_dev = NULL; + struct sta_info *sta; rcu_read_lock(); if (info->status.excessive_retries) { - struct sta_info *sta; sta = sta_info_get(local, hdr->addr1); if (sta) { if (test_sta_flags(sta, WLAN_STA_PS)) { @@ -1426,8 +1413,24 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) } } + fc = hdr->frame_control; + + if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) && + (ieee80211_is_data_qos(fc))) { + u16 tid, ssn; + u8 *qc; + sta = sta_info_get(local, hdr->addr1); + if (sta) { + qc = ieee80211_get_qos_ctl(hdr); + tid = qc[0] & 0xf; + ssn = ((le16_to_cpu(hdr->seq_ctrl) + 0x10) + & IEEE80211_SCTL_SEQ); + ieee80211_send_bar(sta->sdata->dev, hdr->addr1, + tid, ssn); + } + } + if (info->flags & IEEE80211_TX_STAT_TX_FILTERED) { - struct sta_info *sta; sta = sta_info_get(local, hdr->addr1); if (sta) { ieee80211_handle_filtered_frame(local, sta, skb); @@ -1638,7 +1641,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) 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, @@ -1678,8 +1681,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) 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) @@ -1688,13 +1690,13 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) 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; @@ -1703,16 +1705,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) 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) { @@ -1758,9 +1750,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) 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) { @@ -1780,13 +1769,12 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) ieee80211_install_qdisc(local->mdev); /* 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); @@ -1796,7 +1784,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) 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: @@ -1806,10 +1793,8 @@ fail_sta_info: 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; @@ -1819,42 +1804,27 @@ EXPORT_SYMBOL(ieee80211_register_hw); 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); @@ -1871,8 +1841,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) 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);