diff options
author | David S. Miller <davem@davemloft.net> | 2009-07-30 19:26:55 -0700 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-07-30 19:26:55 -0700 |
commit | 2f6d7c1b34403b97fa57473edcb6749d1db5ace3 (patch) | |
tree | 97da33c077b08b72a361ff5a4542b86d190b0164 /net | |
parent | df597efb5737063497f1a4f7c996cc9aec294230 (diff) | |
parent | 1e4247d457c6a42e4a05cb7dfa4e6ea1fa65c112 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Diffstat (limited to 'net')
-rw-r--r-- | net/core/dev.c | 1 | ||||
-rw-r--r-- | net/mac80211/Kconfig | 1 | ||||
-rw-r--r-- | net/mac80211/Makefile | 1 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 14 | ||||
-rw-r--r-- | net/mac80211/ibss.c | 2 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 45 | ||||
-rw-r--r-- | net/mac80211/iface.c | 22 | ||||
-rw-r--r-- | net/mac80211/main.c | 3 | ||||
-rw-r--r-- | net/mac80211/mesh.c | 2 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 35 | ||||
-rw-r--r-- | net/mac80211/rx.c | 21 | ||||
-rw-r--r-- | net/mac80211/scan.c | 304 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 13 | ||||
-rw-r--r-- | net/mac80211/tx.c | 109 | ||||
-rw-r--r-- | net/mac80211/util.c | 13 | ||||
-rw-r--r-- | net/mac80211/wext.c | 235 | ||||
-rw-r--r-- | net/wireless/core.c | 78 | ||||
-rw-r--r-- | net/wireless/core.h | 8 | ||||
-rw-r--r-- | net/wireless/ibss.c | 13 | ||||
-rw-r--r-- | net/wireless/mlme.c | 8 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 206 | ||||
-rw-r--r-- | net/wireless/scan.c | 25 | ||||
-rw-r--r-- | net/wireless/sme.c | 5 | ||||
-rw-r--r-- | net/wireless/wext-compat.c | 180 | ||||
-rw-r--r-- | net/wireless/wext-compat.h | 50 | ||||
-rw-r--r-- | net/wireless/wext-sme.c | 13 |
26 files changed, 846 insertions, 561 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index d6c657ee413..71347668c50 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5344,6 +5344,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char out: return err; } +EXPORT_SYMBOL_GPL(dev_change_net_namespace); static int dev_cpu_callback(struct notifier_block *nfb, unsigned long action, diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 19a4c66e143..7dd77b6d4c9 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -6,7 +6,6 @@ config MAC80211 select CRYPTO_ARC4 select CRYPTO_AES select CRC32 - select WIRELESS_EXT ---help--- This option enables the hardware independent IEEE 802.11 networking stack. diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 91284a74ff9..9f3cf712932 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile @@ -3,7 +3,6 @@ obj-$(CONFIG_MAC80211) += mac80211.o # mac80211 objects mac80211-y := \ main.o \ - wext.o \ sta_info.o \ wep.o \ wpa.o \ diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 52928ad9057..4bbf5007799 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -57,19 +57,9 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name, return 0; } -static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex) +static int ieee80211_del_iface(struct wiphy *wiphy, struct net_device *dev) { - struct net_device *dev; - struct ieee80211_sub_if_data *sdata; - - /* we're under RTNL */ - dev = __dev_get_by_index(&init_net, ifindex); - if (!dev) - return -ENODEV; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - ieee80211_if_remove(sdata); + ieee80211_if_remove(IEEE80211_DEV_TO_SUB_IF(dev)); return 0; } diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 8e2220000e5..6e3cca65c46 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -742,7 +742,7 @@ static void ieee80211_ibss_work(struct work_struct *work) if (!netif_running(sdata->dev)) return; - if (local->sw_scanning || local->hw_scanning) + if (local->scanning) return; if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_ADHOC)) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 6a0177137dd..aec6853cb43 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -24,7 +24,6 @@ #include <linux/spinlock.h> #include <linux/etherdevice.h> #include <net/cfg80211.h> -#include <net/iw_handler.h> #include <net/mac80211.h> #include "key.h" #include "sta_info.h" @@ -570,6 +569,43 @@ enum queue_stop_reason { IEEE80211_QUEUE_STOP_REASON_SKB_ADD, }; +/** + * mac80211 scan flags - currently active scan mode + * + * @SCAN_SW_SCANNING: We're currently in the process of scanning but may as + * well be on the operating channel + * @SCAN_HW_SCANNING: The hardware is scanning for us, we have no way to + * determine if we are on the operating channel or not + * @SCAN_OFF_CHANNEL: We're off our operating channel for scanning, + * gets only set in conjunction with SCAN_SW_SCANNING + */ +enum { + SCAN_SW_SCANNING, + SCAN_HW_SCANNING, + SCAN_OFF_CHANNEL, +}; + +/** + * enum mac80211_scan_state - scan state machine states + * + * @SCAN_DECISION: Main entry point to the scan state machine, this state + * determines if we should keep on scanning or switch back to the + * operating channel + * @SCAN_SET_CHANNEL: Set the next channel to be scanned + * @SCAN_SEND_PROBE: Send probe requests and wait for probe responses + * @SCAN_LEAVE_OPER_CHANNEL: Leave the operating channel, notify the AP + * about us leaving the channel and stop all associated STA interfaces + * @SCAN_ENTER_OPER_CHANNEL: Enter the operating channel again, notify the + * AP about us being back and restart all associated STA interfaces + */ +enum mac80211_scan_state { + SCAN_DECISION, + SCAN_SET_CHANNEL, + SCAN_SEND_PROBE, + SCAN_LEAVE_OPER_CHANNEL, + SCAN_ENTER_OPER_CHANNEL, +}; + struct ieee80211_local { /* embed the driver visible part. * don't cast (use the static inlines below), but we keep @@ -668,7 +704,7 @@ struct ieee80211_local { /* Scanning and BSS list */ struct mutex scan_mtx; - bool sw_scanning, hw_scanning; + unsigned long scanning; struct cfg80211_ssid scan_ssid; struct cfg80211_scan_request int_scan_req; struct cfg80211_scan_request *scan_req; @@ -678,7 +714,7 @@ struct ieee80211_local { int scan_channel_idx; int scan_ies_len; - enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state; + enum mac80211_scan_state next_scan_state; struct delayed_work scan_work; struct ieee80211_sub_if_data *scan_sdata; enum nl80211_channel_type oper_channel_type; @@ -914,9 +950,6 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, void ieee80211_configure_filter(struct ieee80211_local *local); u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata); -/* wireless extensions */ -extern const struct iw_handler_def ieee80211_iw_handler_def; - /* STA code */ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata); int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 2f797a86ced..6c655b6547f 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -335,7 +335,10 @@ static int ieee80211_stop(struct net_device *dev) struct ieee80211_local *local = sdata->local; struct ieee80211_if_init_conf conf; struct sta_info *sta; + unsigned long flags; + struct sk_buff *skb, *tmp; u32 hw_reconf_flags = 0; + int i; /* * Stop TX on this interface first. @@ -515,7 +518,7 @@ static int ieee80211_stop(struct net_device *dev) * the scan_sdata is NULL already don't send out a * scan event to userspace -- the scan is incomplete. */ - if (local->sw_scanning) + if (test_bit(SCAN_SW_SCANNING, &local->scanning)) ieee80211_scan_completed(&local->hw, true); } @@ -551,6 +554,18 @@ static int ieee80211_stop(struct net_device *dev) if (hw_reconf_flags) ieee80211_hw_config(local, hw_reconf_flags); + spin_lock_irqsave(&local->queue_stop_reason_lock, flags); + for (i = 0; i < IEEE80211_MAX_QUEUES; i++) { + skb_queue_walk_safe(&local->pending[i], skb, tmp) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + if (info->control.vif == &sdata->vif) { + __skb_unlink(skb, &local->pending[i]); + dev_kfree_skb_irq(skb); + } + } + } + spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); + return 0; } @@ -669,7 +684,6 @@ static void ieee80211_if_setup(struct net_device *dev) { ether_setup(dev); dev->netdev_ops = &ieee80211_dataif_ops; - dev->wireless_handlers = &ieee80211_iw_handler_def; dev->destructor = free_netdev; } @@ -772,6 +786,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, name, ieee80211_if_setup); if (!ndev) return -ENOMEM; + dev_net_set(ndev, wiphy_net(local->hw.wiphy)); ndev->needed_headroom = local->tx_headroom + 4*6 /* four MAC addresses */ @@ -788,7 +803,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); - ndev->features |= NETIF_F_NETNS_LOCAL; /* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */ sdata = netdev_priv(ndev); @@ -905,7 +919,7 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local) struct ieee80211_sub_if_data *sdata; int count = 0; - if (local->hw_scanning || local->sw_scanning) + if (local->scanning) return ieee80211_idle_off(local, "scanning"); list_for_each_entry(sdata, &local->interfaces, list) { diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 3234f3751d2..c1a799194ff 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -198,7 +198,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, } if (changed & BSS_CHANGED_BEACON_ENABLED) { - if (local->sw_scanning) { + if (test_bit(SCAN_SW_SCANNING, &local->scanning)) { sdata->vif.bss_conf.enable_beacon = false; } else { /* @@ -620,6 +620,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, if (!wiphy) return NULL; + wiphy->netnsok = true; wiphy->privid = mac80211_wiphy_privid; /* Yes, putting cfg80211_bss into ieee80211_bss is a hack */ diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 8a97b142308..9a3826978b1 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -597,7 +597,7 @@ static void ieee80211_mesh_work(struct work_struct *work) if (!netif_running(sdata->dev)) return; - if (local->sw_scanning || local->hw_scanning) + if (local->scanning) return; while ((skb = skb_dequeue(&ifmsh->skb_queue))) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 0b3551da8f4..ee83125ed17 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -581,7 +581,7 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, if (!ifmgd->associated) return; - if (sdata->local->sw_scanning || sdata->local->hw_scanning) + if (sdata->local->scanning) return; /* Disregard subsequent beacons if we are already running a timer @@ -639,7 +639,7 @@ static void ieee80211_enable_ps(struct ieee80211_local *local, * If we are scanning right now then the parameters will * take effect when scan finishes. */ - if (local->hw_scanning || local->sw_scanning) + if (local->scanning) return; if (conf->dynamic_ps_timeout > 0 && @@ -1166,6 +1166,9 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, if (!netif_running(sdata->dev)) return; + if (sdata->local->scanning) + return; + mutex_lock(&ifmgd->mtx); if (!ifmgd->associated) @@ -2000,6 +2003,9 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, case RX_MGMT_CFG80211_ASSOC: cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, skb->len); break; + case RX_MGMT_CFG80211_DEAUTH: + cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len, NULL); + break; default: WARN(1, "unexpected: %d", rma); } @@ -2038,7 +2044,7 @@ static void ieee80211_sta_work(struct work_struct *work) if (!netif_running(sdata->dev)) return; - if (local->sw_scanning || local->hw_scanning) + if (local->scanning) return; if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) @@ -2213,9 +2219,6 @@ static void ieee80211_sta_monitor_work(struct work_struct *work) container_of(work, struct ieee80211_sub_if_data, u.mgd.monitor_work); - if (sdata->local->sw_scanning || sdata->local->hw_scanning) - return; - ieee80211_mgd_probe_ap(sdata, false); } @@ -2377,6 +2380,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, wk->state = IEEE80211_MGD_STATE_PROBE; wk->auth_alg = auth_alg; + wk->timeout = jiffies; /* run right away */ /* * XXX: if still associated need to tell AP that we're going @@ -2448,6 +2452,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, wk->state = IEEE80211_MGD_STATE_ASSOC; wk->tries = 0; + wk->timeout = jiffies; /* run right away */ if (req->use_mfp) { ifmgd->mfp = IEEE80211_MFP_REQUIRED; @@ -2496,8 +2501,13 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, } } - /* cfg80211 should catch this... */ - if (WARN_ON(!bssid)) { + /* + * cfg80211 should catch this ... but it's racy since + * we can receive a deauth frame, process it, hand it + * to cfg80211 while that's in a locked section already + * trying to tell us that the user wants to disconnect. + */ + if (!bssid) { mutex_unlock(&ifmgd->mtx); return -ENOLINK; } @@ -2522,8 +2532,13 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, mutex_lock(&ifmgd->mtx); - /* cfg80211 should catch that */ - if (WARN_ON(&ifmgd->associated->cbss != req->bss)) { + /* + * cfg80211 should catch this ... but it's racy since + * we can receive a disassoc frame, process it, hand it + * to cfg80211 while that's in a locked section already + * trying to tell us that the user wants to disconnect. + */ + if (&ifmgd->associated->cbss != req->bss) { mutex_unlock(&ifmgd->mtx); return -ENOLINK; } diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index b6ddde3848f..25a669c86e1 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -418,10 +418,11 @@ ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx) struct ieee80211_local *local = rx->local; struct sk_buff *skb = rx->skb; - if (unlikely(local->hw_scanning)) + if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning))) return ieee80211_scan_rx(rx->sdata, skb); - if (unlikely(local->sw_scanning)) { + if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning) && + (rx->flags & IEEE80211_RX_IN_SCAN))) { /* drop all the other packets during a software scan anyway */ if (ieee80211_scan_rx(rx->sdata, skb) != RX_QUEUED) dev_kfree_skb(skb); @@ -782,7 +783,7 @@ static void ap_sta_ps_start(struct sta_info *sta) struct ieee80211_local *local = sdata->local; atomic_inc(&sdata->bss->num_sta_ps); - set_and_clear_sta_flags(sta, WLAN_STA_PS, WLAN_STA_PSPOLL); + set_sta_flags(sta, WLAN_STA_PS); drv_sta_notify(local, &sdata->vif, STA_NOTIFY_SLEEP, &sta->sta); #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n", @@ -798,7 +799,7 @@ static int ap_sta_ps_end(struct sta_info *sta) atomic_dec(&sdata->bss->num_sta_ps); - clear_sta_flags(sta, WLAN_STA_PS | WLAN_STA_PSPOLL); + clear_sta_flags(sta, WLAN_STA_PS); drv_sta_notify(local, &sdata->vif, STA_NOTIFY_AWAKE, &sta->sta); if (!skb_queue_empty(&sta->ps_tx_buf)) @@ -1116,14 +1117,15 @@ ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx) skb_queue_empty(&rx->sta->ps_tx_buf); if (skb) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; /* - * Tell TX path to send one frame even though the STA may + * Tell TX path to send this frame even though the STA may * still remain is PS mode after this frame exchange. */ - set_sta_flags(rx->sta, WLAN_STA_PSPOLL); + info->flags |= IEEE80211_TX_CTL_PSPOLL_RESPONSE; #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "STA %pM aid %d: PS Poll (entries after %d)\n", @@ -1138,7 +1140,7 @@ ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx) else hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); - dev_queue_xmit(skb); + ieee80211_add_pending_skb(rx->local, skb); if (no_pending_pkts) sta_info_clear_tim_bit(rx->sta); @@ -1539,7 +1541,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) info = IEEE80211_SKB_CB(fwd_skb); memset(info, 0, sizeof(*info)); info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; - fwd_skb->iif = rx->dev->ifindex; + info->control.vif = &rx->sdata->vif; ieee80211_select_queue(local, fwd_skb); if (is_multicast_ether_addr(fwd_hdr->addr3)) memcpy(fwd_hdr->addr1, fwd_hdr->addr3, @@ -2136,7 +2138,8 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, return; } - if (unlikely(local->sw_scanning || local->hw_scanning)) + if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning) || + test_bit(SCAN_OFF_CHANNEL, &local->scanning))) rx.flags |= IEEE80211_RX_IN_SCAN; ieee80211_parse_qos(&rx); diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 74820656dc8..45731000eb8 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -18,7 +18,6 @@ #include <linux/if_arp.h> #include <linux/rtnetlink.h> #include <net/mac80211.h> -#include <net/iw_handler.h> #include "ieee80211_i.h" #include "driver-ops.h" @@ -265,7 +264,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) mutex_lock(&local->scan_mtx); - if (WARN_ON(!local->hw_scanning && !local->sw_scanning)) { + if (WARN_ON(!local->scanning)) { mutex_unlock(&local->scan_mtx); return; } @@ -275,16 +274,15 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) return; } - if (local->hw_scanning) + if (test_bit(SCAN_HW_SCANNING, &local->scanning)) ieee80211_restore_scan_ies(local); if (local->scan_req != &local->int_scan_req) cfg80211_scan_done(local->scan_req, aborted); local->scan_req = NULL; - was_hw_scan = local->hw_scanning; - local->hw_scanning = false; - local->sw_scanning = false; + was_hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning); + local->scanning = 0; local->scan_channel = NULL; /* we only have to protect scan_req and hw/sw scan */ @@ -366,17 +364,16 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local) ieee80211_bss_info_change_notify( sdata, BSS_CHANGED_BEACON_ENABLED); - if (sdata->vif.type == NL80211_IFTYPE_STATION) { - if (sdata->u.mgd.associated) { - netif_tx_stop_all_queues(sdata->dev); - ieee80211_scan_ps_enable(sdata); - } - } else + /* + * only handle non-STA interfaces here, STA interfaces + * are handled in the scan state machine + */ + if (sdata->vif.type != NL80211_IFTYPE_STATION) netif_tx_stop_all_queues(sdata->dev); } mutex_unlock(&local->iflist_mtx); - local->scan_state = SCAN_SET_CHANNEL; + local->next_scan_state = SCAN_DECISION; local->scan_channel_idx = 0; spin_lock_bh(&local->filter_lock); @@ -434,9 +431,9 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, } if (local->ops->hw_scan) - local->hw_scanning = true; + __set_bit(SCAN_HW_SCANNING, &local->scanning); else - local->sw_scanning = true; + __set_bit(SCAN_SW_SCANNING, &local->scanning); /* * Kicking off the scan need not be protected, * only the scan variable stuff, since now @@ -459,11 +456,9 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, mutex_lock(&local->scan_mtx); if (rc) { - if (local->ops->hw_scan) { - local->hw_scanning = false; + if (local->ops->hw_scan) ieee80211_restore_scan_ies(local); - } else - local->sw_scanning = false; + local->scanning = 0; ieee80211_recalc_idle(local); @@ -474,13 +469,195 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, return rc; } +static int ieee80211_scan_state_decision(struct ieee80211_local *local, + unsigned long *next_delay) +{ + bool associated = false; + struct ieee80211_sub_if_data *sdata; + + /* if no more bands/channels left, complete scan and advance to the idle state */ + if (local->scan_channel_idx >= local->scan_req->n_channels) { + ieee80211_scan_completed(&local->hw, false); + return 1; + } + + /* check if at least one STA interface is associated */ + mutex_lock(&local->iflist_mtx); + list_for_each_entry(sdata, &local->interfaces, list) { + if (!netif_running(sdata->dev)) + continue; + + if (sdata->vif.type == NL80211_IFTYPE_STATION) { + if (sdata->u.mgd.associated) { + associated = true; + break; + } + } + } + mutex_unlock(&local->iflist_mtx); + + if (local->scan_channel) { + /* + * we're currently scanning a different channel, let's + * switch back to the operating channel now if at least + * one interface is associated. Otherwise just scan the + * next channel + */ + if (associated) + local->next_scan_state = SCAN_ENTER_OPER_CHANNEL; + else + local->next_scan_state = SCAN_SET_CHANNEL; + } else { + /* + * we're on the operating channel currently, let's + * leave that channel now to scan another one + */ + local->next_scan_state = SCAN_LEAVE_OPER_CHANNEL; + } + + *next_delay = 0; + return 0; +} + +static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *local, + unsigned long *next_delay) +{ + struct ieee80211_sub_if_data *sdata; + + /* + * notify the AP about us leaving the channel and stop all STA interfaces + */ + mutex_lock(&local->iflist_mtx); + list_for_each_entry(sdata, &local->interfaces, list) { + if (!netif_running(sdata->dev)) + continue; + + if (sdata->vif.type == NL80211_IFTYPE_STATION) { + netif_tx_stop_all_queues(sdata->dev); + if (sdata->u.mgd.associated) + ieee80211_scan_ps_enable(sdata); + } + } + mutex_unlock(&local->iflist_mtx); + + __set_bit(SCAN_OFF_CHANNEL, &local->scanning); + + /* advance to the next channel to be scanned */ + *next_delay = HZ / 10; + local->next_scan_state = SCAN_SET_CHANNEL; +} + +static void ieee80211_scan_state_enter_oper_channel(struct ieee80211_local *local, + unsigned long *next_delay) +{ + struct ieee80211_sub_if_data *sdata = local->scan_sdata; + + /* switch back to the operating channel */ + local->scan_channel = NULL; + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); + + /* + * notify the AP about us being back and restart all STA interfaces + */ + mutex_lock(&local->iflist_mtx); + list_for_each_entry(sdata, &local->interfaces, list) { + if (!netif_running(sdata->dev)) + continue; + + /* Tell AP we're back */ + if (sdata->vif.type == NL80211_IFTYPE_STATION) { + if (sdata->u.mgd.associated) + ieee80211_scan_ps_disable(sdata); + netif_tx_wake_all_queues(sdata->dev); + } + } + mutex_unlock(&local->iflist_mtx); + + __clear_bit(SCAN_OFF_CHANNEL, &local->scanning); + + *next_delay = HZ / 5; + local->next_scan_state = SCAN_DECISION; +} + +static void ieee80211_scan_state_set_channel(struct ieee80211_local *local, + unsigned long *next_delay) +{ + int skip; + struct ieee80211_channel *chan; + struct ieee80211_sub_if_data *sdata = local->scan_sdata; + + skip = 0; + chan = local->scan_req->channels[local->scan_channel_idx]; + + if (chan->flags & IEEE80211_CHAN_DISABLED || + (sdata->vif.type == NL80211_IFTYPE_ADHOC && + chan->flags & IEEE80211_CHAN_NO_IBSS)) + skip = 1; + + if (!skip) { + local->scan_channel = chan; + if (ieee80211_hw_config(local, + IEEE80211_CONF_CHANGE_CHANNEL)) + skip = 1; + } + + /* advance state machine to next channel/band */ + local->scan_channel_idx++; + + if (skip) { + /* if we skip this channel return to the decision state */ + local->next_scan_state = SCAN_DECISION; + return; + } + + /* + * Probe delay is used to update the NAV, cf. 11.1.3.2.2 + * (which unfortunately doesn't say _why_ step a) is done, + * but it waits for the probe delay or until a frame is + * received - and the received frame would update the NAV). + * For now, we do not support waiting until a frame is + * received. + * + * In any case, it is not necessary for a passive scan. + */ + if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN || + !local->scan_req->n_ssids) { + *next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; + local->next_scan_state = SCAN_DECISION; + return; + } + + /* active scan, send probes */ + *next_delay = IEEE80211_PROBE_DELAY; + local->next_scan_state = SCAN_SEND_PROBE; +} + +static void ieee80211_scan_state_send_probe(struct ieee80211_local *local, + unsigned long *next_delay) +{ + int i; + struct ieee80211_sub_if_data *sdata = local->scan_sdata; + + for (i = 0; i < local->scan_req->n_ssids; i++) + ieee80211_send_probe_req( + sdata, NULL, + local->scan_req->ssids[i].ssid, + local->scan_req->ssids[i].ssid_len, + local->scan_req->ie, local->scan_req->ie_len); + + /* + * After sending probe requests, wait for probe responses + * on the channel. + */ + *next_delay = IEEE80211_CHANNEL_TIME; + local->next_scan_state = SCAN_DECISION; +} + void ieee80211_scan_work(struct work_struct *work) { struct ieee80211_local *local = container_of(work, struct ieee80211_local, scan_work.work); struct ieee80211_sub_if_data *sdata = local->scan_sdata; - struct ieee80211_channel *chan; - int skip, i; unsigned long next_delay = 0; mutex_lock(&local->scan_mtx); @@ -489,7 +666,7 @@ void ieee80211_scan_work(struct work_struct *work) return; } - if (local->scan_req && !(local->sw_scanning || local->hw_scanning)) { + if (local->scan_req && !local->scanning) { struct cfg80211_scan_request *req = local->scan_req; int rc; @@ -513,69 +690,30 @@ void ieee80211_scan_work(struct work_struct *work) return; } - switch (local->scan_state) { - case SCAN_SET_CHANNEL: - /* if no more bands/channels left, complete scan */ - if (local->scan_channel_idx >= local->scan_req->n_channels) { - ieee80211_scan_completed(&local->hw, false); - return; - } - skip = 0; - chan = local->scan_req->channels[local->scan_channel_idx]; - - if (chan->flags & IEEE80211_CHAN_DISABLED || - (sdata->vif.type == NL80211_IFTYPE_ADHOC && - chan->flags & IEEE80211_CHAN_NO_IBSS)) - skip = 1; - - if (!skip) { - local->scan_channel = chan; - if (ieee80211_hw_config(local, - IEEE80211_CONF_CHANGE_CHANNEL)) - skip = 1; - } - - /* advance state machine to next channel/band */ - local->scan_channel_idx++; - - if (skip) + /* + * as long as no delay is required advance immediately + * without scheduling a new work + */ + do { + switch (local->next_scan_state) { + case SCAN_DECISION: + if (ieee80211_scan_state_decision(local, &next_delay)) + return; break; - - /* - * Probe delay is used to update the NAV, cf. 11.1.3.2.2 - * (which unfortunately doesn't say _why_ step a) is done, - * but it waits for the probe delay or until a frame is - * received - and the received frame would update the NAV). - * For now, we do not support waiting until a frame is - * received. - * - * In any case, it is not necessary for a passive scan. - */ - if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN || - !local->scan_req->n_ssids) { - next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; + case SCAN_SET_CHANNEL: + ieee80211_scan_state_set_channel(local, &next_delay); + break; + case SCAN_SEND_PROBE: + ieee80211_scan_state_send_probe(local, &next_delay); + break; + case SCAN_LEAVE_OPER_CHANNEL: + ieee80211_scan_state_leave_oper_channel(local, &next_delay); + break; + case SCAN_ENTER_OPER_CHANNEL: + ieee80211_scan_state_enter_oper_channel(local, &next_delay); break; } - - next_delay = IEEE80211_PROBE_DELAY; - local->scan_state = SCAN_SEND_PROBE; - break; - case SCAN_SEND_PROBE: - for (i = 0; i < local->scan_req->n_ssids; i++) - ieee80211_send_probe_req( - sdata, NULL, - local->scan_req->ssids[i].ssid, - local->scan_req->ssids[i].ssid_len, - local->scan_req->ie, local->scan_req->ie_len); - - /* - * After sending probe requests, wait for probe responses - * on the channel. - */ - next_delay = IEEE80211_CHANNEL_TIME; - local->scan_state = SCAN_SET_CHANNEL; - break; - } + } while (next_delay == 0); queue_delayed_work(local->hw.workqueue, &local->scan_work, next_delay); @@ -625,7 +763,7 @@ void ieee80211_scan_cancel(struct ieee80211_local *local) * queued -- mostly at suspend under RTNL. */ mutex_lock(&local->scan_mtx); - swscan = local->sw_scanning; + swscan = test_bit(SCAN_SW_SCANNING, &local->scanning); mutex_unlock(&local->scan_mtx); if (swscan) diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 4ecf10a9bd0..ccc3adf962c 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -30,7 +30,6 @@ * @WLAN_STA_ASSOC_AP: We're associated to that station, it is an AP. * @WLAN_STA_WME: Station is a QoS-STA. * @WLAN_STA_WDS: Station is one of our WDS peers. - * @WLAN_STA_PSPOLL: Station has just PS-polled us. * @WLAN_STA_CLEAR_PS_FILT: Clear PS filter in hardware (using the * IEEE80211_TX_CTL_CLEAR_PS_FILT control flag) when the next * frame to this station is transmitted. @@ -47,7 +46,6 @@ enum ieee80211_sta_info_flags { WLAN_STA_ASSOC_AP = 1<<5, WLAN_STA_WME = 1<<6, WLAN_STA_WDS = 1<<7, - WLAN_STA_PSPOLL = 1<<8, WLAN_STA_CLEAR_PS_FILT = 1<<9, WLAN_STA_MFP = 1<<10, WLAN_STA_SUSPEND = 1<<11 @@ -359,17 +357,6 @@ static inline void clear_sta_flags(struct sta_info *sta, const u32 flags) spin_unlock_irqrestore(&sta->flaglock, irqfl); } -static inline void set_and_clear_sta_flags(struct sta_info *sta, - const u32 set, const u32 clear) -{ - unsigned long irqfl; - - spin_lock_irqsave(&sta->flaglock, irqfl); - sta->flags |= set; - sta->flags &= ~clear; - spin_unlock_irqrestore(&sta->flaglock, irqfl); -} - static inline u32 test_sta_flags(struct sta_info *sta, const u32 flags) { u32 ret; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 2572509d556..4e1b2ba122c 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -192,7 +192,7 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED)) return TX_CONTINUE; - if (unlikely(tx->local->sw_scanning) && + if (unlikely(test_bit(SCAN_OFF_CHANNEL, &tx->local->scanning)) && !ieee80211_is_probe_req(hdr->frame_control) && !ieee80211_is_nullfunc(hdr->frame_control)) /* @@ -373,7 +373,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) staflags = get_sta_flags(sta); if (unlikely((staflags & WLAN_STA_PS) && - !(staflags & WLAN_STA_PSPOLL))) { + !(info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE))) { #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "STA %pM aid %d: PS buffer (entries " "before %d)\n", @@ -400,6 +400,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) sta_info_set_tim_bit(sta); info->control.jiffies = jiffies; + info->control.vif = &tx->sdata->vif; info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; skb_queue_tail(&sta->ps_tx_buf, tx->skb); return TX_QUEUED; @@ -411,24 +412,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) sta->sta.addr); } #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ - if (test_and_clear_sta_flags(sta, WLAN_STA_PSPOLL)) { - /* - * The sleeping station with pending data is now snoozing. - * It queried us for its buffered frames and will go back - * to deep sleep once it got everything. - * - * inform the driver, in case the hardware does powersave - * frame filtering and keeps a station blacklist on its own - * (e.g: p54), so that frames can be delivered unimpeded. - * - * Note: It should be safe to disable the filter now. - * As, it is really unlikely that we still have any pending - * frame for this station in the hw's buffers/fifos left, - * that is not rejected with a unsuccessful tx_status yet. - */ - info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; - } return TX_CONTINUE; } @@ -551,7 +535,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) * Lets not bother rate control if we're associated and cannot * talk to the sta. This should not happen. */ - if (WARN((tx->local->sw_scanning) && + if (WARN(test_bit(SCAN_SW_SCANNING, &tx->local->scanning) && (sta_flags & WLAN_STA_ASSOC) && !rate_usable_index_exists(sband, &tx->sta->sta), "%s: Dropped data frame as no usable bitrate found while " @@ -696,7 +680,7 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) * number, if we have no matching interface then we * neither assign one ourselves nor ask the driver to. */ - if (unlikely(!info->control.vif)) + if (unlikely(info->control.vif->type == NL80211_IFTYPE_MONITOR)) return TX_CONTINUE; if (unlikely(ieee80211_is_ctl(hdr->frame_control))) @@ -1092,6 +1076,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, } else if (*state != HT_AGG_STATE_IDLE) { /* in progress */ queued = true; + info->control.vif = &sdata->vif; info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; __skb_queue_tail(&tid_tx->pending, skb); } @@ -1143,6 +1128,7 @@ static int __ieee80211_tx(struct ieee80211_local *local, { struct sk_buff *skb = *skbp, *next; struct ieee80211_tx_info *info; + struct ieee80211_sub_if_data *sdata; unsigned long flags; int ret, len; bool fragm = false; @@ -1167,13 +1153,32 @@ static int __ieee80211_tx(struct ieee80211_local *local, next = skb->next; len = skb->len; + + sdata = vif_to_sdata(info->control.vif); + + switch (sdata->vif.type) { + case NL80211_IFTYPE_MONITOR: + info->control.vif = NULL; + break; + case NL80211_IFTYPE_AP_VLAN: + info->control.vif = &container_of(sdata->bss, + struct ieee80211_sub_if_data, u.ap)->vif; + break; + default: + /* keep */ + break; + } + ret = drv_tx(local, skb); if (WARN_ON(ret != NETDEV_TX_OK && skb->len != len)) { dev_kfree_skb(skb); ret = NETDEV_TX_OK; } - if (ret != NETDEV_TX_OK) + if (ret != NETDEV_TX_OK) { + info->control.vif = &sdata->vif; return IEEE80211_TX_AGAIN; + } + *skbp = skb = next; ieee80211_led_tx(local, 1); fragm = true; @@ -1386,17 +1391,12 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct ieee80211_sub_if_data *tmp_sdata; int headroom; bool may_encrypt; - enum { - NOT_MONITOR, - FOUND_SDATA, - UNKNOWN_ADDRESS, - } monitor_iface = NOT_MONITOR; dev_hold(sdata->dev); if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && local->hw.conf.dynamic_ps_timeout > 0 && - !local->sw_scanning && !local->hw_scanning && local->ps_sdata) { + !(local->scanning) && local->ps_sdata) { if (local->hw.conf.flags & IEEE80211_CONF_PS) { ieee80211_stop_queues_by_reason(&local->hw, IEEE80211_QUEUE_STOP_REASON_PS); @@ -1424,7 +1424,6 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, u16 len_rthdr; info->flags |= IEEE80211_TX_CTL_INJECTED; - monitor_iface = UNKNOWN_ADDRESS; len_rthdr = ieee80211_get_radiotap_len(skb->data); hdr = (struct ieee80211_hdr *)(skb->data + len_rthdr); @@ -1454,7 +1453,6 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, dev_hold(tmp_sdata->dev); dev_put(sdata->dev); sdata = tmp_sdata; - monitor_iface = FOUND_SDATA; break; } } @@ -1476,13 +1474,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, return; } - tmp_sdata = sdata; - if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) - tmp_sdata = container_of(sdata->bss, - struct ieee80211_sub_if_data, - u.ap); - if (likely(monitor_iface != UNKNOWN_ADDRESS)) - info->control.vif = &tmp_sdata->vif; + info->control.vif = &sdata->vif; ieee80211_select_queue(local, skb); ieee80211_tx(sdata, skb, false); @@ -1534,9 +1526,6 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb, if (unlikely(skb->len < len_rthdr)) goto fail; /* skb too short for claimed rt header extent */ - /* needed because we set skb device to master */ - skb->iif = dev->ifindex; - /* * fix up the pointers accounting for the radiotap * header still being in there. We are being given @@ -1810,8 +1799,6 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, nh_pos += hdrlen; h_pos += hdrlen; - skb->iif = dev->ifindex; - dev->stats.tx_packets++; dev->stats.tx_bytes += skb->len; @@ -1856,32 +1843,13 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata; struct sta_info *sta; struct ieee80211_hdr *hdr; - struct net_device *dev; int ret; bool result = true; - /* does interface still exist? */ - dev = dev_get_by_index(&init_net, skb->iif); - if (!dev) { - dev_kfree_skb(skb); - return true; - } - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) - sdata = container_of(sdata->bss, - struct ieee80211_sub_if_data, - u.ap); - - if (unlikely(info->control.vif && info->control.vif != &sdata->vif)) { - dev_kfree_skb(skb); - result = true; - goto out; - } + sdata = vif_to_sdata(info->control.vif); if (info->flags & IEEE80211_TX_INTFL_NEED_TXPROCESSING) { - /* do not use sdata, it may have been changed above */ - ieee80211_tx(IEEE80211_DEV_TO_SUB_IF(dev), skb, true); + ieee80211_tx(sdata, skb, true); } else { hdr = (struct ieee80211_hdr *)skb->data; sta = sta_info_get(local, hdr->addr1); @@ -1891,9 +1859,6 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local, result = false; } - out: - dev_put(dev); - return result; } @@ -1921,10 +1886,21 @@ void ieee80211_tx_pending(unsigned long data) while (!skb_queue_empty(&local->pending[i])) { struct sk_buff *skb = __skb_dequeue(&local->pending[i]); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_sub_if_data *sdata; + + if (WARN_ON(!info->control.vif)) { + kfree_skb(skb); + continue; + } + + sdata = vif_to_sdata(info->control.vif); + dev_hold(sdata->dev); spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); txok = ieee80211_tx_pending_skb(local, skb); + dev_put(sdata->dev); if (!txok) __skb_queue_head(&local->pending[i], skb); spin_lock_irqsave(&local->queue_stop_reason_lock, @@ -2234,7 +2210,6 @@ void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, skb_set_network_header(skb, 0); skb_set_transport_header(skb, 0); - skb->iif = sdata->dev->ifindex; if (!encrypt) info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 7fc55846d60..8502936e531 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -336,6 +336,12 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local, struct ieee80211_hw *hw = &local->hw; unsigned long flags; int queue = skb_get_queue_mapping(skb); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + + if (WARN_ON(!info->control.vif)) { + kfree(skb); + return; + } spin_lock_irqsave(&local->queue_stop_reason_lock, flags); __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD); @@ -358,6 +364,13 @@ int ieee80211_add_pending_skbs(struct ieee80211_local *local, IEEE80211_QUEUE_STOP_REASON_SKB_ADD); while ((skb = skb_dequeue(skbs))) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + + if (WARN_ON(!info->control.vif)) { + kfree(skb); + continue; + } + ret++; queue = skb_get_queue_mapping(skb); __skb_queue_tail(&local->pending[queue], skb); diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c deleted file mode 100644 index 5acb8140ee5..00000000000 --- a/net/mac80211/wext.c +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright 2002-2005, Instant802 Networks, Inc. - * Copyright 2005-2006, Devicescape Software, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/netdevice.h> -#include <linux/types.h> -#include <linux/slab.h> -#include <linux/skbuff.h> -#include <linux/etherdevice.h> -#include <linux/if_arp.h> -#include <linux/wireless.h> -#include <net/iw_handler.h> -#include <asm/uaccess.h> - -#include <net/mac80211.h> -#include "ieee80211_i.h" -#include "led.h" -#include "rate.h" -#include "wpa.h" -#include "aes_ccm.h" - - -static int ieee80211_ioctl_siwfreq(struct net_device *dev, - struct iw_request_info *info, - struct iw_freq *freq, char *extra) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_local *local = sdata->local; - struct ieee80211_channel *chan; - - if (sdata->vif.type == NL80211_IFTYPE_ADHOC) - return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra); - else if (sdata->vif.type == NL80211_IFTYPE_STATION) - return cfg80211_mgd_wext_siwfreq(dev, info, freq, extra); - - /* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */ - if (freq->e == 0) { - if (freq->m < 0) - return -EINVAL; - else - chan = ieee80211_get_channel(local->hw.wiphy, - ieee80211_channel_to_frequency(freq->m)); - } else { - int i, div = 1000000; - for (i = 0; i < freq->e; i++) - div /= 10; - if (div <= 0) - return -EINVAL; - chan = ieee80211_get_channel(local->hw.wiphy, freq->m / div); - } - - if (!chan) - return -EINVAL; - - if (chan->flags & IEEE80211_CHAN_DISABLED) - return -EINVAL; - - /* - * no change except maybe auto -> fixed, ignore the HT - * setting so you can fix a channel you're on already - */ - if (local->oper_channel == chan) - return 0; - - local->oper_channel = chan; - local->oper_channel_type = NL80211_CHAN_NO_HT; - ieee80211_hw_config(local, 0); - - return 0; -} - - -static int ieee80211_ioctl_giwfreq(struct net_device *dev, - struct iw_request_info *info, - struct iw_freq *freq, char *extra) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - if (sdata->vif.type == NL80211_IFTYPE_ADHOC) - return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra); - else if (sdata->vif.type == NL80211_IFTYPE_STATION) - return cfg80211_mgd_wext_giwfreq(dev, info, freq, extra); - - freq->m = local->oper_channel->center_freq; - freq->e = 6; - - return 0; -} - - -static int ieee80211_ioctl_siwessid(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *ssid) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - if (sdata->vif.type == NL80211_IFTYPE_ADHOC) - return cfg80211_ibss_wext_siwessid(dev, info, data, ssid); - else if (sdata->vif.type == NL80211_IFTYPE_STATION) - return cfg80211_mgd_wext_siwessid(dev, info, data, ssid); - - return -EOPNOTSUPP; -} - - -static int ieee80211_ioctl_giwessid(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *ssid) -{ - struct ieee80211_sub_if_data *sdata; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - if (sdata->vif.type == NL80211_IFTYPE_ADHOC) - return cfg80211_ibss_wext_giwessid(dev, info, data, ssid); - else if (sdata->vif.type == NL80211_IFTYPE_STATION) - return cfg80211_mgd_wext_giwessid(dev, info, data, ssid); - - return -EOPNOTSUPP; -} - - -static int ieee80211_ioctl_siwap(struct net_device *dev, - struct iw_request_info *info, - struct sockaddr *ap_addr, char *extra) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - if (sdata->vif.type == NL80211_IFTYPE_ADHOC) - return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra); - - if (sdata->vif.type == NL80211_IFTYPE_STATION) - return cfg80211_mgd_wext_siwap(dev, info, ap_addr, extra); - - if (sdata->vif.type == NL80211_IFTYPE_WDS) - return cfg80211_wds_wext_siwap(dev, info, ap_addr, extra); - return -EOPNOTSUPP; -} - - -static int ieee80211_ioctl_giwap(struct net_device *dev, - struct iw_request_info *info, - struct sockaddr *ap_addr, char *extra) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - if (sdata->vif.type == NL80211_IFTYPE_ADHOC) - return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra); - - if (sdata->vif.type == NL80211_IFTYPE_STATION) - return cfg80211_mgd_wext_giwap(dev, info, ap_addr, extra); - - if (sdata->vif.type == NL80211_IFTYPE_WDS) - return cfg80211_wds_wext_giwap(dev, info, ap_addr, extra); - - return -EOPNOTSUPP; -} - - -/* Structures to export the Wireless Handlers */ - -static const iw_handler ieee80211_handler[] = -{ - (iw_handler) NULL, /* SIOCSIWCOMMIT */ - (iw_handler) cfg80211_wext_giwname, /* SIOCGIWNAME */ - (iw_handler) NULL, /* SIOCSIWNWID */ - (iw_handler) NULL, /* SIOCGIWNWID */ - (iw_handler) ieee80211_ioctl_siwfreq, /* SIOCSIWFREQ */ - (iw_handler) ieee80211_ioctl_giwfreq, /* SIOCGIWFREQ */ - (iw_handler) cfg80211_wext_siwmode, /* SIOCSIWMODE */ - (iw_handler) cfg80211_wext_giwmode, /* SIOCGIWMODE */ - (iw_handler) NULL, /* SIOCSIWSENS */ - (iw_handler) NULL, /* SIOCGIWSENS */ - (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */ - (iw_handler) cfg80211_wext_giwrange, /* SIOCGIWRANGE */ - (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */ - (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */ - (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */ - (iw_handler) NULL /* kernel code */, /* SIOCGIWSTATS */ - (iw_handler) NULL, /* SIOCSIWSPY */ - (iw_handler) NULL, /* SIOCGIWSPY */ - (iw_handler) NULL, /* SIOCSIWTHRSPY */ - (iw_handler) NULL, /* SIOCGIWTHRSPY */ - (iw_handler) ieee80211_ioctl_siwap, /* SIOCSIWAP */ - (iw_handler) ieee80211_ioctl_giwap, /* SIOCGIWAP */ - (iw_handler) cfg80211_wext_siwmlme, /* SIOCSIWMLME */ - (iw_handler) NULL, /* SIOCGIWAPLIST */ - (iw_handler) cfg80211_wext_siwscan, /* SIOCSIWSCAN */ - (iw_handler) cfg80211_wext_giwscan, /* SIOCGIWSCAN */ - (iw_handler) ieee80211_ioctl_siwessid, /* SIOCSIWESSID */ - (iw_handler) ieee80211_ioctl_giwessid, /* SIOCGIWESSID */ - (iw_handler) NULL, /* SIOCSIWNICKN */ - (iw_handler) NULL, /* SIOCGIWNICKN */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) cfg80211_wext_siwrate, /* SIOCSIWRATE */ - (iw_handler) cfg80211_wext_giwrate, /* SIOCGIWRATE */ - (iw_handler) cfg80211_wext_siwrts, /* SIOCSIWRTS */ - (iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */ - (iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */ - (iw_handler) cfg80211_wext_giwfrag, /* SIOCGIWFRAG */ - (iw_handler) cfg80211_wext_siwtxpower, /* SIOCSIWTXPOW */ - (iw_handler) cfg80211_wext_giwtxpower, /* SIOCGIWTXPOW */ - (iw_handler) cfg80211_wext_siwretry, /* SIOCSIWRETRY */ - (iw_handler) cfg80211_wext_giwretry, /* SIOCGIWRETRY */ - (iw_handler) cfg80211_wext_siwencode, /* SIOCSIWENCODE */ - (iw_handler) cfg80211_wext_giwencode, /* SIOCGIWENCODE */ - (iw_handler) cfg80211_wext_siwpower, /* SIOCSIWPOWER */ - (iw_handler) cfg80211_wext_giwpower, /* SIOCGIWPOWER */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) cfg80211_wext_siwgenie, /* SIOCSIWGENIE */ - (iw_handler) NULL, /* SIOCGIWGENIE */ - (iw_handler) cfg80211_wext_siwauth, /* SIOCSIWAUTH */ - (iw_handler) cfg80211_wext_giwauth, /* SIOCGIWAUTH */ - (iw_handler) cfg80211_wext_siwencodeext, /* SIOCSIWENCODEEXT */ - (iw_handler) NULL, /* SIOCGIWENCODEEXT */ - (iw_handler) NULL, /* SIOCSIWPMKSA */ - (iw_handler) NULL, /* -- hole -- */ -}; - -const struct iw_handler_def ieee80211_iw_handler_def = -{ - .num_standard = ARRAY_SIZE(ieee80211_handler), - .standard = (iw_handler *) ieee80211_handler, - .get_wireless_stats = cfg80211_wireless_stats, -}; diff --git a/net/wireless/core.c b/net/wireless/core.c index 6891cd0e38d..f9fee65dc06 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -19,6 +19,7 @@ #include "core.h" #include "sysfs.h" #include "debugfs.h" +#include "wext-compat.h" /* name for sysfs, %d is appended */ #define PHY_NAME "phy" @@ -106,7 +107,7 @@ __cfg80211_rdev_from_info(struct genl_info *info) if (info->attrs[NL80211_ATTR_IFINDEX]) { ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]); - dev = dev_get_by_index(&init_net, ifindex); + dev = dev_get_by_index(genl_info_net(info), ifindex); if (dev) { if (dev->ieee80211_ptr) byifidx = @@ -151,13 +152,13 @@ cfg80211_get_dev_from_info(struct genl_info *info) } struct cfg80211_registered_device * -cfg80211_get_dev_from_ifindex(int ifindex) +cfg80211_get_dev_from_ifindex(struct net *net, int ifindex) { struct cfg80211_registered_device *rdev = ERR_PTR(-ENODEV); struct net_device *dev; mutex_lock(&cfg80211_mutex); - dev = dev_get_by_index(&init_net, ifindex); + dev = dev_get_by_index(net, ifindex); if (!dev) goto out; if (dev->ieee80211_ptr) { @@ -222,6 +223,42 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, return 0; } +int cfg80211_switch_netns(struct cfg80211_registered_device *rdev, + struct net *net) +{ + struct wireless_dev *wdev; + int err = 0; + + if (!rdev->wiphy.netnsok) + return -EOPNOTSUPP; + + list_for_each_entry(wdev, &rdev->netdev_list, list) { + wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL; + err = dev_change_net_namespace(wdev->netdev, net, "wlan%d"); + if (err) + break; + wdev->netdev->features |= NETIF_F_NETNS_LOCAL; + } + + if (err) { + /* failed -- clean up to old netns */ + net = wiphy_net(&rdev->wiphy); + + list_for_each_entry_continue_reverse(wdev, &rdev->netdev_list, + list) { + wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL; + err = dev_change_net_namespace(wdev->netdev, net, + "wlan%d"); + WARN_ON(err); + wdev->netdev->features |= NETIF_F_NETNS_LOCAL; + } + } + + wiphy_net_set(&rdev->wiphy, net); + + return err; +} + static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data) { struct cfg80211_registered_device *rdev = data; @@ -375,6 +412,8 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) rdev->wiphy.dev.class = &ieee80211_class; rdev->wiphy.dev.platform_data = rdev; + wiphy_net_set(&rdev->wiphy, &init_net); + rdev->rfkill_ops.set_block = cfg80211_rfkill_set_block; rdev->rfkill = rfkill_alloc(dev_name(&rdev->wiphy.dev), &rdev->wiphy.dev, RFKILL_TYPE_WLAN, @@ -615,6 +654,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, spin_lock_init(&wdev->event_lock); mutex_lock(&rdev->devlist_mtx); list_add(&wdev->list, &rdev->netdev_list); + /* can only change netns with wiphy */ + dev->features |= NETIF_F_NETNS_LOCAL; + if (sysfs_create_link(&dev->dev.kobj, &rdev->wiphy.dev.kobj, "phy80211")) { printk(KERN_ERR "wireless: failed to add phy80211 " @@ -624,6 +666,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, wdev->sme_state = CFG80211_SME_IDLE; mutex_unlock(&rdev->devlist_mtx); #ifdef CONFIG_WIRELESS_EXT + if (!dev->wireless_handlers) + dev->wireless_handlers = &cfg80211_wext_handler; wdev->wext.default_key = -1; wdev->wext.default_mgmt_key = -1; wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; @@ -705,10 +749,32 @@ static struct notifier_block cfg80211_netdev_notifier = { .notifier_call = cfg80211_netdev_notifier_call, }; -static int cfg80211_init(void) +static void __net_exit cfg80211_pernet_exit(struct net *net) +{ + struct cfg80211_registered_device *rdev; + + rtnl_lock(); + mutex_lock(&cfg80211_mutex); + list_for_each_entry(rdev, &cfg80211_rdev_list, list) { + if (net_eq(wiphy_net(&rdev->wiphy), net)) + WARN_ON(cfg80211_switch_netns(rdev, &init_net)); + } + mutex_unlock(&cfg80211_mutex); + rtnl_unlock(); +} + +static struct pernet_operations cfg80211_pernet_ops = { + .exit = cfg80211_pernet_exit, +}; + +static int __init cfg80211_init(void) { int err; + err = register_pernet_device(&cfg80211_pernet_ops); + if (err) + goto out_fail_pernet; + err = wiphy_sysfs_init(); if (err) goto out_fail_sysfs; @@ -736,9 +802,10 @@ out_fail_nl80211: out_fail_notifier: wiphy_sysfs_exit(); out_fail_sysfs: + unregister_pernet_device(&cfg80211_pernet_ops); +out_fail_pernet: return err; } - subsys_initcall(cfg80211_init); static void cfg80211_exit(void) @@ -748,5 +815,6 @@ static void cfg80211_exit(void) unregister_netdevice_notifier(&cfg80211_netdev_notifier); wiphy_sysfs_exit(); regulatory_exit(); + unregister_pernet_device(&cfg80211_pernet_ops); } module_exit(cfg80211_exit); diff --git a/net/wireless/core.h b/net/wireless/core.h index 2ec8ddbe57d..6d903c1d721 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -66,6 +66,9 @@ struct cfg80211_registered_device { struct work_struct conn_work; struct work_struct event_work; + /* current channel */ + struct ieee80211_channel *channel; + #ifdef CONFIG_CFG80211_DEBUGFS /* Debugfs entries */ struct wiphy_debugfsdentries { @@ -170,7 +173,10 @@ struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx); /* identical to cfg80211_get_dev_from_info but only operate on ifindex */ extern struct cfg80211_registered_device * -cfg80211_get_dev_from_ifindex(int ifindex); +cfg80211_get_dev_from_ifindex(struct net *net, int ifindex); + +int cfg80211_switch_netns(struct cfg80211_registered_device *rdev, + struct net *net); static inline void cfg80211_lock_rdev(struct cfg80211_registered_device *rdev) { diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 8b65e212ae4..4d7a084b35e 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -7,6 +7,7 @@ #include <linux/etherdevice.h> #include <linux/if_arp.h> #include <net/cfg80211.h> +#include "wext-compat.h" #include "nl80211.h" @@ -312,8 +313,6 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev, return err; } -/* temporary symbol - mark GPL - in the future the handler won't be */ -EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwfreq); int cfg80211_ibss_wext_giwfreq(struct net_device *dev, struct iw_request_info *info, @@ -342,8 +341,6 @@ int cfg80211_ibss_wext_giwfreq(struct net_device *dev, /* no channel if not joining */ return -EINVAL; } -/* temporary symbol - mark GPL - in the future the handler won't be */ -EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_giwfreq); int cfg80211_ibss_wext_siwessid(struct net_device *dev, struct iw_request_info *info, @@ -384,8 +381,6 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev, return err; } -/* temporary symbol - mark GPL - in the future the handler won't be */ -EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwessid); int cfg80211_ibss_wext_giwessid(struct net_device *dev, struct iw_request_info *info, @@ -413,8 +408,6 @@ int cfg80211_ibss_wext_giwessid(struct net_device *dev, return 0; } -/* temporary symbol - mark GPL - in the future the handler won't be */ -EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_giwessid); int cfg80211_ibss_wext_siwap(struct net_device *dev, struct iw_request_info *info, @@ -469,8 +462,6 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev, return err; } -/* temporary symbol - mark GPL - in the future the handler won't be */ -EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwap); int cfg80211_ibss_wext_giwap(struct net_device *dev, struct iw_request_info *info, @@ -496,6 +487,4 @@ int cfg80211_ibss_wext_giwap(struct net_device *dev, return 0; } -/* temporary symbol - mark GPL - in the future the handler won't be */ -EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_giwap); #endif diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 5b9b2212082..097a87d7bae 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -8,7 +8,9 @@ #include <linux/module.h> #include <linux/netdevice.h> #include <linux/nl80211.h> +#include <linux/wireless.h> #include <net/cfg80211.h> +#include <net/iw_handler.h> #include "core.h" #include "nl80211.h" @@ -545,6 +547,12 @@ static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, ASSERT_WDEV_LOCK(wdev); + if (wdev->sme_state != CFG80211_SME_CONNECTED) + return -ENOTCONN; + + if (WARN_ON(!wdev->current_bss)) + return -ENOTCONN; + memset(&req, 0, sizeof(req)); req.reason_code = reason; req.ie = ie; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index da450ef1fc7..0cd548267d4 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -14,8 +14,10 @@ #include <linux/rtnetlink.h> #include <linux/netlink.h> #include <linux/etherdevice.h> +#include <net/net_namespace.h> #include <net/genetlink.h> #include <net/cfg80211.h> +#include <net/sock.h> #include "core.h" #include "nl80211.h" #include "reg.h" @@ -27,24 +29,26 @@ static struct genl_family nl80211_fam = { .hdrsize = 0, /* no private header */ .version = 1, /* no particular meaning now */ .maxattr = NL80211_ATTR_MAX, + .netnsok = true, }; /* internal helper: get rdev and dev */ -static int get_rdev_dev_by_info_ifindex(struct nlattr **attrs, +static int get_rdev_dev_by_info_ifindex(struct genl_info *info, struct cfg80211_registered_device **rdev, struct net_device **dev) { + struct nlattr **attrs = info->attrs; int ifindex; if (!attrs[NL80211_ATTR_IFINDEX]) return -EINVAL; ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]); - *dev = dev_get_by_index(&init_net, ifindex); + *dev = dev_get_by_index(genl_info_net(info), ifindex); if (!*dev) return -ENODEV; - *rdev = cfg80211_get_dev_from_ifindex(ifindex); + *rdev = cfg80211_get_dev_from_ifindex(genl_info_net(info), ifindex); if (IS_ERR(*rdev)) { dev_put(*dev); return PTR_ERR(*rdev); @@ -133,6 +137,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { [NL80211_ATTR_PRIVACY] = { .type = NLA_FLAG }, [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 }, [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, + [NL80211_ATTR_PID] = { .type = NLA_U32 }, }; /* policy for the attributes */ @@ -532,6 +537,10 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, CMD(deauth, DEAUTHENTICATE); CMD(disassoc, DISASSOCIATE); CMD(join_ibss, JOIN_IBSS); + if (dev->wiphy.netnsok) { + i++; + NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); + } #undef CMD @@ -562,6 +571,8 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) mutex_lock(&cfg80211_mutex); list_for_each_entry(dev, &cfg80211_rdev_list, list) { + if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk))) + continue; if (++idx <= start) continue; if (nl80211_send_wiphy(skb, NETLINK_CB(cb->skb).pid, @@ -746,6 +757,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) channel_type); if (result) goto bad_res; + + rdev->channel = chan; } changed = 0; @@ -867,6 +880,8 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * mutex_lock(&cfg80211_mutex); list_for_each_entry(dev, &cfg80211_rdev_list, list) { + if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk))) + continue; if (wp_idx < wp_start) { wp_idx++; continue; @@ -907,7 +922,7 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) struct net_device *netdev; int err; - err = get_rdev_dev_by_info_ifindex(info->attrs, &dev, &netdev); + err = get_rdev_dev_by_info_ifindex(info, &dev, &netdev); if (err) return err; @@ -975,7 +990,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto unlock_rtnl; @@ -1098,26 +1113,25 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev; - int ifindex, err; + int err; struct net_device *dev; rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto unlock_rtnl; - ifindex = dev->ifindex; - dev_put(dev); if (!rdev->ops->del_virtual_intf) { err = -EOPNOTSUPP; goto out; } - err = rdev->ops->del_virtual_intf(&rdev->wiphy, ifindex); + err = rdev->ops->del_virtual_intf(&rdev->wiphy, dev); out: cfg80211_unlock_rdev(rdev); + dev_put(dev); unlock_rtnl: rtnl_unlock(); return err; @@ -1195,7 +1209,7 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto unlock_rtnl; @@ -1274,7 +1288,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto unlock_rtnl; @@ -1333,7 +1347,7 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto unlock_rtnl; @@ -1380,7 +1394,7 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto unlock_rtnl; @@ -1429,7 +1443,7 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto unlock_rtnl; @@ -1516,7 +1530,7 @@ static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto unlock_rtnl; @@ -1726,13 +1740,13 @@ static int nl80211_dump_station(struct sk_buff *skb, rtnl_lock(); - netdev = __dev_get_by_index(&init_net, ifidx); + netdev = __dev_get_by_index(sock_net(skb->sk), ifidx); if (!netdev) { err = -ENODEV; goto out_rtnl; } - dev = cfg80211_get_dev_from_ifindex(ifidx); + dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); if (IS_ERR(dev)) { err = PTR_ERR(dev); goto out_rtnl; @@ -1791,7 +1805,7 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto out_rtnl; @@ -1829,14 +1843,16 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) /* * Get vlan interface making sure it is on the right wiphy. */ -static int get_vlan(struct nlattr *vlanattr, +static int get_vlan(struct genl_info *info, struct cfg80211_registered_device *rdev, struct net_device **vlan) { + struct nlattr *vlanattr = info->attrs[NL80211_ATTR_STA_VLAN]; *vlan = NULL; if (vlanattr) { - *vlan = dev_get_by_index(&init_net, nla_get_u32(vlanattr)); + *vlan = dev_get_by_index(genl_info_net(info), + nla_get_u32(vlanattr)); if (!*vlan) return -ENODEV; if (!(*vlan)->ieee80211_ptr) @@ -1891,11 +1907,11 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto out_rtnl; - err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], rdev, ¶ms.vlan); + err = get_vlan(info, rdev, ¶ms.vlan); if (err) goto out; @@ -2004,11 +2020,11 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto out_rtnl; - err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], rdev, ¶ms.vlan); + err = get_vlan(info, rdev, ¶ms.vlan); if (err) goto out; @@ -2079,7 +2095,7 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto out_rtnl; @@ -2185,13 +2201,13 @@ static int nl80211_dump_mpath(struct sk_buff *skb, rtnl_lock(); - netdev = __dev_get_by_index(&init_net, ifidx); + netdev = __dev_get_by_index(sock_net(skb->sk), ifidx); if (!netdev) { err = -ENODEV; goto out_rtnl; } - dev = cfg80211_get_dev_from_ifindex(ifidx); + dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); if (IS_ERR(dev)) { err = PTR_ERR(dev); goto out_rtnl; @@ -2255,7 +2271,7 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto out_rtnl; @@ -2314,7 +2330,7 @@ static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto out_rtnl; @@ -2362,7 +2378,7 @@ static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto out_rtnl; @@ -2404,7 +2420,7 @@ static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto out_rtnl; @@ -2455,7 +2471,7 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto out_rtnl; @@ -2574,7 +2590,7 @@ static int nl80211_get_mesh_params(struct sk_buff *skb, rtnl_lock(); /* Look up our device */ - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto out_rtnl; @@ -2691,7 +2707,7 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto out_rtnl; @@ -2947,7 +2963,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto out_rtnl; @@ -3069,14 +3085,16 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) request->ie_len); } - request->ifidx = dev->ifindex; + request->dev = dev; request->wiphy = &rdev->wiphy; rdev->scan_req = request; err = rdev->ops->scan(&rdev->wiphy, dev, request); - if (!err) + if (!err) { nl80211_send_scan_start(rdev, dev); + dev_hold(dev); + } out_free: if (err) { @@ -3198,11 +3216,11 @@ static int nl80211_dump_scan(struct sk_buff *skb, cb->args[0] = ifidx; } - dev = dev_get_by_index(&init_net, ifidx); + dev = dev_get_by_index(sock_net(skb->sk), ifidx); if (!dev) return -ENODEV; - rdev = cfg80211_get_dev_from_ifindex(ifidx); + rdev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); if (IS_ERR(rdev)) { err = PTR_ERR(rdev); goto out_put_netdev; @@ -3312,7 +3330,7 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto unlock_rtnl; @@ -3369,6 +3387,8 @@ static int nl80211_crypto_settings(struct genl_info *info, struct cfg80211_crypto_settings *settings, int cipher_limit) { + memset(settings, 0, sizeof(*settings)); + settings->control_port = info->attrs[NL80211_ATTR_CONTROL_PORT]; if (info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]) { @@ -3448,7 +3468,7 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto unlock_rtnl; @@ -3531,7 +3551,7 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto unlock_rtnl; @@ -3593,7 +3613,7 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto unlock_rtnl; @@ -3666,7 +3686,7 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto unlock_rtnl; @@ -3739,7 +3759,7 @@ static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto unlock_rtnl; @@ -3924,7 +3944,7 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) return err; rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto unlock_rtnl; @@ -4000,7 +4020,7 @@ static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto unlock_rtnl; @@ -4024,6 +4044,47 @@ unlock_rtnl: return err; } +static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev; + struct net *net; + int err; + u32 pid; + + if (!info->attrs[NL80211_ATTR_PID]) + return -EINVAL; + + pid = nla_get_u32(info->attrs[NL80211_ATTR_PID]); + + rtnl_lock(); + + rdev = cfg80211_get_dev_from_info(info); + if (IS_ERR(rdev)) { + err = PTR_ERR(rdev); + goto out; + } + + net = get_net_ns_by_pid(pid); + if (IS_ERR(net)) { + err = PTR_ERR(net); + goto out; + } + + err = 0; + + /* check if anything to do */ + if (net_eq(wiphy_net(&rdev->wiphy), net)) + goto out_put_net; + + err = cfg80211_switch_netns(rdev, net); + out_put_net: + put_net(net); + out: + cfg80211_unlock_rdev(rdev); + rtnl_unlock(); + return err; +} + static struct genl_ops nl80211_ops[] = { { .cmd = NL80211_CMD_GET_WIPHY, @@ -4257,6 +4318,12 @@ static struct genl_ops nl80211_ops[] = { .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, }, + { + .cmd = NL80211_CMD_SET_WIPHY_NETNS, + .doit = nl80211_wiphy_netns, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, }; static struct genl_multicast_group nl80211_mlme_mcgrp = { .name = "mlme", @@ -4288,7 +4355,8 @@ void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev) return; } - genlmsg_multicast(msg, 0, nl80211_config_mcgrp.id, GFP_KERNEL); + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_config_mcgrp.id, GFP_KERNEL); } static int nl80211_add_scan_req(struct sk_buff *msg, @@ -4365,7 +4433,8 @@ void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, return; } - genlmsg_multicast(msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL); + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_scan_mcgrp.id, GFP_KERNEL); } void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, @@ -4383,7 +4452,8 @@ void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, return; } - genlmsg_multicast(msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL); + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_scan_mcgrp.id, GFP_KERNEL); } void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, @@ -4401,7 +4471,8 @@ void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, return; } - genlmsg_multicast(msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL); + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_scan_mcgrp.id, GFP_KERNEL); } /* @@ -4450,7 +4521,10 @@ void nl80211_send_reg_change_event(struct regulatory_request *request) return; } - genlmsg_multicast(msg, 0, nl80211_regulatory_mcgrp.id, GFP_KERNEL); + rcu_read_lock(); + genlmsg_multicast_allns(msg, 0, nl80211_regulatory_mcgrp.id, + GFP_ATOMIC); + rcu_read_unlock(); return; @@ -4486,7 +4560,8 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev, return; } - genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, gfp); return; nla_put_failure: @@ -4553,7 +4628,8 @@ static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev, return; } - genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, gfp); return; nla_put_failure: @@ -4611,7 +4687,8 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev, return; } - genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, gfp); return; nla_put_failure: @@ -4651,7 +4728,8 @@ void nl80211_send_roamed(struct cfg80211_registered_device *rdev, return; } - genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, gfp); return; nla_put_failure: @@ -4691,7 +4769,8 @@ void nl80211_send_disconnected(struct cfg80211_registered_device *rdev, return; } - genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_KERNEL); + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, GFP_KERNEL); return; nla_put_failure: @@ -4726,7 +4805,8 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, return; } - genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, gfp); return; nla_put_failure: @@ -4766,7 +4846,8 @@ void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, return; } - genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, gfp); return; nla_put_failure: @@ -4819,7 +4900,10 @@ void nl80211_send_beacon_hint_event(struct wiphy *wiphy, return; } - genlmsg_multicast(msg, 0, nl80211_regulatory_mcgrp.id, GFP_ATOMIC); + rcu_read_lock(); + genlmsg_multicast_allns(msg, 0, nl80211_regulatory_mcgrp.id, + GFP_ATOMIC); + rcu_read_unlock(); return; diff --git a/net/wireless/scan.c b/net/wireless/scan.c index decc59fe0ee..67714d7ed5b 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -14,8 +14,9 @@ #include <net/iw_handler.h> #include "core.h" #include "nl80211.h" +#include "wext-compat.h" -#define IEEE80211_SCAN_RESULT_EXPIRE (10 * HZ) +#define IEEE80211_SCAN_RESULT_EXPIRE (15 * HZ) void __cfg80211_scan_done(struct work_struct *wk) { @@ -32,9 +33,7 @@ void __cfg80211_scan_done(struct work_struct *wk) mutex_lock(&rdev->mtx); request = rdev->scan_req; - dev = dev_get_by_index(&init_net, request->ifidx); - if (!dev) - goto out; + dev = request->dev; /* * This must be before sending the other events! @@ -58,7 +57,6 @@ void __cfg80211_scan_done(struct work_struct *wk) dev_put(dev); - out: cfg80211_unlock_rdev(rdev); wiphy_to_dev(request->wiphy)->scan_req = NULL; kfree(request); @@ -66,17 +64,10 @@ void __cfg80211_scan_done(struct work_struct *wk) void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) { - struct net_device *dev = dev_get_by_index(&init_net, request->ifidx); - if (WARN_ON(!dev)) { - kfree(request); - return; - } - WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req); request->aborted = aborted; schedule_work(&wiphy_to_dev(request->wiphy)->scan_done_wk); - dev_put(dev); } EXPORT_SYMBOL(cfg80211_scan_done); @@ -592,7 +583,7 @@ int cfg80211_wext_siwscan(struct net_device *dev, if (!netif_running(dev)) return -ENETDOWN; - rdev = cfg80211_get_dev_from_ifindex(dev->ifindex); + rdev = cfg80211_get_dev_from_ifindex(dev_net(dev), dev->ifindex); if (IS_ERR(rdev)) return PTR_ERR(rdev); @@ -617,7 +608,7 @@ int cfg80211_wext_siwscan(struct net_device *dev, } creq->wiphy = wiphy; - creq->ifidx = dev->ifindex; + creq->dev = dev; creq->ssids = (void *)(creq + 1); creq->channels = (void *)(creq->ssids + 1); creq->n_channels = n_channels; @@ -654,8 +645,10 @@ int cfg80211_wext_siwscan(struct net_device *dev, if (err) { rdev->scan_req = NULL; kfree(creq); - } else + } else { nl80211_send_scan_start(rdev, dev); + dev_hold(dev); + } out: cfg80211_unlock_rdev(rdev); return err; @@ -948,7 +941,7 @@ int cfg80211_wext_giwscan(struct net_device *dev, if (!netif_running(dev)) return -ENETDOWN; - rdev = cfg80211_get_dev_from_ifindex(dev->ifindex); + rdev = cfg80211_get_dev_from_ifindex(dev_net(dev), dev->ifindex); if (IS_ERR(rdev)) return PTR_ERR(rdev); diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 82de2d9795f..d2b5d4ce0a0 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -8,6 +8,8 @@ #include <linux/etherdevice.h> #include <linux/if_arp.h> #include <linux/workqueue.h> +#include <linux/wireless.h> +#include <net/iw_handler.h> #include <net/cfg80211.h> #include <net/rtnetlink.h> #include "nl80211.h" @@ -86,7 +88,7 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev) wdev->conn->params.ssid_len); request->ssids[0].ssid_len = wdev->conn->params.ssid_len; - request->ifidx = wdev->netdev->ifindex; + request->dev = wdev->netdev; request->wiphy = &rdev->wiphy; rdev->scan_req = request; @@ -95,6 +97,7 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev) if (!err) { wdev->conn->state = CFG80211_CONN_SCANNING; nl80211_send_scan_start(rdev, wdev->netdev); + dev_hold(wdev->netdev); } else { rdev->scan_req = NULL; kfree(request); diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index c7351a98e66..e4e90e249ba 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -14,6 +14,7 @@ #include <linux/etherdevice.h> #include <net/iw_handler.h> #include <net/cfg80211.h> +#include "wext-compat.h" #include "core.h" int cfg80211_wext_giwname(struct net_device *dev, @@ -300,7 +301,6 @@ struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy, return ERR_PTR(-EINVAL); return chan; } -EXPORT_SYMBOL_GPL(cfg80211_wext_freq); int cfg80211_wext_siwrts(struct net_device *dev, struct iw_request_info *info, @@ -759,6 +759,58 @@ int cfg80211_wext_giwencode(struct net_device *dev, } EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode); +int cfg80211_wext_siwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct ieee80211_channel *chan; + int err; + + switch (wdev->iftype) { + case NL80211_IFTYPE_STATION: + return cfg80211_mgd_wext_siwfreq(dev, info, freq, extra); + case NL80211_IFTYPE_ADHOC: + return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra); + default: + chan = cfg80211_wext_freq(wdev->wiphy, freq); + if (!chan) + return -EINVAL; + if (IS_ERR(chan)) + return PTR_ERR(chan); + err = rdev->ops->set_channel(wdev->wiphy, chan, + NL80211_CHAN_NO_HT); + if (err) + return err; + rdev->channel = chan; + return 0; + } +} +EXPORT_SYMBOL_GPL(cfg80211_wext_siwfreq); + +int cfg80211_wext_giwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + + switch (wdev->iftype) { + case NL80211_IFTYPE_STATION: + return cfg80211_mgd_wext_giwfreq(dev, info, freq, extra); + case NL80211_IFTYPE_ADHOC: + return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra); + default: + if (!rdev->channel) + return -EINVAL; + freq->m = rdev->channel->center_freq; + freq->e = 6; + return 0; + } +} +EXPORT_SYMBOL_GPL(cfg80211_wext_giwfreq); + int cfg80211_wext_siwtxpower(struct net_device *dev, struct iw_request_info *info, union iwreq_data *data, char *extra) @@ -1097,9 +1149,9 @@ int cfg80211_wext_giwpower(struct net_device *dev, } EXPORT_SYMBOL_GPL(cfg80211_wext_giwpower); -int cfg80211_wds_wext_siwap(struct net_device *dev, - struct iw_request_info *info, - struct sockaddr *addr, char *extra) +static int cfg80211_wds_wext_siwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *addr, char *extra) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); @@ -1125,11 +1177,10 @@ int cfg80211_wds_wext_siwap(struct net_device *dev, return 0; } -EXPORT_SYMBOL_GPL(cfg80211_wds_wext_siwap); -int cfg80211_wds_wext_giwap(struct net_device *dev, - struct iw_request_info *info, - struct sockaddr *addr, char *extra) +static int cfg80211_wds_wext_giwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *addr, char *extra) { struct wireless_dev *wdev = dev->ieee80211_ptr; @@ -1141,7 +1192,6 @@ int cfg80211_wds_wext_giwap(struct net_device *dev, return 0; } -EXPORT_SYMBOL_GPL(cfg80211_wds_wext_giwap); int cfg80211_wext_siwrate(struct net_device *dev, struct iw_request_info *info, @@ -1275,3 +1325,115 @@ struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev) return &wstats; } EXPORT_SYMBOL_GPL(cfg80211_wireless_stats); + +int cfg80211_wext_siwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + switch (wdev->iftype) { + case NL80211_IFTYPE_ADHOC: + return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra); + case NL80211_IFTYPE_STATION: + return cfg80211_mgd_wext_siwap(dev, info, ap_addr, extra); + case NL80211_IFTYPE_WDS: + return cfg80211_wds_wext_siwap(dev, info, ap_addr, extra); + default: + return -EOPNOTSUPP; + } +} +EXPORT_SYMBOL_GPL(cfg80211_wext_siwap); + +int cfg80211_wext_giwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + switch (wdev->iftype) { + case NL80211_IFTYPE_ADHOC: + return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra); + case NL80211_IFTYPE_STATION: + return cfg80211_mgd_wext_giwap(dev, info, ap_addr, extra); + case NL80211_IFTYPE_WDS: + return cfg80211_wds_wext_giwap(dev, info, ap_addr, extra); + default: + return -EOPNOTSUPP; + } +} +EXPORT_SYMBOL_GPL(cfg80211_wext_giwap); + +int cfg80211_wext_siwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + switch (wdev->iftype) { + case NL80211_IFTYPE_ADHOC: + return cfg80211_ibss_wext_siwessid(dev, info, data, ssid); + case NL80211_IFTYPE_STATION: + return cfg80211_mgd_wext_siwessid(dev, info, data, ssid); + default: + return -EOPNOTSUPP; + } +} +EXPORT_SYMBOL_GPL(cfg80211_wext_siwessid); + +int cfg80211_wext_giwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + switch (wdev->iftype) { + case NL80211_IFTYPE_ADHOC: + return cfg80211_ibss_wext_giwessid(dev, info, data, ssid); + case NL80211_IFTYPE_STATION: + return cfg80211_mgd_wext_giwessid(dev, info, data, ssid); + default: + return -EOPNOTSUPP; + } +} +EXPORT_SYMBOL_GPL(cfg80211_wext_giwessid); + +static const iw_handler cfg80211_handlers[] = { + [IW_IOCTL_IDX(SIOCGIWNAME)] = (iw_handler) cfg80211_wext_giwname, + [IW_IOCTL_IDX(SIOCSIWFREQ)] = (iw_handler) cfg80211_wext_siwfreq, + [IW_IOCTL_IDX(SIOCGIWFREQ)] = (iw_handler) cfg80211_wext_giwfreq, + [IW_IOCTL_IDX(SIOCSIWMODE)] = (iw_handler) cfg80211_wext_siwmode, + [IW_IOCTL_IDX(SIOCGIWMODE)] = (iw_handler) cfg80211_wext_giwmode, + [IW_IOCTL_IDX(SIOCGIWRANGE)] = (iw_handler) cfg80211_wext_giwrange, + [IW_IOCTL_IDX(SIOCSIWAP)] = (iw_handler) cfg80211_wext_siwap, + [IW_IOCTL_IDX(SIOCGIWAP)] = (iw_handler) cfg80211_wext_giwap, + [IW_IOCTL_IDX(SIOCSIWMLME)] = (iw_handler) cfg80211_wext_siwmlme, + [IW_IOCTL_IDX(SIOCSIWSCAN)] = (iw_handler) cfg80211_wext_siwscan, + [IW_IOCTL_IDX(SIOCGIWSCAN)] = (iw_handler) cfg80211_wext_giwscan, + [IW_IOCTL_IDX(SIOCSIWESSID)] = (iw_handler) cfg80211_wext_siwessid, + [IW_IOCTL_IDX(SIOCGIWESSID)] = (iw_handler) cfg80211_wext_giwessid, + [IW_IOCTL_IDX(SIOCSIWRATE)] = (iw_handler) cfg80211_wext_siwrate, + [IW_IOCTL_IDX(SIOCGIWRATE)] = (iw_handler) cfg80211_wext_giwrate, + [IW_IOCTL_IDX(SIOCSIWRTS)] = (iw_handler) cfg80211_wext_siwrts, + [IW_IOCTL_IDX(SIOCGIWRTS)] = (iw_handler) cfg80211_wext_giwrts, + [IW_IOCTL_IDX(SIOCSIWFRAG)] = (iw_handler) cfg80211_wext_siwfrag, + [IW_IOCTL_IDX(SIOCGIWFRAG)] = (iw_handler) cfg80211_wext_giwfrag, + [IW_IOCTL_IDX(SIOCSIWTXPOW)] = (iw_handler) cfg80211_wext_siwtxpower, + [IW_IOCTL_IDX(SIOCGIWTXPOW)] = (iw_handler) cfg80211_wext_giwtxpower, + [IW_IOCTL_IDX(SIOCSIWRETRY)] = (iw_handler) cfg80211_wext_siwretry, + [IW_IOCTL_IDX(SIOCGIWRETRY)] = (iw_handler) cfg80211_wext_giwretry, + [IW_IOCTL_IDX(SIOCSIWENCODE)] = (iw_handler) cfg80211_wext_siwencode, + [IW_IOCTL_IDX(SIOCGIWENCODE)] = (iw_handler) cfg80211_wext_giwencode, + [IW_IOCTL_IDX(SIOCSIWPOWER)] = (iw_handler) cfg80211_wext_siwpower, + [IW_IOCTL_IDX(SIOCGIWPOWER)] = (iw_handler) cfg80211_wext_giwpower, + [IW_IOCTL_IDX(SIOCSIWGENIE)] = (iw_handler) cfg80211_wext_siwgenie, + [IW_IOCTL_IDX(SIOCSIWAUTH)] = (iw_handler) cfg80211_wext_siwauth, + [IW_IOCTL_IDX(SIOCGIWAUTH)] = (iw_handler) cfg80211_wext_giwauth, + [IW_IOCTL_IDX(SIOCSIWENCODEEXT)]= (iw_handler) cfg80211_wext_siwencodeext, +}; + +const struct iw_handler_def cfg80211_wext_handler = { + .num_standard = ARRAY_SIZE(cfg80211_handlers), + .standard = cfg80211_handlers, + .get_wireless_stats = cfg80211_wireless_stats, +}; diff --git a/net/wireless/wext-compat.h b/net/wireless/wext-compat.h new file mode 100644 index 00000000000..9a377474958 --- /dev/null +++ b/net/wireless/wext-compat.h @@ -0,0 +1,50 @@ +#ifndef __WEXT_COMPAT +#define __WEXT_COMPAT + +#include <net/iw_handler.h> +#include <linux/wireless.h> + +int cfg80211_ibss_wext_siwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra); +int cfg80211_ibss_wext_giwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra); +int cfg80211_ibss_wext_siwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra); +int cfg80211_ibss_wext_giwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra); +int cfg80211_ibss_wext_siwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid); +int cfg80211_ibss_wext_giwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid); + +int cfg80211_mgd_wext_siwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra); +int cfg80211_mgd_wext_giwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra); +int cfg80211_mgd_wext_siwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra); +int cfg80211_mgd_wext_giwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra); +int cfg80211_mgd_wext_siwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid); +int cfg80211_mgd_wext_giwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid); + +struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy, + struct iw_freq *freq); + + +extern const struct iw_handler_def cfg80211_wext_handler; +#endif /* __WEXT_COMPAT */ diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index 4c689fd865b..7bacbd1c2af 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c @@ -8,6 +8,7 @@ #include <linux/etherdevice.h> #include <linux/if_arp.h> #include <net/cfg80211.h> +#include "wext-compat.h" #include "nl80211.h" int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, @@ -108,8 +109,6 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev, cfg80211_unlock_rdev(rdev); return err; } -/* temporary symbol - mark GPL - in the future the handler won't be */ -EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwfreq); int cfg80211_mgd_wext_giwfreq(struct net_device *dev, struct iw_request_info *info, @@ -138,8 +137,6 @@ int cfg80211_mgd_wext_giwfreq(struct net_device *dev, /* no channel if not joining */ return -EINVAL; } -/* temporary symbol - mark GPL - in the future the handler won't be */ -EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_giwfreq); int cfg80211_mgd_wext_siwessid(struct net_device *dev, struct iw_request_info *info, @@ -195,8 +192,6 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev, cfg80211_unlock_rdev(wiphy_to_dev(wdev->wiphy)); return err; } -/* temporary symbol - mark GPL - in the future the handler won't be */ -EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwessid); int cfg80211_mgd_wext_giwessid(struct net_device *dev, struct iw_request_info *info, @@ -221,8 +216,6 @@ int cfg80211_mgd_wext_giwessid(struct net_device *dev, return 0; } -/* temporary symbol - mark GPL - in the future the handler won't be */ -EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_giwessid); int cfg80211_mgd_wext_siwap(struct net_device *dev, struct iw_request_info *info, @@ -276,8 +269,6 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev, cfg80211_unlock_rdev(wiphy_to_dev(wdev->wiphy)); return err; } -/* temporary symbol - mark GPL - in the future the handler won't be */ -EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwap); int cfg80211_mgd_wext_giwap(struct net_device *dev, struct iw_request_info *info, @@ -302,8 +293,6 @@ int cfg80211_mgd_wext_giwap(struct net_device *dev, return 0; } -/* temporary symbol - mark GPL - in the future the handler won't be */ -EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_giwap); int cfg80211_wext_siwgenie(struct net_device *dev, struct iw_request_info *info, |