diff options
Diffstat (limited to 'net/mac80211/main.c')
| -rw-r--r-- | net/mac80211/main.c | 1363 |
1 files changed, 740 insertions, 623 deletions
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 092a017b237..d17c26d6e36 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -9,7 +9,6 @@ */ #include <net/mac80211.h> -#include <net/ieee80211_radiotap.h> #include <linux/module.h> #include <linux/init.h> #include <linux/netdevice.h> @@ -18,41 +17,26 @@ #include <linux/skbuff.h> #include <linux/etherdevice.h> #include <linux/if_arp.h> -#include <linux/wireless.h> #include <linux/rtnetlink.h> #include <linux/bitmap.h> -#include <linux/pm_qos_params.h> +#include <linux/pm_qos.h> +#include <linux/inetdevice.h> #include <net/net_namespace.h> #include <net/cfg80211.h> +#include <net/addrconf.h> #include "ieee80211_i.h" #include "driver-ops.h" #include "rate.h" #include "mesh.h" #include "wep.h" -#include "wme.h" -#include "aes_ccm.h" #include "led.h" #include "cfg.h" #include "debugfs.h" -#include "debugfs_netdev.h" -/* - * For seeing transmitted packets on monitor interfaces - * we have a radiotap header too. - */ -struct ieee80211_tx_status_rtap_hdr { - struct ieee80211_radiotap_header hdr; - u8 rate; - u8 padding_for_rate; - __le16 tx_flags; - u8 data_retries; -} __attribute__ ((packed)); - - -/* must be called under mdev tx lock */ void ieee80211_configure_filter(struct ieee80211_local *local) { + u64 mc; unsigned int changed_flags; unsigned int new_flags = 0; @@ -62,9 +46,13 @@ void ieee80211_configure_filter(struct ieee80211_local *local) if (atomic_read(&local->iff_allmultis)) new_flags |= FIF_ALLMULTI; - if (local->monitors) + if (local->monitors || test_bit(SCAN_SW_SCANNING, &local->scanning) || + test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning)) new_flags |= FIF_BCN_PRBRESP_PROMISC; + if (local->fif_probe_req || local->probe_req_reg) + new_flags |= FIF_PROBE_REQ; + if (local->fif_fcsfail) new_flags |= FIF_FCSFAIL; @@ -77,121 +65,114 @@ void ieee80211_configure_filter(struct ieee80211_local *local) if (local->fif_other_bss) new_flags |= FIF_OTHER_BSS; + if (local->fif_pspoll) + new_flags |= FIF_PSPOLL; + + spin_lock_bh(&local->filter_lock); changed_flags = local->filter_flags ^ new_flags; + mc = drv_prepare_multicast(local, &local->mc_list); + spin_unlock_bh(&local->filter_lock); + /* be a bit nasty */ new_flags |= (1<<31); - drv_configure_filter(local, changed_flags, &new_flags, - local->mdev->mc_count, - local->mdev->mc_list); + drv_configure_filter(local, changed_flags, &new_flags, mc); WARN_ON(new_flags & (1<<31)); local->filter_flags = new_flags & ~(1<<31); } -/* master interface */ - -static int header_parse_80211(const struct sk_buff *skb, unsigned char *haddr) +static void ieee80211_reconfig_filter(struct work_struct *work) { - memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */ - return ETH_ALEN; -} + struct ieee80211_local *local = + container_of(work, struct ieee80211_local, reconfig_filter); -static const struct header_ops ieee80211_header_ops = { - .create = eth_header, - .parse = header_parse_80211, - .rebuild = eth_rebuild_header, - .cache = eth_header_cache, - .cache_update = eth_header_cache_update, -}; + ieee80211_configure_filter(local); +} -static int ieee80211_master_open(struct net_device *dev) +static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local) { - struct ieee80211_master_priv *mpriv = netdev_priv(dev); - struct ieee80211_local *local = mpriv->local; struct ieee80211_sub_if_data *sdata; - int res = -EOPNOTSUPP; - - /* we hold the RTNL here so can safely walk the list */ - list_for_each_entry(sdata, &local->interfaces, list) { - if (netif_running(sdata->dev)) { - res = 0; - break; - } - } - - if (res) - return res; + struct cfg80211_chan_def chandef = {}; + u32 changed = 0; + int power; + u32 offchannel_flag; + + offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL; + + if (local->scan_chandef.chan) { + chandef = local->scan_chandef; + } else if (local->tmp_channel) { + chandef.chan = local->tmp_channel; + chandef.width = NL80211_CHAN_WIDTH_20_NOHT; + chandef.center_freq1 = chandef.chan->center_freq; + } else + chandef = local->_oper_chandef; + + WARN(!cfg80211_chandef_valid(&chandef), + "control:%d MHz width:%d center: %d/%d MHz", + chandef.chan->center_freq, chandef.width, + chandef.center_freq1, chandef.center_freq2); + + if (!cfg80211_chandef_identical(&chandef, &local->_oper_chandef)) + local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL; + else + local->hw.conf.flags &= ~IEEE80211_CONF_OFFCHANNEL; - netif_tx_start_all_queues(local->mdev); + offchannel_flag ^= local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL; - return 0; -} + if (offchannel_flag || + !cfg80211_chandef_identical(&local->hw.conf.chandef, + &local->_oper_chandef)) { + local->hw.conf.chandef = chandef; + changed |= IEEE80211_CONF_CHANGE_CHANNEL; + } -static int ieee80211_master_stop(struct net_device *dev) -{ - struct ieee80211_master_priv *mpriv = netdev_priv(dev); - struct ieee80211_local *local = mpriv->local; - struct ieee80211_sub_if_data *sdata; + if (!conf_is_ht(&local->hw.conf)) { + /* + * mac80211.h documents that this is only valid + * when the channel is set to an HT type, and + * that otherwise STATIC is used. + */ + local->hw.conf.smps_mode = IEEE80211_SMPS_STATIC; + } else if (local->hw.conf.smps_mode != local->smps_mode) { + local->hw.conf.smps_mode = local->smps_mode; + changed |= IEEE80211_CONF_CHANGE_SMPS; + } - /* we hold the RTNL here so can safely walk the list */ - list_for_each_entry(sdata, &local->interfaces, list) - if (netif_running(sdata->dev)) - dev_close(sdata->dev); + power = ieee80211_chandef_max_power(&chandef); - return 0; -} + rcu_read_lock(); + list_for_each_entry_rcu(sdata, &local->interfaces, list) { + if (!rcu_access_pointer(sdata->vif.chanctx_conf)) + continue; + if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) + continue; + power = min(power, sdata->vif.bss_conf.txpower); + } + rcu_read_unlock(); -static void ieee80211_master_set_multicast_list(struct net_device *dev) -{ - struct ieee80211_master_priv *mpriv = netdev_priv(dev); - struct ieee80211_local *local = mpriv->local; + if (local->hw.conf.power_level != power) { + changed |= IEEE80211_CONF_CHANGE_POWER; + local->hw.conf.power_level = power; + } - ieee80211_configure_filter(local); + return changed; } int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) { - struct ieee80211_channel *chan, *scan_chan; int ret = 0; - int power; - enum nl80211_channel_type channel_type; might_sleep(); - scan_chan = local->scan_channel; - - if (scan_chan) { - chan = scan_chan; - channel_type = NL80211_CHAN_NO_HT; - } else { - chan = local->oper_channel; - channel_type = local->oper_channel_type; - } - - if (chan != local->hw.conf.channel || - channel_type != local->hw.conf.channel_type) { - local->hw.conf.channel = chan; - local->hw.conf.channel_type = channel_type; - changed |= IEEE80211_CONF_CHANGE_CHANNEL; - } - - if (scan_chan) - power = chan->max_power; + if (!local->use_chanctx) + changed |= ieee80211_hw_conf_chan(local); else - power = local->power_constr_level ? - (chan->max_power - local->power_constr_level) : - chan->max_power; - - if (local->user_power_level >= 0) - power = min(power, local->user_power_level); - - if (local->hw.conf.power_level != power) { - changed |= IEEE80211_CONF_CHANGE_POWER; - local->hw.conf.power_level = power; - } + changed &= ~(IEEE80211_CONF_CHANGE_CHANNEL | + IEEE80211_CONF_CHANGE_POWER); if (changed && local->open_count) { ret = drv_config(local, changed); @@ -219,78 +200,11 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, u32 changed) { struct ieee80211_local *local = sdata->local; - static const u8 zero[ETH_ALEN] = { 0 }; - - if (!changed) - return; - if (sdata->vif.type == NL80211_IFTYPE_STATION) { - /* - * While not associated, claim a BSSID of all-zeroes - * so that drivers don't do any weird things with the - * BSSID at that time. - */ - if (sdata->vif.bss_conf.assoc) - sdata->vif.bss_conf.bssid = sdata->u.mgd.bssid; - else - sdata->vif.bss_conf.bssid = zero; - } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) - sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid; - else if (sdata->vif.type == NL80211_IFTYPE_AP) - sdata->vif.bss_conf.bssid = sdata->dev->dev_addr; - else if (ieee80211_vif_is_mesh(&sdata->vif)) { - sdata->vif.bss_conf.bssid = zero; - } else { - WARN_ON(1); + if (!changed || sdata->vif.type == NL80211_IFTYPE_AP_VLAN) return; - } - - switch (sdata->vif.type) { - case NL80211_IFTYPE_AP: - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_MESH_POINT: - break; - default: - /* do not warn to simplify caller in scan.c */ - changed &= ~BSS_CHANGED_BEACON_ENABLED; - if (WARN_ON(changed & BSS_CHANGED_BEACON)) - return; - break; - } - - if (changed & BSS_CHANGED_BEACON_ENABLED) { - if (local->sw_scanning) { - sdata->vif.bss_conf.enable_beacon = false; - } else { - /* - * Beacon should be enabled, but AP mode must - * check whether there is a beacon configured. - */ - switch (sdata->vif.type) { - case NL80211_IFTYPE_AP: - sdata->vif.bss_conf.enable_beacon = - !!rcu_dereference(sdata->u.ap.beacon); - break; - case NL80211_IFTYPE_ADHOC: - sdata->vif.bss_conf.enable_beacon = - !!rcu_dereference(sdata->u.ibss.presp); - break; - case NL80211_IFTYPE_MESH_POINT: - sdata->vif.bss_conf.enable_beacon = true; - break; - default: - /* not reached */ - WARN_ON(1); - break; - } - } - } - - drv_bss_info_changed(local, &sdata->vif, - &sdata->vif.bss_conf, changed); - /* DEPRECATED */ - local->hw.conf.beacon_int = sdata->vif.bss_conf.beacon_int; + drv_bss_info_changed(local, sdata, &sdata->vif.bss_conf, changed); } u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata) @@ -303,63 +217,24 @@ u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata) BSS_CHANGED_ERP_SLOT; } -void ieee80211_tx_status_irqsafe(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); - int tmp; - - skb->dev = local->mdev; - skb->pkt_type = IEEE80211_TX_STATUS_MSG; - skb_queue_tail(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS ? - &local->skb_queue : &local->skb_queue_unreliable, skb); - tmp = skb_queue_len(&local->skb_queue) + - skb_queue_len(&local->skb_queue_unreliable); - while (tmp > IEEE80211_IRQSAFE_QUEUE_LIMIT && - (skb = skb_dequeue(&local->skb_queue_unreliable))) { - dev_kfree_skb_irq(skb); - tmp--; - I802_DEBUG_INC(local->tx_status_drop); - } - tasklet_schedule(&local->tasklet); -} -EXPORT_SYMBOL(ieee80211_tx_status_irqsafe); - static void ieee80211_tasklet_handler(unsigned long data) { struct ieee80211_local *local = (struct ieee80211_local *) data; struct sk_buff *skb; - struct ieee80211_rx_status rx_status; - struct ieee80211_ra_tid *ra_tid; while ((skb = skb_dequeue(&local->skb_queue)) || (skb = skb_dequeue(&local->skb_queue_unreliable))) { switch (skb->pkt_type) { case IEEE80211_RX_MSG: - /* status is in skb->cb */ - memcpy(&rx_status, skb->cb, sizeof(rx_status)); /* Clear skb->pkt_type in order to not confuse kernel * netstack. */ skb->pkt_type = 0; - __ieee80211_rx(local_to_hw(local), skb, &rx_status); + ieee80211_rx(&local->hw, skb); break; case IEEE80211_TX_STATUS_MSG: skb->pkt_type = 0; - ieee80211_tx_status(local_to_hw(local), skb); - break; - case IEEE80211_DELBA_MSG: - ra_tid = (struct ieee80211_ra_tid *) &skb->cb; - ieee80211_stop_tx_ba_cb(local_to_hw(local), - ra_tid->ra, ra_tid->tid); - dev_kfree_skb(skb); + ieee80211_tx_status(&local->hw, skb); break; - case IEEE80211_ADDBA_MSG: - ra_tid = (struct ieee80211_ra_tid *) &skb->cb; - ieee80211_start_tx_ba_cb(local_to_hw(local), - ra_tid->ra, ra_tid->tid); - dev_kfree_skb(skb); - break ; default: WARN(1, "mac80211: Packet is of unknown type %d\n", skb->pkt_type); @@ -369,292 +244,242 @@ static void ieee80211_tasklet_handler(unsigned long data) } } -static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, - struct sta_info *sta, - struct sk_buff *skb) +static void ieee80211_restart_work(struct work_struct *work) { - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - - sta->tx_filtered_count++; - - /* - * Clear the TX filter mask for this STA when sending the next - * packet. If the STA went to power save mode, this will happen - * when it wakes up for the next time. - */ - set_sta_flags(sta, WLAN_STA_CLEAR_PS_FILT); + struct ieee80211_local *local = + container_of(work, struct ieee80211_local, restart_work); - /* - * This code races in the following way: - * - * (1) STA sends frame indicating it will go to sleep and does so - * (2) hardware/firmware adds STA to filter list, passes frame up - * (3) hardware/firmware processes TX fifo and suppresses a frame - * (4) we get TX status before having processed the frame and - * knowing that the STA has gone to sleep. - * - * This is actually quite unlikely even when both those events are - * processed from interrupts coming in quickly after one another or - * even at the same time because we queue both TX status events and - * RX frames to be processed by a tasklet and process them in the - * same order that they were received or TX status last. Hence, there - * is no race as long as the frame RX is processed before the next TX - * status, which drivers can ensure, see below. - * - * Note that this can only happen if the hardware or firmware can - * actually add STAs to the filter list, if this is done by the - * driver in response to set_tim() (which will only reduce the race - * this whole filtering tries to solve, not completely solve it) - * this situation cannot happen. - * - * To completely solve this race drivers need to make sure that they - * (a) don't mix the irq-safe/not irq-safe TX status/RX processing - * functions and - * (b) always process RX events before TX status events if ordering - * can be unknown, for example with different interrupt status - * bits. - */ - if (test_sta_flags(sta, WLAN_STA_PS) && - skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) { - skb_queue_tail(&sta->tx_filtered, skb); - return; - } + /* wait for scan work complete */ + flush_workqueue(local->workqueue); - if (!test_sta_flags(sta, WLAN_STA_PS) && - !(info->flags & IEEE80211_TX_INTFL_RETRIED)) { - /* Software retry the packet once */ - info->flags |= IEEE80211_TX_INTFL_RETRIED; - ieee80211_add_pending_skb(local, skb); - return; - } + WARN(test_bit(SCAN_HW_SCANNING, &local->scanning), + "%s called with hardware scan in progress\n", __func__); -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - if (net_ratelimit()) - printk(KERN_DEBUG "%s: dropped TX filtered frame, " - "queue_len=%d PS=%d @%lu\n", - wiphy_name(local->hw.wiphy), - skb_queue_len(&sta->tx_filtered), - !!test_sta_flags(sta, WLAN_STA_PS), jiffies); -#endif - dev_kfree_skb(skb); + rtnl_lock(); + ieee80211_scan_cancel(local); + ieee80211_reconfig(local); + rtnl_unlock(); } -void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) +void ieee80211_restart_hw(struct ieee80211_hw *hw) { - struct sk_buff *skb2; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_local *local = hw_to_local(hw); - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - u16 frag, type; - __le16 fc; - struct ieee80211_supported_band *sband; - struct ieee80211_tx_status_rtap_hdr *rthdr; - struct ieee80211_sub_if_data *sdata; - struct net_device *prev_dev = NULL; - struct sta_info *sta; - int retry_count = -1, i; - - for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { - /* the HW cannot have attempted that rate */ - if (i >= hw->max_rates) { - info->status.rates[i].idx = -1; - info->status.rates[i].count = 0; - } - - retry_count += info->status.rates[i].count; - } - if (retry_count < 0) - retry_count = 0; - - rcu_read_lock(); - - sband = local->hw.wiphy->bands[info->band]; - - sta = sta_info_get(local, hdr->addr1); - if (sta) { - if (!(info->flags & IEEE80211_TX_STAT_ACK) && - test_sta_flags(sta, WLAN_STA_PS)) { - /* - * The STA is in power save mode, so assume - * that this TX packet failed because of that. - */ - ieee80211_handle_filtered_frame(local, sta, skb); - rcu_read_unlock(); - return; - } - - fc = hdr->frame_control; + trace_api_restart_hw(local); - if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) && - (ieee80211_is_data_qos(fc))) { - u16 tid, ssn; - u8 *qc; + wiphy_info(hw->wiphy, + "Hardware restart was requested\n"); - 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, hdr->addr1, - tid, ssn); - } + /* use this reason, ieee80211_reconfig will unblock it */ + ieee80211_stop_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP, + IEEE80211_QUEUE_STOP_REASON_SUSPEND); - if (info->flags & IEEE80211_TX_STAT_TX_FILTERED) { - ieee80211_handle_filtered_frame(local, sta, skb); - rcu_read_unlock(); - return; - } else { - if (!(info->flags & IEEE80211_TX_STAT_ACK)) - sta->tx_retry_failed++; - sta->tx_retry_count += retry_count; - } - - rate_control_tx_status(local, sband, sta, skb); - } - - rcu_read_unlock(); + /* + * Stop all Rx during the reconfig. We don't want state changes + * or driver callbacks while this is in progress. + */ + local->in_reconfig = true; + barrier(); - ieee80211_led_tx(local, 0); - - /* SNMP counters - * Fragments are passed to low-level drivers as separate skbs, so these - * are actually fragments, not frames. Update frame counters only for - * the first fragment of the frame. */ - - frag = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG; - type = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_FTYPE; - - if (info->flags & IEEE80211_TX_STAT_ACK) { - if (frag == 0) { - local->dot11TransmittedFrameCount++; - if (is_multicast_ether_addr(hdr->addr1)) - local->dot11MulticastTransmittedFrameCount++; - if (retry_count > 0) - local->dot11RetryCount++; - if (retry_count > 1) - local->dot11MultipleRetryCount++; - } + schedule_work(&local->restart_work); +} +EXPORT_SYMBOL(ieee80211_restart_hw); - /* This counter shall be incremented for an acknowledged MPDU - * with an individual address in the address 1 field or an MPDU - * with a multicast address in the address 1 field of type Data - * or Management. */ - if (!is_multicast_ether_addr(hdr->addr1) || - type == IEEE80211_FTYPE_DATA || - type == IEEE80211_FTYPE_MGMT) - local->dot11TransmittedFragmentCount++; - } else { - if (frag == 0) - local->dot11FailedCount++; +#ifdef CONFIG_INET +static int ieee80211_ifa_changed(struct notifier_block *nb, + unsigned long data, void *arg) +{ + struct in_ifaddr *ifa = arg; + struct ieee80211_local *local = + container_of(nb, struct ieee80211_local, + ifa_notifier); + struct net_device *ndev = ifa->ifa_dev->dev; + struct wireless_dev *wdev = ndev->ieee80211_ptr; + struct in_device *idev; + struct ieee80211_sub_if_data *sdata; + struct ieee80211_bss_conf *bss_conf; + struct ieee80211_if_managed *ifmgd; + int c = 0; + + /* Make sure it's our interface that got changed */ + if (!wdev) + return NOTIFY_DONE; + + if (wdev->wiphy != local->hw.wiphy) + return NOTIFY_DONE; + + sdata = IEEE80211_DEV_TO_SUB_IF(ndev); + bss_conf = &sdata->vif.bss_conf; + + /* ARP filtering is only supported in managed mode */ + if (sdata->vif.type != NL80211_IFTYPE_STATION) + return NOTIFY_DONE; + + idev = __in_dev_get_rtnl(sdata->dev); + if (!idev) + return NOTIFY_DONE; + + ifmgd = &sdata->u.mgd; + sdata_lock(sdata); + + /* Copy the addresses to the bss_conf list */ + ifa = idev->ifa_list; + while (ifa) { + if (c < IEEE80211_BSS_ARP_ADDR_LIST_LEN) + bss_conf->arp_addr_list[c] = ifa->ifa_address; + ifa = ifa->ifa_next; + c++; } - /* this was a transmitted frame, but now we want to reuse it */ - skb_orphan(skb); + bss_conf->arp_addr_cnt = c; - /* - * This is a bit racy but we can avoid a lot of work - * with this test... - */ - if (!local->monitors && !local->cooked_mntrs) { - dev_kfree_skb(skb); - return; - } + /* Configure driver only if associated (which also implies it is up) */ + if (ifmgd->associated) + ieee80211_bss_info_change_notify(sdata, + BSS_CHANGED_ARP_FILTER); - /* send frame to monitor interfaces now */ + sdata_unlock(sdata); - if (skb_headroom(skb) < sizeof(*rthdr)) { - printk(KERN_ERR "ieee80211_tx_status: headroom too small\n"); - dev_kfree_skb(skb); - return; - } + return NOTIFY_OK; +} +#endif - rthdr = (struct ieee80211_tx_status_rtap_hdr *) - skb_push(skb, sizeof(*rthdr)); +#if IS_ENABLED(CONFIG_IPV6) +static int ieee80211_ifa6_changed(struct notifier_block *nb, + unsigned long data, void *arg) +{ + struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)arg; + struct inet6_dev *idev = ifa->idev; + struct net_device *ndev = ifa->idev->dev; + struct ieee80211_local *local = + container_of(nb, struct ieee80211_local, ifa6_notifier); + struct wireless_dev *wdev = ndev->ieee80211_ptr; + struct ieee80211_sub_if_data *sdata; - memset(rthdr, 0, sizeof(*rthdr)); - rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr)); - rthdr->hdr.it_present = - cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) | - (1 << IEEE80211_RADIOTAP_DATA_RETRIES) | - (1 << IEEE80211_RADIOTAP_RATE)); + /* Make sure it's our interface that got changed */ + if (!wdev || wdev->wiphy != local->hw.wiphy) + return NOTIFY_DONE; - if (!(info->flags & IEEE80211_TX_STAT_ACK) && - !is_multicast_ether_addr(hdr->addr1)) - rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL); + sdata = IEEE80211_DEV_TO_SUB_IF(ndev); /* - * XXX: Once radiotap gets the bitmap reset thing the vendor - * extensions proposal contains, we can actually report - * the whole set of tries we did. + * For now only support station mode. This is mostly because + * doing AP would have to handle AP_VLAN in some way ... */ - if ((info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) || - (info->status.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) - rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS); - else if (info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) - rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS); - if (info->status.rates[0].idx >= 0 && - !(info->status.rates[0].flags & IEEE80211_TX_RC_MCS)) - rthdr->rate = sband->bitrates[ - info->status.rates[0].idx].bitrate / 5; - - /* for now report the total retry_count */ - rthdr->data_retries = retry_count; - - /* XXX: is this sufficient for BPF? */ - skb_set_mac_header(skb, 0); - skb->ip_summed = CHECKSUM_UNNECESSARY; - skb->pkt_type = PACKET_OTHERHOST; - skb->protocol = htons(ETH_P_802_2); - memset(skb->cb, 0, sizeof(skb->cb)); + if (sdata->vif.type != NL80211_IFTYPE_STATION) + return NOTIFY_DONE; - rcu_read_lock(); - list_for_each_entry_rcu(sdata, &local->interfaces, list) { - if (sdata->vif.type == NL80211_IFTYPE_MONITOR) { - if (!netif_running(sdata->dev)) - continue; - - if (prev_dev) { - skb2 = skb_clone(skb, GFP_ATOMIC); - if (skb2) { - skb2->dev = prev_dev; - netif_rx(skb2); - } - } + drv_ipv6_addr_change(local, sdata, idev); - prev_dev = sdata->dev; - } - } - if (prev_dev) { - skb->dev = prev_dev; - netif_rx(skb); - skb = NULL; - } - rcu_read_unlock(); - dev_kfree_skb(skb); + return NOTIFY_OK; } -EXPORT_SYMBOL(ieee80211_tx_status); - -static void ieee80211_restart_work(struct work_struct *work) -{ - struct ieee80211_local *local = - container_of(work, struct ieee80211_local, restart_work); +#endif - rtnl_lock(); - ieee80211_reconfig(local); - rtnl_unlock(); -} +/* There isn't a lot of sense in it, but you can transmit anything you like */ +static const struct ieee80211_txrx_stypes +ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { + [NL80211_IFTYPE_ADHOC] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_AUTH >> 4) | + BIT(IEEE80211_STYPE_DEAUTH >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4), + }, + [NL80211_IFTYPE_STATION] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4), + }, + [NL80211_IFTYPE_AP] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | + BIT(IEEE80211_STYPE_DISASSOC >> 4) | + BIT(IEEE80211_STYPE_AUTH >> 4) | + BIT(IEEE80211_STYPE_DEAUTH >> 4) | + BIT(IEEE80211_STYPE_ACTION >> 4), + }, + [NL80211_IFTYPE_AP_VLAN] = { + /* copy AP */ + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | + BIT(IEEE80211_STYPE_DISASSOC >> 4) | + BIT(IEEE80211_STYPE_AUTH >> 4) | + BIT(IEEE80211_STYPE_DEAUTH >> 4) | + BIT(IEEE80211_STYPE_ACTION >> 4), + }, + [NL80211_IFTYPE_P2P_CLIENT] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4), + }, + [NL80211_IFTYPE_P2P_GO] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | + BIT(IEEE80211_STYPE_DISASSOC >> 4) | + BIT(IEEE80211_STYPE_AUTH >> 4) | + BIT(IEEE80211_STYPE_DEAUTH >> 4) | + BIT(IEEE80211_STYPE_ACTION >> 4), + }, + [NL80211_IFTYPE_MESH_POINT] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_AUTH >> 4) | + BIT(IEEE80211_STYPE_DEAUTH >> 4), + }, + [NL80211_IFTYPE_P2P_DEVICE] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4), + }, +}; -void ieee80211_restart_hw(struct ieee80211_hw *hw) -{ - struct ieee80211_local *local = hw_to_local(hw); +static const struct ieee80211_ht_cap mac80211_ht_capa_mod_mask = { + .ampdu_params_info = IEEE80211_HT_AMPDU_PARM_FACTOR | + IEEE80211_HT_AMPDU_PARM_DENSITY, + + .cap_info = cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH_20_40 | + IEEE80211_HT_CAP_MAX_AMSDU | + IEEE80211_HT_CAP_SGI_20 | + IEEE80211_HT_CAP_SGI_40 | + IEEE80211_HT_CAP_LDPC_CODING | + IEEE80211_HT_CAP_40MHZ_INTOLERANT), + .mcs = { + .rx_mask = { 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, }, + }, +}; - /* use this reason, __ieee80211_resume will unblock it */ - ieee80211_stop_queues_by_reason(hw, - IEEE80211_QUEUE_STOP_REASON_SUSPEND); +static const struct ieee80211_vht_cap mac80211_vht_capa_mod_mask = { + .vht_cap_info = + cpu_to_le32(IEEE80211_VHT_CAP_RXLDPC | + IEEE80211_VHT_CAP_SHORT_GI_80 | + IEEE80211_VHT_CAP_SHORT_GI_160 | + IEEE80211_VHT_CAP_RXSTBC_1 | + IEEE80211_VHT_CAP_RXSTBC_2 | + IEEE80211_VHT_CAP_RXSTBC_3 | + IEEE80211_VHT_CAP_RXSTBC_4 | + IEEE80211_VHT_CAP_TXSTBC | + IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | + IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | + IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN | + IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN | + IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK), + .supp_mcs = { + .rx_mcs_map = cpu_to_le16(~0), + .tx_mcs_map = cpu_to_le16(~0), + }, +}; - schedule_work(&local->restart_work); -} -EXPORT_SYMBOL(ieee80211_restart_hw); +static const u8 extended_capabilities[] = { + 0, 0, 0, 0, 0, 0, 0, + WLAN_EXT_CAPA8_OPMODE_NOTIF, +}; struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, const struct ieee80211_ops *ops) @@ -662,6 +487,23 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, struct ieee80211_local *local; int priv_size, i; struct wiphy *wiphy; + bool use_chanctx; + + if (WARN_ON(!ops->tx || !ops->start || !ops->stop || !ops->config || + !ops->add_interface || !ops->remove_interface || + !ops->configure_filter)) + return NULL; + + if (WARN_ON(ops->sta_state && (ops->sta_add || ops->sta_remove))) + return NULL; + + /* check all or no channel context operations exist */ + i = !!ops->add_chanctx + !!ops->remove_chanctx + + !!ops->change_chanctx + !!ops->assign_vif_chanctx + + !!ops->unassign_vif_chanctx; + if (WARN_ON(i != 0 && i != 5)) + return NULL; + use_chanctx = i == 5; /* Ensure 32-byte alignment of our private data and hw private data. * We use the wiphy priv data for both our ieee80211_local and for @@ -685,11 +527,38 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, if (!wiphy) return NULL; + wiphy->mgmt_stypes = ieee80211_default_mgmt_stypes; + wiphy->privid = mac80211_wiphy_privid; - /* Yes, putting cfg80211_bss into ieee80211_bss is a hack */ - wiphy->bss_priv_size = sizeof(struct ieee80211_bss) - - sizeof(struct cfg80211_bss); + wiphy->flags |= WIPHY_FLAG_NETNS_OK | + WIPHY_FLAG_4ADDR_AP | + WIPHY_FLAG_4ADDR_STATION | + WIPHY_FLAG_REPORTS_OBSS | + WIPHY_FLAG_OFFCHAN_TX; + + wiphy->extended_capabilities = extended_capabilities; + wiphy->extended_capabilities_mask = extended_capabilities; + wiphy->extended_capabilities_len = ARRAY_SIZE(extended_capabilities); + + if (ops->remain_on_channel) + wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; + + wiphy->features |= NL80211_FEATURE_SK_TX_STATUS | + NL80211_FEATURE_SAE | + NL80211_FEATURE_HT_IBSS | + NL80211_FEATURE_VIF_TXPOWER | + NL80211_FEATURE_USERSPACE_MPM; + + if (!ops->hw_scan) + wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN | + NL80211_FEATURE_AP_SCAN; + + + if (!ops->set_key) + wiphy->flags |= WIPHY_FLAG_IBSS_RSN; + + wiphy->bss_priv_size = sizeof(struct ieee80211_bss); local = wiphy_priv(wiphy); @@ -697,35 +566,54 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN); - BUG_ON(!ops->tx); - BUG_ON(!ops->start); - BUG_ON(!ops->stop); - BUG_ON(!ops->config); - BUG_ON(!ops->add_interface); - BUG_ON(!ops->remove_interface); - BUG_ON(!ops->configure_filter); local->ops = ops; + local->use_chanctx = use_chanctx; /* set up some defaults */ local->hw.queues = 1; local->hw.max_rates = 1; + local->hw.max_report_rates = 0; + local->hw.max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF; + local->hw.max_tx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF; + local->hw.offchannel_tx_hw_queue = IEEE80211_INVAL_HW_QUEUE; local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; - local->hw.conf.radio_enabled = true; - local->user_power_level = -1; + local->hw.radiotap_mcs_details = IEEE80211_RADIOTAP_MCS_HAVE_MCS | + IEEE80211_RADIOTAP_MCS_HAVE_GI | + IEEE80211_RADIOTAP_MCS_HAVE_BW; + local->hw.radiotap_vht_details = IEEE80211_RADIOTAP_VHT_KNOWN_GI | + IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH; + local->hw.uapsd_queues = IEEE80211_DEFAULT_UAPSD_QUEUES; + local->hw.uapsd_max_sp_len = IEEE80211_DEFAULT_MAX_SP_LEN; + local->user_power_level = IEEE80211_UNSET_POWER_LEVEL; + wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask; + wiphy->vht_capa_mod_mask = &mac80211_vht_capa_mod_mask; INIT_LIST_HEAD(&local->interfaces); - mutex_init(&local->iflist_mtx); - mutex_init(&local->scan_mtx); - spin_lock_init(&local->key_lock); + __hw_addr_init(&local->mc_list); + + mutex_init(&local->iflist_mtx); + mutex_init(&local->mtx); + mutex_init(&local->key_mtx); + spin_lock_init(&local->filter_lock); + spin_lock_init(&local->rx_path_lock); spin_lock_init(&local->queue_stop_reason_lock); + INIT_LIST_HEAD(&local->chanctx_list); + mutex_init(&local->chanctx_mtx); + INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work); INIT_WORK(&local->restart_work, ieee80211_restart_work); + INIT_WORK(&local->radar_detected_work, + ieee80211_dfs_radar_detected_work); + + INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter); + local->smps_mode = IEEE80211_SMPS_OFF; + INIT_WORK(&local->dynamic_ps_enable_work, ieee80211_dynamic_ps_enable_work); INIT_WORK(&local->dynamic_ps_disable_work, @@ -733,55 +621,46 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, setup_timer(&local->dynamic_ps_timer, ieee80211_dynamic_ps_timer, (unsigned long) local); + INIT_WORK(&local->sched_scan_stopped_work, + ieee80211_sched_scan_stopped_work); + + spin_lock_init(&local->ack_status_lock); + idr_init(&local->ack_status_frames); + sta_info_init(local); - for (i = 0; i < IEEE80211_MAX_QUEUES; i++) + for (i = 0; i < IEEE80211_MAX_QUEUES; i++) { skb_queue_head_init(&local->pending[i]); + atomic_set(&local->agg_queue_stop[i], 0); + } tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending, (unsigned long)local); - tasklet_disable(&local->tx_pending_tasklet); tasklet_init(&local->tasklet, ieee80211_tasklet_handler, (unsigned long) local); - tasklet_disable(&local->tasklet); skb_queue_head_init(&local->skb_queue); skb_queue_head_init(&local->skb_queue_unreliable); - spin_lock_init(&local->ampdu_lock); + ieee80211_led_names(local); - return local_to_hw(local); -} -EXPORT_SYMBOL(ieee80211_alloc_hw); - -static const struct net_device_ops ieee80211_master_ops = { - .ndo_start_xmit = ieee80211_master_start_xmit, - .ndo_open = ieee80211_master_open, - .ndo_stop = ieee80211_master_stop, - .ndo_set_multicast_list = ieee80211_master_set_multicast_list, - .ndo_select_queue = ieee80211_select_queue, -}; + ieee80211_roc_setup(local); -static void ieee80211_master_setup(struct net_device *mdev) -{ - mdev->type = ARPHRD_IEEE80211; - mdev->netdev_ops = &ieee80211_master_ops; - mdev->header_ops = &ieee80211_header_ops; - mdev->tx_queue_len = 1000; - mdev->addr_len = ETH_ALEN; + return &local->hw; } +EXPORT_SYMBOL(ieee80211_alloc_hw); -int ieee80211_register_hw(struct ieee80211_hw *hw) +static int ieee80211_init_cipher_suites(struct ieee80211_local *local) { - struct ieee80211_local *local = hw_to_local(hw); - int result; - enum ieee80211_band band; - struct net_device *mdev; - struct ieee80211_master_priv *mpriv; - int channels, i, j, max_bitrates; - bool supp_ht; + bool have_wep = !(IS_ERR(local->wep_tx_tfm) || + IS_ERR(local->wep_rx_tfm)); + bool have_mfp = local->hw.flags & IEEE80211_HW_MFP_CAPABLE; + const struct ieee80211_cipher_scheme *cs = local->hw.cipher_schemes; + int n_suites = 0, r = 0, w = 0; + u32 *suites; static const u32 cipher_suites[] = { + /* keep WEP first, it may be removed below */ WLAN_CIPHER_SUITE_WEP40, WLAN_CIPHER_SUITE_WEP104, WLAN_CIPHER_SUITE_TKIP, @@ -791,6 +670,143 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) WLAN_CIPHER_SUITE_AES_CMAC }; + /* Driver specifies the ciphers, we have nothing to do... */ + if (local->hw.wiphy->cipher_suites && have_wep) + return 0; + + /* Set up cipher suites if driver relies on mac80211 cipher defs */ + if (!local->hw.wiphy->cipher_suites && !cs) { + local->hw.wiphy->cipher_suites = cipher_suites; + local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); + + if (!have_mfp) + local->hw.wiphy->n_cipher_suites--; + + if (!have_wep) { + local->hw.wiphy->cipher_suites += 2; + local->hw.wiphy->n_cipher_suites -= 2; + } + + return 0; + } + + if (!local->hw.wiphy->cipher_suites) { + /* + * Driver specifies cipher schemes only + * We start counting ciphers defined by schemes, TKIP and CCMP + */ + n_suites = local->hw.n_cipher_schemes + 2; + + /* check if we have WEP40 and WEP104 */ + if (have_wep) + n_suites += 2; + + /* check if we have AES_CMAC */ + if (have_mfp) + n_suites++; + + suites = kmalloc(sizeof(u32) * n_suites, GFP_KERNEL); + if (!suites) + return -ENOMEM; + + suites[w++] = WLAN_CIPHER_SUITE_CCMP; + suites[w++] = WLAN_CIPHER_SUITE_TKIP; + + if (have_wep) { + suites[w++] = WLAN_CIPHER_SUITE_WEP40; + suites[w++] = WLAN_CIPHER_SUITE_WEP104; + } + + if (have_mfp) + suites[w++] = WLAN_CIPHER_SUITE_AES_CMAC; + + for (r = 0; r < local->hw.n_cipher_schemes; r++) + suites[w++] = cs[r].cipher; + } else { + /* Driver provides cipher suites, but we need to exclude WEP */ + suites = kmemdup(local->hw.wiphy->cipher_suites, + sizeof(u32) * local->hw.wiphy->n_cipher_suites, + GFP_KERNEL); + if (!suites) + return -ENOMEM; + + for (r = 0; r < local->hw.wiphy->n_cipher_suites; r++) { + u32 suite = local->hw.wiphy->cipher_suites[r]; + + if (suite == WLAN_CIPHER_SUITE_WEP40 || + suite == WLAN_CIPHER_SUITE_WEP104) + continue; + suites[w++] = suite; + } + } + + local->hw.wiphy->cipher_suites = suites; + local->hw.wiphy->n_cipher_suites = w; + local->wiphy_ciphers_allocated = true; + + return 0; +} + +int ieee80211_register_hw(struct ieee80211_hw *hw) +{ + struct ieee80211_local *local = hw_to_local(hw); + int result, i; + enum ieee80211_band band; + int channels, max_bitrates; + bool supp_ht, supp_vht; + netdev_features_t feature_whitelist; + struct cfg80211_chan_def dflt_chandef = {}; + + if (hw->flags & IEEE80211_HW_QUEUE_CONTROL && + (local->hw.offchannel_tx_hw_queue == IEEE80211_INVAL_HW_QUEUE || + local->hw.offchannel_tx_hw_queue >= local->hw.queues)) + return -EINVAL; + +#ifdef CONFIG_PM + if (hw->wiphy->wowlan && (!local->ops->suspend || !local->ops->resume)) + return -EINVAL; +#endif + + if (!local->use_chanctx) { + for (i = 0; i < local->hw.wiphy->n_iface_combinations; i++) { + const struct ieee80211_iface_combination *comb; + + comb = &local->hw.wiphy->iface_combinations[i]; + + if (comb->num_different_channels > 1) + return -EINVAL; + } + } else { + /* + * WDS is currently prohibited when channel contexts are used + * because there's no clear definition of which channel WDS + * type interfaces use + */ + if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_WDS)) + return -EINVAL; + + /* DFS currently not supported with channel context drivers */ + for (i = 0; i < local->hw.wiphy->n_iface_combinations; i++) { + const struct ieee80211_iface_combination *comb; + + comb = &local->hw.wiphy->iface_combinations[i]; + + if (comb->radar_detect_widths) + return -EINVAL; + } + } + + /* Only HW csum features are currently compatible with mac80211 */ + feature_whitelist = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_HW_CSUM; + if (WARN_ON(hw->netdev_features & ~feature_whitelist)) + return -EINVAL; + + if (hw->max_report_rates == 0) + hw->max_report_rates = hw->max_rates; + + local->rx_chains = 1; + /* * generic code guarantees at least one band, * set this very early because much code assumes @@ -799,52 +815,117 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) channels = 0; max_bitrates = 0; supp_ht = false; + supp_vht = false; for (band = 0; band < IEEE80211_NUM_BANDS; band++) { struct ieee80211_supported_band *sband; sband = local->hw.wiphy->bands[band]; if (!sband) continue; - if (!local->oper_channel) { + + if (!dflt_chandef.chan) { + cfg80211_chandef_create(&dflt_chandef, + &sband->channels[0], + NL80211_CHAN_NO_HT); /* init channel we're on */ - local->hw.conf.channel = - local->oper_channel = &sband->channels[0]; - local->hw.conf.channel_type = NL80211_CHAN_NO_HT; + if (!local->use_chanctx && !local->_oper_chandef.chan) { + local->hw.conf.chandef = dflt_chandef; + local->_oper_chandef = dflt_chandef; + } + local->monitor_chandef = dflt_chandef; } + channels += sband->n_channels; if (max_bitrates < sband->n_bitrates) max_bitrates = sband->n_bitrates; supp_ht = supp_ht || sband->ht_cap.ht_supported; - } + supp_vht = supp_vht || sband->vht_cap.vht_supported; - local->int_scan_req.n_channels = channels; - local->int_scan_req.channels = kzalloc(sizeof(void *) * channels, GFP_KERNEL); - if (!local->int_scan_req.channels) - return -ENOMEM; + if (sband->ht_cap.ht_supported) + local->rx_chains = + max(ieee80211_mcs_to_chains(&sband->ht_cap.mcs), + local->rx_chains); + + /* TODO: consider VHT for RX chains, hopefully it's the same */ + } /* if low-level driver supports AP, we also support VLAN */ - if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) - local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN); + if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) { + hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN); + hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_AP_VLAN); + } /* mac80211 always supports monitor */ - local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); + hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); + hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_MONITOR); - if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) + /* mac80211 doesn't support more than one IBSS interface right now */ + for (i = 0; i < hw->wiphy->n_iface_combinations; i++) { + const struct ieee80211_iface_combination *c; + int j; + + c = &hw->wiphy->iface_combinations[i]; + + for (j = 0; j < c->n_limits; j++) + if ((c->limits[j].types & BIT(NL80211_IFTYPE_ADHOC)) && + c->limits[j].max > 1) + return -EINVAL; + } + + local->int_scan_req = kzalloc(sizeof(*local->int_scan_req) + + sizeof(void *) * channels, GFP_KERNEL); + if (!local->int_scan_req) + return -ENOMEM; + + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + if (!local->hw.wiphy->bands[band]) + continue; + local->int_scan_req->rates[band] = (u32) -1; + } + +#ifndef CONFIG_MAC80211_MESH + /* mesh depends on Kconfig, but drivers should set it if they want */ + local->hw.wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MESH_POINT); +#endif + + /* if the underlying driver supports mesh, mac80211 will (at least) + * provide routing of mesh authentication frames to userspace */ + if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_MESH_POINT)) + local->hw.wiphy->flags |= WIPHY_FLAG_MESH_AUTH; + + /* mac80211 supports control port protocol changing */ + local->hw.wiphy->flags |= WIPHY_FLAG_CONTROL_PORT_PROTOCOL; + + if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) { local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; - else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) + } else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) { local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; + if (hw->max_signal <= 0) { + result = -EINVAL; + goto fail_wiphy_register; + } + } + + WARN((local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD) + && (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK), + "U-APSD not supported with HW_PS_NULLFUNC_STACK\n"); /* * Calculate scan IE length -- we need this to alloc * memory and to subtract from the driver limit. It - * includes the (extended) supported rates and HT + * includes the DS Params, (extended) supported rates, and HT * information -- SSID is the driver's responsibility. */ - local->scan_ies_len = 4 + max_bitrates; /* (ext) supp rates */ + local->scan_ies_len = 4 + max_bitrates /* (ext) supp rates */ + + 3 /* DS Params */; if (supp_ht) local->scan_ies_len += 2 + sizeof(struct ieee80211_ht_cap); + if (supp_vht) + local->scan_ies_len += + 2 + sizeof(struct ieee80211_vht_cap); + if (!local->ops->hw_scan) { /* For hw_scan, driver needs to set these up. */ local->hw.wiphy->max_scan_ssids = 4; @@ -861,10 +942,21 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) if (local->hw.wiphy->max_scan_ie_len) local->hw.wiphy->max_scan_ie_len -= local->scan_ies_len; - local->hw.wiphy->cipher_suites = cipher_suites; - local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); - if (!(local->hw.flags & IEEE80211_HW_MFP_CAPABLE)) - local->hw.wiphy->n_cipher_suites--; + WARN_ON(!ieee80211_cs_list_valid(local->hw.cipher_schemes, + local->hw.n_cipher_schemes)); + + result = ieee80211_init_cipher_suites(local); + if (result < 0) + goto fail_wiphy_register; + + if (!local->ops->remain_on_channel) + local->hw.wiphy->max_remain_on_channel_duration = 5000; + + /* mac80211 based drivers don't support internal TDLS setup */ + if (local->hw.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) + local->hw.wiphy->flags |= WIPHY_FLAG_TDLS_EXTERNAL_SETUP; + + local->hw.wiphy->max_num_csa_counters = IEEE80211_MAX_CSA_COUNTERS_NUM; result = wiphy_register(local->hw.wiphy); if (result < 0) @@ -877,19 +969,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) if (hw->queues > IEEE80211_MAX_QUEUES) hw->queues = IEEE80211_MAX_QUEUES; - mdev = alloc_netdev_mq(sizeof(struct ieee80211_master_priv), - "wmaster%d", ieee80211_master_setup, - hw->queues); - if (!mdev) - goto fail_mdev_alloc; - - mpriv = netdev_priv(mdev); - mpriv->local = local; - local->mdev = mdev; - - local->hw.workqueue = - create_singlethread_workqueue(wiphy_name(local->hw.wiphy)); - if (!local->hw.workqueue) { + local->workqueue = + alloc_ordered_workqueue("%s", 0, wiphy_name(local->hw.wiphy)); + if (!local->workqueue) { result = -ENOMEM; goto fail_workqueue; } @@ -900,44 +982,37 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) * interfaces, but never both at the same time. */ local->tx_headroom = max_t(unsigned int , local->hw.extra_tx_headroom, - sizeof(struct ieee80211_tx_status_rtap_hdr)); + IEEE80211_TX_STATUS_HEADROOM); debugfs_hw_add(local); + /* + * if the driver doesn't specify a max listen interval we + * use 5 which should be a safe default + */ if (local->hw.max_listen_interval == 0) - local->hw.max_listen_interval = 1; + local->hw.max_listen_interval = 5; local->hw.conf.listen_interval = local->hw.max_listen_interval; - result = sta_info_start(local); - if (result < 0) - goto fail_sta_info; + local->dynamic_ps_forced_timeout = -1; result = ieee80211_wep_init(local); - if (result < 0) { - printk(KERN_DEBUG "%s: Failed to initialize wep: %d\n", - wiphy_name(local->hw.wiphy), result); - goto fail_wep; - } - - rtnl_lock(); - result = dev_alloc_name(local->mdev, local->mdev->name); if (result < 0) - goto fail_dev; + wiphy_debug(local->hw.wiphy, "Failed to initialize wep: %d\n", + result); - memcpy(local->mdev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); - SET_NETDEV_DEV(local->mdev, wiphy_dev(local->hw.wiphy)); - local->mdev->features |= NETIF_F_NETNS_LOCAL; + local->hw.conf.flags = IEEE80211_CONF_IDLE; - result = register_netdevice(local->mdev); - if (result < 0) - goto fail_dev; + ieee80211_led_init(local); + + rtnl_lock(); result = ieee80211_init_rate_ctrl_alg(local, hw->rate_control_algorithm); if (result < 0) { - printk(KERN_DEBUG "%s: Failed to initialize rate control " - "algorithm\n", wiphy_name(local->hw.wiphy)); + wiphy_debug(local->hw.wiphy, + "Failed to initialize rate control algorithm\n"); goto fail_rate; } @@ -946,65 +1021,79 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) result = ieee80211_if_add(local, "wlan%d", NULL, NL80211_IFTYPE_STATION, NULL); if (result) - printk(KERN_WARNING "%s: Failed to add default virtual iface\n", - wiphy_name(local->hw.wiphy)); + wiphy_warn(local->hw.wiphy, + "Failed to add default virtual iface\n"); } rtnl_unlock(); - ieee80211_led_init(local); - - /* alloc internal scan request */ - i = 0; - local->int_scan_req.ssids = &local->scan_ssid; - local->int_scan_req.n_ssids = 1; - for (band = 0; band < IEEE80211_NUM_BANDS; band++) { - if (!hw->wiphy->bands[band]) - continue; - for (j = 0; j < hw->wiphy->bands[band]->n_channels; j++) { - local->int_scan_req.channels[i] = - &hw->wiphy->bands[band]->channels[j]; - i++; - } - } - local->network_latency_notifier.notifier_call = ieee80211_max_network_latency; result = pm_qos_add_notifier(PM_QOS_NETWORK_LATENCY, &local->network_latency_notifier); - if (result) { rtnl_lock(); goto fail_pm_qos; } +#ifdef CONFIG_INET + local->ifa_notifier.notifier_call = ieee80211_ifa_changed; + result = register_inetaddr_notifier(&local->ifa_notifier); + if (result) + goto fail_ifa; +#endif + +#if IS_ENABLED(CONFIG_IPV6) + local->ifa6_notifier.notifier_call = ieee80211_ifa6_changed; + result = register_inet6addr_notifier(&local->ifa6_notifier); + if (result) + goto fail_ifa6; +#endif + return 0; +#if IS_ENABLED(CONFIG_IPV6) + fail_ifa6: +#ifdef CONFIG_INET + unregister_inetaddr_notifier(&local->ifa_notifier); +#endif +#endif +#if defined(CONFIG_INET) || defined(CONFIG_IPV6) + fail_ifa: + pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY, + &local->network_latency_notifier); + rtnl_lock(); +#endif fail_pm_qos: ieee80211_led_exit(local); ieee80211_remove_interfaces(local); fail_rate: - unregister_netdevice(local->mdev); - local->mdev = NULL; - fail_dev: rtnl_unlock(); ieee80211_wep_free(local); - fail_wep: sta_info_stop(local); - fail_sta_info: - debugfs_hw_del(local); - destroy_workqueue(local->hw.workqueue); + destroy_workqueue(local->workqueue); fail_workqueue: - if (local->mdev) - free_netdev(local->mdev); - fail_mdev_alloc: wiphy_unregister(local->hw.wiphy); fail_wiphy_register: - kfree(local->int_scan_req.channels); + if (local->wiphy_ciphers_allocated) + kfree(local->hw.wiphy->cipher_suites); + kfree(local->int_scan_req); return result; } EXPORT_SYMBOL(ieee80211_register_hw); +void ieee80211_napi_add(struct ieee80211_hw *hw, struct napi_struct *napi, + struct net_device *napi_dev, + int (*poll)(struct napi_struct *, int), + int weight) +{ + struct ieee80211_local *local = hw_to_local(hw); + + netif_napi_add(napi_dev, napi, poll, weight); + local->napi = napi; +} +EXPORT_SYMBOL_GPL(ieee80211_napi_add); + void ieee80211_unregister_hw(struct ieee80211_hw *hw) { struct ieee80211_local *local = hw_to_local(hw); @@ -1014,6 +1103,12 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY, &local->network_latency_notifier); +#ifdef CONFIG_INET + unregister_inetaddr_notifier(&local->ifa_notifier); +#endif +#if IS_ENABLED(CONFIG_IPV6) + unregister_inet6addr_notifier(&local->ifa6_notifier); +#endif rtnl_lock(); @@ -1022,42 +1117,54 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) * because the driver cannot be handing us frames any * more and the tasklet is killed. */ - - /* First, we remove all virtual interfaces. */ ieee80211_remove_interfaces(local); - /* then, finally, remove the master interface */ - unregister_netdevice(local->mdev); - rtnl_unlock(); + cancel_work_sync(&local->restart_work); + cancel_work_sync(&local->reconfig_filter); + flush_work(&local->sched_scan_stopped_work); + ieee80211_clear_tx_pending(local); - sta_info_stop(local); rate_control_deinitialize(local); - debugfs_hw_del(local); - if (skb_queue_len(&local->skb_queue) - || skb_queue_len(&local->skb_queue_unreliable)) - printk(KERN_WARNING "%s: skb_queue not empty\n", - wiphy_name(local->hw.wiphy)); + if (skb_queue_len(&local->skb_queue) || + skb_queue_len(&local->skb_queue_unreliable)) + wiphy_warn(local->hw.wiphy, "skb_queue not empty\n"); skb_queue_purge(&local->skb_queue); skb_queue_purge(&local->skb_queue_unreliable); - destroy_workqueue(local->hw.workqueue); + destroy_workqueue(local->workqueue); wiphy_unregister(local->hw.wiphy); + sta_info_stop(local); ieee80211_wep_free(local); ieee80211_led_exit(local); - free_netdev(local->mdev); - kfree(local->int_scan_req.channels); + kfree(local->int_scan_req); } EXPORT_SYMBOL(ieee80211_unregister_hw); +static int ieee80211_free_ack_frame(int id, void *p, void *data) +{ + WARN_ONCE(1, "Have pending ack frames!\n"); + kfree_skb(p); + return 0; +} + void ieee80211_free_hw(struct ieee80211_hw *hw) { struct ieee80211_local *local = hw_to_local(hw); mutex_destroy(&local->iflist_mtx); - mutex_destroy(&local->scan_mtx); + mutex_destroy(&local->mtx); + + if (local->wiphy_ciphers_allocated) + kfree(local->hw.wiphy->cipher_suites); + + idr_for_each(&local->ack_status_frames, + ieee80211_free_ack_frame, NULL); + idr_destroy(&local->ack_status_frames); + + kfree(rcu_access_pointer(local->tx_latency)); wiphy_free(local->hw.wiphy); } @@ -1076,30 +1183,40 @@ static int __init ieee80211_init(void) if (ret) return ret; + ret = rc80211_minstrel_ht_init(); + if (ret) + goto err_minstrel; + ret = rc80211_pid_init(); if (ret) - return ret; + goto err_pid; - ieee80211_debugfs_netdev_init(); + ret = ieee80211_iface_init(); + if (ret) + goto err_netdev; return 0; + err_netdev: + rc80211_pid_exit(); + err_pid: + rc80211_minstrel_ht_exit(); + err_minstrel: + rc80211_minstrel_exit(); + + return ret; } static void __exit ieee80211_exit(void) { rc80211_pid_exit(); + rc80211_minstrel_ht_exit(); rc80211_minstrel_exit(); - /* - * For key todo, it'll be empty by now but the work - * might still be scheduled. - */ - flush_scheduled_work(); + ieee80211s_stop(); - if (mesh_allocated) - ieee80211s_stop(); + ieee80211_iface_exit(); - ieee80211_debugfs_netdev_exit(); + rcu_barrier(); } |
