1c2d1560aSJohannes Berg /* 2c2d1560aSJohannes Berg * Copyright 2002-2005, Instant802 Networks, Inc. 3c2d1560aSJohannes Berg * Copyright 2005-2006, Devicescape Software, Inc. 4c2d1560aSJohannes Berg * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> 5c2d1560aSJohannes Berg * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> 6c2d1560aSJohannes Berg * 7c2d1560aSJohannes Berg * This program is free software; you can redistribute it and/or modify 8c2d1560aSJohannes Berg * it under the terms of the GNU General Public License version 2 as 9c2d1560aSJohannes Berg * published by the Free Software Foundation. 10c2d1560aSJohannes Berg * 11c2d1560aSJohannes Berg * utilities for mac80211 12c2d1560aSJohannes Berg */ 13c2d1560aSJohannes Berg 14c2d1560aSJohannes Berg #include <net/mac80211.h> 15c2d1560aSJohannes Berg #include <linux/netdevice.h> 16c2d1560aSJohannes Berg #include <linux/types.h> 17c2d1560aSJohannes Berg #include <linux/slab.h> 18c2d1560aSJohannes Berg #include <linux/skbuff.h> 19c2d1560aSJohannes Berg #include <linux/etherdevice.h> 20c2d1560aSJohannes Berg #include <linux/if_arp.h> 21c2d1560aSJohannes Berg #include <linux/wireless.h> 22c2d1560aSJohannes Berg #include <linux/bitmap.h> 23d91f36dbSJohannes Berg #include <linux/crc32.h> 24881d966bSEric W. Biederman #include <net/net_namespace.h> 25c2d1560aSJohannes Berg #include <net/cfg80211.h> 26dabeb344SJohannes Berg #include <net/rtnetlink.h> 27c2d1560aSJohannes Berg 28c2d1560aSJohannes Berg #include "ieee80211_i.h" 2924487981SJohannes Berg #include "driver-ops.h" 302c8dccc7SJohannes Berg #include "rate.h" 31ee385855SLuis Carlos Cobo #include "mesh.h" 32c2d1560aSJohannes Berg #include "wme.h" 33f2753ddbSJohannes Berg #include "led.h" 34fffd0934SJohannes Berg #include "wep.h" 35c2d1560aSJohannes Berg 36c2d1560aSJohannes Berg /* privid for wiphys to determine whether they belong to us or not */ 37c2d1560aSJohannes Berg void *mac80211_wiphy_privid = &mac80211_wiphy_privid; 38c2d1560aSJohannes Berg 399a95371aSLuis R. Rodriguez struct ieee80211_hw *wiphy_to_ieee80211_hw(struct wiphy *wiphy) 409a95371aSLuis R. Rodriguez { 419a95371aSLuis R. Rodriguez struct ieee80211_local *local; 429a95371aSLuis R. Rodriguez BUG_ON(!wiphy); 439a95371aSLuis R. Rodriguez 449a95371aSLuis R. Rodriguez local = wiphy_priv(wiphy); 459a95371aSLuis R. Rodriguez return &local->hw; 469a95371aSLuis R. Rodriguez } 479a95371aSLuis R. Rodriguez EXPORT_SYMBOL(wiphy_to_ieee80211_hw); 48c2d1560aSJohannes Berg 4971364716SRon Rindjunsky u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, 5005c914feSJohannes Berg enum nl80211_iftype type) 51c2d1560aSJohannes Berg { 52a494bb1cSHarvey Harrison __le16 fc = hdr->frame_control; 53c2d1560aSJohannes Berg 5498f0b0a3SRon Rindjunsky /* drop ACK/CTS frames and incorrect hdr len (ctrl) */ 5598f0b0a3SRon Rindjunsky if (len < 16) 56c2d1560aSJohannes Berg return NULL; 57c2d1560aSJohannes Berg 58a494bb1cSHarvey Harrison if (ieee80211_is_data(fc)) { 5998f0b0a3SRon Rindjunsky if (len < 24) /* drop incorrect hdr len (data) */ 6098f0b0a3SRon Rindjunsky return NULL; 61a494bb1cSHarvey Harrison 62a494bb1cSHarvey Harrison if (ieee80211_has_a4(fc)) 63c2d1560aSJohannes Berg return NULL; 64a494bb1cSHarvey Harrison if (ieee80211_has_tods(fc)) 65a494bb1cSHarvey Harrison return hdr->addr1; 66a494bb1cSHarvey Harrison if (ieee80211_has_fromds(fc)) 67c2d1560aSJohannes Berg return hdr->addr2; 68a494bb1cSHarvey Harrison 69c2d1560aSJohannes Berg return hdr->addr3; 70c2d1560aSJohannes Berg } 71a494bb1cSHarvey Harrison 72a494bb1cSHarvey Harrison if (ieee80211_is_mgmt(fc)) { 7398f0b0a3SRon Rindjunsky if (len < 24) /* drop incorrect hdr len (mgmt) */ 7498f0b0a3SRon Rindjunsky return NULL; 75c2d1560aSJohannes Berg return hdr->addr3; 76a494bb1cSHarvey Harrison } 77a494bb1cSHarvey Harrison 78a494bb1cSHarvey Harrison if (ieee80211_is_ctl(fc)) { 79a494bb1cSHarvey Harrison if(ieee80211_is_pspoll(fc)) 80c2d1560aSJohannes Berg return hdr->addr1; 81a494bb1cSHarvey Harrison 82a494bb1cSHarvey Harrison if (ieee80211_is_back_req(fc)) { 8371364716SRon Rindjunsky switch (type) { 8405c914feSJohannes Berg case NL80211_IFTYPE_STATION: 8571364716SRon Rindjunsky return hdr->addr2; 8605c914feSJohannes Berg case NL80211_IFTYPE_AP: 8705c914feSJohannes Berg case NL80211_IFTYPE_AP_VLAN: 8871364716SRon Rindjunsky return hdr->addr1; 8971364716SRon Rindjunsky default: 90a494bb1cSHarvey Harrison break; /* fall through to the return */ 9171364716SRon Rindjunsky } 9271364716SRon Rindjunsky } 93c2d1560aSJohannes Berg } 94c2d1560aSJohannes Berg 95c2d1560aSJohannes Berg return NULL; 96c2d1560aSJohannes Berg } 97c2d1560aSJohannes Berg 985cf121c3SJohannes Berg void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx) 99c2d1560aSJohannes Berg { 1002de8e0d9SJohannes Berg struct sk_buff *skb = tx->skb; 1012de8e0d9SJohannes Berg struct ieee80211_hdr *hdr; 102c2d1560aSJohannes Berg 1032de8e0d9SJohannes Berg do { 1042de8e0d9SJohannes Berg hdr = (struct ieee80211_hdr *) skb->data; 105c2d1560aSJohannes Berg hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); 1062de8e0d9SJohannes Berg } while ((skb = skb->next)); 107c2d1560aSJohannes Berg } 108c2d1560aSJohannes Berg 109c2d1560aSJohannes Berg int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, 110c2d1560aSJohannes Berg int rate, int erp, int short_preamble) 111c2d1560aSJohannes Berg { 112c2d1560aSJohannes Berg int dur; 113c2d1560aSJohannes Berg 114c2d1560aSJohannes Berg /* calculate duration (in microseconds, rounded up to next higher 115c2d1560aSJohannes Berg * integer if it includes a fractional microsecond) to send frame of 116c2d1560aSJohannes Berg * len bytes (does not include FCS) at the given rate. Duration will 117c2d1560aSJohannes Berg * also include SIFS. 118c2d1560aSJohannes Berg * 119c2d1560aSJohannes Berg * rate is in 100 kbps, so divident is multiplied by 10 in the 120c2d1560aSJohannes Berg * DIV_ROUND_UP() operations. 121c2d1560aSJohannes Berg */ 122c2d1560aSJohannes Berg 1238318d78aSJohannes Berg if (local->hw.conf.channel->band == IEEE80211_BAND_5GHZ || erp) { 124c2d1560aSJohannes Berg /* 125c2d1560aSJohannes Berg * OFDM: 126c2d1560aSJohannes Berg * 127c2d1560aSJohannes Berg * N_DBPS = DATARATE x 4 128c2d1560aSJohannes Berg * N_SYM = Ceiling((16+8xLENGTH+6) / N_DBPS) 129c2d1560aSJohannes Berg * (16 = SIGNAL time, 6 = tail bits) 130c2d1560aSJohannes Berg * TXTIME = T_PREAMBLE + T_SIGNAL + T_SYM x N_SYM + Signal Ext 131c2d1560aSJohannes Berg * 132c2d1560aSJohannes Berg * T_SYM = 4 usec 133c2d1560aSJohannes Berg * 802.11a - 17.5.2: aSIFSTime = 16 usec 134c2d1560aSJohannes Berg * 802.11g - 19.8.4: aSIFSTime = 10 usec + 135c2d1560aSJohannes Berg * signal ext = 6 usec 136c2d1560aSJohannes Berg */ 137c2d1560aSJohannes Berg dur = 16; /* SIFS + signal ext */ 138c2d1560aSJohannes Berg dur += 16; /* 17.3.2.3: T_PREAMBLE = 16 usec */ 139c2d1560aSJohannes Berg dur += 4; /* 17.3.2.3: T_SIGNAL = 4 usec */ 140c2d1560aSJohannes Berg dur += 4 * DIV_ROUND_UP((16 + 8 * (len + 4) + 6) * 10, 141c2d1560aSJohannes Berg 4 * rate); /* T_SYM x N_SYM */ 142c2d1560aSJohannes Berg } else { 143c2d1560aSJohannes Berg /* 144c2d1560aSJohannes Berg * 802.11b or 802.11g with 802.11b compatibility: 145c2d1560aSJohannes Berg * 18.3.4: TXTIME = PreambleLength + PLCPHeaderTime + 146c2d1560aSJohannes Berg * Ceiling(((LENGTH+PBCC)x8)/DATARATE). PBCC=0. 147c2d1560aSJohannes Berg * 148c2d1560aSJohannes Berg * 802.11 (DS): 15.3.3, 802.11b: 18.3.4 149c2d1560aSJohannes Berg * aSIFSTime = 10 usec 150c2d1560aSJohannes Berg * aPreambleLength = 144 usec or 72 usec with short preamble 151c2d1560aSJohannes Berg * aPLCPHeaderLength = 48 usec or 24 usec with short preamble 152c2d1560aSJohannes Berg */ 153c2d1560aSJohannes Berg dur = 10; /* aSIFSTime = 10 usec */ 154c2d1560aSJohannes Berg dur += short_preamble ? (72 + 24) : (144 + 48); 155c2d1560aSJohannes Berg 156c2d1560aSJohannes Berg dur += DIV_ROUND_UP(8 * (len + 4) * 10, rate); 157c2d1560aSJohannes Berg } 158c2d1560aSJohannes Berg 159c2d1560aSJohannes Berg return dur; 160c2d1560aSJohannes Berg } 161c2d1560aSJohannes Berg 162c2d1560aSJohannes Berg /* Exported duration function for driver use */ 16332bfd35dSJohannes Berg __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, 16432bfd35dSJohannes Berg struct ieee80211_vif *vif, 1658318d78aSJohannes Berg size_t frame_len, 1668318d78aSJohannes Berg struct ieee80211_rate *rate) 167c2d1560aSJohannes Berg { 168c2d1560aSJohannes Berg struct ieee80211_local *local = hw_to_local(hw); 16925d834e1SJohannes Berg struct ieee80211_sub_if_data *sdata; 170c2d1560aSJohannes Berg u16 dur; 171c2d1560aSJohannes Berg int erp; 17225d834e1SJohannes Berg bool short_preamble = false; 173c2d1560aSJohannes Berg 1748318d78aSJohannes Berg erp = 0; 17525d834e1SJohannes Berg if (vif) { 17625d834e1SJohannes Berg sdata = vif_to_sdata(vif); 177bda3933aSJohannes Berg short_preamble = sdata->vif.bss_conf.use_short_preamble; 1788318d78aSJohannes Berg if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) 1798318d78aSJohannes Berg erp = rate->flags & IEEE80211_RATE_ERP_G; 18025d834e1SJohannes Berg } 1818318d78aSJohannes Berg 1828318d78aSJohannes Berg dur = ieee80211_frame_duration(local, frame_len, rate->bitrate, erp, 18325d834e1SJohannes Berg short_preamble); 184c2d1560aSJohannes Berg 185c2d1560aSJohannes Berg return cpu_to_le16(dur); 186c2d1560aSJohannes Berg } 187c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_generic_frame_duration); 188c2d1560aSJohannes Berg 18932bfd35dSJohannes Berg __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, 19032bfd35dSJohannes Berg struct ieee80211_vif *vif, size_t frame_len, 191e039fa4aSJohannes Berg const struct ieee80211_tx_info *frame_txctl) 192c2d1560aSJohannes Berg { 193c2d1560aSJohannes Berg struct ieee80211_local *local = hw_to_local(hw); 194c2d1560aSJohannes Berg struct ieee80211_rate *rate; 19525d834e1SJohannes Berg struct ieee80211_sub_if_data *sdata; 196471b3efdSJohannes Berg bool short_preamble; 197c2d1560aSJohannes Berg int erp; 198c2d1560aSJohannes Berg u16 dur; 1992e92e6f2SJohannes Berg struct ieee80211_supported_band *sband; 2002e92e6f2SJohannes Berg 2012e92e6f2SJohannes Berg sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; 202c2d1560aSJohannes Berg 20325d834e1SJohannes Berg short_preamble = false; 2047e9ed188SDaniel Drake 205e039fa4aSJohannes Berg rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx]; 2068318d78aSJohannes Berg 2078318d78aSJohannes Berg erp = 0; 20825d834e1SJohannes Berg if (vif) { 20925d834e1SJohannes Berg sdata = vif_to_sdata(vif); 210bda3933aSJohannes Berg short_preamble = sdata->vif.bss_conf.use_short_preamble; 2118318d78aSJohannes Berg if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) 2128318d78aSJohannes Berg erp = rate->flags & IEEE80211_RATE_ERP_G; 21325d834e1SJohannes Berg } 214c2d1560aSJohannes Berg 215c2d1560aSJohannes Berg /* CTS duration */ 2168318d78aSJohannes Berg dur = ieee80211_frame_duration(local, 10, rate->bitrate, 217c2d1560aSJohannes Berg erp, short_preamble); 218c2d1560aSJohannes Berg /* Data frame duration */ 2198318d78aSJohannes Berg dur += ieee80211_frame_duration(local, frame_len, rate->bitrate, 220c2d1560aSJohannes Berg erp, short_preamble); 221c2d1560aSJohannes Berg /* ACK duration */ 2228318d78aSJohannes Berg dur += ieee80211_frame_duration(local, 10, rate->bitrate, 223c2d1560aSJohannes Berg erp, short_preamble); 224c2d1560aSJohannes Berg 225c2d1560aSJohannes Berg return cpu_to_le16(dur); 226c2d1560aSJohannes Berg } 227c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_rts_duration); 228c2d1560aSJohannes Berg 22932bfd35dSJohannes Berg __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, 23032bfd35dSJohannes Berg struct ieee80211_vif *vif, 231c2d1560aSJohannes Berg size_t frame_len, 232e039fa4aSJohannes Berg const struct ieee80211_tx_info *frame_txctl) 233c2d1560aSJohannes Berg { 234c2d1560aSJohannes Berg struct ieee80211_local *local = hw_to_local(hw); 235c2d1560aSJohannes Berg struct ieee80211_rate *rate; 23625d834e1SJohannes Berg struct ieee80211_sub_if_data *sdata; 237471b3efdSJohannes Berg bool short_preamble; 238c2d1560aSJohannes Berg int erp; 239c2d1560aSJohannes Berg u16 dur; 2402e92e6f2SJohannes Berg struct ieee80211_supported_band *sband; 2412e92e6f2SJohannes Berg 2422e92e6f2SJohannes Berg sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; 243c2d1560aSJohannes Berg 24425d834e1SJohannes Berg short_preamble = false; 2457e9ed188SDaniel Drake 246e039fa4aSJohannes Berg rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx]; 2478318d78aSJohannes Berg erp = 0; 24825d834e1SJohannes Berg if (vif) { 24925d834e1SJohannes Berg sdata = vif_to_sdata(vif); 250bda3933aSJohannes Berg short_preamble = sdata->vif.bss_conf.use_short_preamble; 2518318d78aSJohannes Berg if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) 2528318d78aSJohannes Berg erp = rate->flags & IEEE80211_RATE_ERP_G; 25325d834e1SJohannes Berg } 254c2d1560aSJohannes Berg 255c2d1560aSJohannes Berg /* Data frame duration */ 2568318d78aSJohannes Berg dur = ieee80211_frame_duration(local, frame_len, rate->bitrate, 257c2d1560aSJohannes Berg erp, short_preamble); 258e039fa4aSJohannes Berg if (!(frame_txctl->flags & IEEE80211_TX_CTL_NO_ACK)) { 259c2d1560aSJohannes Berg /* ACK duration */ 2608318d78aSJohannes Berg dur += ieee80211_frame_duration(local, 10, rate->bitrate, 261c2d1560aSJohannes Berg erp, short_preamble); 262c2d1560aSJohannes Berg } 263c2d1560aSJohannes Berg 264c2d1560aSJohannes Berg return cpu_to_le16(dur); 265c2d1560aSJohannes Berg } 266c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_ctstoself_duration); 267c2d1560aSJohannes Berg 268ce7c9111SKalle Valo static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, 269ce7c9111SKalle Valo enum queue_stop_reason reason) 270c2d1560aSJohannes Berg { 271c2d1560aSJohannes Berg struct ieee80211_local *local = hw_to_local(hw); 272c2d1560aSJohannes Berg 273e4e72fb4SJohannes Berg if (WARN_ON(queue >= hw->queues)) 27496f5e66eSJohannes Berg return; 27596f5e66eSJohannes Berg 276ce7c9111SKalle Valo __clear_bit(reason, &local->queue_stop_reasons[queue]); 277ce7c9111SKalle Valo 278ce7c9111SKalle Valo if (local->queue_stop_reasons[queue] != 0) 279ce7c9111SKalle Valo /* someone still has this queue stopped */ 280ce7c9111SKalle Valo return; 281ce7c9111SKalle Valo 2823b8d81e0SJohannes Berg if (!skb_queue_empty(&local->pending[queue])) 2833b8d81e0SJohannes Berg tasklet_schedule(&local->tx_pending_tasklet); 284c2d1560aSJohannes Berg } 285ce7c9111SKalle Valo 28696f5e66eSJohannes Berg void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, 287ce7c9111SKalle Valo enum queue_stop_reason reason) 288ce7c9111SKalle Valo { 289ce7c9111SKalle Valo struct ieee80211_local *local = hw_to_local(hw); 290ce7c9111SKalle Valo unsigned long flags; 291ce7c9111SKalle Valo 292ce7c9111SKalle Valo spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 293ce7c9111SKalle Valo __ieee80211_wake_queue(hw, queue, reason); 294ce7c9111SKalle Valo spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 295ce7c9111SKalle Valo } 296ce7c9111SKalle Valo 297ce7c9111SKalle Valo void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue) 298ce7c9111SKalle Valo { 299ce7c9111SKalle Valo ieee80211_wake_queue_by_reason(hw, queue, 300ce7c9111SKalle Valo IEEE80211_QUEUE_STOP_REASON_DRIVER); 301ce7c9111SKalle Valo } 302c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_wake_queue); 303c2d1560aSJohannes Berg 304ce7c9111SKalle Valo static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, 305ce7c9111SKalle Valo enum queue_stop_reason reason) 306c2d1560aSJohannes Berg { 307c2d1560aSJohannes Berg struct ieee80211_local *local = hw_to_local(hw); 308c2d1560aSJohannes Berg 309e4e72fb4SJohannes Berg if (WARN_ON(queue >= hw->queues)) 31096f5e66eSJohannes Berg return; 31196f5e66eSJohannes Berg 3122a577d98SJohannes Berg __set_bit(reason, &local->queue_stop_reasons[queue]); 313c2d1560aSJohannes Berg } 314ce7c9111SKalle Valo 31596f5e66eSJohannes Berg void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, 316ce7c9111SKalle Valo enum queue_stop_reason reason) 317ce7c9111SKalle Valo { 318ce7c9111SKalle Valo struct ieee80211_local *local = hw_to_local(hw); 319ce7c9111SKalle Valo unsigned long flags; 320ce7c9111SKalle Valo 321ce7c9111SKalle Valo spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 322ce7c9111SKalle Valo __ieee80211_stop_queue(hw, queue, reason); 323ce7c9111SKalle Valo spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 324ce7c9111SKalle Valo } 325ce7c9111SKalle Valo 326ce7c9111SKalle Valo void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue) 327ce7c9111SKalle Valo { 328ce7c9111SKalle Valo ieee80211_stop_queue_by_reason(hw, queue, 329ce7c9111SKalle Valo IEEE80211_QUEUE_STOP_REASON_DRIVER); 330ce7c9111SKalle Valo } 331c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_stop_queue); 332c2d1560aSJohannes Berg 3338f77f384SJohannes Berg void ieee80211_add_pending_skb(struct ieee80211_local *local, 3348f77f384SJohannes Berg struct sk_buff *skb) 3358f77f384SJohannes Berg { 3368f77f384SJohannes Berg struct ieee80211_hw *hw = &local->hw; 3378f77f384SJohannes Berg unsigned long flags; 3388f77f384SJohannes Berg int queue = skb_get_queue_mapping(skb); 339a7bc376cSJohannes Berg struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 340a7bc376cSJohannes Berg 341a7bc376cSJohannes Berg if (WARN_ON(!info->control.vif)) { 342a7bc376cSJohannes Berg kfree(skb); 343a7bc376cSJohannes Berg return; 344a7bc376cSJohannes Berg } 3458f77f384SJohannes Berg 3468f77f384SJohannes Berg spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 3478f77f384SJohannes Berg __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD); 3483b8d81e0SJohannes Berg __skb_queue_tail(&local->pending[queue], skb); 3498f77f384SJohannes Berg __ieee80211_wake_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD); 3508f77f384SJohannes Berg spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 3518f77f384SJohannes Berg } 3528f77f384SJohannes Berg 3538f77f384SJohannes Berg int ieee80211_add_pending_skbs(struct ieee80211_local *local, 3548f77f384SJohannes Berg struct sk_buff_head *skbs) 3558f77f384SJohannes Berg { 3568f77f384SJohannes Berg struct ieee80211_hw *hw = &local->hw; 3578f77f384SJohannes Berg struct sk_buff *skb; 3588f77f384SJohannes Berg unsigned long flags; 3598f77f384SJohannes Berg int queue, ret = 0, i; 3608f77f384SJohannes Berg 3618f77f384SJohannes Berg spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 3628f77f384SJohannes Berg for (i = 0; i < hw->queues; i++) 3638f77f384SJohannes Berg __ieee80211_stop_queue(hw, i, 3648f77f384SJohannes Berg IEEE80211_QUEUE_STOP_REASON_SKB_ADD); 3658f77f384SJohannes Berg 3668f77f384SJohannes Berg while ((skb = skb_dequeue(skbs))) { 367a7bc376cSJohannes Berg struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 368a7bc376cSJohannes Berg 369a7bc376cSJohannes Berg if (WARN_ON(!info->control.vif)) { 370a7bc376cSJohannes Berg kfree(skb); 371a7bc376cSJohannes Berg continue; 372a7bc376cSJohannes Berg } 373a7bc376cSJohannes Berg 3748f77f384SJohannes Berg ret++; 3758f77f384SJohannes Berg queue = skb_get_queue_mapping(skb); 3763b8d81e0SJohannes Berg __skb_queue_tail(&local->pending[queue], skb); 3778f77f384SJohannes Berg } 3788f77f384SJohannes Berg 3793b8d81e0SJohannes Berg for (i = 0; i < hw->queues; i++) 3808f77f384SJohannes Berg __ieee80211_wake_queue(hw, i, 3818f77f384SJohannes Berg IEEE80211_QUEUE_STOP_REASON_SKB_ADD); 3828f77f384SJohannes Berg spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 3838f77f384SJohannes Berg 3848f77f384SJohannes Berg return ret; 3858f77f384SJohannes Berg } 3868f77f384SJohannes Berg 387ce7c9111SKalle Valo void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, 388ce7c9111SKalle Valo enum queue_stop_reason reason) 389c2d1560aSJohannes Berg { 390ce7c9111SKalle Valo struct ieee80211_local *local = hw_to_local(hw); 391ce7c9111SKalle Valo unsigned long flags; 392c2d1560aSJohannes Berg int i; 393c2d1560aSJohannes Berg 394ce7c9111SKalle Valo spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 395ce7c9111SKalle Valo 39696f5e66eSJohannes Berg for (i = 0; i < hw->queues; i++) 397ce7c9111SKalle Valo __ieee80211_stop_queue(hw, i, reason); 398ce7c9111SKalle Valo 399ce7c9111SKalle Valo spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 400ce7c9111SKalle Valo } 401ce7c9111SKalle Valo 402ce7c9111SKalle Valo void ieee80211_stop_queues(struct ieee80211_hw *hw) 403ce7c9111SKalle Valo { 404ce7c9111SKalle Valo ieee80211_stop_queues_by_reason(hw, 405ce7c9111SKalle Valo IEEE80211_QUEUE_STOP_REASON_DRIVER); 406c2d1560aSJohannes Berg } 407c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_stop_queues); 408c2d1560aSJohannes Berg 40992ab8535STomas Winkler int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue) 41092ab8535STomas Winkler { 41192ab8535STomas Winkler struct ieee80211_local *local = hw_to_local(hw); 4123b8d81e0SJohannes Berg unsigned long flags; 4133b8d81e0SJohannes Berg int ret; 41496f5e66eSJohannes Berg 415e4e72fb4SJohannes Berg if (WARN_ON(queue >= hw->queues)) 41696f5e66eSJohannes Berg return true; 41796f5e66eSJohannes Berg 4183b8d81e0SJohannes Berg spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 4193b8d81e0SJohannes Berg ret = !!local->queue_stop_reasons[queue]; 4203b8d81e0SJohannes Berg spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 4213b8d81e0SJohannes Berg return ret; 42292ab8535STomas Winkler } 42392ab8535STomas Winkler EXPORT_SYMBOL(ieee80211_queue_stopped); 42492ab8535STomas Winkler 425ce7c9111SKalle Valo void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, 426ce7c9111SKalle Valo enum queue_stop_reason reason) 427c2d1560aSJohannes Berg { 428ce7c9111SKalle Valo struct ieee80211_local *local = hw_to_local(hw); 429ce7c9111SKalle Valo unsigned long flags; 430c2d1560aSJohannes Berg int i; 431c2d1560aSJohannes Berg 432ce7c9111SKalle Valo spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 433ce7c9111SKalle Valo 434e4e72fb4SJohannes Berg for (i = 0; i < hw->queues; i++) 435ce7c9111SKalle Valo __ieee80211_wake_queue(hw, i, reason); 436ce7c9111SKalle Valo 437ce7c9111SKalle Valo spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 438ce7c9111SKalle Valo } 439ce7c9111SKalle Valo 440ce7c9111SKalle Valo void ieee80211_wake_queues(struct ieee80211_hw *hw) 441ce7c9111SKalle Valo { 442ce7c9111SKalle Valo ieee80211_wake_queues_by_reason(hw, IEEE80211_QUEUE_STOP_REASON_DRIVER); 443c2d1560aSJohannes Berg } 444c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_wake_queues); 445dabeb344SJohannes Berg 44632bfd35dSJohannes Berg void ieee80211_iterate_active_interfaces( 44732bfd35dSJohannes Berg struct ieee80211_hw *hw, 448dabeb344SJohannes Berg void (*iterator)(void *data, u8 *mac, 44932bfd35dSJohannes Berg struct ieee80211_vif *vif), 450dabeb344SJohannes Berg void *data) 451dabeb344SJohannes Berg { 452dabeb344SJohannes Berg struct ieee80211_local *local = hw_to_local(hw); 453dabeb344SJohannes Berg struct ieee80211_sub_if_data *sdata; 454dabeb344SJohannes Berg 455c771c9d8SJohannes Berg mutex_lock(&local->iflist_mtx); 4562f561febSIvo van Doorn 4572f561febSIvo van Doorn list_for_each_entry(sdata, &local->interfaces, list) { 4582f561febSIvo van Doorn switch (sdata->vif.type) { 45905c914feSJohannes Berg case __NL80211_IFTYPE_AFTER_LAST: 46005c914feSJohannes Berg case NL80211_IFTYPE_UNSPECIFIED: 46105c914feSJohannes Berg case NL80211_IFTYPE_MONITOR: 46205c914feSJohannes Berg case NL80211_IFTYPE_AP_VLAN: 4632f561febSIvo van Doorn continue; 46405c914feSJohannes Berg case NL80211_IFTYPE_AP: 46505c914feSJohannes Berg case NL80211_IFTYPE_STATION: 46605c914feSJohannes Berg case NL80211_IFTYPE_ADHOC: 46705c914feSJohannes Berg case NL80211_IFTYPE_WDS: 46805c914feSJohannes Berg case NL80211_IFTYPE_MESH_POINT: 4692f561febSIvo van Doorn break; 4702f561febSIvo van Doorn } 4712f561febSIvo van Doorn if (netif_running(sdata->dev)) 4722f561febSIvo van Doorn iterator(data, sdata->dev->dev_addr, 4732f561febSIvo van Doorn &sdata->vif); 4742f561febSIvo van Doorn } 4752f561febSIvo van Doorn 476c771c9d8SJohannes Berg mutex_unlock(&local->iflist_mtx); 4772f561febSIvo van Doorn } 4782f561febSIvo van Doorn EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces); 4792f561febSIvo van Doorn 4802f561febSIvo van Doorn void ieee80211_iterate_active_interfaces_atomic( 4812f561febSIvo van Doorn struct ieee80211_hw *hw, 4822f561febSIvo van Doorn void (*iterator)(void *data, u8 *mac, 4832f561febSIvo van Doorn struct ieee80211_vif *vif), 4842f561febSIvo van Doorn void *data) 4852f561febSIvo van Doorn { 4862f561febSIvo van Doorn struct ieee80211_local *local = hw_to_local(hw); 4872f561febSIvo van Doorn struct ieee80211_sub_if_data *sdata; 4882f561febSIvo van Doorn 489e38bad47SJohannes Berg rcu_read_lock(); 490dabeb344SJohannes Berg 491e38bad47SJohannes Berg list_for_each_entry_rcu(sdata, &local->interfaces, list) { 49251fb61e7SJohannes Berg switch (sdata->vif.type) { 49305c914feSJohannes Berg case __NL80211_IFTYPE_AFTER_LAST: 49405c914feSJohannes Berg case NL80211_IFTYPE_UNSPECIFIED: 49505c914feSJohannes Berg case NL80211_IFTYPE_MONITOR: 49605c914feSJohannes Berg case NL80211_IFTYPE_AP_VLAN: 497dabeb344SJohannes Berg continue; 49805c914feSJohannes Berg case NL80211_IFTYPE_AP: 49905c914feSJohannes Berg case NL80211_IFTYPE_STATION: 50005c914feSJohannes Berg case NL80211_IFTYPE_ADHOC: 50105c914feSJohannes Berg case NL80211_IFTYPE_WDS: 50205c914feSJohannes Berg case NL80211_IFTYPE_MESH_POINT: 503dabeb344SJohannes Berg break; 504dabeb344SJohannes Berg } 505dabeb344SJohannes Berg if (netif_running(sdata->dev)) 506dabeb344SJohannes Berg iterator(data, sdata->dev->dev_addr, 50732bfd35dSJohannes Berg &sdata->vif); 508dabeb344SJohannes Berg } 509e38bad47SJohannes Berg 510e38bad47SJohannes Berg rcu_read_unlock(); 511dabeb344SJohannes Berg } 5122f561febSIvo van Doorn EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic); 51337ffc8daSJohannes Berg 51442935ecaSLuis R. Rodriguez /* 51542935ecaSLuis R. Rodriguez * Nothing should have been stuffed into the workqueue during 51642935ecaSLuis R. Rodriguez * the suspend->resume cycle. If this WARN is seen then there 51742935ecaSLuis R. Rodriguez * is a bug with either the driver suspend or something in 51842935ecaSLuis R. Rodriguez * mac80211 stuffing into the workqueue which we haven't yet 51942935ecaSLuis R. Rodriguez * cleared during mac80211's suspend cycle. 52042935ecaSLuis R. Rodriguez */ 52142935ecaSLuis R. Rodriguez static bool ieee80211_can_queue_work(struct ieee80211_local *local) 52242935ecaSLuis R. Rodriguez { 52342935ecaSLuis R. Rodriguez if (WARN(local->suspended, "queueing ieee80211 work while " 52442935ecaSLuis R. Rodriguez "going to suspend\n")) 52542935ecaSLuis R. Rodriguez return false; 52642935ecaSLuis R. Rodriguez 52742935ecaSLuis R. Rodriguez return true; 52842935ecaSLuis R. Rodriguez } 52942935ecaSLuis R. Rodriguez 53042935ecaSLuis R. Rodriguez void ieee80211_queue_work(struct ieee80211_hw *hw, struct work_struct *work) 53142935ecaSLuis R. Rodriguez { 53242935ecaSLuis R. Rodriguez struct ieee80211_local *local = hw_to_local(hw); 53342935ecaSLuis R. Rodriguez 53442935ecaSLuis R. Rodriguez if (!ieee80211_can_queue_work(local)) 53542935ecaSLuis R. Rodriguez return; 53642935ecaSLuis R. Rodriguez 53742935ecaSLuis R. Rodriguez queue_work(local->workqueue, work); 53842935ecaSLuis R. Rodriguez } 53942935ecaSLuis R. Rodriguez EXPORT_SYMBOL(ieee80211_queue_work); 54042935ecaSLuis R. Rodriguez 54142935ecaSLuis R. Rodriguez void ieee80211_queue_delayed_work(struct ieee80211_hw *hw, 54242935ecaSLuis R. Rodriguez struct delayed_work *dwork, 54342935ecaSLuis R. Rodriguez unsigned long delay) 54442935ecaSLuis R. Rodriguez { 54542935ecaSLuis R. Rodriguez struct ieee80211_local *local = hw_to_local(hw); 54642935ecaSLuis R. Rodriguez 54742935ecaSLuis R. Rodriguez if (!ieee80211_can_queue_work(local)) 54842935ecaSLuis R. Rodriguez return; 54942935ecaSLuis R. Rodriguez 55042935ecaSLuis R. Rodriguez queue_delayed_work(local->workqueue, dwork, delay); 55142935ecaSLuis R. Rodriguez } 55242935ecaSLuis R. Rodriguez EXPORT_SYMBOL(ieee80211_queue_delayed_work); 55342935ecaSLuis R. Rodriguez 55437ffc8daSJohannes Berg void ieee802_11_parse_elems(u8 *start, size_t len, 55537ffc8daSJohannes Berg struct ieee802_11_elems *elems) 55637ffc8daSJohannes Berg { 557d91f36dbSJohannes Berg ieee802_11_parse_elems_crc(start, len, elems, 0, 0); 558d91f36dbSJohannes Berg } 559d91f36dbSJohannes Berg 560d91f36dbSJohannes Berg u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, 561d91f36dbSJohannes Berg struct ieee802_11_elems *elems, 562d91f36dbSJohannes Berg u64 filter, u32 crc) 563d91f36dbSJohannes Berg { 56437ffc8daSJohannes Berg size_t left = len; 56537ffc8daSJohannes Berg u8 *pos = start; 566d91f36dbSJohannes Berg bool calc_crc = filter != 0; 56737ffc8daSJohannes Berg 56837ffc8daSJohannes Berg memset(elems, 0, sizeof(*elems)); 56937ffc8daSJohannes Berg elems->ie_start = start; 57037ffc8daSJohannes Berg elems->total_len = len; 57137ffc8daSJohannes Berg 57237ffc8daSJohannes Berg while (left >= 2) { 57337ffc8daSJohannes Berg u8 id, elen; 57437ffc8daSJohannes Berg 57537ffc8daSJohannes Berg id = *pos++; 57637ffc8daSJohannes Berg elen = *pos++; 57737ffc8daSJohannes Berg left -= 2; 57837ffc8daSJohannes Berg 57937ffc8daSJohannes Berg if (elen > left) 580d91f36dbSJohannes Berg break; 581d91f36dbSJohannes Berg 582d91f36dbSJohannes Berg if (calc_crc && id < 64 && (filter & BIT(id))) 583d91f36dbSJohannes Berg crc = crc32_be(crc, pos - 2, elen + 2); 58437ffc8daSJohannes Berg 58537ffc8daSJohannes Berg switch (id) { 58637ffc8daSJohannes Berg case WLAN_EID_SSID: 58737ffc8daSJohannes Berg elems->ssid = pos; 58837ffc8daSJohannes Berg elems->ssid_len = elen; 58937ffc8daSJohannes Berg break; 59037ffc8daSJohannes Berg case WLAN_EID_SUPP_RATES: 59137ffc8daSJohannes Berg elems->supp_rates = pos; 59237ffc8daSJohannes Berg elems->supp_rates_len = elen; 59337ffc8daSJohannes Berg break; 59437ffc8daSJohannes Berg case WLAN_EID_FH_PARAMS: 59537ffc8daSJohannes Berg elems->fh_params = pos; 59637ffc8daSJohannes Berg elems->fh_params_len = elen; 59737ffc8daSJohannes Berg break; 59837ffc8daSJohannes Berg case WLAN_EID_DS_PARAMS: 59937ffc8daSJohannes Berg elems->ds_params = pos; 60037ffc8daSJohannes Berg elems->ds_params_len = elen; 60137ffc8daSJohannes Berg break; 60237ffc8daSJohannes Berg case WLAN_EID_CF_PARAMS: 60337ffc8daSJohannes Berg elems->cf_params = pos; 60437ffc8daSJohannes Berg elems->cf_params_len = elen; 60537ffc8daSJohannes Berg break; 60637ffc8daSJohannes Berg case WLAN_EID_TIM: 607e7ec86f5SJohannes Berg if (elen >= sizeof(struct ieee80211_tim_ie)) { 608e7ec86f5SJohannes Berg elems->tim = (void *)pos; 60937ffc8daSJohannes Berg elems->tim_len = elen; 610e7ec86f5SJohannes Berg } 61137ffc8daSJohannes Berg break; 61237ffc8daSJohannes Berg case WLAN_EID_IBSS_PARAMS: 61337ffc8daSJohannes Berg elems->ibss_params = pos; 61437ffc8daSJohannes Berg elems->ibss_params_len = elen; 61537ffc8daSJohannes Berg break; 61637ffc8daSJohannes Berg case WLAN_EID_CHALLENGE: 61737ffc8daSJohannes Berg elems->challenge = pos; 61837ffc8daSJohannes Berg elems->challenge_len = elen; 61937ffc8daSJohannes Berg break; 620d91f36dbSJohannes Berg case WLAN_EID_VENDOR_SPECIFIC: 62137ffc8daSJohannes Berg if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 && 62237ffc8daSJohannes Berg pos[2] == 0xf2) { 62337ffc8daSJohannes Berg /* Microsoft OUI (00:50:F2) */ 624d91f36dbSJohannes Berg 625d91f36dbSJohannes Berg if (calc_crc) 626d91f36dbSJohannes Berg crc = crc32_be(crc, pos - 2, elen + 2); 627d91f36dbSJohannes Berg 62837ffc8daSJohannes Berg if (pos[3] == 1) { 62937ffc8daSJohannes Berg /* OUI Type 1 - WPA IE */ 63037ffc8daSJohannes Berg elems->wpa = pos; 63137ffc8daSJohannes Berg elems->wpa_len = elen; 63237ffc8daSJohannes Berg } else if (elen >= 5 && pos[3] == 2) { 633d91f36dbSJohannes Berg /* OUI Type 2 - WMM IE */ 63437ffc8daSJohannes Berg if (pos[4] == 0) { 63537ffc8daSJohannes Berg elems->wmm_info = pos; 63637ffc8daSJohannes Berg elems->wmm_info_len = elen; 63737ffc8daSJohannes Berg } else if (pos[4] == 1) { 63837ffc8daSJohannes Berg elems->wmm_param = pos; 63937ffc8daSJohannes Berg elems->wmm_param_len = elen; 64037ffc8daSJohannes Berg } 64137ffc8daSJohannes Berg } 64237ffc8daSJohannes Berg } 64337ffc8daSJohannes Berg break; 64437ffc8daSJohannes Berg case WLAN_EID_RSN: 64537ffc8daSJohannes Berg elems->rsn = pos; 64637ffc8daSJohannes Berg elems->rsn_len = elen; 64737ffc8daSJohannes Berg break; 64837ffc8daSJohannes Berg case WLAN_EID_ERP_INFO: 64937ffc8daSJohannes Berg elems->erp_info = pos; 65037ffc8daSJohannes Berg elems->erp_info_len = elen; 65137ffc8daSJohannes Berg break; 65237ffc8daSJohannes Berg case WLAN_EID_EXT_SUPP_RATES: 65337ffc8daSJohannes Berg elems->ext_supp_rates = pos; 65437ffc8daSJohannes Berg elems->ext_supp_rates_len = elen; 65537ffc8daSJohannes Berg break; 65637ffc8daSJohannes Berg case WLAN_EID_HT_CAPABILITY: 65709914813SJohannes Berg if (elen >= sizeof(struct ieee80211_ht_cap)) 65809914813SJohannes Berg elems->ht_cap_elem = (void *)pos; 65937ffc8daSJohannes Berg break; 660d9fe60deSJohannes Berg case WLAN_EID_HT_INFORMATION: 661d9fe60deSJohannes Berg if (elen >= sizeof(struct ieee80211_ht_info)) 66209914813SJohannes Berg elems->ht_info_elem = (void *)pos; 66337ffc8daSJohannes Berg break; 66437ffc8daSJohannes Berg case WLAN_EID_MESH_ID: 66537ffc8daSJohannes Berg elems->mesh_id = pos; 66637ffc8daSJohannes Berg elems->mesh_id_len = elen; 66737ffc8daSJohannes Berg break; 66837ffc8daSJohannes Berg case WLAN_EID_MESH_CONFIG: 66937ffc8daSJohannes Berg elems->mesh_config = pos; 67037ffc8daSJohannes Berg elems->mesh_config_len = elen; 67137ffc8daSJohannes Berg break; 67237ffc8daSJohannes Berg case WLAN_EID_PEER_LINK: 67337ffc8daSJohannes Berg elems->peer_link = pos; 67437ffc8daSJohannes Berg elems->peer_link_len = elen; 67537ffc8daSJohannes Berg break; 67637ffc8daSJohannes Berg case WLAN_EID_PREQ: 67737ffc8daSJohannes Berg elems->preq = pos; 67837ffc8daSJohannes Berg elems->preq_len = elen; 67937ffc8daSJohannes Berg break; 68037ffc8daSJohannes Berg case WLAN_EID_PREP: 68137ffc8daSJohannes Berg elems->prep = pos; 68237ffc8daSJohannes Berg elems->prep_len = elen; 68337ffc8daSJohannes Berg break; 68437ffc8daSJohannes Berg case WLAN_EID_PERR: 68537ffc8daSJohannes Berg elems->perr = pos; 68637ffc8daSJohannes Berg elems->perr_len = elen; 68737ffc8daSJohannes Berg break; 68837ffc8daSJohannes Berg case WLAN_EID_CHANNEL_SWITCH: 68937ffc8daSJohannes Berg elems->ch_switch_elem = pos; 69037ffc8daSJohannes Berg elems->ch_switch_elem_len = elen; 69137ffc8daSJohannes Berg break; 69237ffc8daSJohannes Berg case WLAN_EID_QUIET: 69337ffc8daSJohannes Berg if (!elems->quiet_elem) { 69437ffc8daSJohannes Berg elems->quiet_elem = pos; 69537ffc8daSJohannes Berg elems->quiet_elem_len = elen; 69637ffc8daSJohannes Berg } 69737ffc8daSJohannes Berg elems->num_of_quiet_elem++; 69837ffc8daSJohannes Berg break; 69937ffc8daSJohannes Berg case WLAN_EID_COUNTRY: 70037ffc8daSJohannes Berg elems->country_elem = pos; 70137ffc8daSJohannes Berg elems->country_elem_len = elen; 70237ffc8daSJohannes Berg break; 70337ffc8daSJohannes Berg case WLAN_EID_PWR_CONSTRAINT: 70437ffc8daSJohannes Berg elems->pwr_constr_elem = pos; 70537ffc8daSJohannes Berg elems->pwr_constr_elem_len = elen; 70637ffc8daSJohannes Berg break; 707f797eb7eSJouni Malinen case WLAN_EID_TIMEOUT_INTERVAL: 708f797eb7eSJouni Malinen elems->timeout_int = pos; 709f797eb7eSJouni Malinen elems->timeout_int_len = elen; 71063a5ab82SJouni Malinen break; 71137ffc8daSJohannes Berg default: 71237ffc8daSJohannes Berg break; 71337ffc8daSJohannes Berg } 71437ffc8daSJohannes Berg 71537ffc8daSJohannes Berg left -= elen; 71637ffc8daSJohannes Berg pos += elen; 71737ffc8daSJohannes Berg } 718d91f36dbSJohannes Berg 719d91f36dbSJohannes Berg return crc; 72037ffc8daSJohannes Berg } 7215825fe10SJohannes Berg 7225825fe10SJohannes Berg void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata) 7235825fe10SJohannes Berg { 7245825fe10SJohannes Berg struct ieee80211_local *local = sdata->local; 7255825fe10SJohannes Berg struct ieee80211_tx_queue_params qparam; 726aa837e1dSJohannes Berg int queue; 727aa837e1dSJohannes Berg bool use_11b; 728aa837e1dSJohannes Berg int aCWmin, aCWmax; 7295825fe10SJohannes Berg 7305825fe10SJohannes Berg if (!local->ops->conf_tx) 7315825fe10SJohannes Berg return; 7325825fe10SJohannes Berg 7335825fe10SJohannes Berg memset(&qparam, 0, sizeof(qparam)); 7345825fe10SJohannes Berg 735aa837e1dSJohannes Berg use_11b = (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) && 736aa837e1dSJohannes Berg !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE); 7375825fe10SJohannes Berg 738aa837e1dSJohannes Berg for (queue = 0; queue < local_to_hw(local)->queues; queue++) { 739aa837e1dSJohannes Berg /* Set defaults according to 802.11-2007 Table 7-37 */ 740aa837e1dSJohannes Berg aCWmax = 1023; 741aa837e1dSJohannes Berg if (use_11b) 742aa837e1dSJohannes Berg aCWmin = 31; 7435825fe10SJohannes Berg else 744aa837e1dSJohannes Berg aCWmin = 15; 7455825fe10SJohannes Berg 746aa837e1dSJohannes Berg switch (queue) { 747aa837e1dSJohannes Berg case 3: /* AC_BK */ 7487ba10a8eSJohannes Berg qparam.cw_max = aCWmax; 7497ba10a8eSJohannes Berg qparam.cw_min = aCWmin; 7505825fe10SJohannes Berg qparam.txop = 0; 751aa837e1dSJohannes Berg qparam.aifs = 7; 752aa837e1dSJohannes Berg break; 753aa837e1dSJohannes Berg default: /* never happens but let's not leave undefined */ 754aa837e1dSJohannes Berg case 2: /* AC_BE */ 7557ba10a8eSJohannes Berg qparam.cw_max = aCWmax; 7567ba10a8eSJohannes Berg qparam.cw_min = aCWmin; 757aa837e1dSJohannes Berg qparam.txop = 0; 758aa837e1dSJohannes Berg qparam.aifs = 3; 759aa837e1dSJohannes Berg break; 760aa837e1dSJohannes Berg case 1: /* AC_VI */ 761aa837e1dSJohannes Berg qparam.cw_max = aCWmin; 762aa837e1dSJohannes Berg qparam.cw_min = (aCWmin + 1) / 2 - 1; 763aa837e1dSJohannes Berg if (use_11b) 764aa837e1dSJohannes Berg qparam.txop = 6016/32; 765aa837e1dSJohannes Berg else 766aa837e1dSJohannes Berg qparam.txop = 3008/32; 767aa837e1dSJohannes Berg qparam.aifs = 2; 768aa837e1dSJohannes Berg break; 769aa837e1dSJohannes Berg case 0: /* AC_VO */ 770aa837e1dSJohannes Berg qparam.cw_max = (aCWmin + 1) / 2 - 1; 771aa837e1dSJohannes Berg qparam.cw_min = (aCWmin + 1) / 4 - 1; 772aa837e1dSJohannes Berg if (use_11b) 773aa837e1dSJohannes Berg qparam.txop = 3264/32; 774aa837e1dSJohannes Berg else 775aa837e1dSJohannes Berg qparam.txop = 1504/32; 776aa837e1dSJohannes Berg qparam.aifs = 2; 777aa837e1dSJohannes Berg break; 778aa837e1dSJohannes Berg } 7795825fe10SJohannes Berg 780aa837e1dSJohannes Berg drv_conf_tx(local, queue, &qparam); 781aa837e1dSJohannes Berg } 7825825fe10SJohannes Berg } 783e50db65cSJohannes Berg 78446900298SJohannes Berg void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, 78546900298SJohannes Berg const size_t supp_rates_len, 78646900298SJohannes Berg const u8 *supp_rates) 78746900298SJohannes Berg { 78846900298SJohannes Berg struct ieee80211_local *local = sdata->local; 78946900298SJohannes Berg int i, have_higher_than_11mbit = 0; 79046900298SJohannes Berg 79146900298SJohannes Berg /* cf. IEEE 802.11 9.2.12 */ 79246900298SJohannes Berg for (i = 0; i < supp_rates_len; i++) 79346900298SJohannes Berg if ((supp_rates[i] & 0x7f) * 5 > 110) 79446900298SJohannes Berg have_higher_than_11mbit = 1; 79546900298SJohannes Berg 79646900298SJohannes Berg if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && 79746900298SJohannes Berg have_higher_than_11mbit) 79846900298SJohannes Berg sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; 79946900298SJohannes Berg else 80046900298SJohannes Berg sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; 80146900298SJohannes Berg 80246900298SJohannes Berg ieee80211_set_wmm_default(sdata); 80346900298SJohannes Berg } 80446900298SJohannes Berg 805881d948cSJohannes Berg u32 ieee80211_mandatory_rates(struct ieee80211_local *local, 80696dd22acSJohannes Berg enum ieee80211_band band) 80796dd22acSJohannes Berg { 80896dd22acSJohannes Berg struct ieee80211_supported_band *sband; 80996dd22acSJohannes Berg struct ieee80211_rate *bitrates; 810881d948cSJohannes Berg u32 mandatory_rates; 81196dd22acSJohannes Berg enum ieee80211_rate_flags mandatory_flag; 81296dd22acSJohannes Berg int i; 81396dd22acSJohannes Berg 81496dd22acSJohannes Berg sband = local->hw.wiphy->bands[band]; 81596dd22acSJohannes Berg if (!sband) { 81696dd22acSJohannes Berg WARN_ON(1); 81796dd22acSJohannes Berg sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; 81896dd22acSJohannes Berg } 81996dd22acSJohannes Berg 82096dd22acSJohannes Berg if (band == IEEE80211_BAND_2GHZ) 82196dd22acSJohannes Berg mandatory_flag = IEEE80211_RATE_MANDATORY_B; 82296dd22acSJohannes Berg else 82396dd22acSJohannes Berg mandatory_flag = IEEE80211_RATE_MANDATORY_A; 82496dd22acSJohannes Berg 82596dd22acSJohannes Berg bitrates = sband->bitrates; 82696dd22acSJohannes Berg mandatory_rates = 0; 82796dd22acSJohannes Berg for (i = 0; i < sband->n_bitrates; i++) 82896dd22acSJohannes Berg if (bitrates[i].flags & mandatory_flag) 82996dd22acSJohannes Berg mandatory_rates |= BIT(i); 83096dd22acSJohannes Berg return mandatory_rates; 83196dd22acSJohannes Berg } 83246900298SJohannes Berg 83346900298SJohannes Berg void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, 83446900298SJohannes Berg u16 transaction, u16 auth_alg, 835fffd0934SJohannes Berg u8 *extra, size_t extra_len, const u8 *bssid, 836fffd0934SJohannes Berg const u8 *key, u8 key_len, u8 key_idx) 83746900298SJohannes Berg { 83846900298SJohannes Berg struct ieee80211_local *local = sdata->local; 83946900298SJohannes Berg struct sk_buff *skb; 84046900298SJohannes Berg struct ieee80211_mgmt *mgmt; 841fffd0934SJohannes Berg int err; 84246900298SJohannes Berg 84346900298SJohannes Berg skb = dev_alloc_skb(local->hw.extra_tx_headroom + 84465fc73acSJouni Malinen sizeof(*mgmt) + 6 + extra_len); 84546900298SJohannes Berg if (!skb) { 84646900298SJohannes Berg printk(KERN_DEBUG "%s: failed to allocate buffer for auth " 84746900298SJohannes Berg "frame\n", sdata->dev->name); 84846900298SJohannes Berg return; 84946900298SJohannes Berg } 85046900298SJohannes Berg skb_reserve(skb, local->hw.extra_tx_headroom); 85146900298SJohannes Berg 85246900298SJohannes Berg mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6); 85346900298SJohannes Berg memset(mgmt, 0, 24 + 6); 85446900298SJohannes Berg mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | 85546900298SJohannes Berg IEEE80211_STYPE_AUTH); 85646900298SJohannes Berg memcpy(mgmt->da, bssid, ETH_ALEN); 85746900298SJohannes Berg memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); 85846900298SJohannes Berg memcpy(mgmt->bssid, bssid, ETH_ALEN); 85946900298SJohannes Berg mgmt->u.auth.auth_alg = cpu_to_le16(auth_alg); 86046900298SJohannes Berg mgmt->u.auth.auth_transaction = cpu_to_le16(transaction); 86146900298SJohannes Berg mgmt->u.auth.status_code = cpu_to_le16(0); 86246900298SJohannes Berg if (extra) 86346900298SJohannes Berg memcpy(skb_put(skb, extra_len), extra, extra_len); 86446900298SJohannes Berg 865fffd0934SJohannes Berg if (auth_alg == WLAN_AUTH_SHARED_KEY && transaction == 3) { 866fffd0934SJohannes Berg mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); 867fffd0934SJohannes Berg err = ieee80211_wep_encrypt(local, skb, key, key_len, key_idx); 868fffd0934SJohannes Berg WARN_ON(err); 869fffd0934SJohannes Berg } 870fffd0934SJohannes Berg 871fffd0934SJohannes Berg ieee80211_tx_skb(sdata, skb, 0); 87246900298SJohannes Berg } 87346900298SJohannes Berg 874de95a54bSJohannes Berg int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, 875de95a54bSJohannes Berg const u8 *ie, size_t ie_len) 876de95a54bSJohannes Berg { 877de95a54bSJohannes Berg struct ieee80211_supported_band *sband; 878de95a54bSJohannes Berg u8 *pos, *supp_rates_len, *esupp_rates_len = NULL; 879de95a54bSJohannes Berg int i; 880de95a54bSJohannes Berg 881de95a54bSJohannes Berg sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; 882de95a54bSJohannes Berg 883de95a54bSJohannes Berg pos = buffer; 884de95a54bSJohannes Berg 885de95a54bSJohannes Berg *pos++ = WLAN_EID_SUPP_RATES; 886de95a54bSJohannes Berg supp_rates_len = pos; 887de95a54bSJohannes Berg *pos++ = 0; 888de95a54bSJohannes Berg 889de95a54bSJohannes Berg for (i = 0; i < sband->n_bitrates; i++) { 890de95a54bSJohannes Berg struct ieee80211_rate *rate = &sband->bitrates[i]; 891de95a54bSJohannes Berg 892de95a54bSJohannes Berg if (esupp_rates_len) { 893de95a54bSJohannes Berg *esupp_rates_len += 1; 894de95a54bSJohannes Berg } else if (*supp_rates_len == 8) { 895de95a54bSJohannes Berg *pos++ = WLAN_EID_EXT_SUPP_RATES; 896de95a54bSJohannes Berg esupp_rates_len = pos; 897de95a54bSJohannes Berg *pos++ = 1; 898de95a54bSJohannes Berg } else 899de95a54bSJohannes Berg *supp_rates_len += 1; 900de95a54bSJohannes Berg 901de95a54bSJohannes Berg *pos++ = rate->bitrate / 5; 902de95a54bSJohannes Berg } 903de95a54bSJohannes Berg 9045ef2d41aSJohannes Berg if (sband->ht_cap.ht_supported) { 9055ef2d41aSJohannes Berg __le16 tmp = cpu_to_le16(sband->ht_cap.cap); 9065ef2d41aSJohannes Berg 9075ef2d41aSJohannes Berg *pos++ = WLAN_EID_HT_CAPABILITY; 9085ef2d41aSJohannes Berg *pos++ = sizeof(struct ieee80211_ht_cap); 9095ef2d41aSJohannes Berg memset(pos, 0, sizeof(struct ieee80211_ht_cap)); 9105ef2d41aSJohannes Berg memcpy(pos, &tmp, sizeof(u16)); 9115ef2d41aSJohannes Berg pos += sizeof(u16); 9125ef2d41aSJohannes Berg /* TODO: needs a define here for << 2 */ 9135ef2d41aSJohannes Berg *pos++ = sband->ht_cap.ampdu_factor | 9145ef2d41aSJohannes Berg (sband->ht_cap.ampdu_density << 2); 9155ef2d41aSJohannes Berg memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); 9165ef2d41aSJohannes Berg pos += sizeof(sband->ht_cap.mcs); 9175ef2d41aSJohannes Berg pos += 2 + 4 + 1; /* ext info, BF cap, antsel */ 9185ef2d41aSJohannes Berg } 9195ef2d41aSJohannes Berg 920de95a54bSJohannes Berg /* 921de95a54bSJohannes Berg * If adding more here, adjust code in main.c 922de95a54bSJohannes Berg * that calculates local->scan_ies_len. 923de95a54bSJohannes Berg */ 924de95a54bSJohannes Berg 925de95a54bSJohannes Berg if (ie) { 926de95a54bSJohannes Berg memcpy(pos, ie, ie_len); 927de95a54bSJohannes Berg pos += ie_len; 928de95a54bSJohannes Berg } 929de95a54bSJohannes Berg 930de95a54bSJohannes Berg return pos - buffer; 931de95a54bSJohannes Berg } 932de95a54bSJohannes Berg 93346900298SJohannes Berg void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, 934de95a54bSJohannes Berg const u8 *ssid, size_t ssid_len, 935de95a54bSJohannes Berg const u8 *ie, size_t ie_len) 93646900298SJohannes Berg { 93746900298SJohannes Berg struct ieee80211_local *local = sdata->local; 93846900298SJohannes Berg struct sk_buff *skb; 93946900298SJohannes Berg struct ieee80211_mgmt *mgmt; 940de95a54bSJohannes Berg u8 *pos; 94146900298SJohannes Berg 94246900298SJohannes Berg skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 + 94365fc73acSJouni Malinen ie_len); 94446900298SJohannes Berg if (!skb) { 94546900298SJohannes Berg printk(KERN_DEBUG "%s: failed to allocate buffer for probe " 94646900298SJohannes Berg "request\n", sdata->dev->name); 94746900298SJohannes Berg return; 94846900298SJohannes Berg } 94946900298SJohannes Berg skb_reserve(skb, local->hw.extra_tx_headroom); 95046900298SJohannes Berg 95146900298SJohannes Berg mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); 95246900298SJohannes Berg memset(mgmt, 0, 24); 95346900298SJohannes Berg mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | 95446900298SJohannes Berg IEEE80211_STYPE_PROBE_REQ); 95546900298SJohannes Berg memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); 95646900298SJohannes Berg if (dst) { 95746900298SJohannes Berg memcpy(mgmt->da, dst, ETH_ALEN); 95846900298SJohannes Berg memcpy(mgmt->bssid, dst, ETH_ALEN); 95946900298SJohannes Berg } else { 96046900298SJohannes Berg memset(mgmt->da, 0xff, ETH_ALEN); 96146900298SJohannes Berg memset(mgmt->bssid, 0xff, ETH_ALEN); 96246900298SJohannes Berg } 96346900298SJohannes Berg pos = skb_put(skb, 2 + ssid_len); 96446900298SJohannes Berg *pos++ = WLAN_EID_SSID; 96546900298SJohannes Berg *pos++ = ssid_len; 96646900298SJohannes Berg memcpy(pos, ssid, ssid_len); 967de95a54bSJohannes Berg pos += ssid_len; 96846900298SJohannes Berg 969de95a54bSJohannes Berg skb_put(skb, ieee80211_build_preq_ies(local, pos, ie, ie_len)); 97046900298SJohannes Berg 97146900298SJohannes Berg ieee80211_tx_skb(sdata, skb, 0); 97246900298SJohannes Berg } 97346900298SJohannes Berg 97446900298SJohannes Berg u32 ieee80211_sta_get_rates(struct ieee80211_local *local, 97546900298SJohannes Berg struct ieee802_11_elems *elems, 97646900298SJohannes Berg enum ieee80211_band band) 97746900298SJohannes Berg { 97846900298SJohannes Berg struct ieee80211_supported_band *sband; 97946900298SJohannes Berg struct ieee80211_rate *bitrates; 98046900298SJohannes Berg size_t num_rates; 98146900298SJohannes Berg u32 supp_rates; 98246900298SJohannes Berg int i, j; 98346900298SJohannes Berg sband = local->hw.wiphy->bands[band]; 98446900298SJohannes Berg 98546900298SJohannes Berg if (!sband) { 98646900298SJohannes Berg WARN_ON(1); 98746900298SJohannes Berg sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; 98846900298SJohannes Berg } 98946900298SJohannes Berg 99046900298SJohannes Berg bitrates = sband->bitrates; 99146900298SJohannes Berg num_rates = sband->n_bitrates; 99246900298SJohannes Berg supp_rates = 0; 99346900298SJohannes Berg for (i = 0; i < elems->supp_rates_len + 99446900298SJohannes Berg elems->ext_supp_rates_len; i++) { 99546900298SJohannes Berg u8 rate = 0; 99646900298SJohannes Berg int own_rate; 99746900298SJohannes Berg if (i < elems->supp_rates_len) 99846900298SJohannes Berg rate = elems->supp_rates[i]; 99946900298SJohannes Berg else if (elems->ext_supp_rates) 100046900298SJohannes Berg rate = elems->ext_supp_rates 100146900298SJohannes Berg [i - elems->supp_rates_len]; 100246900298SJohannes Berg own_rate = 5 * (rate & 0x7f); 100346900298SJohannes Berg for (j = 0; j < num_rates; j++) 100446900298SJohannes Berg if (bitrates[j].bitrate == own_rate) 100546900298SJohannes Berg supp_rates |= BIT(j); 100646900298SJohannes Berg } 100746900298SJohannes Berg return supp_rates; 100846900298SJohannes Berg } 1009f2753ddbSJohannes Berg 1010f2753ddbSJohannes Berg int ieee80211_reconfig(struct ieee80211_local *local) 1011f2753ddbSJohannes Berg { 1012f2753ddbSJohannes Berg struct ieee80211_hw *hw = &local->hw; 1013f2753ddbSJohannes Berg struct ieee80211_sub_if_data *sdata; 1014f2753ddbSJohannes Berg struct ieee80211_if_init_conf conf; 1015f2753ddbSJohannes Berg struct sta_info *sta; 1016f2753ddbSJohannes Berg unsigned long flags; 1017f2753ddbSJohannes Berg int res; 10185bb644a0SJohannes Berg bool from_suspend = local->suspended; 10195bb644a0SJohannes Berg 10205bb644a0SJohannes Berg /* 10215bb644a0SJohannes Berg * We're going to start the hardware, at that point 10225bb644a0SJohannes Berg * we are no longer suspended and can RX frames. 10235bb644a0SJohannes Berg */ 10245bb644a0SJohannes Berg local->suspended = false; 1025f2753ddbSJohannes Berg 1026f2753ddbSJohannes Berg /* restart hardware */ 1027f2753ddbSJohannes Berg if (local->open_count) { 102824487981SJohannes Berg res = drv_start(local); 1029f2753ddbSJohannes Berg 10301f87f7d3SJohannes Berg ieee80211_led_radio(local, true); 1031f2753ddbSJohannes Berg } 1032f2753ddbSJohannes Berg 1033f2753ddbSJohannes Berg /* add interfaces */ 1034f2753ddbSJohannes Berg list_for_each_entry(sdata, &local->interfaces, list) { 1035f2753ddbSJohannes Berg if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && 1036f2753ddbSJohannes Berg sdata->vif.type != NL80211_IFTYPE_MONITOR && 1037f2753ddbSJohannes Berg netif_running(sdata->dev)) { 1038f2753ddbSJohannes Berg conf.vif = &sdata->vif; 1039f2753ddbSJohannes Berg conf.type = sdata->vif.type; 1040f2753ddbSJohannes Berg conf.mac_addr = sdata->dev->dev_addr; 104124487981SJohannes Berg res = drv_add_interface(local, &conf); 1042f2753ddbSJohannes Berg } 1043f2753ddbSJohannes Berg } 1044f2753ddbSJohannes Berg 1045f2753ddbSJohannes Berg /* add STAs back */ 1046f2753ddbSJohannes Berg if (local->ops->sta_notify) { 1047f2753ddbSJohannes Berg spin_lock_irqsave(&local->sta_lock, flags); 1048f2753ddbSJohannes Berg list_for_each_entry(sta, &local->sta_list, list) { 10495bb644a0SJohannes Berg sdata = sta->sdata; 1050f2753ddbSJohannes Berg if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) 1051f2753ddbSJohannes Berg sdata = container_of(sdata->bss, 1052f2753ddbSJohannes Berg struct ieee80211_sub_if_data, 1053f2753ddbSJohannes Berg u.ap); 1054f2753ddbSJohannes Berg 105524487981SJohannes Berg drv_sta_notify(local, &sdata->vif, STA_NOTIFY_ADD, 105624487981SJohannes Berg &sta->sta); 1057f2753ddbSJohannes Berg } 1058f2753ddbSJohannes Berg spin_unlock_irqrestore(&local->sta_lock, flags); 1059f2753ddbSJohannes Berg } 1060f2753ddbSJohannes Berg 1061f2753ddbSJohannes Berg /* Clear Suspend state so that ADDBA requests can be processed */ 1062f2753ddbSJohannes Berg 1063f2753ddbSJohannes Berg rcu_read_lock(); 1064f2753ddbSJohannes Berg 1065f2753ddbSJohannes Berg if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { 1066f2753ddbSJohannes Berg list_for_each_entry_rcu(sta, &local->sta_list, list) { 1067f2753ddbSJohannes Berg clear_sta_flags(sta, WLAN_STA_SUSPEND); 1068f2753ddbSJohannes Berg } 1069f2753ddbSJohannes Berg } 1070f2753ddbSJohannes Berg 1071f2753ddbSJohannes Berg rcu_read_unlock(); 1072f2753ddbSJohannes Berg 1073f2753ddbSJohannes Berg /* setup RTS threshold */ 107424487981SJohannes Berg drv_set_rts_threshold(local, hw->wiphy->rts_threshold); 1075f2753ddbSJohannes Berg 1076f2753ddbSJohannes Berg /* reconfigure hardware */ 1077f2753ddbSJohannes Berg ieee80211_hw_config(local, ~0); 1078f2753ddbSJohannes Berg 10793b8d81e0SJohannes Berg spin_lock_bh(&local->filter_lock); 1080f2753ddbSJohannes Berg ieee80211_configure_filter(local); 10813b8d81e0SJohannes Berg spin_unlock_bh(&local->filter_lock); 1082f2753ddbSJohannes Berg 1083f2753ddbSJohannes Berg /* Finally also reconfigure all the BSS information */ 1084f2753ddbSJohannes Berg list_for_each_entry(sdata, &local->interfaces, list) { 1085f2753ddbSJohannes Berg u32 changed = ~0; 1086f2753ddbSJohannes Berg if (!netif_running(sdata->dev)) 1087f2753ddbSJohannes Berg continue; 1088f2753ddbSJohannes Berg switch (sdata->vif.type) { 1089f2753ddbSJohannes Berg case NL80211_IFTYPE_STATION: 1090f2753ddbSJohannes Berg /* disable beacon change bits */ 10912d0ddec5SJohannes Berg changed &= ~(BSS_CHANGED_BEACON | 10922d0ddec5SJohannes Berg BSS_CHANGED_BEACON_ENABLED); 1093f2753ddbSJohannes Berg /* fall through */ 1094f2753ddbSJohannes Berg case NL80211_IFTYPE_ADHOC: 1095f2753ddbSJohannes Berg case NL80211_IFTYPE_AP: 1096f2753ddbSJohannes Berg case NL80211_IFTYPE_MESH_POINT: 10972d0ddec5SJohannes Berg ieee80211_bss_info_change_notify(sdata, changed); 1098f2753ddbSJohannes Berg break; 1099f2753ddbSJohannes Berg case NL80211_IFTYPE_WDS: 1100f2753ddbSJohannes Berg break; 1101f2753ddbSJohannes Berg case NL80211_IFTYPE_AP_VLAN: 1102f2753ddbSJohannes Berg case NL80211_IFTYPE_MONITOR: 1103f2753ddbSJohannes Berg /* ignore virtual */ 1104f2753ddbSJohannes Berg break; 1105f2753ddbSJohannes Berg case NL80211_IFTYPE_UNSPECIFIED: 1106f2753ddbSJohannes Berg case __NL80211_IFTYPE_AFTER_LAST: 1107f2753ddbSJohannes Berg WARN_ON(1); 1108f2753ddbSJohannes Berg break; 1109f2753ddbSJohannes Berg } 1110f2753ddbSJohannes Berg } 1111f2753ddbSJohannes Berg 1112f2753ddbSJohannes Berg /* add back keys */ 1113f2753ddbSJohannes Berg list_for_each_entry(sdata, &local->interfaces, list) 1114f2753ddbSJohannes Berg if (netif_running(sdata->dev)) 1115f2753ddbSJohannes Berg ieee80211_enable_keys(sdata); 1116f2753ddbSJohannes Berg 1117f2753ddbSJohannes Berg ieee80211_wake_queues_by_reason(hw, 1118f2753ddbSJohannes Berg IEEE80211_QUEUE_STOP_REASON_SUSPEND); 1119f2753ddbSJohannes Berg 11205bb644a0SJohannes Berg /* 11215bb644a0SJohannes Berg * If this is for hw restart things are still running. 11225bb644a0SJohannes Berg * We may want to change that later, however. 11235bb644a0SJohannes Berg */ 11245bb644a0SJohannes Berg if (!from_suspend) 11255bb644a0SJohannes Berg return 0; 11265bb644a0SJohannes Berg 11275bb644a0SJohannes Berg #ifdef CONFIG_PM 11285bb644a0SJohannes Berg local->suspended = false; 11295bb644a0SJohannes Berg 11305bb644a0SJohannes Berg list_for_each_entry(sdata, &local->interfaces, list) { 11315bb644a0SJohannes Berg switch(sdata->vif.type) { 11325bb644a0SJohannes Berg case NL80211_IFTYPE_STATION: 11335bb644a0SJohannes Berg ieee80211_sta_restart(sdata); 11345bb644a0SJohannes Berg break; 11355bb644a0SJohannes Berg case NL80211_IFTYPE_ADHOC: 11365bb644a0SJohannes Berg ieee80211_ibss_restart(sdata); 11375bb644a0SJohannes Berg break; 11385bb644a0SJohannes Berg case NL80211_IFTYPE_MESH_POINT: 11395bb644a0SJohannes Berg ieee80211_mesh_restart(sdata); 11405bb644a0SJohannes Berg break; 11415bb644a0SJohannes Berg default: 11425bb644a0SJohannes Berg break; 11435bb644a0SJohannes Berg } 11445bb644a0SJohannes Berg } 11455bb644a0SJohannes Berg 11465bb644a0SJohannes Berg add_timer(&local->sta_cleanup); 11475bb644a0SJohannes Berg 11485bb644a0SJohannes Berg spin_lock_irqsave(&local->sta_lock, flags); 11495bb644a0SJohannes Berg list_for_each_entry(sta, &local->sta_list, list) 11505bb644a0SJohannes Berg mesh_plink_restart(sta); 11515bb644a0SJohannes Berg spin_unlock_irqrestore(&local->sta_lock, flags); 11525bb644a0SJohannes Berg #else 11535bb644a0SJohannes Berg WARN_ON(1); 11545bb644a0SJohannes Berg #endif 1155f2753ddbSJohannes Berg return 0; 1156f2753ddbSJohannes Berg } 115742935ecaSLuis R. Rodriguez 1158