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/bitmap.h> 22d91f36dbSJohannes Berg #include <linux/crc32.h> 23881d966bSEric W. Biederman #include <net/net_namespace.h> 24c2d1560aSJohannes Berg #include <net/cfg80211.h> 25dabeb344SJohannes Berg #include <net/rtnetlink.h> 26c2d1560aSJohannes Berg 27c2d1560aSJohannes Berg #include "ieee80211_i.h" 2824487981SJohannes Berg #include "driver-ops.h" 292c8dccc7SJohannes Berg #include "rate.h" 30ee385855SLuis Carlos Cobo #include "mesh.h" 31c2d1560aSJohannes Berg #include "wme.h" 32f2753ddbSJohannes Berg #include "led.h" 33fffd0934SJohannes Berg #include "wep.h" 34c2d1560aSJohannes Berg 35c2d1560aSJohannes Berg /* privid for wiphys to determine whether they belong to us or not */ 36c2d1560aSJohannes Berg void *mac80211_wiphy_privid = &mac80211_wiphy_privid; 37c2d1560aSJohannes Berg 389a95371aSLuis R. Rodriguez struct ieee80211_hw *wiphy_to_ieee80211_hw(struct wiphy *wiphy) 399a95371aSLuis R. Rodriguez { 409a95371aSLuis R. Rodriguez struct ieee80211_local *local; 419a95371aSLuis R. Rodriguez BUG_ON(!wiphy); 429a95371aSLuis R. Rodriguez 439a95371aSLuis R. Rodriguez local = wiphy_priv(wiphy); 449a95371aSLuis R. Rodriguez return &local->hw; 459a95371aSLuis R. Rodriguez } 469a95371aSLuis R. Rodriguez EXPORT_SYMBOL(wiphy_to_ieee80211_hw); 47c2d1560aSJohannes Berg 4871364716SRon Rindjunsky u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, 4905c914feSJohannes Berg enum nl80211_iftype type) 50c2d1560aSJohannes Berg { 51a494bb1cSHarvey Harrison __le16 fc = hdr->frame_control; 52c2d1560aSJohannes Berg 5398f0b0a3SRon Rindjunsky /* drop ACK/CTS frames and incorrect hdr len (ctrl) */ 5498f0b0a3SRon Rindjunsky if (len < 16) 55c2d1560aSJohannes Berg return NULL; 56c2d1560aSJohannes Berg 57a494bb1cSHarvey Harrison if (ieee80211_is_data(fc)) { 5898f0b0a3SRon Rindjunsky if (len < 24) /* drop incorrect hdr len (data) */ 5998f0b0a3SRon Rindjunsky return NULL; 60a494bb1cSHarvey Harrison 61a494bb1cSHarvey Harrison if (ieee80211_has_a4(fc)) 62c2d1560aSJohannes Berg return NULL; 63a494bb1cSHarvey Harrison if (ieee80211_has_tods(fc)) 64a494bb1cSHarvey Harrison return hdr->addr1; 65a494bb1cSHarvey Harrison if (ieee80211_has_fromds(fc)) 66c2d1560aSJohannes Berg return hdr->addr2; 67a494bb1cSHarvey Harrison 68c2d1560aSJohannes Berg return hdr->addr3; 69c2d1560aSJohannes Berg } 70a494bb1cSHarvey Harrison 71a494bb1cSHarvey Harrison if (ieee80211_is_mgmt(fc)) { 7298f0b0a3SRon Rindjunsky if (len < 24) /* drop incorrect hdr len (mgmt) */ 7398f0b0a3SRon Rindjunsky return NULL; 74c2d1560aSJohannes Berg return hdr->addr3; 75a494bb1cSHarvey Harrison } 76a494bb1cSHarvey Harrison 77a494bb1cSHarvey Harrison if (ieee80211_is_ctl(fc)) { 78a494bb1cSHarvey Harrison if(ieee80211_is_pspoll(fc)) 79c2d1560aSJohannes Berg return hdr->addr1; 80a494bb1cSHarvey Harrison 81a494bb1cSHarvey Harrison if (ieee80211_is_back_req(fc)) { 8271364716SRon Rindjunsky switch (type) { 8305c914feSJohannes Berg case NL80211_IFTYPE_STATION: 8471364716SRon Rindjunsky return hdr->addr2; 8505c914feSJohannes Berg case NL80211_IFTYPE_AP: 8605c914feSJohannes Berg case NL80211_IFTYPE_AP_VLAN: 8771364716SRon Rindjunsky return hdr->addr1; 8871364716SRon Rindjunsky default: 89a494bb1cSHarvey Harrison break; /* fall through to the return */ 9071364716SRon Rindjunsky } 9171364716SRon Rindjunsky } 92c2d1560aSJohannes Berg } 93c2d1560aSJohannes Berg 94c2d1560aSJohannes Berg return NULL; 95c2d1560aSJohannes Berg } 96c2d1560aSJohannes Berg 975cf121c3SJohannes Berg void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx) 98c2d1560aSJohannes Berg { 992de8e0d9SJohannes Berg struct sk_buff *skb = tx->skb; 1002de8e0d9SJohannes Berg struct ieee80211_hdr *hdr; 101c2d1560aSJohannes Berg 1022de8e0d9SJohannes Berg do { 1032de8e0d9SJohannes Berg hdr = (struct ieee80211_hdr *) skb->data; 104c2d1560aSJohannes Berg hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); 1052de8e0d9SJohannes Berg } while ((skb = skb->next)); 106c2d1560aSJohannes Berg } 107c2d1560aSJohannes Berg 108c2d1560aSJohannes Berg int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, 109c2d1560aSJohannes Berg int rate, int erp, int short_preamble) 110c2d1560aSJohannes Berg { 111c2d1560aSJohannes Berg int dur; 112c2d1560aSJohannes Berg 113c2d1560aSJohannes Berg /* calculate duration (in microseconds, rounded up to next higher 114c2d1560aSJohannes Berg * integer if it includes a fractional microsecond) to send frame of 115c2d1560aSJohannes Berg * len bytes (does not include FCS) at the given rate. Duration will 116c2d1560aSJohannes Berg * also include SIFS. 117c2d1560aSJohannes Berg * 118c2d1560aSJohannes Berg * rate is in 100 kbps, so divident is multiplied by 10 in the 119c2d1560aSJohannes Berg * DIV_ROUND_UP() operations. 120c2d1560aSJohannes Berg */ 121c2d1560aSJohannes Berg 1228318d78aSJohannes Berg if (local->hw.conf.channel->band == IEEE80211_BAND_5GHZ || erp) { 123c2d1560aSJohannes Berg /* 124c2d1560aSJohannes Berg * OFDM: 125c2d1560aSJohannes Berg * 126c2d1560aSJohannes Berg * N_DBPS = DATARATE x 4 127c2d1560aSJohannes Berg * N_SYM = Ceiling((16+8xLENGTH+6) / N_DBPS) 128c2d1560aSJohannes Berg * (16 = SIGNAL time, 6 = tail bits) 129c2d1560aSJohannes Berg * TXTIME = T_PREAMBLE + T_SIGNAL + T_SYM x N_SYM + Signal Ext 130c2d1560aSJohannes Berg * 131c2d1560aSJohannes Berg * T_SYM = 4 usec 132c2d1560aSJohannes Berg * 802.11a - 17.5.2: aSIFSTime = 16 usec 133c2d1560aSJohannes Berg * 802.11g - 19.8.4: aSIFSTime = 10 usec + 134c2d1560aSJohannes Berg * signal ext = 6 usec 135c2d1560aSJohannes Berg */ 136c2d1560aSJohannes Berg dur = 16; /* SIFS + signal ext */ 137c2d1560aSJohannes Berg dur += 16; /* 17.3.2.3: T_PREAMBLE = 16 usec */ 138c2d1560aSJohannes Berg dur += 4; /* 17.3.2.3: T_SIGNAL = 4 usec */ 139c2d1560aSJohannes Berg dur += 4 * DIV_ROUND_UP((16 + 8 * (len + 4) + 6) * 10, 140c2d1560aSJohannes Berg 4 * rate); /* T_SYM x N_SYM */ 141c2d1560aSJohannes Berg } else { 142c2d1560aSJohannes Berg /* 143c2d1560aSJohannes Berg * 802.11b or 802.11g with 802.11b compatibility: 144c2d1560aSJohannes Berg * 18.3.4: TXTIME = PreambleLength + PLCPHeaderTime + 145c2d1560aSJohannes Berg * Ceiling(((LENGTH+PBCC)x8)/DATARATE). PBCC=0. 146c2d1560aSJohannes Berg * 147c2d1560aSJohannes Berg * 802.11 (DS): 15.3.3, 802.11b: 18.3.4 148c2d1560aSJohannes Berg * aSIFSTime = 10 usec 149c2d1560aSJohannes Berg * aPreambleLength = 144 usec or 72 usec with short preamble 150c2d1560aSJohannes Berg * aPLCPHeaderLength = 48 usec or 24 usec with short preamble 151c2d1560aSJohannes Berg */ 152c2d1560aSJohannes Berg dur = 10; /* aSIFSTime = 10 usec */ 153c2d1560aSJohannes Berg dur += short_preamble ? (72 + 24) : (144 + 48); 154c2d1560aSJohannes Berg 155c2d1560aSJohannes Berg dur += DIV_ROUND_UP(8 * (len + 4) * 10, rate); 156c2d1560aSJohannes Berg } 157c2d1560aSJohannes Berg 158c2d1560aSJohannes Berg return dur; 159c2d1560aSJohannes Berg } 160c2d1560aSJohannes Berg 161c2d1560aSJohannes Berg /* Exported duration function for driver use */ 16232bfd35dSJohannes Berg __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, 16332bfd35dSJohannes Berg struct ieee80211_vif *vif, 1648318d78aSJohannes Berg size_t frame_len, 1658318d78aSJohannes Berg struct ieee80211_rate *rate) 166c2d1560aSJohannes Berg { 167c2d1560aSJohannes Berg struct ieee80211_local *local = hw_to_local(hw); 16825d834e1SJohannes Berg struct ieee80211_sub_if_data *sdata; 169c2d1560aSJohannes Berg u16 dur; 170c2d1560aSJohannes Berg int erp; 17125d834e1SJohannes Berg bool short_preamble = false; 172c2d1560aSJohannes Berg 1738318d78aSJohannes Berg erp = 0; 17425d834e1SJohannes Berg if (vif) { 17525d834e1SJohannes Berg sdata = vif_to_sdata(vif); 176bda3933aSJohannes Berg short_preamble = sdata->vif.bss_conf.use_short_preamble; 1778318d78aSJohannes Berg if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) 1788318d78aSJohannes Berg erp = rate->flags & IEEE80211_RATE_ERP_G; 17925d834e1SJohannes Berg } 1808318d78aSJohannes Berg 1818318d78aSJohannes Berg dur = ieee80211_frame_duration(local, frame_len, rate->bitrate, erp, 18225d834e1SJohannes Berg short_preamble); 183c2d1560aSJohannes Berg 184c2d1560aSJohannes Berg return cpu_to_le16(dur); 185c2d1560aSJohannes Berg } 186c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_generic_frame_duration); 187c2d1560aSJohannes Berg 18832bfd35dSJohannes Berg __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, 18932bfd35dSJohannes Berg struct ieee80211_vif *vif, size_t frame_len, 190e039fa4aSJohannes Berg const struct ieee80211_tx_info *frame_txctl) 191c2d1560aSJohannes Berg { 192c2d1560aSJohannes Berg struct ieee80211_local *local = hw_to_local(hw); 193c2d1560aSJohannes Berg struct ieee80211_rate *rate; 19425d834e1SJohannes Berg struct ieee80211_sub_if_data *sdata; 195471b3efdSJohannes Berg bool short_preamble; 196c2d1560aSJohannes Berg int erp; 197c2d1560aSJohannes Berg u16 dur; 1982e92e6f2SJohannes Berg struct ieee80211_supported_band *sband; 1992e92e6f2SJohannes Berg 2002e92e6f2SJohannes Berg sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; 201c2d1560aSJohannes Berg 20225d834e1SJohannes Berg short_preamble = false; 2037e9ed188SDaniel Drake 204e039fa4aSJohannes Berg rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx]; 2058318d78aSJohannes Berg 2068318d78aSJohannes Berg erp = 0; 20725d834e1SJohannes Berg if (vif) { 20825d834e1SJohannes Berg sdata = vif_to_sdata(vif); 209bda3933aSJohannes Berg short_preamble = sdata->vif.bss_conf.use_short_preamble; 2108318d78aSJohannes Berg if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) 2118318d78aSJohannes Berg erp = rate->flags & IEEE80211_RATE_ERP_G; 21225d834e1SJohannes Berg } 213c2d1560aSJohannes Berg 214c2d1560aSJohannes Berg /* CTS duration */ 2158318d78aSJohannes Berg dur = ieee80211_frame_duration(local, 10, rate->bitrate, 216c2d1560aSJohannes Berg erp, short_preamble); 217c2d1560aSJohannes Berg /* Data frame duration */ 2188318d78aSJohannes Berg dur += ieee80211_frame_duration(local, frame_len, rate->bitrate, 219c2d1560aSJohannes Berg erp, short_preamble); 220c2d1560aSJohannes Berg /* ACK duration */ 2218318d78aSJohannes Berg dur += ieee80211_frame_duration(local, 10, rate->bitrate, 222c2d1560aSJohannes Berg erp, short_preamble); 223c2d1560aSJohannes Berg 224c2d1560aSJohannes Berg return cpu_to_le16(dur); 225c2d1560aSJohannes Berg } 226c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_rts_duration); 227c2d1560aSJohannes Berg 22832bfd35dSJohannes Berg __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, 22932bfd35dSJohannes Berg struct ieee80211_vif *vif, 230c2d1560aSJohannes Berg size_t frame_len, 231e039fa4aSJohannes Berg const struct ieee80211_tx_info *frame_txctl) 232c2d1560aSJohannes Berg { 233c2d1560aSJohannes Berg struct ieee80211_local *local = hw_to_local(hw); 234c2d1560aSJohannes Berg struct ieee80211_rate *rate; 23525d834e1SJohannes Berg struct ieee80211_sub_if_data *sdata; 236471b3efdSJohannes Berg bool short_preamble; 237c2d1560aSJohannes Berg int erp; 238c2d1560aSJohannes Berg u16 dur; 2392e92e6f2SJohannes Berg struct ieee80211_supported_band *sband; 2402e92e6f2SJohannes Berg 2412e92e6f2SJohannes Berg sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; 242c2d1560aSJohannes Berg 24325d834e1SJohannes Berg short_preamble = false; 2447e9ed188SDaniel Drake 245e039fa4aSJohannes Berg rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx]; 2468318d78aSJohannes Berg erp = 0; 24725d834e1SJohannes Berg if (vif) { 24825d834e1SJohannes Berg sdata = vif_to_sdata(vif); 249bda3933aSJohannes Berg short_preamble = sdata->vif.bss_conf.use_short_preamble; 2508318d78aSJohannes Berg if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) 2518318d78aSJohannes Berg erp = rate->flags & IEEE80211_RATE_ERP_G; 25225d834e1SJohannes Berg } 253c2d1560aSJohannes Berg 254c2d1560aSJohannes Berg /* Data frame duration */ 2558318d78aSJohannes Berg dur = ieee80211_frame_duration(local, frame_len, rate->bitrate, 256c2d1560aSJohannes Berg erp, short_preamble); 257e039fa4aSJohannes Berg if (!(frame_txctl->flags & IEEE80211_TX_CTL_NO_ACK)) { 258c2d1560aSJohannes Berg /* ACK duration */ 2598318d78aSJohannes Berg dur += ieee80211_frame_duration(local, 10, rate->bitrate, 260c2d1560aSJohannes Berg erp, short_preamble); 261c2d1560aSJohannes Berg } 262c2d1560aSJohannes Berg 263c2d1560aSJohannes Berg return cpu_to_le16(dur); 264c2d1560aSJohannes Berg } 265c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_ctstoself_duration); 266c2d1560aSJohannes Berg 267ce7c9111SKalle Valo static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, 268ce7c9111SKalle Valo enum queue_stop_reason reason) 269c2d1560aSJohannes Berg { 270c2d1560aSJohannes Berg struct ieee80211_local *local = hw_to_local(hw); 271cf0277e7SJohannes Berg struct ieee80211_sub_if_data *sdata; 272c2d1560aSJohannes Berg 273b5878a2dSJohannes Berg trace_wake_queue(local, queue, reason); 274b5878a2dSJohannes Berg 275e4e72fb4SJohannes Berg if (WARN_ON(queue >= hw->queues)) 27696f5e66eSJohannes Berg return; 27796f5e66eSJohannes Berg 278ce7c9111SKalle Valo __clear_bit(reason, &local->queue_stop_reasons[queue]); 279ce7c9111SKalle Valo 280ce7c9111SKalle Valo if (local->queue_stop_reasons[queue] != 0) 281ce7c9111SKalle Valo /* someone still has this queue stopped */ 282ce7c9111SKalle Valo return; 283ce7c9111SKalle Valo 2847236fe29SJohannes Berg if (skb_queue_empty(&local->pending[queue])) { 285cf0277e7SJohannes Berg rcu_read_lock(); 2865b714c6aSJohannes Berg list_for_each_entry_rcu(sdata, &local->interfaces, list) { 2875b714c6aSJohannes Berg if (test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state)) 2885b714c6aSJohannes Berg continue; 2892337db8dSJohannes Berg netif_wake_subqueue(sdata->dev, queue); 2905b714c6aSJohannes Berg } 291cf0277e7SJohannes Berg rcu_read_unlock(); 2927236fe29SJohannes Berg } else 2937236fe29SJohannes Berg tasklet_schedule(&local->tx_pending_tasklet); 294c2d1560aSJohannes Berg } 295ce7c9111SKalle Valo 29696f5e66eSJohannes Berg void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, 297ce7c9111SKalle Valo enum queue_stop_reason reason) 298ce7c9111SKalle Valo { 299ce7c9111SKalle Valo struct ieee80211_local *local = hw_to_local(hw); 300ce7c9111SKalle Valo unsigned long flags; 301ce7c9111SKalle Valo 302ce7c9111SKalle Valo spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 303ce7c9111SKalle Valo __ieee80211_wake_queue(hw, queue, reason); 304ce7c9111SKalle Valo spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 305ce7c9111SKalle Valo } 306ce7c9111SKalle Valo 307ce7c9111SKalle Valo void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue) 308ce7c9111SKalle Valo { 309ce7c9111SKalle Valo ieee80211_wake_queue_by_reason(hw, queue, 310ce7c9111SKalle Valo IEEE80211_QUEUE_STOP_REASON_DRIVER); 311ce7c9111SKalle Valo } 312c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_wake_queue); 313c2d1560aSJohannes Berg 314ce7c9111SKalle Valo static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, 315ce7c9111SKalle Valo enum queue_stop_reason reason) 316c2d1560aSJohannes Berg { 317c2d1560aSJohannes Berg struct ieee80211_local *local = hw_to_local(hw); 318cf0277e7SJohannes Berg struct ieee80211_sub_if_data *sdata; 319c2d1560aSJohannes Berg 320b5878a2dSJohannes Berg trace_stop_queue(local, queue, reason); 321b5878a2dSJohannes Berg 322e4e72fb4SJohannes Berg if (WARN_ON(queue >= hw->queues)) 32396f5e66eSJohannes Berg return; 32496f5e66eSJohannes Berg 3252a577d98SJohannes Berg __set_bit(reason, &local->queue_stop_reasons[queue]); 326cf0277e7SJohannes Berg 327cf0277e7SJohannes Berg rcu_read_lock(); 328cf0277e7SJohannes Berg list_for_each_entry_rcu(sdata, &local->interfaces, list) 3292337db8dSJohannes Berg netif_stop_subqueue(sdata->dev, queue); 330cf0277e7SJohannes Berg rcu_read_unlock(); 331c2d1560aSJohannes Berg } 332ce7c9111SKalle Valo 33396f5e66eSJohannes Berg void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, 334ce7c9111SKalle Valo enum queue_stop_reason reason) 335ce7c9111SKalle Valo { 336ce7c9111SKalle Valo struct ieee80211_local *local = hw_to_local(hw); 337ce7c9111SKalle Valo unsigned long flags; 338ce7c9111SKalle Valo 339ce7c9111SKalle Valo spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 340ce7c9111SKalle Valo __ieee80211_stop_queue(hw, queue, reason); 341ce7c9111SKalle Valo spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 342ce7c9111SKalle Valo } 343ce7c9111SKalle Valo 344ce7c9111SKalle Valo void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue) 345ce7c9111SKalle Valo { 346ce7c9111SKalle Valo ieee80211_stop_queue_by_reason(hw, queue, 347ce7c9111SKalle Valo IEEE80211_QUEUE_STOP_REASON_DRIVER); 348ce7c9111SKalle Valo } 349c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_stop_queue); 350c2d1560aSJohannes Berg 3518f77f384SJohannes Berg void ieee80211_add_pending_skb(struct ieee80211_local *local, 3528f77f384SJohannes Berg struct sk_buff *skb) 3538f77f384SJohannes Berg { 3548f77f384SJohannes Berg struct ieee80211_hw *hw = &local->hw; 3558f77f384SJohannes Berg unsigned long flags; 3568f77f384SJohannes Berg int queue = skb_get_queue_mapping(skb); 357a7bc376cSJohannes Berg struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 358a7bc376cSJohannes Berg 359a7bc376cSJohannes Berg if (WARN_ON(!info->control.vif)) { 3600819663dSRoel Kluin kfree_skb(skb); 361a7bc376cSJohannes Berg return; 362a7bc376cSJohannes Berg } 3638f77f384SJohannes Berg 3648f77f384SJohannes Berg spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 3658f77f384SJohannes Berg __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD); 3663b8d81e0SJohannes Berg __skb_queue_tail(&local->pending[queue], skb); 3678f77f384SJohannes Berg __ieee80211_wake_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD); 3688f77f384SJohannes Berg spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 3698f77f384SJohannes Berg } 3708f77f384SJohannes Berg 37150a9432dSJohannes Berg int ieee80211_add_pending_skbs_fn(struct ieee80211_local *local, 37250a9432dSJohannes Berg struct sk_buff_head *skbs, 37350a9432dSJohannes Berg void (*fn)(void *data), void *data) 3748f77f384SJohannes Berg { 3758f77f384SJohannes Berg struct ieee80211_hw *hw = &local->hw; 3768f77f384SJohannes Berg struct sk_buff *skb; 3778f77f384SJohannes Berg unsigned long flags; 3788f77f384SJohannes Berg int queue, ret = 0, i; 3798f77f384SJohannes Berg 3808f77f384SJohannes Berg spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 3818f77f384SJohannes Berg for (i = 0; i < hw->queues; i++) 3828f77f384SJohannes Berg __ieee80211_stop_queue(hw, i, 3838f77f384SJohannes Berg IEEE80211_QUEUE_STOP_REASON_SKB_ADD); 3848f77f384SJohannes Berg 3858f77f384SJohannes Berg while ((skb = skb_dequeue(skbs))) { 386a7bc376cSJohannes Berg struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 387a7bc376cSJohannes Berg 388a7bc376cSJohannes Berg if (WARN_ON(!info->control.vif)) { 3890819663dSRoel Kluin kfree_skb(skb); 390a7bc376cSJohannes Berg continue; 391a7bc376cSJohannes Berg } 392a7bc376cSJohannes Berg 3938f77f384SJohannes Berg ret++; 3948f77f384SJohannes Berg queue = skb_get_queue_mapping(skb); 3953b8d81e0SJohannes Berg __skb_queue_tail(&local->pending[queue], skb); 3968f77f384SJohannes Berg } 3978f77f384SJohannes Berg 39850a9432dSJohannes Berg if (fn) 39950a9432dSJohannes Berg fn(data); 40050a9432dSJohannes Berg 4013b8d81e0SJohannes Berg for (i = 0; i < hw->queues; i++) 4028f77f384SJohannes Berg __ieee80211_wake_queue(hw, i, 4038f77f384SJohannes Berg IEEE80211_QUEUE_STOP_REASON_SKB_ADD); 4048f77f384SJohannes Berg spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 4058f77f384SJohannes Berg 4068f77f384SJohannes Berg return ret; 4078f77f384SJohannes Berg } 4088f77f384SJohannes Berg 40950a9432dSJohannes Berg int ieee80211_add_pending_skbs(struct ieee80211_local *local, 41050a9432dSJohannes Berg struct sk_buff_head *skbs) 41150a9432dSJohannes Berg { 41250a9432dSJohannes Berg return ieee80211_add_pending_skbs_fn(local, skbs, NULL, NULL); 41350a9432dSJohannes Berg } 41450a9432dSJohannes Berg 415ce7c9111SKalle Valo void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, 416ce7c9111SKalle Valo enum queue_stop_reason reason) 417c2d1560aSJohannes Berg { 418ce7c9111SKalle Valo struct ieee80211_local *local = hw_to_local(hw); 419ce7c9111SKalle Valo unsigned long flags; 420c2d1560aSJohannes Berg int i; 421c2d1560aSJohannes Berg 422ce7c9111SKalle Valo spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 423ce7c9111SKalle Valo 42496f5e66eSJohannes Berg for (i = 0; i < hw->queues; i++) 425ce7c9111SKalle Valo __ieee80211_stop_queue(hw, i, reason); 426ce7c9111SKalle Valo 427ce7c9111SKalle Valo spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 428ce7c9111SKalle Valo } 429ce7c9111SKalle Valo 430ce7c9111SKalle Valo void ieee80211_stop_queues(struct ieee80211_hw *hw) 431ce7c9111SKalle Valo { 432ce7c9111SKalle Valo ieee80211_stop_queues_by_reason(hw, 433ce7c9111SKalle Valo IEEE80211_QUEUE_STOP_REASON_DRIVER); 434c2d1560aSJohannes Berg } 435c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_stop_queues); 436c2d1560aSJohannes Berg 43792ab8535STomas Winkler int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue) 43892ab8535STomas Winkler { 43992ab8535STomas Winkler struct ieee80211_local *local = hw_to_local(hw); 4403b8d81e0SJohannes Berg unsigned long flags; 4413b8d81e0SJohannes Berg int ret; 44296f5e66eSJohannes Berg 443e4e72fb4SJohannes Berg if (WARN_ON(queue >= hw->queues)) 44496f5e66eSJohannes Berg return true; 44596f5e66eSJohannes Berg 4463b8d81e0SJohannes Berg spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 4473b8d81e0SJohannes Berg ret = !!local->queue_stop_reasons[queue]; 4483b8d81e0SJohannes Berg spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 4493b8d81e0SJohannes Berg return ret; 45092ab8535STomas Winkler } 45192ab8535STomas Winkler EXPORT_SYMBOL(ieee80211_queue_stopped); 45292ab8535STomas Winkler 453ce7c9111SKalle Valo void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, 454ce7c9111SKalle Valo enum queue_stop_reason reason) 455c2d1560aSJohannes Berg { 456ce7c9111SKalle Valo struct ieee80211_local *local = hw_to_local(hw); 457ce7c9111SKalle Valo unsigned long flags; 458c2d1560aSJohannes Berg int i; 459c2d1560aSJohannes Berg 460ce7c9111SKalle Valo spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 461ce7c9111SKalle Valo 462e4e72fb4SJohannes Berg for (i = 0; i < hw->queues; i++) 463ce7c9111SKalle Valo __ieee80211_wake_queue(hw, i, reason); 464ce7c9111SKalle Valo 465ce7c9111SKalle Valo spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 466ce7c9111SKalle Valo } 467ce7c9111SKalle Valo 468ce7c9111SKalle Valo void ieee80211_wake_queues(struct ieee80211_hw *hw) 469ce7c9111SKalle Valo { 470ce7c9111SKalle Valo ieee80211_wake_queues_by_reason(hw, IEEE80211_QUEUE_STOP_REASON_DRIVER); 471c2d1560aSJohannes Berg } 472c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_wake_queues); 473dabeb344SJohannes Berg 47432bfd35dSJohannes Berg void ieee80211_iterate_active_interfaces( 47532bfd35dSJohannes Berg struct ieee80211_hw *hw, 476dabeb344SJohannes Berg void (*iterator)(void *data, u8 *mac, 47732bfd35dSJohannes Berg struct ieee80211_vif *vif), 478dabeb344SJohannes Berg void *data) 479dabeb344SJohannes Berg { 480dabeb344SJohannes Berg struct ieee80211_local *local = hw_to_local(hw); 481dabeb344SJohannes Berg struct ieee80211_sub_if_data *sdata; 482dabeb344SJohannes Berg 483c771c9d8SJohannes Berg mutex_lock(&local->iflist_mtx); 4842f561febSIvo van Doorn 4852f561febSIvo van Doorn list_for_each_entry(sdata, &local->interfaces, list) { 4862f561febSIvo van Doorn switch (sdata->vif.type) { 48705c914feSJohannes Berg case NL80211_IFTYPE_MONITOR: 48805c914feSJohannes Berg case NL80211_IFTYPE_AP_VLAN: 4892f561febSIvo van Doorn continue; 4902ca27bcfSJohannes Berg default: 4912f561febSIvo van Doorn break; 4922f561febSIvo van Doorn } 4939607e6b6SJohannes Berg if (ieee80211_sdata_running(sdata)) 49447846c9bSJohannes Berg iterator(data, sdata->vif.addr, 4952f561febSIvo van Doorn &sdata->vif); 4962f561febSIvo van Doorn } 4972f561febSIvo van Doorn 498c771c9d8SJohannes Berg mutex_unlock(&local->iflist_mtx); 4992f561febSIvo van Doorn } 5002f561febSIvo van Doorn EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces); 5012f561febSIvo van Doorn 5022f561febSIvo van Doorn void ieee80211_iterate_active_interfaces_atomic( 5032f561febSIvo van Doorn struct ieee80211_hw *hw, 5042f561febSIvo van Doorn void (*iterator)(void *data, u8 *mac, 5052f561febSIvo van Doorn struct ieee80211_vif *vif), 5062f561febSIvo van Doorn void *data) 5072f561febSIvo van Doorn { 5082f561febSIvo van Doorn struct ieee80211_local *local = hw_to_local(hw); 5092f561febSIvo van Doorn struct ieee80211_sub_if_data *sdata; 5102f561febSIvo van Doorn 511e38bad47SJohannes Berg rcu_read_lock(); 512dabeb344SJohannes Berg 513e38bad47SJohannes Berg list_for_each_entry_rcu(sdata, &local->interfaces, list) { 51451fb61e7SJohannes Berg switch (sdata->vif.type) { 51505c914feSJohannes Berg case NL80211_IFTYPE_MONITOR: 51605c914feSJohannes Berg case NL80211_IFTYPE_AP_VLAN: 517dabeb344SJohannes Berg continue; 5182ca27bcfSJohannes Berg default: 519dabeb344SJohannes Berg break; 520dabeb344SJohannes Berg } 5219607e6b6SJohannes Berg if (ieee80211_sdata_running(sdata)) 52247846c9bSJohannes Berg iterator(data, sdata->vif.addr, 52332bfd35dSJohannes Berg &sdata->vif); 524dabeb344SJohannes Berg } 525e38bad47SJohannes Berg 526e38bad47SJohannes Berg rcu_read_unlock(); 527dabeb344SJohannes Berg } 5282f561febSIvo van Doorn EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic); 52937ffc8daSJohannes Berg 53042935ecaSLuis R. Rodriguez /* 53142935ecaSLuis R. Rodriguez * Nothing should have been stuffed into the workqueue during 53242935ecaSLuis R. Rodriguez * the suspend->resume cycle. If this WARN is seen then there 53342935ecaSLuis R. Rodriguez * is a bug with either the driver suspend or something in 53442935ecaSLuis R. Rodriguez * mac80211 stuffing into the workqueue which we haven't yet 53542935ecaSLuis R. Rodriguez * cleared during mac80211's suspend cycle. 53642935ecaSLuis R. Rodriguez */ 53742935ecaSLuis R. Rodriguez static bool ieee80211_can_queue_work(struct ieee80211_local *local) 53842935ecaSLuis R. Rodriguez { 539ceb99fe0SJohannes Berg if (WARN(local->suspended && !local->resuming, 540ceb99fe0SJohannes Berg "queueing ieee80211 work while going to suspend\n")) 54142935ecaSLuis R. Rodriguez return false; 54242935ecaSLuis R. Rodriguez 54342935ecaSLuis R. Rodriguez return true; 54442935ecaSLuis R. Rodriguez } 54542935ecaSLuis R. Rodriguez 54642935ecaSLuis R. Rodriguez void ieee80211_queue_work(struct ieee80211_hw *hw, struct work_struct *work) 54742935ecaSLuis R. Rodriguez { 54842935ecaSLuis R. Rodriguez struct ieee80211_local *local = hw_to_local(hw); 54942935ecaSLuis R. Rodriguez 55042935ecaSLuis R. Rodriguez if (!ieee80211_can_queue_work(local)) 55142935ecaSLuis R. Rodriguez return; 55242935ecaSLuis R. Rodriguez 55342935ecaSLuis R. Rodriguez queue_work(local->workqueue, work); 55442935ecaSLuis R. Rodriguez } 55542935ecaSLuis R. Rodriguez EXPORT_SYMBOL(ieee80211_queue_work); 55642935ecaSLuis R. Rodriguez 55742935ecaSLuis R. Rodriguez void ieee80211_queue_delayed_work(struct ieee80211_hw *hw, 55842935ecaSLuis R. Rodriguez struct delayed_work *dwork, 55942935ecaSLuis R. Rodriguez unsigned long delay) 56042935ecaSLuis R. Rodriguez { 56142935ecaSLuis R. Rodriguez struct ieee80211_local *local = hw_to_local(hw); 56242935ecaSLuis R. Rodriguez 56342935ecaSLuis R. Rodriguez if (!ieee80211_can_queue_work(local)) 56442935ecaSLuis R. Rodriguez return; 56542935ecaSLuis R. Rodriguez 56642935ecaSLuis R. Rodriguez queue_delayed_work(local->workqueue, dwork, delay); 56742935ecaSLuis R. Rodriguez } 56842935ecaSLuis R. Rodriguez EXPORT_SYMBOL(ieee80211_queue_delayed_work); 56942935ecaSLuis R. Rodriguez 57037ffc8daSJohannes Berg void ieee802_11_parse_elems(u8 *start, size_t len, 57137ffc8daSJohannes Berg struct ieee802_11_elems *elems) 57237ffc8daSJohannes Berg { 573d91f36dbSJohannes Berg ieee802_11_parse_elems_crc(start, len, elems, 0, 0); 574d91f36dbSJohannes Berg } 575d91f36dbSJohannes Berg 576d91f36dbSJohannes Berg u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, 577d91f36dbSJohannes Berg struct ieee802_11_elems *elems, 578d91f36dbSJohannes Berg u64 filter, u32 crc) 579d91f36dbSJohannes Berg { 58037ffc8daSJohannes Berg size_t left = len; 58137ffc8daSJohannes Berg u8 *pos = start; 582d91f36dbSJohannes Berg bool calc_crc = filter != 0; 58337ffc8daSJohannes Berg 58437ffc8daSJohannes Berg memset(elems, 0, sizeof(*elems)); 58537ffc8daSJohannes Berg elems->ie_start = start; 58637ffc8daSJohannes Berg elems->total_len = len; 58737ffc8daSJohannes Berg 58837ffc8daSJohannes Berg while (left >= 2) { 58937ffc8daSJohannes Berg u8 id, elen; 59037ffc8daSJohannes Berg 59137ffc8daSJohannes Berg id = *pos++; 59237ffc8daSJohannes Berg elen = *pos++; 59337ffc8daSJohannes Berg left -= 2; 59437ffc8daSJohannes Berg 59537ffc8daSJohannes Berg if (elen > left) 596d91f36dbSJohannes Berg break; 597d91f36dbSJohannes Berg 5981814077fSVasanthakumar Thiagarajan if (calc_crc && id < 64 && (filter & (1ULL << id))) 599d91f36dbSJohannes Berg crc = crc32_be(crc, pos - 2, elen + 2); 60037ffc8daSJohannes Berg 60137ffc8daSJohannes Berg switch (id) { 60237ffc8daSJohannes Berg case WLAN_EID_SSID: 60337ffc8daSJohannes Berg elems->ssid = pos; 60437ffc8daSJohannes Berg elems->ssid_len = elen; 60537ffc8daSJohannes Berg break; 60637ffc8daSJohannes Berg case WLAN_EID_SUPP_RATES: 60737ffc8daSJohannes Berg elems->supp_rates = pos; 60837ffc8daSJohannes Berg elems->supp_rates_len = elen; 60937ffc8daSJohannes Berg break; 61037ffc8daSJohannes Berg case WLAN_EID_FH_PARAMS: 61137ffc8daSJohannes Berg elems->fh_params = pos; 61237ffc8daSJohannes Berg elems->fh_params_len = elen; 61337ffc8daSJohannes Berg break; 61437ffc8daSJohannes Berg case WLAN_EID_DS_PARAMS: 61537ffc8daSJohannes Berg elems->ds_params = pos; 61637ffc8daSJohannes Berg elems->ds_params_len = elen; 61737ffc8daSJohannes Berg break; 61837ffc8daSJohannes Berg case WLAN_EID_CF_PARAMS: 61937ffc8daSJohannes Berg elems->cf_params = pos; 62037ffc8daSJohannes Berg elems->cf_params_len = elen; 62137ffc8daSJohannes Berg break; 62237ffc8daSJohannes Berg case WLAN_EID_TIM: 623e7ec86f5SJohannes Berg if (elen >= sizeof(struct ieee80211_tim_ie)) { 624e7ec86f5SJohannes Berg elems->tim = (void *)pos; 62537ffc8daSJohannes Berg elems->tim_len = elen; 626e7ec86f5SJohannes Berg } 62737ffc8daSJohannes Berg break; 62837ffc8daSJohannes Berg case WLAN_EID_IBSS_PARAMS: 62937ffc8daSJohannes Berg elems->ibss_params = pos; 63037ffc8daSJohannes Berg elems->ibss_params_len = elen; 63137ffc8daSJohannes Berg break; 63237ffc8daSJohannes Berg case WLAN_EID_CHALLENGE: 63337ffc8daSJohannes Berg elems->challenge = pos; 63437ffc8daSJohannes Berg elems->challenge_len = elen; 63537ffc8daSJohannes Berg break; 636d91f36dbSJohannes Berg case WLAN_EID_VENDOR_SPECIFIC: 63737ffc8daSJohannes Berg if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 && 63837ffc8daSJohannes Berg pos[2] == 0xf2) { 63937ffc8daSJohannes Berg /* Microsoft OUI (00:50:F2) */ 640d91f36dbSJohannes Berg 641d91f36dbSJohannes Berg if (calc_crc) 642d91f36dbSJohannes Berg crc = crc32_be(crc, pos - 2, elen + 2); 643d91f36dbSJohannes Berg 64437ffc8daSJohannes Berg if (pos[3] == 1) { 64537ffc8daSJohannes Berg /* OUI Type 1 - WPA IE */ 64637ffc8daSJohannes Berg elems->wpa = pos; 64737ffc8daSJohannes Berg elems->wpa_len = elen; 64837ffc8daSJohannes Berg } else if (elen >= 5 && pos[3] == 2) { 649d91f36dbSJohannes Berg /* OUI Type 2 - WMM IE */ 65037ffc8daSJohannes Berg if (pos[4] == 0) { 65137ffc8daSJohannes Berg elems->wmm_info = pos; 65237ffc8daSJohannes Berg elems->wmm_info_len = elen; 65337ffc8daSJohannes Berg } else if (pos[4] == 1) { 65437ffc8daSJohannes Berg elems->wmm_param = pos; 65537ffc8daSJohannes Berg elems->wmm_param_len = elen; 65637ffc8daSJohannes Berg } 65737ffc8daSJohannes Berg } 65837ffc8daSJohannes Berg } 65937ffc8daSJohannes Berg break; 66037ffc8daSJohannes Berg case WLAN_EID_RSN: 66137ffc8daSJohannes Berg elems->rsn = pos; 66237ffc8daSJohannes Berg elems->rsn_len = elen; 66337ffc8daSJohannes Berg break; 66437ffc8daSJohannes Berg case WLAN_EID_ERP_INFO: 66537ffc8daSJohannes Berg elems->erp_info = pos; 66637ffc8daSJohannes Berg elems->erp_info_len = elen; 66737ffc8daSJohannes Berg break; 66837ffc8daSJohannes Berg case WLAN_EID_EXT_SUPP_RATES: 66937ffc8daSJohannes Berg elems->ext_supp_rates = pos; 67037ffc8daSJohannes Berg elems->ext_supp_rates_len = elen; 67137ffc8daSJohannes Berg break; 67237ffc8daSJohannes Berg case WLAN_EID_HT_CAPABILITY: 67309914813SJohannes Berg if (elen >= sizeof(struct ieee80211_ht_cap)) 67409914813SJohannes Berg elems->ht_cap_elem = (void *)pos; 67537ffc8daSJohannes Berg break; 676d9fe60deSJohannes Berg case WLAN_EID_HT_INFORMATION: 677d9fe60deSJohannes Berg if (elen >= sizeof(struct ieee80211_ht_info)) 67809914813SJohannes Berg elems->ht_info_elem = (void *)pos; 67937ffc8daSJohannes Berg break; 68037ffc8daSJohannes Berg case WLAN_EID_MESH_ID: 68137ffc8daSJohannes Berg elems->mesh_id = pos; 68237ffc8daSJohannes Berg elems->mesh_id_len = elen; 68337ffc8daSJohannes Berg break; 68437ffc8daSJohannes Berg case WLAN_EID_MESH_CONFIG: 685136cfa28SRui Paulo if (elen >= sizeof(struct ieee80211_meshconf_ie)) 686136cfa28SRui Paulo elems->mesh_config = (void *)pos; 68737ffc8daSJohannes Berg break; 68837ffc8daSJohannes Berg case WLAN_EID_PEER_LINK: 68937ffc8daSJohannes Berg elems->peer_link = pos; 69037ffc8daSJohannes Berg elems->peer_link_len = elen; 69137ffc8daSJohannes Berg break; 69237ffc8daSJohannes Berg case WLAN_EID_PREQ: 69337ffc8daSJohannes Berg elems->preq = pos; 69437ffc8daSJohannes Berg elems->preq_len = elen; 69537ffc8daSJohannes Berg break; 69637ffc8daSJohannes Berg case WLAN_EID_PREP: 69737ffc8daSJohannes Berg elems->prep = pos; 69837ffc8daSJohannes Berg elems->prep_len = elen; 69937ffc8daSJohannes Berg break; 70037ffc8daSJohannes Berg case WLAN_EID_PERR: 70137ffc8daSJohannes Berg elems->perr = pos; 70237ffc8daSJohannes Berg elems->perr_len = elen; 70337ffc8daSJohannes Berg break; 70490a5e169SRui Paulo case WLAN_EID_RANN: 70590a5e169SRui Paulo if (elen >= sizeof(struct ieee80211_rann_ie)) 70690a5e169SRui Paulo elems->rann = (void *)pos; 70790a5e169SRui Paulo break; 70837ffc8daSJohannes Berg case WLAN_EID_CHANNEL_SWITCH: 70937ffc8daSJohannes Berg elems->ch_switch_elem = pos; 71037ffc8daSJohannes Berg elems->ch_switch_elem_len = elen; 71137ffc8daSJohannes Berg break; 71237ffc8daSJohannes Berg case WLAN_EID_QUIET: 71337ffc8daSJohannes Berg if (!elems->quiet_elem) { 71437ffc8daSJohannes Berg elems->quiet_elem = pos; 71537ffc8daSJohannes Berg elems->quiet_elem_len = elen; 71637ffc8daSJohannes Berg } 71737ffc8daSJohannes Berg elems->num_of_quiet_elem++; 71837ffc8daSJohannes Berg break; 71937ffc8daSJohannes Berg case WLAN_EID_COUNTRY: 72037ffc8daSJohannes Berg elems->country_elem = pos; 72137ffc8daSJohannes Berg elems->country_elem_len = elen; 72237ffc8daSJohannes Berg break; 72337ffc8daSJohannes Berg case WLAN_EID_PWR_CONSTRAINT: 72437ffc8daSJohannes Berg elems->pwr_constr_elem = pos; 72537ffc8daSJohannes Berg elems->pwr_constr_elem_len = elen; 72637ffc8daSJohannes Berg break; 727f797eb7eSJouni Malinen case WLAN_EID_TIMEOUT_INTERVAL: 728f797eb7eSJouni Malinen elems->timeout_int = pos; 729f797eb7eSJouni Malinen elems->timeout_int_len = elen; 73063a5ab82SJouni Malinen break; 73137ffc8daSJohannes Berg default: 73237ffc8daSJohannes Berg break; 73337ffc8daSJohannes Berg } 73437ffc8daSJohannes Berg 73537ffc8daSJohannes Berg left -= elen; 73637ffc8daSJohannes Berg pos += elen; 73737ffc8daSJohannes Berg } 738d91f36dbSJohannes Berg 739d91f36dbSJohannes Berg return crc; 74037ffc8daSJohannes Berg } 7415825fe10SJohannes Berg 7425825fe10SJohannes Berg void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata) 7435825fe10SJohannes Berg { 7445825fe10SJohannes Berg struct ieee80211_local *local = sdata->local; 7455825fe10SJohannes Berg struct ieee80211_tx_queue_params qparam; 746aa837e1dSJohannes Berg int queue; 747aa837e1dSJohannes Berg bool use_11b; 748aa837e1dSJohannes Berg int aCWmin, aCWmax; 7495825fe10SJohannes Berg 7505825fe10SJohannes Berg if (!local->ops->conf_tx) 7515825fe10SJohannes Berg return; 7525825fe10SJohannes Berg 7535825fe10SJohannes Berg memset(&qparam, 0, sizeof(qparam)); 7545825fe10SJohannes Berg 755aa837e1dSJohannes Berg use_11b = (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) && 756aa837e1dSJohannes Berg !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE); 7575825fe10SJohannes Berg 758aa837e1dSJohannes Berg for (queue = 0; queue < local_to_hw(local)->queues; queue++) { 759aa837e1dSJohannes Berg /* Set defaults according to 802.11-2007 Table 7-37 */ 760aa837e1dSJohannes Berg aCWmax = 1023; 761aa837e1dSJohannes Berg if (use_11b) 762aa837e1dSJohannes Berg aCWmin = 31; 7635825fe10SJohannes Berg else 764aa837e1dSJohannes Berg aCWmin = 15; 7655825fe10SJohannes Berg 766aa837e1dSJohannes Berg switch (queue) { 767aa837e1dSJohannes Berg case 3: /* AC_BK */ 7687ba10a8eSJohannes Berg qparam.cw_max = aCWmax; 7697ba10a8eSJohannes Berg qparam.cw_min = aCWmin; 7705825fe10SJohannes Berg qparam.txop = 0; 771aa837e1dSJohannes Berg qparam.aifs = 7; 772aa837e1dSJohannes Berg break; 773aa837e1dSJohannes Berg default: /* never happens but let's not leave undefined */ 774aa837e1dSJohannes Berg case 2: /* AC_BE */ 7757ba10a8eSJohannes Berg qparam.cw_max = aCWmax; 7767ba10a8eSJohannes Berg qparam.cw_min = aCWmin; 777aa837e1dSJohannes Berg qparam.txop = 0; 778aa837e1dSJohannes Berg qparam.aifs = 3; 779aa837e1dSJohannes Berg break; 780aa837e1dSJohannes Berg case 1: /* AC_VI */ 781aa837e1dSJohannes Berg qparam.cw_max = aCWmin; 782aa837e1dSJohannes Berg qparam.cw_min = (aCWmin + 1) / 2 - 1; 783aa837e1dSJohannes Berg if (use_11b) 784aa837e1dSJohannes Berg qparam.txop = 6016/32; 785aa837e1dSJohannes Berg else 786aa837e1dSJohannes Berg qparam.txop = 3008/32; 787aa837e1dSJohannes Berg qparam.aifs = 2; 788aa837e1dSJohannes Berg break; 789aa837e1dSJohannes Berg case 0: /* AC_VO */ 790aa837e1dSJohannes Berg qparam.cw_max = (aCWmin + 1) / 2 - 1; 791aa837e1dSJohannes Berg qparam.cw_min = (aCWmin + 1) / 4 - 1; 792aa837e1dSJohannes Berg if (use_11b) 793aa837e1dSJohannes Berg qparam.txop = 3264/32; 794aa837e1dSJohannes Berg else 795aa837e1dSJohannes Berg qparam.txop = 1504/32; 796aa837e1dSJohannes Berg qparam.aifs = 2; 797aa837e1dSJohannes Berg break; 798aa837e1dSJohannes Berg } 7995825fe10SJohannes Berg 800ab13315aSKalle Valo qparam.uapsd = false; 801ab13315aSKalle Valo 802aa837e1dSJohannes Berg drv_conf_tx(local, queue, &qparam); 803aa837e1dSJohannes Berg } 804e1b3ec1aSStanislaw Gruszka 805e1b3ec1aSStanislaw Gruszka /* after reinitialize QoS TX queues setting to default, 806e1b3ec1aSStanislaw Gruszka * disable QoS at all */ 807d9734979SSujith 808d9734979SSujith if (sdata->vif.type != NL80211_IFTYPE_MONITOR) { 809d9734979SSujith sdata->vif.bss_conf.qos = 810d9734979SSujith sdata->vif.type != NL80211_IFTYPE_STATION; 8114ced3f74SJohannes Berg ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_QOS); 8125825fe10SJohannes Berg } 813d9734979SSujith } 814e50db65cSJohannes Berg 81546900298SJohannes Berg void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, 81646900298SJohannes Berg const size_t supp_rates_len, 81746900298SJohannes Berg const u8 *supp_rates) 81846900298SJohannes Berg { 81946900298SJohannes Berg struct ieee80211_local *local = sdata->local; 82046900298SJohannes Berg int i, have_higher_than_11mbit = 0; 82146900298SJohannes Berg 82246900298SJohannes Berg /* cf. IEEE 802.11 9.2.12 */ 82346900298SJohannes Berg for (i = 0; i < supp_rates_len; i++) 82446900298SJohannes Berg if ((supp_rates[i] & 0x7f) * 5 > 110) 82546900298SJohannes Berg have_higher_than_11mbit = 1; 82646900298SJohannes Berg 82746900298SJohannes Berg if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && 82846900298SJohannes Berg have_higher_than_11mbit) 82946900298SJohannes Berg sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; 83046900298SJohannes Berg else 83146900298SJohannes Berg sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; 83246900298SJohannes Berg 83346900298SJohannes Berg ieee80211_set_wmm_default(sdata); 83446900298SJohannes Berg } 83546900298SJohannes Berg 836881d948cSJohannes Berg u32 ieee80211_mandatory_rates(struct ieee80211_local *local, 83796dd22acSJohannes Berg enum ieee80211_band band) 83896dd22acSJohannes Berg { 83996dd22acSJohannes Berg struct ieee80211_supported_band *sband; 84096dd22acSJohannes Berg struct ieee80211_rate *bitrates; 841881d948cSJohannes Berg u32 mandatory_rates; 84296dd22acSJohannes Berg enum ieee80211_rate_flags mandatory_flag; 84396dd22acSJohannes Berg int i; 84496dd22acSJohannes Berg 84596dd22acSJohannes Berg sband = local->hw.wiphy->bands[band]; 84696dd22acSJohannes Berg if (!sband) { 84796dd22acSJohannes Berg WARN_ON(1); 84896dd22acSJohannes Berg sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; 84996dd22acSJohannes Berg } 85096dd22acSJohannes Berg 85196dd22acSJohannes Berg if (band == IEEE80211_BAND_2GHZ) 85296dd22acSJohannes Berg mandatory_flag = IEEE80211_RATE_MANDATORY_B; 85396dd22acSJohannes Berg else 85496dd22acSJohannes Berg mandatory_flag = IEEE80211_RATE_MANDATORY_A; 85596dd22acSJohannes Berg 85696dd22acSJohannes Berg bitrates = sband->bitrates; 85796dd22acSJohannes Berg mandatory_rates = 0; 85896dd22acSJohannes Berg for (i = 0; i < sband->n_bitrates; i++) 85996dd22acSJohannes Berg if (bitrates[i].flags & mandatory_flag) 86096dd22acSJohannes Berg mandatory_rates |= BIT(i); 86196dd22acSJohannes Berg return mandatory_rates; 86296dd22acSJohannes Berg } 86346900298SJohannes Berg 86446900298SJohannes Berg void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, 86546900298SJohannes Berg u16 transaction, u16 auth_alg, 866fffd0934SJohannes Berg u8 *extra, size_t extra_len, const u8 *bssid, 867fffd0934SJohannes Berg const u8 *key, u8 key_len, u8 key_idx) 86846900298SJohannes Berg { 86946900298SJohannes Berg struct ieee80211_local *local = sdata->local; 87046900298SJohannes Berg struct sk_buff *skb; 87146900298SJohannes Berg struct ieee80211_mgmt *mgmt; 872fffd0934SJohannes Berg int err; 87346900298SJohannes Berg 87446900298SJohannes Berg skb = dev_alloc_skb(local->hw.extra_tx_headroom + 87565fc73acSJouni Malinen sizeof(*mgmt) + 6 + extra_len); 87646900298SJohannes Berg if (!skb) { 87746900298SJohannes Berg printk(KERN_DEBUG "%s: failed to allocate buffer for auth " 87847846c9bSJohannes Berg "frame\n", sdata->name); 87946900298SJohannes Berg return; 88046900298SJohannes Berg } 88146900298SJohannes Berg skb_reserve(skb, local->hw.extra_tx_headroom); 88246900298SJohannes Berg 88346900298SJohannes Berg mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6); 88446900298SJohannes Berg memset(mgmt, 0, 24 + 6); 88546900298SJohannes Berg mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | 88646900298SJohannes Berg IEEE80211_STYPE_AUTH); 88746900298SJohannes Berg memcpy(mgmt->da, bssid, ETH_ALEN); 88847846c9bSJohannes Berg memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); 88946900298SJohannes Berg memcpy(mgmt->bssid, bssid, ETH_ALEN); 89046900298SJohannes Berg mgmt->u.auth.auth_alg = cpu_to_le16(auth_alg); 89146900298SJohannes Berg mgmt->u.auth.auth_transaction = cpu_to_le16(transaction); 89246900298SJohannes Berg mgmt->u.auth.status_code = cpu_to_le16(0); 89346900298SJohannes Berg if (extra) 89446900298SJohannes Berg memcpy(skb_put(skb, extra_len), extra, extra_len); 89546900298SJohannes Berg 896fffd0934SJohannes Berg if (auth_alg == WLAN_AUTH_SHARED_KEY && transaction == 3) { 897fffd0934SJohannes Berg mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); 898fffd0934SJohannes Berg err = ieee80211_wep_encrypt(local, skb, key, key_len, key_idx); 899fffd0934SJohannes Berg WARN_ON(err); 900fffd0934SJohannes Berg } 901fffd0934SJohannes Berg 90262ae67beSJohannes Berg IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; 90362ae67beSJohannes Berg ieee80211_tx_skb(sdata, skb); 90446900298SJohannes Berg } 90546900298SJohannes Berg 906de95a54bSJohannes Berg int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, 9074d36ec58SJohannes Berg const u8 *ie, size_t ie_len, 908651b5225SJouni Malinen enum ieee80211_band band, u32 rate_mask, 909651b5225SJouni Malinen u8 channel) 910de95a54bSJohannes Berg { 911de95a54bSJohannes Berg struct ieee80211_supported_band *sband; 9128e664fb3SJohannes Berg u8 *pos; 9138e664fb3SJohannes Berg size_t offset = 0, noffset; 9148e664fb3SJohannes Berg int supp_rates_len, i; 9158dcb2003SJouni Malinen u8 rates[32]; 9168dcb2003SJouni Malinen int num_rates; 9178dcb2003SJouni Malinen int ext_rates_len; 918de95a54bSJohannes Berg 9194d36ec58SJohannes Berg sband = local->hw.wiphy->bands[band]; 920de95a54bSJohannes Berg 921de95a54bSJohannes Berg pos = buffer; 922de95a54bSJohannes Berg 9238dcb2003SJouni Malinen num_rates = 0; 9248dcb2003SJouni Malinen for (i = 0; i < sband->n_bitrates; i++) { 9258dcb2003SJouni Malinen if ((BIT(i) & rate_mask) == 0) 9268dcb2003SJouni Malinen continue; /* skip rate */ 9278dcb2003SJouni Malinen rates[num_rates++] = (u8) (sband->bitrates[i].bitrate / 5); 9288dcb2003SJouni Malinen } 9298dcb2003SJouni Malinen 9308dcb2003SJouni Malinen supp_rates_len = min_t(int, num_rates, 8); 9318e664fb3SJohannes Berg 932de95a54bSJohannes Berg *pos++ = WLAN_EID_SUPP_RATES; 9338e664fb3SJohannes Berg *pos++ = supp_rates_len; 9348dcb2003SJouni Malinen memcpy(pos, rates, supp_rates_len); 9358dcb2003SJouni Malinen pos += supp_rates_len; 936de95a54bSJohannes Berg 9378e664fb3SJohannes Berg /* insert "request information" if in custom IEs */ 9388e664fb3SJohannes Berg if (ie && ie_len) { 9398e664fb3SJohannes Berg static const u8 before_extrates[] = { 9408e664fb3SJohannes Berg WLAN_EID_SSID, 9418e664fb3SJohannes Berg WLAN_EID_SUPP_RATES, 9428e664fb3SJohannes Berg WLAN_EID_REQUEST, 9438e664fb3SJohannes Berg }; 9448e664fb3SJohannes Berg noffset = ieee80211_ie_split(ie, ie_len, 9458e664fb3SJohannes Berg before_extrates, 9468e664fb3SJohannes Berg ARRAY_SIZE(before_extrates), 9478e664fb3SJohannes Berg offset); 9488e664fb3SJohannes Berg memcpy(pos, ie + offset, noffset - offset); 9498e664fb3SJohannes Berg pos += noffset - offset; 9508e664fb3SJohannes Berg offset = noffset; 9518e664fb3SJohannes Berg } 9528e664fb3SJohannes Berg 9538dcb2003SJouni Malinen ext_rates_len = num_rates - supp_rates_len; 9548dcb2003SJouni Malinen if (ext_rates_len > 0) { 955de95a54bSJohannes Berg *pos++ = WLAN_EID_EXT_SUPP_RATES; 9568dcb2003SJouni Malinen *pos++ = ext_rates_len; 9578dcb2003SJouni Malinen memcpy(pos, rates + supp_rates_len, ext_rates_len); 9588dcb2003SJouni Malinen pos += ext_rates_len; 9598e664fb3SJohannes Berg } 9608e664fb3SJohannes Berg 961651b5225SJouni Malinen if (channel && sband->band == IEEE80211_BAND_2GHZ) { 962651b5225SJouni Malinen *pos++ = WLAN_EID_DS_PARAMS; 963651b5225SJouni Malinen *pos++ = 1; 964651b5225SJouni Malinen *pos++ = channel; 965651b5225SJouni Malinen } 966651b5225SJouni Malinen 9678e664fb3SJohannes Berg /* insert custom IEs that go before HT */ 9688e664fb3SJohannes Berg if (ie && ie_len) { 9698e664fb3SJohannes Berg static const u8 before_ht[] = { 9708e664fb3SJohannes Berg WLAN_EID_SSID, 9718e664fb3SJohannes Berg WLAN_EID_SUPP_RATES, 9728e664fb3SJohannes Berg WLAN_EID_REQUEST, 9738e664fb3SJohannes Berg WLAN_EID_EXT_SUPP_RATES, 9748e664fb3SJohannes Berg WLAN_EID_DS_PARAMS, 9758e664fb3SJohannes Berg WLAN_EID_SUPPORTED_REGULATORY_CLASSES, 9768e664fb3SJohannes Berg }; 9778e664fb3SJohannes Berg noffset = ieee80211_ie_split(ie, ie_len, 9788e664fb3SJohannes Berg before_ht, ARRAY_SIZE(before_ht), 9798e664fb3SJohannes Berg offset); 9808e664fb3SJohannes Berg memcpy(pos, ie + offset, noffset - offset); 9818e664fb3SJohannes Berg pos += noffset - offset; 9828e664fb3SJohannes Berg offset = noffset; 983de95a54bSJohannes Berg } 984de95a54bSJohannes Berg 9855ef2d41aSJohannes Berg if (sband->ht_cap.ht_supported) { 986f38fd12fSJohannes Berg u16 cap = sband->ht_cap.cap; 987f38fd12fSJohannes Berg __le16 tmp; 988f38fd12fSJohannes Berg 989f38fd12fSJohannes Berg if (ieee80211_disable_40mhz_24ghz && 990f38fd12fSJohannes Berg sband->band == IEEE80211_BAND_2GHZ) { 991f38fd12fSJohannes Berg cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; 992f38fd12fSJohannes Berg cap &= ~IEEE80211_HT_CAP_SGI_40; 993f38fd12fSJohannes Berg } 9945ef2d41aSJohannes Berg 9955ef2d41aSJohannes Berg *pos++ = WLAN_EID_HT_CAPABILITY; 9965ef2d41aSJohannes Berg *pos++ = sizeof(struct ieee80211_ht_cap); 9975ef2d41aSJohannes Berg memset(pos, 0, sizeof(struct ieee80211_ht_cap)); 998f38fd12fSJohannes Berg tmp = cpu_to_le16(cap); 9995ef2d41aSJohannes Berg memcpy(pos, &tmp, sizeof(u16)); 10005ef2d41aSJohannes Berg pos += sizeof(u16); 10015ef2d41aSJohannes Berg *pos++ = sband->ht_cap.ampdu_factor | 1002f38fd12fSJohannes Berg (sband->ht_cap.ampdu_density << 1003f38fd12fSJohannes Berg IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT); 10045ef2d41aSJohannes Berg memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); 10055ef2d41aSJohannes Berg pos += sizeof(sband->ht_cap.mcs); 10065ef2d41aSJohannes Berg pos += 2 + 4 + 1; /* ext info, BF cap, antsel */ 10075ef2d41aSJohannes Berg } 10085ef2d41aSJohannes Berg 1009de95a54bSJohannes Berg /* 1010de95a54bSJohannes Berg * If adding more here, adjust code in main.c 1011de95a54bSJohannes Berg * that calculates local->scan_ies_len. 1012de95a54bSJohannes Berg */ 1013de95a54bSJohannes Berg 10148e664fb3SJohannes Berg /* add any remaining custom IEs */ 10158e664fb3SJohannes Berg if (ie && ie_len) { 10168e664fb3SJohannes Berg noffset = ie_len; 10178e664fb3SJohannes Berg memcpy(pos, ie + offset, noffset - offset); 10188e664fb3SJohannes Berg pos += noffset - offset; 1019de95a54bSJohannes Berg } 1020de95a54bSJohannes Berg 1021de95a54bSJohannes Berg return pos - buffer; 1022de95a54bSJohannes Berg } 1023de95a54bSJohannes Berg 1024a619a4c0SJuuso Oikarinen struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, 1025a619a4c0SJuuso Oikarinen u8 *dst, 1026de95a54bSJohannes Berg const u8 *ssid, size_t ssid_len, 1027de95a54bSJohannes Berg const u8 *ie, size_t ie_len) 102846900298SJohannes Berg { 102946900298SJohannes Berg struct ieee80211_local *local = sdata->local; 103046900298SJohannes Berg struct sk_buff *skb; 103146900298SJohannes Berg struct ieee80211_mgmt *mgmt; 10327c12ce8bSKalle Valo size_t buf_len; 10337c12ce8bSKalle Valo u8 *buf; 1034651b5225SJouni Malinen u8 chan; 103546900298SJohannes Berg 10367c12ce8bSKalle Valo /* FIXME: come up with a proper value */ 10377c12ce8bSKalle Valo buf = kmalloc(200 + ie_len, GFP_KERNEL); 10387c12ce8bSKalle Valo if (!buf) { 10397c12ce8bSKalle Valo printk(KERN_DEBUG "%s: failed to allocate temporary IE " 10407c12ce8bSKalle Valo "buffer\n", sdata->name); 1041a619a4c0SJuuso Oikarinen return NULL; 104246900298SJohannes Berg } 104346900298SJohannes Berg 1044651b5225SJouni Malinen chan = ieee80211_frequency_to_channel( 1045651b5225SJouni Malinen local->hw.conf.channel->center_freq); 1046651b5225SJouni Malinen 10477c12ce8bSKalle Valo buf_len = ieee80211_build_preq_ies(local, buf, ie, ie_len, 10488dcb2003SJouni Malinen local->hw.conf.channel->band, 10498dcb2003SJouni Malinen sdata->rc_rateidx_mask 1050651b5225SJouni Malinen [local->hw.conf.channel->band], 1051651b5225SJouni Malinen chan); 10527c12ce8bSKalle Valo 10537c12ce8bSKalle Valo skb = ieee80211_probereq_get(&local->hw, &sdata->vif, 10547c12ce8bSKalle Valo ssid, ssid_len, 10557c12ce8bSKalle Valo buf, buf_len); 10567c12ce8bSKalle Valo 105746900298SJohannes Berg if (dst) { 10587c12ce8bSKalle Valo mgmt = (struct ieee80211_mgmt *) skb->data; 105946900298SJohannes Berg memcpy(mgmt->da, dst, ETH_ALEN); 106046900298SJohannes Berg memcpy(mgmt->bssid, dst, ETH_ALEN); 106146900298SJohannes Berg } 106246900298SJohannes Berg 106362ae67beSJohannes Berg IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; 1064145b6d1aSMing Lei kfree(buf); 1065a619a4c0SJuuso Oikarinen 1066a619a4c0SJuuso Oikarinen return skb; 1067a619a4c0SJuuso Oikarinen } 1068a619a4c0SJuuso Oikarinen 1069a619a4c0SJuuso Oikarinen void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, 1070a619a4c0SJuuso Oikarinen const u8 *ssid, size_t ssid_len, 1071a619a4c0SJuuso Oikarinen const u8 *ie, size_t ie_len) 1072a619a4c0SJuuso Oikarinen { 1073a619a4c0SJuuso Oikarinen struct sk_buff *skb; 1074a619a4c0SJuuso Oikarinen 1075a619a4c0SJuuso Oikarinen skb = ieee80211_build_probe_req(sdata, dst, ssid, ssid_len, ie, ie_len); 1076a619a4c0SJuuso Oikarinen if (skb) 1077a619a4c0SJuuso Oikarinen ieee80211_tx_skb(sdata, skb); 107846900298SJohannes Berg } 107946900298SJohannes Berg 108046900298SJohannes Berg u32 ieee80211_sta_get_rates(struct ieee80211_local *local, 108146900298SJohannes Berg struct ieee802_11_elems *elems, 108246900298SJohannes Berg enum ieee80211_band band) 108346900298SJohannes Berg { 108446900298SJohannes Berg struct ieee80211_supported_band *sband; 108546900298SJohannes Berg struct ieee80211_rate *bitrates; 108646900298SJohannes Berg size_t num_rates; 108746900298SJohannes Berg u32 supp_rates; 108846900298SJohannes Berg int i, j; 108946900298SJohannes Berg sband = local->hw.wiphy->bands[band]; 109046900298SJohannes Berg 109146900298SJohannes Berg if (!sband) { 109246900298SJohannes Berg WARN_ON(1); 109346900298SJohannes Berg sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; 109446900298SJohannes Berg } 109546900298SJohannes Berg 109646900298SJohannes Berg bitrates = sband->bitrates; 109746900298SJohannes Berg num_rates = sband->n_bitrates; 109846900298SJohannes Berg supp_rates = 0; 109946900298SJohannes Berg for (i = 0; i < elems->supp_rates_len + 110046900298SJohannes Berg elems->ext_supp_rates_len; i++) { 110146900298SJohannes Berg u8 rate = 0; 110246900298SJohannes Berg int own_rate; 110346900298SJohannes Berg if (i < elems->supp_rates_len) 110446900298SJohannes Berg rate = elems->supp_rates[i]; 110546900298SJohannes Berg else if (elems->ext_supp_rates) 110646900298SJohannes Berg rate = elems->ext_supp_rates 110746900298SJohannes Berg [i - elems->supp_rates_len]; 110846900298SJohannes Berg own_rate = 5 * (rate & 0x7f); 110946900298SJohannes Berg for (j = 0; j < num_rates; j++) 111046900298SJohannes Berg if (bitrates[j].bitrate == own_rate) 111146900298SJohannes Berg supp_rates |= BIT(j); 111246900298SJohannes Berg } 111346900298SJohannes Berg return supp_rates; 111446900298SJohannes Berg } 1115f2753ddbSJohannes Berg 111684f6a01cSJohannes Berg void ieee80211_stop_device(struct ieee80211_local *local) 111784f6a01cSJohannes Berg { 111884f6a01cSJohannes Berg ieee80211_led_radio(local, false); 111984f6a01cSJohannes Berg 112084f6a01cSJohannes Berg cancel_work_sync(&local->reconfig_filter); 112184f6a01cSJohannes Berg 112284f6a01cSJohannes Berg flush_workqueue(local->workqueue); 1123678f415fSLennert Buytenhek drv_stop(local); 112484f6a01cSJohannes Berg } 112584f6a01cSJohannes Berg 1126f2753ddbSJohannes Berg int ieee80211_reconfig(struct ieee80211_local *local) 1127f2753ddbSJohannes Berg { 1128f2753ddbSJohannes Berg struct ieee80211_hw *hw = &local->hw; 1129f2753ddbSJohannes Berg struct ieee80211_sub_if_data *sdata; 1130f2753ddbSJohannes Berg struct sta_info *sta; 1131f2753ddbSJohannes Berg int res; 11325bb644a0SJohannes Berg 1133ceb99fe0SJohannes Berg if (local->suspended) 1134ceb99fe0SJohannes Berg local->resuming = true; 1135f2753ddbSJohannes Berg 1136f2753ddbSJohannes Berg /* restart hardware */ 1137f2753ddbSJohannes Berg if (local->open_count) { 113824feda00SLuis R. Rodriguez /* 113924feda00SLuis R. Rodriguez * Upon resume hardware can sometimes be goofy due to 114024feda00SLuis R. Rodriguez * various platform / driver / bus issues, so restarting 114124feda00SLuis R. Rodriguez * the device may at times not work immediately. Propagate 114224feda00SLuis R. Rodriguez * the error. 114324feda00SLuis R. Rodriguez */ 114424487981SJohannes Berg res = drv_start(local); 114524feda00SLuis R. Rodriguez if (res) { 1146c7a00dc7SJohn W. Linville WARN(local->suspended, "Hardware became unavailable " 1147c7a00dc7SJohn W. Linville "upon resume. This could be a software issue " 1148c7a00dc7SJohn W. Linville "prior to suspend or a hardware issue.\n"); 114924feda00SLuis R. Rodriguez return res; 115024feda00SLuis R. Rodriguez } 1151f2753ddbSJohannes Berg 11521f87f7d3SJohannes Berg ieee80211_led_radio(local, true); 1153f2753ddbSJohannes Berg } 1154f2753ddbSJohannes Berg 1155f2753ddbSJohannes Berg /* add interfaces */ 1156f2753ddbSJohannes Berg list_for_each_entry(sdata, &local->interfaces, list) { 1157f2753ddbSJohannes Berg if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && 1158f2753ddbSJohannes Berg sdata->vif.type != NL80211_IFTYPE_MONITOR && 11591ed32e4fSJohannes Berg ieee80211_sdata_running(sdata)) 11601ed32e4fSJohannes Berg res = drv_add_interface(local, &sdata->vif); 1161f2753ddbSJohannes Berg } 1162f2753ddbSJohannes Berg 1163f2753ddbSJohannes Berg /* add STAs back */ 116434e89507SJohannes Berg mutex_lock(&local->sta_mtx); 1165f2753ddbSJohannes Berg list_for_each_entry(sta, &local->sta_list, list) { 116634e89507SJohannes Berg if (sta->uploaded) { 11675bb644a0SJohannes Berg sdata = sta->sdata; 1168f2753ddbSJohannes Berg if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) 1169f2753ddbSJohannes Berg sdata = container_of(sdata->bss, 1170f2753ddbSJohannes Berg struct ieee80211_sub_if_data, 1171f2753ddbSJohannes Berg u.ap); 1172f2753ddbSJohannes Berg 117334e89507SJohannes Berg WARN_ON(drv_sta_add(local, sdata, &sta->sta)); 1174f2753ddbSJohannes Berg } 1175f2753ddbSJohannes Berg } 117634e89507SJohannes Berg mutex_unlock(&local->sta_mtx); 1177f2753ddbSJohannes Berg 1178f23a4780SArik Nemtsov /* setup fragmentation threshold */ 1179f23a4780SArik Nemtsov drv_set_frag_threshold(local, hw->wiphy->frag_threshold); 1180f23a4780SArik Nemtsov 1181f2753ddbSJohannes Berg /* setup RTS threshold */ 118224487981SJohannes Berg drv_set_rts_threshold(local, hw->wiphy->rts_threshold); 1183f2753ddbSJohannes Berg 1184f2753ddbSJohannes Berg /* reconfigure hardware */ 1185f2753ddbSJohannes Berg ieee80211_hw_config(local, ~0); 1186f2753ddbSJohannes Berg 1187f2753ddbSJohannes Berg ieee80211_configure_filter(local); 1188f2753ddbSJohannes Berg 1189f2753ddbSJohannes Berg /* Finally also reconfigure all the BSS information */ 1190f2753ddbSJohannes Berg list_for_each_entry(sdata, &local->interfaces, list) { 1191ac8dd506SJohannes Berg u32 changed; 1192ac8dd506SJohannes Berg 11939607e6b6SJohannes Berg if (!ieee80211_sdata_running(sdata)) 1194f2753ddbSJohannes Berg continue; 1195ac8dd506SJohannes Berg 1196ac8dd506SJohannes Berg /* common change flags for all interface types */ 1197ac8dd506SJohannes Berg changed = BSS_CHANGED_ERP_CTS_PROT | 1198ac8dd506SJohannes Berg BSS_CHANGED_ERP_PREAMBLE | 1199ac8dd506SJohannes Berg BSS_CHANGED_ERP_SLOT | 1200ac8dd506SJohannes Berg BSS_CHANGED_HT | 1201ac8dd506SJohannes Berg BSS_CHANGED_BASIC_RATES | 1202ac8dd506SJohannes Berg BSS_CHANGED_BEACON_INT | 1203ac8dd506SJohannes Berg BSS_CHANGED_BSSID | 12044ced3f74SJohannes Berg BSS_CHANGED_CQM | 12054ced3f74SJohannes Berg BSS_CHANGED_QOS; 1206ac8dd506SJohannes Berg 1207f2753ddbSJohannes Berg switch (sdata->vif.type) { 1208f2753ddbSJohannes Berg case NL80211_IFTYPE_STATION: 1209ac8dd506SJohannes Berg changed |= BSS_CHANGED_ASSOC; 1210ac8dd506SJohannes Berg ieee80211_bss_info_change_notify(sdata, changed); 1211ac8dd506SJohannes Berg break; 1212f2753ddbSJohannes Berg case NL80211_IFTYPE_ADHOC: 1213ac8dd506SJohannes Berg changed |= BSS_CHANGED_IBSS; 1214ac8dd506SJohannes Berg /* fall through */ 1215f2753ddbSJohannes Berg case NL80211_IFTYPE_AP: 1216f2753ddbSJohannes Berg case NL80211_IFTYPE_MESH_POINT: 1217ac8dd506SJohannes Berg changed |= BSS_CHANGED_BEACON | 1218ac8dd506SJohannes Berg BSS_CHANGED_BEACON_ENABLED; 12192d0ddec5SJohannes Berg ieee80211_bss_info_change_notify(sdata, changed); 1220f2753ddbSJohannes Berg break; 1221f2753ddbSJohannes Berg case NL80211_IFTYPE_WDS: 1222f2753ddbSJohannes Berg break; 1223f2753ddbSJohannes Berg case NL80211_IFTYPE_AP_VLAN: 1224f2753ddbSJohannes Berg case NL80211_IFTYPE_MONITOR: 1225f2753ddbSJohannes Berg /* ignore virtual */ 1226f2753ddbSJohannes Berg break; 1227f2753ddbSJohannes Berg case NL80211_IFTYPE_UNSPECIFIED: 12282e161f78SJohannes Berg case NUM_NL80211_IFTYPES: 12292ca27bcfSJohannes Berg case NL80211_IFTYPE_P2P_CLIENT: 12302ca27bcfSJohannes Berg case NL80211_IFTYPE_P2P_GO: 1231f2753ddbSJohannes Berg WARN_ON(1); 1232f2753ddbSJohannes Berg break; 1233f2753ddbSJohannes Berg } 1234f2753ddbSJohannes Berg } 1235f2753ddbSJohannes Berg 12362a419056SJohannes Berg /* 12372a419056SJohannes Berg * Clear the WLAN_STA_BLOCK_BA flag so new aggregation 12382a419056SJohannes Berg * sessions can be established after a resume. 12392a419056SJohannes Berg * 12402a419056SJohannes Berg * Also tear down aggregation sessions since reconfiguring 12412a419056SJohannes Berg * them in a hardware restart scenario is not easily done 12422a419056SJohannes Berg * right now, and the hardware will have lost information 12432a419056SJohannes Berg * about the sessions, but we and the AP still think they 12442a419056SJohannes Berg * are active. This is really a workaround though. 12452a419056SJohannes Berg */ 124674e2bd1fSWey-Yi Guy if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { 12472a419056SJohannes Berg mutex_lock(&local->sta_mtx); 12482a419056SJohannes Berg 12492a419056SJohannes Berg list_for_each_entry(sta, &local->sta_list, list) { 125053f73c09SJohannes Berg ieee80211_sta_tear_down_BA_sessions(sta, true); 12512a419056SJohannes Berg clear_sta_flags(sta, WLAN_STA_BLOCK_BA); 125274e2bd1fSWey-Yi Guy } 12532a419056SJohannes Berg 12542a419056SJohannes Berg mutex_unlock(&local->sta_mtx); 125574e2bd1fSWey-Yi Guy } 125674e2bd1fSWey-Yi Guy 1257f2753ddbSJohannes Berg /* add back keys */ 1258f2753ddbSJohannes Berg list_for_each_entry(sdata, &local->interfaces, list) 12599607e6b6SJohannes Berg if (ieee80211_sdata_running(sdata)) 1260f2753ddbSJohannes Berg ieee80211_enable_keys(sdata); 1261f2753ddbSJohannes Berg 1262f2753ddbSJohannes Berg ieee80211_wake_queues_by_reason(hw, 1263f2753ddbSJohannes Berg IEEE80211_QUEUE_STOP_REASON_SUSPEND); 1264f2753ddbSJohannes Berg 12655bb644a0SJohannes Berg /* 12665bb644a0SJohannes Berg * If this is for hw restart things are still running. 12675bb644a0SJohannes Berg * We may want to change that later, however. 12685bb644a0SJohannes Berg */ 1269ceb99fe0SJohannes Berg if (!local->suspended) 12705bb644a0SJohannes Berg return 0; 12715bb644a0SJohannes Berg 12725bb644a0SJohannes Berg #ifdef CONFIG_PM 1273ceb99fe0SJohannes Berg /* first set suspended false, then resuming */ 12745bb644a0SJohannes Berg local->suspended = false; 1275ceb99fe0SJohannes Berg mb(); 1276ceb99fe0SJohannes Berg local->resuming = false; 12775bb644a0SJohannes Berg 12785bb644a0SJohannes Berg list_for_each_entry(sdata, &local->interfaces, list) { 12795bb644a0SJohannes Berg switch(sdata->vif.type) { 12805bb644a0SJohannes Berg case NL80211_IFTYPE_STATION: 12815bb644a0SJohannes Berg ieee80211_sta_restart(sdata); 12825bb644a0SJohannes Berg break; 12835bb644a0SJohannes Berg case NL80211_IFTYPE_ADHOC: 12845bb644a0SJohannes Berg ieee80211_ibss_restart(sdata); 12855bb644a0SJohannes Berg break; 12865bb644a0SJohannes Berg case NL80211_IFTYPE_MESH_POINT: 12875bb644a0SJohannes Berg ieee80211_mesh_restart(sdata); 12885bb644a0SJohannes Berg break; 12895bb644a0SJohannes Berg default: 12905bb644a0SJohannes Berg break; 12915bb644a0SJohannes Berg } 12925bb644a0SJohannes Berg } 12935bb644a0SJohannes Berg 12945bb644a0SJohannes Berg add_timer(&local->sta_cleanup); 12955bb644a0SJohannes Berg 129634e89507SJohannes Berg mutex_lock(&local->sta_mtx); 12975bb644a0SJohannes Berg list_for_each_entry(sta, &local->sta_list, list) 12985bb644a0SJohannes Berg mesh_plink_restart(sta); 129934e89507SJohannes Berg mutex_unlock(&local->sta_mtx); 13005bb644a0SJohannes Berg #else 13015bb644a0SJohannes Berg WARN_ON(1); 13025bb644a0SJohannes Berg #endif 1303f2753ddbSJohannes Berg return 0; 1304f2753ddbSJohannes Berg } 130542935ecaSLuis R. Rodriguez 13060f78231bSJohannes Berg static int check_mgd_smps(struct ieee80211_if_managed *ifmgd, 13070f78231bSJohannes Berg enum ieee80211_smps_mode *smps_mode) 13080f78231bSJohannes Berg { 13090f78231bSJohannes Berg if (ifmgd->associated) { 13100f78231bSJohannes Berg *smps_mode = ifmgd->ap_smps; 13110f78231bSJohannes Berg 13120f78231bSJohannes Berg if (*smps_mode == IEEE80211_SMPS_AUTOMATIC) { 13130f78231bSJohannes Berg if (ifmgd->powersave) 13140f78231bSJohannes Berg *smps_mode = IEEE80211_SMPS_DYNAMIC; 13150f78231bSJohannes Berg else 13160f78231bSJohannes Berg *smps_mode = IEEE80211_SMPS_OFF; 13170f78231bSJohannes Berg } 13180f78231bSJohannes Berg 13190f78231bSJohannes Berg return 1; 13200f78231bSJohannes Berg } 13210f78231bSJohannes Berg 13220f78231bSJohannes Berg return 0; 13230f78231bSJohannes Berg } 13240f78231bSJohannes Berg 13250f78231bSJohannes Berg /* must hold iflist_mtx */ 1326025e6be2SJohannes Berg void ieee80211_recalc_smps(struct ieee80211_local *local) 13270f78231bSJohannes Berg { 13280f78231bSJohannes Berg struct ieee80211_sub_if_data *sdata; 13290f78231bSJohannes Berg enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_OFF; 13300f78231bSJohannes Berg int count = 0; 13310f78231bSJohannes Berg 133246a5ebafSJohannes Berg lockdep_assert_held(&local->iflist_mtx); 13330f78231bSJohannes Berg 13340f78231bSJohannes Berg /* 13350f78231bSJohannes Berg * This function could be improved to handle multiple 13360f78231bSJohannes Berg * interfaces better, but right now it makes any 13370f78231bSJohannes Berg * non-station interfaces force SM PS to be turned 13380f78231bSJohannes Berg * off. If there are multiple station interfaces it 13390f78231bSJohannes Berg * could also use the best possible mode, e.g. if 13400f78231bSJohannes Berg * one is in static and the other in dynamic then 13410f78231bSJohannes Berg * dynamic is ok. 13420f78231bSJohannes Berg */ 13430f78231bSJohannes Berg 13440f78231bSJohannes Berg list_for_each_entry(sdata, &local->interfaces, list) { 134526a58456SJohannes Berg if (!ieee80211_sdata_running(sdata)) 13460f78231bSJohannes Berg continue; 13470f78231bSJohannes Berg if (sdata->vif.type != NL80211_IFTYPE_STATION) 13480f78231bSJohannes Berg goto set; 1349025e6be2SJohannes Berg 13500f78231bSJohannes Berg count += check_mgd_smps(&sdata->u.mgd, &smps_mode); 13510f78231bSJohannes Berg 13520f78231bSJohannes Berg if (count > 1) { 13530f78231bSJohannes Berg smps_mode = IEEE80211_SMPS_OFF; 13540f78231bSJohannes Berg break; 13550f78231bSJohannes Berg } 13560f78231bSJohannes Berg } 13570f78231bSJohannes Berg 13580f78231bSJohannes Berg if (smps_mode == local->smps_mode) 13590f78231bSJohannes Berg return; 13600f78231bSJohannes Berg 13610f78231bSJohannes Berg set: 13620f78231bSJohannes Berg local->smps_mode = smps_mode; 13630f78231bSJohannes Berg /* changed flag is auto-detected for this */ 13640f78231bSJohannes Berg ieee80211_hw_config(local, 0); 13650f78231bSJohannes Berg } 13668e664fb3SJohannes Berg 13678e664fb3SJohannes Berg static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id) 13688e664fb3SJohannes Berg { 13698e664fb3SJohannes Berg int i; 13708e664fb3SJohannes Berg 13718e664fb3SJohannes Berg for (i = 0; i < n_ids; i++) 13728e664fb3SJohannes Berg if (ids[i] == id) 13738e664fb3SJohannes Berg return true; 13748e664fb3SJohannes Berg return false; 13758e664fb3SJohannes Berg } 13768e664fb3SJohannes Berg 13778e664fb3SJohannes Berg /** 13788e664fb3SJohannes Berg * ieee80211_ie_split - split an IE buffer according to ordering 13798e664fb3SJohannes Berg * 13808e664fb3SJohannes Berg * @ies: the IE buffer 13818e664fb3SJohannes Berg * @ielen: the length of the IE buffer 13828e664fb3SJohannes Berg * @ids: an array with element IDs that are allowed before 13838e664fb3SJohannes Berg * the split 13848e664fb3SJohannes Berg * @n_ids: the size of the element ID array 13858e664fb3SJohannes Berg * @offset: offset where to start splitting in the buffer 13868e664fb3SJohannes Berg * 13878e664fb3SJohannes Berg * This function splits an IE buffer by updating the @offset 13888e664fb3SJohannes Berg * variable to point to the location where the buffer should be 13898e664fb3SJohannes Berg * split. 13908e664fb3SJohannes Berg * 13918e664fb3SJohannes Berg * It assumes that the given IE buffer is well-formed, this 13928e664fb3SJohannes Berg * has to be guaranteed by the caller! 13938e664fb3SJohannes Berg * 13948e664fb3SJohannes Berg * It also assumes that the IEs in the buffer are ordered 13958e664fb3SJohannes Berg * correctly, if not the result of using this function will not 13968e664fb3SJohannes Berg * be ordered correctly either, i.e. it does no reordering. 13978e664fb3SJohannes Berg * 13988e664fb3SJohannes Berg * The function returns the offset where the next part of the 13998e664fb3SJohannes Berg * buffer starts, which may be @ielen if the entire (remainder) 14008e664fb3SJohannes Berg * of the buffer should be used. 14018e664fb3SJohannes Berg */ 14028e664fb3SJohannes Berg size_t ieee80211_ie_split(const u8 *ies, size_t ielen, 14038e664fb3SJohannes Berg const u8 *ids, int n_ids, size_t offset) 14048e664fb3SJohannes Berg { 14058e664fb3SJohannes Berg size_t pos = offset; 14068e664fb3SJohannes Berg 14078e664fb3SJohannes Berg while (pos < ielen && ieee80211_id_in_list(ids, n_ids, ies[pos])) 14088e664fb3SJohannes Berg pos += 2 + ies[pos + 1]; 14098e664fb3SJohannes Berg 14108e664fb3SJohannes Berg return pos; 14118e664fb3SJohannes Berg } 14128e664fb3SJohannes Berg 14138e664fb3SJohannes Berg size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset) 14148e664fb3SJohannes Berg { 14158e664fb3SJohannes Berg size_t pos = offset; 14168e664fb3SJohannes Berg 14178e664fb3SJohannes Berg while (pos < ielen && ies[pos] != WLAN_EID_VENDOR_SPECIFIC) 14188e664fb3SJohannes Berg pos += 2 + ies[pos + 1]; 14198e664fb3SJohannes Berg 14208e664fb3SJohannes Berg return pos; 14218e664fb3SJohannes Berg } 1422