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> 22dd76986bSJohannes 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 { 99252b86c4SJohannes Berg struct sk_buff *skb; 1002de8e0d9SJohannes Berg struct ieee80211_hdr *hdr; 101c2d1560aSJohannes Berg 102252b86c4SJohannes Berg skb_queue_walk(&tx->skbs, skb) { 1032de8e0d9SJohannes Berg hdr = (struct ieee80211_hdr *) skb->data; 104c2d1560aSJohannes Berg hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); 105252b86c4SJohannes Berg } 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 371b0b97a8aSJohannes Berg void 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; 378b0b97a8aSJohannes Berg int queue, 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 queue = skb_get_queue_mapping(skb); 3943b8d81e0SJohannes Berg __skb_queue_tail(&local->pending[queue], skb); 3958f77f384SJohannes Berg } 3968f77f384SJohannes Berg 39750a9432dSJohannes Berg if (fn) 39850a9432dSJohannes Berg fn(data); 39950a9432dSJohannes Berg 4003b8d81e0SJohannes Berg for (i = 0; i < hw->queues; i++) 4018f77f384SJohannes Berg __ieee80211_wake_queue(hw, i, 4028f77f384SJohannes Berg IEEE80211_QUEUE_STOP_REASON_SKB_ADD); 4038f77f384SJohannes Berg spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 4048f77f384SJohannes Berg } 4058f77f384SJohannes Berg 406b0b97a8aSJohannes Berg void ieee80211_add_pending_skbs(struct ieee80211_local *local, 40750a9432dSJohannes Berg struct sk_buff_head *skbs) 40850a9432dSJohannes Berg { 409b0b97a8aSJohannes Berg ieee80211_add_pending_skbs_fn(local, skbs, NULL, NULL); 41050a9432dSJohannes Berg } 41150a9432dSJohannes Berg 412ce7c9111SKalle Valo void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, 413ce7c9111SKalle Valo enum queue_stop_reason reason) 414c2d1560aSJohannes Berg { 415ce7c9111SKalle Valo struct ieee80211_local *local = hw_to_local(hw); 416ce7c9111SKalle Valo unsigned long flags; 417c2d1560aSJohannes Berg int i; 418c2d1560aSJohannes Berg 419ce7c9111SKalle Valo spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 420ce7c9111SKalle Valo 42196f5e66eSJohannes Berg for (i = 0; i < hw->queues; i++) 422ce7c9111SKalle Valo __ieee80211_stop_queue(hw, i, reason); 423ce7c9111SKalle Valo 424ce7c9111SKalle Valo spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 425ce7c9111SKalle Valo } 426ce7c9111SKalle Valo 427ce7c9111SKalle Valo void ieee80211_stop_queues(struct ieee80211_hw *hw) 428ce7c9111SKalle Valo { 429ce7c9111SKalle Valo ieee80211_stop_queues_by_reason(hw, 430ce7c9111SKalle Valo IEEE80211_QUEUE_STOP_REASON_DRIVER); 431c2d1560aSJohannes Berg } 432c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_stop_queues); 433c2d1560aSJohannes Berg 43492ab8535STomas Winkler int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue) 43592ab8535STomas Winkler { 43692ab8535STomas Winkler struct ieee80211_local *local = hw_to_local(hw); 4373b8d81e0SJohannes Berg unsigned long flags; 4383b8d81e0SJohannes Berg int ret; 43996f5e66eSJohannes Berg 440e4e72fb4SJohannes Berg if (WARN_ON(queue >= hw->queues)) 44196f5e66eSJohannes Berg return true; 44296f5e66eSJohannes Berg 4433b8d81e0SJohannes Berg spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 4443b8d81e0SJohannes Berg ret = !!local->queue_stop_reasons[queue]; 4453b8d81e0SJohannes Berg spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 4463b8d81e0SJohannes Berg return ret; 44792ab8535STomas Winkler } 44892ab8535STomas Winkler EXPORT_SYMBOL(ieee80211_queue_stopped); 44992ab8535STomas Winkler 450ce7c9111SKalle Valo void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, 451ce7c9111SKalle Valo enum queue_stop_reason reason) 452c2d1560aSJohannes Berg { 453ce7c9111SKalle Valo struct ieee80211_local *local = hw_to_local(hw); 454ce7c9111SKalle Valo unsigned long flags; 455c2d1560aSJohannes Berg int i; 456c2d1560aSJohannes Berg 457ce7c9111SKalle Valo spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 458ce7c9111SKalle Valo 459e4e72fb4SJohannes Berg for (i = 0; i < hw->queues; i++) 460ce7c9111SKalle Valo __ieee80211_wake_queue(hw, i, reason); 461ce7c9111SKalle Valo 462ce7c9111SKalle Valo spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 463ce7c9111SKalle Valo } 464ce7c9111SKalle Valo 465ce7c9111SKalle Valo void ieee80211_wake_queues(struct ieee80211_hw *hw) 466ce7c9111SKalle Valo { 467ce7c9111SKalle Valo ieee80211_wake_queues_by_reason(hw, IEEE80211_QUEUE_STOP_REASON_DRIVER); 468c2d1560aSJohannes Berg } 469c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_wake_queues); 470dabeb344SJohannes Berg 47132bfd35dSJohannes Berg void ieee80211_iterate_active_interfaces( 47232bfd35dSJohannes Berg struct ieee80211_hw *hw, 473dabeb344SJohannes Berg void (*iterator)(void *data, u8 *mac, 47432bfd35dSJohannes Berg struct ieee80211_vif *vif), 475dabeb344SJohannes Berg void *data) 476dabeb344SJohannes Berg { 477dabeb344SJohannes Berg struct ieee80211_local *local = hw_to_local(hw); 478dabeb344SJohannes Berg struct ieee80211_sub_if_data *sdata; 479dabeb344SJohannes Berg 480c771c9d8SJohannes Berg mutex_lock(&local->iflist_mtx); 4812f561febSIvo van Doorn 4822f561febSIvo van Doorn list_for_each_entry(sdata, &local->interfaces, list) { 4832f561febSIvo van Doorn switch (sdata->vif.type) { 48405c914feSJohannes Berg case NL80211_IFTYPE_MONITOR: 48505c914feSJohannes Berg case NL80211_IFTYPE_AP_VLAN: 4862f561febSIvo van Doorn continue; 4872ca27bcfSJohannes Berg default: 4882f561febSIvo van Doorn break; 4892f561febSIvo van Doorn } 4909607e6b6SJohannes Berg if (ieee80211_sdata_running(sdata)) 49147846c9bSJohannes Berg iterator(data, sdata->vif.addr, 4922f561febSIvo van Doorn &sdata->vif); 4932f561febSIvo van Doorn } 4942f561febSIvo van Doorn 495c771c9d8SJohannes Berg mutex_unlock(&local->iflist_mtx); 4962f561febSIvo van Doorn } 4972f561febSIvo van Doorn EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces); 4982f561febSIvo van Doorn 4992f561febSIvo van Doorn void ieee80211_iterate_active_interfaces_atomic( 5002f561febSIvo van Doorn struct ieee80211_hw *hw, 5012f561febSIvo van Doorn void (*iterator)(void *data, u8 *mac, 5022f561febSIvo van Doorn struct ieee80211_vif *vif), 5032f561febSIvo van Doorn void *data) 5042f561febSIvo van Doorn { 5052f561febSIvo van Doorn struct ieee80211_local *local = hw_to_local(hw); 5062f561febSIvo van Doorn struct ieee80211_sub_if_data *sdata; 5072f561febSIvo van Doorn 508e38bad47SJohannes Berg rcu_read_lock(); 509dabeb344SJohannes Berg 510e38bad47SJohannes Berg list_for_each_entry_rcu(sdata, &local->interfaces, list) { 51151fb61e7SJohannes Berg switch (sdata->vif.type) { 51205c914feSJohannes Berg case NL80211_IFTYPE_MONITOR: 51305c914feSJohannes Berg case NL80211_IFTYPE_AP_VLAN: 514dabeb344SJohannes Berg continue; 5152ca27bcfSJohannes Berg default: 516dabeb344SJohannes Berg break; 517dabeb344SJohannes Berg } 5189607e6b6SJohannes Berg if (ieee80211_sdata_running(sdata)) 51947846c9bSJohannes Berg iterator(data, sdata->vif.addr, 52032bfd35dSJohannes Berg &sdata->vif); 521dabeb344SJohannes Berg } 522e38bad47SJohannes Berg 523e38bad47SJohannes Berg rcu_read_unlock(); 524dabeb344SJohannes Berg } 5252f561febSIvo van Doorn EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic); 52637ffc8daSJohannes Berg 52742935ecaSLuis R. Rodriguez /* 52842935ecaSLuis R. Rodriguez * Nothing should have been stuffed into the workqueue during 52942935ecaSLuis R. Rodriguez * the suspend->resume cycle. If this WARN is seen then there 53042935ecaSLuis R. Rodriguez * is a bug with either the driver suspend or something in 53142935ecaSLuis R. Rodriguez * mac80211 stuffing into the workqueue which we haven't yet 53242935ecaSLuis R. Rodriguez * cleared during mac80211's suspend cycle. 53342935ecaSLuis R. Rodriguez */ 53442935ecaSLuis R. Rodriguez static bool ieee80211_can_queue_work(struct ieee80211_local *local) 53542935ecaSLuis R. Rodriguez { 536ceb99fe0SJohannes Berg if (WARN(local->suspended && !local->resuming, 537ceb99fe0SJohannes Berg "queueing ieee80211 work while going to suspend\n")) 53842935ecaSLuis R. Rodriguez return false; 53942935ecaSLuis R. Rodriguez 54042935ecaSLuis R. Rodriguez return true; 54142935ecaSLuis R. Rodriguez } 54242935ecaSLuis R. Rodriguez 54342935ecaSLuis R. Rodriguez void ieee80211_queue_work(struct ieee80211_hw *hw, struct work_struct *work) 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_work(local->workqueue, work); 55142935ecaSLuis R. Rodriguez } 55242935ecaSLuis R. Rodriguez EXPORT_SYMBOL(ieee80211_queue_work); 55342935ecaSLuis R. Rodriguez 55442935ecaSLuis R. Rodriguez void ieee80211_queue_delayed_work(struct ieee80211_hw *hw, 55542935ecaSLuis R. Rodriguez struct delayed_work *dwork, 55642935ecaSLuis R. Rodriguez unsigned long delay) 55742935ecaSLuis R. Rodriguez { 55842935ecaSLuis R. Rodriguez struct ieee80211_local *local = hw_to_local(hw); 55942935ecaSLuis R. Rodriguez 56042935ecaSLuis R. Rodriguez if (!ieee80211_can_queue_work(local)) 56142935ecaSLuis R. Rodriguez return; 56242935ecaSLuis R. Rodriguez 56342935ecaSLuis R. Rodriguez queue_delayed_work(local->workqueue, dwork, delay); 56442935ecaSLuis R. Rodriguez } 56542935ecaSLuis R. Rodriguez EXPORT_SYMBOL(ieee80211_queue_delayed_work); 56642935ecaSLuis R. Rodriguez 567dd76986bSJohannes Berg u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, 568dd76986bSJohannes Berg struct ieee802_11_elems *elems, 569dd76986bSJohannes Berg u64 filter, u32 crc) 570dd76986bSJohannes Berg { 571dd76986bSJohannes Berg size_t left = len; 572dd76986bSJohannes Berg u8 *pos = start; 573dd76986bSJohannes Berg bool calc_crc = filter != 0; 574dd76986bSJohannes Berg 575dd76986bSJohannes Berg memset(elems, 0, sizeof(*elems)); 576dd76986bSJohannes Berg elems->ie_start = start; 577dd76986bSJohannes Berg elems->total_len = len; 578dd76986bSJohannes Berg 579dd76986bSJohannes Berg while (left >= 2) { 580dd76986bSJohannes Berg u8 id, elen; 581dd76986bSJohannes Berg 582dd76986bSJohannes Berg id = *pos++; 583dd76986bSJohannes Berg elen = *pos++; 584dd76986bSJohannes Berg left -= 2; 585dd76986bSJohannes Berg 586dd76986bSJohannes Berg if (elen > left) 587dd76986bSJohannes Berg break; 588dd76986bSJohannes Berg 589dd76986bSJohannes Berg if (calc_crc && id < 64 && (filter & (1ULL << id))) 590dd76986bSJohannes Berg crc = crc32_be(crc, pos - 2, elen + 2); 591dd76986bSJohannes Berg 592dd76986bSJohannes Berg switch (id) { 593dd76986bSJohannes Berg case WLAN_EID_SSID: 594dd76986bSJohannes Berg elems->ssid = pos; 595dd76986bSJohannes Berg elems->ssid_len = elen; 596dd76986bSJohannes Berg break; 597dd76986bSJohannes Berg case WLAN_EID_SUPP_RATES: 598dd76986bSJohannes Berg elems->supp_rates = pos; 599dd76986bSJohannes Berg elems->supp_rates_len = elen; 600dd76986bSJohannes Berg break; 601dd76986bSJohannes Berg case WLAN_EID_FH_PARAMS: 602dd76986bSJohannes Berg elems->fh_params = pos; 603dd76986bSJohannes Berg elems->fh_params_len = elen; 604dd76986bSJohannes Berg break; 605dd76986bSJohannes Berg case WLAN_EID_DS_PARAMS: 606dd76986bSJohannes Berg elems->ds_params = pos; 607dd76986bSJohannes Berg elems->ds_params_len = elen; 608dd76986bSJohannes Berg break; 609dd76986bSJohannes Berg case WLAN_EID_CF_PARAMS: 610dd76986bSJohannes Berg elems->cf_params = pos; 611dd76986bSJohannes Berg elems->cf_params_len = elen; 612dd76986bSJohannes Berg break; 613dd76986bSJohannes Berg case WLAN_EID_TIM: 614dd76986bSJohannes Berg if (elen >= sizeof(struct ieee80211_tim_ie)) { 615dd76986bSJohannes Berg elems->tim = (void *)pos; 616dd76986bSJohannes Berg elems->tim_len = elen; 617dd76986bSJohannes Berg } 618dd76986bSJohannes Berg break; 619dd76986bSJohannes Berg case WLAN_EID_IBSS_PARAMS: 620dd76986bSJohannes Berg elems->ibss_params = pos; 621dd76986bSJohannes Berg elems->ibss_params_len = elen; 622dd76986bSJohannes Berg break; 623dd76986bSJohannes Berg case WLAN_EID_CHALLENGE: 624dd76986bSJohannes Berg elems->challenge = pos; 625dd76986bSJohannes Berg elems->challenge_len = elen; 626dd76986bSJohannes Berg break; 627dd76986bSJohannes Berg case WLAN_EID_VENDOR_SPECIFIC: 628dd76986bSJohannes Berg if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 && 629dd76986bSJohannes Berg pos[2] == 0xf2) { 630dd76986bSJohannes Berg /* Microsoft OUI (00:50:F2) */ 631dd76986bSJohannes Berg 632dd76986bSJohannes Berg if (calc_crc) 633dd76986bSJohannes Berg crc = crc32_be(crc, pos - 2, elen + 2); 634dd76986bSJohannes Berg 635dd76986bSJohannes Berg if (pos[3] == 1) { 636dd76986bSJohannes Berg /* OUI Type 1 - WPA IE */ 637dd76986bSJohannes Berg elems->wpa = pos; 638dd76986bSJohannes Berg elems->wpa_len = elen; 639dd76986bSJohannes Berg } else if (elen >= 5 && pos[3] == 2) { 640dd76986bSJohannes Berg /* OUI Type 2 - WMM IE */ 641dd76986bSJohannes Berg if (pos[4] == 0) { 642dd76986bSJohannes Berg elems->wmm_info = pos; 643dd76986bSJohannes Berg elems->wmm_info_len = elen; 644dd76986bSJohannes Berg } else if (pos[4] == 1) { 645dd76986bSJohannes Berg elems->wmm_param = pos; 646dd76986bSJohannes Berg elems->wmm_param_len = elen; 647dd76986bSJohannes Berg } 648dd76986bSJohannes Berg } 649dd76986bSJohannes Berg } 650dd76986bSJohannes Berg break; 651dd76986bSJohannes Berg case WLAN_EID_RSN: 652dd76986bSJohannes Berg elems->rsn = pos; 653dd76986bSJohannes Berg elems->rsn_len = elen; 654dd76986bSJohannes Berg break; 655dd76986bSJohannes Berg case WLAN_EID_ERP_INFO: 656dd76986bSJohannes Berg elems->erp_info = pos; 657dd76986bSJohannes Berg elems->erp_info_len = elen; 658dd76986bSJohannes Berg break; 659dd76986bSJohannes Berg case WLAN_EID_EXT_SUPP_RATES: 660dd76986bSJohannes Berg elems->ext_supp_rates = pos; 661dd76986bSJohannes Berg elems->ext_supp_rates_len = elen; 662dd76986bSJohannes Berg break; 663dd76986bSJohannes Berg case WLAN_EID_HT_CAPABILITY: 664dd76986bSJohannes Berg if (elen >= sizeof(struct ieee80211_ht_cap)) 665dd76986bSJohannes Berg elems->ht_cap_elem = (void *)pos; 666dd76986bSJohannes Berg break; 667dd76986bSJohannes Berg case WLAN_EID_HT_INFORMATION: 668dd76986bSJohannes Berg if (elen >= sizeof(struct ieee80211_ht_info)) 669dd76986bSJohannes Berg elems->ht_info_elem = (void *)pos; 670dd76986bSJohannes Berg break; 671dd76986bSJohannes Berg case WLAN_EID_MESH_ID: 672dd76986bSJohannes Berg elems->mesh_id = pos; 673dd76986bSJohannes Berg elems->mesh_id_len = elen; 674dd76986bSJohannes Berg break; 675dd76986bSJohannes Berg case WLAN_EID_MESH_CONFIG: 676dd76986bSJohannes Berg if (elen >= sizeof(struct ieee80211_meshconf_ie)) 677dd76986bSJohannes Berg elems->mesh_config = (void *)pos; 678dd76986bSJohannes Berg break; 679dd76986bSJohannes Berg case WLAN_EID_PEER_MGMT: 680dd76986bSJohannes Berg elems->peering = pos; 681dd76986bSJohannes Berg elems->peering_len = elen; 682dd76986bSJohannes Berg break; 683dd76986bSJohannes Berg case WLAN_EID_PREQ: 684dd76986bSJohannes Berg elems->preq = pos; 685dd76986bSJohannes Berg elems->preq_len = elen; 686dd76986bSJohannes Berg break; 687dd76986bSJohannes Berg case WLAN_EID_PREP: 688dd76986bSJohannes Berg elems->prep = pos; 689dd76986bSJohannes Berg elems->prep_len = elen; 690dd76986bSJohannes Berg break; 691dd76986bSJohannes Berg case WLAN_EID_PERR: 692dd76986bSJohannes Berg elems->perr = pos; 693dd76986bSJohannes Berg elems->perr_len = elen; 694dd76986bSJohannes Berg break; 695dd76986bSJohannes Berg case WLAN_EID_RANN: 696dd76986bSJohannes Berg if (elen >= sizeof(struct ieee80211_rann_ie)) 697dd76986bSJohannes Berg elems->rann = (void *)pos; 698dd76986bSJohannes Berg break; 699dd76986bSJohannes Berg case WLAN_EID_CHANNEL_SWITCH: 700dd76986bSJohannes Berg elems->ch_switch_elem = pos; 701dd76986bSJohannes Berg elems->ch_switch_elem_len = elen; 702dd76986bSJohannes Berg break; 703dd76986bSJohannes Berg case WLAN_EID_QUIET: 704dd76986bSJohannes Berg if (!elems->quiet_elem) { 705dd76986bSJohannes Berg elems->quiet_elem = pos; 706dd76986bSJohannes Berg elems->quiet_elem_len = elen; 707dd76986bSJohannes Berg } 708dd76986bSJohannes Berg elems->num_of_quiet_elem++; 709dd76986bSJohannes Berg break; 710dd76986bSJohannes Berg case WLAN_EID_COUNTRY: 711dd76986bSJohannes Berg elems->country_elem = pos; 712dd76986bSJohannes Berg elems->country_elem_len = elen; 713dd76986bSJohannes Berg break; 714dd76986bSJohannes Berg case WLAN_EID_PWR_CONSTRAINT: 715dd76986bSJohannes Berg elems->pwr_constr_elem = pos; 716dd76986bSJohannes Berg elems->pwr_constr_elem_len = elen; 717dd76986bSJohannes Berg break; 718dd76986bSJohannes Berg case WLAN_EID_TIMEOUT_INTERVAL: 719dd76986bSJohannes Berg elems->timeout_int = pos; 720dd76986bSJohannes Berg elems->timeout_int_len = elen; 721dd76986bSJohannes Berg break; 722dd76986bSJohannes Berg default: 723dd76986bSJohannes Berg break; 724dd76986bSJohannes Berg } 725dd76986bSJohannes Berg 726dd76986bSJohannes Berg left -= elen; 727dd76986bSJohannes Berg pos += elen; 728dd76986bSJohannes Berg } 729dd76986bSJohannes Berg 730dd76986bSJohannes Berg return crc; 731dd76986bSJohannes Berg } 732dd76986bSJohannes Berg 73337ffc8daSJohannes Berg void ieee802_11_parse_elems(u8 *start, size_t len, 73437ffc8daSJohannes Berg struct ieee802_11_elems *elems) 73537ffc8daSJohannes Berg { 736d91f36dbSJohannes Berg ieee802_11_parse_elems_crc(start, len, elems, 0, 0); 737d91f36dbSJohannes Berg } 738d91f36dbSJohannes Berg 7395825fe10SJohannes Berg void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata) 7405825fe10SJohannes Berg { 7415825fe10SJohannes Berg struct ieee80211_local *local = sdata->local; 7425825fe10SJohannes Berg struct ieee80211_tx_queue_params qparam; 743aa837e1dSJohannes Berg int queue; 744aa837e1dSJohannes Berg bool use_11b; 745aa837e1dSJohannes Berg int aCWmin, aCWmax; 7465825fe10SJohannes Berg 7475825fe10SJohannes Berg if (!local->ops->conf_tx) 7485825fe10SJohannes Berg return; 7495825fe10SJohannes Berg 7505825fe10SJohannes Berg memset(&qparam, 0, sizeof(qparam)); 7515825fe10SJohannes Berg 752aa837e1dSJohannes Berg use_11b = (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) && 753aa837e1dSJohannes Berg !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE); 7545825fe10SJohannes Berg 755aa837e1dSJohannes Berg for (queue = 0; queue < local_to_hw(local)->queues; queue++) { 756aa837e1dSJohannes Berg /* Set defaults according to 802.11-2007 Table 7-37 */ 757aa837e1dSJohannes Berg aCWmax = 1023; 758aa837e1dSJohannes Berg if (use_11b) 759aa837e1dSJohannes Berg aCWmin = 31; 7605825fe10SJohannes Berg else 761aa837e1dSJohannes Berg aCWmin = 15; 7625825fe10SJohannes Berg 763aa837e1dSJohannes Berg switch (queue) { 764aa837e1dSJohannes Berg case 3: /* AC_BK */ 7657ba10a8eSJohannes Berg qparam.cw_max = aCWmax; 7667ba10a8eSJohannes Berg qparam.cw_min = aCWmin; 7675825fe10SJohannes Berg qparam.txop = 0; 768aa837e1dSJohannes Berg qparam.aifs = 7; 769aa837e1dSJohannes Berg break; 770aa837e1dSJohannes Berg default: /* never happens but let's not leave undefined */ 771aa837e1dSJohannes Berg case 2: /* AC_BE */ 7727ba10a8eSJohannes Berg qparam.cw_max = aCWmax; 7737ba10a8eSJohannes Berg qparam.cw_min = aCWmin; 774aa837e1dSJohannes Berg qparam.txop = 0; 775aa837e1dSJohannes Berg qparam.aifs = 3; 776aa837e1dSJohannes Berg break; 777aa837e1dSJohannes Berg case 1: /* AC_VI */ 778aa837e1dSJohannes Berg qparam.cw_max = aCWmin; 779aa837e1dSJohannes Berg qparam.cw_min = (aCWmin + 1) / 2 - 1; 780aa837e1dSJohannes Berg if (use_11b) 781aa837e1dSJohannes Berg qparam.txop = 6016/32; 782aa837e1dSJohannes Berg else 783aa837e1dSJohannes Berg qparam.txop = 3008/32; 784aa837e1dSJohannes Berg qparam.aifs = 2; 785aa837e1dSJohannes Berg break; 786aa837e1dSJohannes Berg case 0: /* AC_VO */ 787aa837e1dSJohannes Berg qparam.cw_max = (aCWmin + 1) / 2 - 1; 788aa837e1dSJohannes Berg qparam.cw_min = (aCWmin + 1) / 4 - 1; 789aa837e1dSJohannes Berg if (use_11b) 790aa837e1dSJohannes Berg qparam.txop = 3264/32; 791aa837e1dSJohannes Berg else 792aa837e1dSJohannes Berg qparam.txop = 1504/32; 793aa837e1dSJohannes Berg qparam.aifs = 2; 794aa837e1dSJohannes Berg break; 795aa837e1dSJohannes Berg } 7965825fe10SJohannes Berg 797ab13315aSKalle Valo qparam.uapsd = false; 798ab13315aSKalle Valo 799f6f3def3SEliad Peller sdata->tx_conf[queue] = qparam; 800f6f3def3SEliad Peller drv_conf_tx(local, sdata, queue, &qparam); 801aa837e1dSJohannes Berg } 802e1b3ec1aSStanislaw Gruszka 803e1b3ec1aSStanislaw Gruszka /* after reinitialize QoS TX queues setting to default, 804e1b3ec1aSStanislaw Gruszka * disable QoS at all */ 805d9734979SSujith 806d9734979SSujith if (sdata->vif.type != NL80211_IFTYPE_MONITOR) { 807d9734979SSujith sdata->vif.bss_conf.qos = 808d9734979SSujith sdata->vif.type != NL80211_IFTYPE_STATION; 8094ced3f74SJohannes Berg ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_QOS); 8105825fe10SJohannes Berg } 811d9734979SSujith } 812e50db65cSJohannes Berg 81346900298SJohannes Berg void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, 81446900298SJohannes Berg const size_t supp_rates_len, 81546900298SJohannes Berg const u8 *supp_rates) 81646900298SJohannes Berg { 81746900298SJohannes Berg struct ieee80211_local *local = sdata->local; 81846900298SJohannes Berg int i, have_higher_than_11mbit = 0; 81946900298SJohannes Berg 82046900298SJohannes Berg /* cf. IEEE 802.11 9.2.12 */ 82146900298SJohannes Berg for (i = 0; i < supp_rates_len; i++) 82246900298SJohannes Berg if ((supp_rates[i] & 0x7f) * 5 > 110) 82346900298SJohannes Berg have_higher_than_11mbit = 1; 82446900298SJohannes Berg 82546900298SJohannes Berg if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && 82646900298SJohannes Berg have_higher_than_11mbit) 82746900298SJohannes Berg sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; 82846900298SJohannes Berg else 82946900298SJohannes Berg sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; 83046900298SJohannes Berg 83146900298SJohannes Berg ieee80211_set_wmm_default(sdata); 83246900298SJohannes Berg } 83346900298SJohannes Berg 834881d948cSJohannes Berg u32 ieee80211_mandatory_rates(struct ieee80211_local *local, 83596dd22acSJohannes Berg enum ieee80211_band band) 83696dd22acSJohannes Berg { 83796dd22acSJohannes Berg struct ieee80211_supported_band *sband; 83896dd22acSJohannes Berg struct ieee80211_rate *bitrates; 839881d948cSJohannes Berg u32 mandatory_rates; 84096dd22acSJohannes Berg enum ieee80211_rate_flags mandatory_flag; 84196dd22acSJohannes Berg int i; 84296dd22acSJohannes Berg 84396dd22acSJohannes Berg sband = local->hw.wiphy->bands[band]; 84496dd22acSJohannes Berg if (!sband) { 84596dd22acSJohannes Berg WARN_ON(1); 84696dd22acSJohannes Berg sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; 84796dd22acSJohannes Berg } 84896dd22acSJohannes Berg 84996dd22acSJohannes Berg if (band == IEEE80211_BAND_2GHZ) 85096dd22acSJohannes Berg mandatory_flag = IEEE80211_RATE_MANDATORY_B; 85196dd22acSJohannes Berg else 85296dd22acSJohannes Berg mandatory_flag = IEEE80211_RATE_MANDATORY_A; 85396dd22acSJohannes Berg 85496dd22acSJohannes Berg bitrates = sband->bitrates; 85596dd22acSJohannes Berg mandatory_rates = 0; 85696dd22acSJohannes Berg for (i = 0; i < sband->n_bitrates; i++) 85796dd22acSJohannes Berg if (bitrates[i].flags & mandatory_flag) 85896dd22acSJohannes Berg mandatory_rates |= BIT(i); 85996dd22acSJohannes Berg return mandatory_rates; 86096dd22acSJohannes Berg } 86146900298SJohannes Berg 86246900298SJohannes Berg void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, 86346900298SJohannes Berg u16 transaction, u16 auth_alg, 864fffd0934SJohannes Berg u8 *extra, size_t extra_len, const u8 *bssid, 865fffd0934SJohannes Berg const u8 *key, u8 key_len, u8 key_idx) 86646900298SJohannes Berg { 86746900298SJohannes Berg struct ieee80211_local *local = sdata->local; 86846900298SJohannes Berg struct sk_buff *skb; 86946900298SJohannes Berg struct ieee80211_mgmt *mgmt; 870fffd0934SJohannes Berg int err; 87146900298SJohannes Berg 87246900298SJohannes Berg skb = dev_alloc_skb(local->hw.extra_tx_headroom + 87365fc73acSJouni Malinen sizeof(*mgmt) + 6 + extra_len); 874d15b8459SJoe Perches if (!skb) 87546900298SJohannes Berg return; 876d15b8459SJoe Perches 87746900298SJohannes Berg skb_reserve(skb, local->hw.extra_tx_headroom); 87846900298SJohannes Berg 87946900298SJohannes Berg mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6); 88046900298SJohannes Berg memset(mgmt, 0, 24 + 6); 88146900298SJohannes Berg mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | 88246900298SJohannes Berg IEEE80211_STYPE_AUTH); 88346900298SJohannes Berg memcpy(mgmt->da, bssid, ETH_ALEN); 88447846c9bSJohannes Berg memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); 88546900298SJohannes Berg memcpy(mgmt->bssid, bssid, ETH_ALEN); 88646900298SJohannes Berg mgmt->u.auth.auth_alg = cpu_to_le16(auth_alg); 88746900298SJohannes Berg mgmt->u.auth.auth_transaction = cpu_to_le16(transaction); 88846900298SJohannes Berg mgmt->u.auth.status_code = cpu_to_le16(0); 88946900298SJohannes Berg if (extra) 89046900298SJohannes Berg memcpy(skb_put(skb, extra_len), extra, extra_len); 89146900298SJohannes Berg 892fffd0934SJohannes Berg if (auth_alg == WLAN_AUTH_SHARED_KEY && transaction == 3) { 893fffd0934SJohannes Berg mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); 894fffd0934SJohannes Berg err = ieee80211_wep_encrypt(local, skb, key, key_len, key_idx); 895fffd0934SJohannes Berg WARN_ON(err); 896fffd0934SJohannes Berg } 897fffd0934SJohannes Berg 89862ae67beSJohannes Berg IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; 89962ae67beSJohannes Berg ieee80211_tx_skb(sdata, skb); 90046900298SJohannes Berg } 90146900298SJohannes Berg 902de95a54bSJohannes Berg int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, 9034d36ec58SJohannes Berg const u8 *ie, size_t ie_len, 904651b5225SJouni Malinen enum ieee80211_band band, u32 rate_mask, 905651b5225SJouni Malinen u8 channel) 906de95a54bSJohannes Berg { 907de95a54bSJohannes Berg struct ieee80211_supported_band *sband; 9088e664fb3SJohannes Berg u8 *pos; 9098e664fb3SJohannes Berg size_t offset = 0, noffset; 9108e664fb3SJohannes Berg int supp_rates_len, i; 9118dcb2003SJouni Malinen u8 rates[32]; 9128dcb2003SJouni Malinen int num_rates; 9138dcb2003SJouni Malinen int ext_rates_len; 914de95a54bSJohannes Berg 9154d36ec58SJohannes Berg sband = local->hw.wiphy->bands[band]; 916de95a54bSJohannes Berg 917de95a54bSJohannes Berg pos = buffer; 918de95a54bSJohannes Berg 9198dcb2003SJouni Malinen num_rates = 0; 9208dcb2003SJouni Malinen for (i = 0; i < sband->n_bitrates; i++) { 9218dcb2003SJouni Malinen if ((BIT(i) & rate_mask) == 0) 9228dcb2003SJouni Malinen continue; /* skip rate */ 9238dcb2003SJouni Malinen rates[num_rates++] = (u8) (sband->bitrates[i].bitrate / 5); 9248dcb2003SJouni Malinen } 9258dcb2003SJouni Malinen 9268dcb2003SJouni Malinen supp_rates_len = min_t(int, num_rates, 8); 9278e664fb3SJohannes Berg 928de95a54bSJohannes Berg *pos++ = WLAN_EID_SUPP_RATES; 9298e664fb3SJohannes Berg *pos++ = supp_rates_len; 9308dcb2003SJouni Malinen memcpy(pos, rates, supp_rates_len); 9318dcb2003SJouni Malinen pos += supp_rates_len; 932de95a54bSJohannes Berg 9338e664fb3SJohannes Berg /* insert "request information" if in custom IEs */ 9348e664fb3SJohannes Berg if (ie && ie_len) { 9358e664fb3SJohannes Berg static const u8 before_extrates[] = { 9368e664fb3SJohannes Berg WLAN_EID_SSID, 9378e664fb3SJohannes Berg WLAN_EID_SUPP_RATES, 9388e664fb3SJohannes Berg WLAN_EID_REQUEST, 9398e664fb3SJohannes Berg }; 9408e664fb3SJohannes Berg noffset = ieee80211_ie_split(ie, ie_len, 9418e664fb3SJohannes Berg before_extrates, 9428e664fb3SJohannes Berg ARRAY_SIZE(before_extrates), 9438e664fb3SJohannes Berg offset); 9448e664fb3SJohannes Berg memcpy(pos, ie + offset, noffset - offset); 9458e664fb3SJohannes Berg pos += noffset - offset; 9468e664fb3SJohannes Berg offset = noffset; 9478e664fb3SJohannes Berg } 9488e664fb3SJohannes Berg 9498dcb2003SJouni Malinen ext_rates_len = num_rates - supp_rates_len; 9508dcb2003SJouni Malinen if (ext_rates_len > 0) { 951de95a54bSJohannes Berg *pos++ = WLAN_EID_EXT_SUPP_RATES; 9528dcb2003SJouni Malinen *pos++ = ext_rates_len; 9538dcb2003SJouni Malinen memcpy(pos, rates + supp_rates_len, ext_rates_len); 9548dcb2003SJouni Malinen pos += ext_rates_len; 9558e664fb3SJohannes Berg } 9568e664fb3SJohannes Berg 957651b5225SJouni Malinen if (channel && sband->band == IEEE80211_BAND_2GHZ) { 958651b5225SJouni Malinen *pos++ = WLAN_EID_DS_PARAMS; 959651b5225SJouni Malinen *pos++ = 1; 960651b5225SJouni Malinen *pos++ = channel; 961651b5225SJouni Malinen } 962651b5225SJouni Malinen 9638e664fb3SJohannes Berg /* insert custom IEs that go before HT */ 9648e664fb3SJohannes Berg if (ie && ie_len) { 9658e664fb3SJohannes Berg static const u8 before_ht[] = { 9668e664fb3SJohannes Berg WLAN_EID_SSID, 9678e664fb3SJohannes Berg WLAN_EID_SUPP_RATES, 9688e664fb3SJohannes Berg WLAN_EID_REQUEST, 9698e664fb3SJohannes Berg WLAN_EID_EXT_SUPP_RATES, 9708e664fb3SJohannes Berg WLAN_EID_DS_PARAMS, 9718e664fb3SJohannes Berg WLAN_EID_SUPPORTED_REGULATORY_CLASSES, 9728e664fb3SJohannes Berg }; 9738e664fb3SJohannes Berg noffset = ieee80211_ie_split(ie, ie_len, 9748e664fb3SJohannes Berg before_ht, ARRAY_SIZE(before_ht), 9758e664fb3SJohannes Berg offset); 9768e664fb3SJohannes Berg memcpy(pos, ie + offset, noffset - offset); 9778e664fb3SJohannes Berg pos += noffset - offset; 9788e664fb3SJohannes Berg offset = noffset; 979de95a54bSJohannes Berg } 980de95a54bSJohannes Berg 98142e7aa77SAlexander Simon if (sband->ht_cap.ht_supported) 98242e7aa77SAlexander Simon pos = ieee80211_ie_build_ht_cap(pos, sband, sband->ht_cap.cap); 9835ef2d41aSJohannes Berg 984de95a54bSJohannes Berg /* 985de95a54bSJohannes Berg * If adding more here, adjust code in main.c 986de95a54bSJohannes Berg * that calculates local->scan_ies_len. 987de95a54bSJohannes Berg */ 988de95a54bSJohannes Berg 9898e664fb3SJohannes Berg /* add any remaining custom IEs */ 9908e664fb3SJohannes Berg if (ie && ie_len) { 9918e664fb3SJohannes Berg noffset = ie_len; 9928e664fb3SJohannes Berg memcpy(pos, ie + offset, noffset - offset); 9938e664fb3SJohannes Berg pos += noffset - offset; 994de95a54bSJohannes Berg } 995de95a54bSJohannes Berg 996de95a54bSJohannes Berg return pos - buffer; 997de95a54bSJohannes Berg } 998de95a54bSJohannes Berg 999a619a4c0SJuuso Oikarinen struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, 100085a237feSJohannes Berg u8 *dst, u32 ratemask, 1001de95a54bSJohannes Berg const u8 *ssid, size_t ssid_len, 1002a806c558SPaul Stewart const u8 *ie, size_t ie_len, 1003a806c558SPaul Stewart bool directed) 100446900298SJohannes Berg { 100546900298SJohannes Berg struct ieee80211_local *local = sdata->local; 100646900298SJohannes Berg struct sk_buff *skb; 100746900298SJohannes Berg struct ieee80211_mgmt *mgmt; 10087c12ce8bSKalle Valo size_t buf_len; 10097c12ce8bSKalle Valo u8 *buf; 1010651b5225SJouni Malinen u8 chan; 101146900298SJohannes Berg 10127c12ce8bSKalle Valo /* FIXME: come up with a proper value */ 10137c12ce8bSKalle Valo buf = kmalloc(200 + ie_len, GFP_KERNEL); 1014d15b8459SJoe Perches if (!buf) 1015a619a4c0SJuuso Oikarinen return NULL; 101646900298SJohannes Berg 1017a806c558SPaul Stewart /* 1018a806c558SPaul Stewart * Do not send DS Channel parameter for directed probe requests 1019a806c558SPaul Stewart * in order to maximize the chance that we get a response. Some 1020a806c558SPaul Stewart * badly-behaved APs don't respond when this parameter is included. 1021a806c558SPaul Stewart */ 1022a806c558SPaul Stewart if (directed) 1023a806c558SPaul Stewart chan = 0; 1024a806c558SPaul Stewart else 1025651b5225SJouni Malinen chan = ieee80211_frequency_to_channel( 1026651b5225SJouni Malinen local->hw.conf.channel->center_freq); 1027651b5225SJouni Malinen 10287c12ce8bSKalle Valo buf_len = ieee80211_build_preq_ies(local, buf, ie, ie_len, 10298dcb2003SJouni Malinen local->hw.conf.channel->band, 103085a237feSJohannes Berg ratemask, chan); 10317c12ce8bSKalle Valo 10327c12ce8bSKalle Valo skb = ieee80211_probereq_get(&local->hw, &sdata->vif, 10337c12ce8bSKalle Valo ssid, ssid_len, 10347c12ce8bSKalle Valo buf, buf_len); 10357c12ce8bSKalle Valo 103646900298SJohannes Berg if (dst) { 10377c12ce8bSKalle Valo mgmt = (struct ieee80211_mgmt *) skb->data; 103846900298SJohannes Berg memcpy(mgmt->da, dst, ETH_ALEN); 103946900298SJohannes Berg memcpy(mgmt->bssid, dst, ETH_ALEN); 104046900298SJohannes Berg } 104146900298SJohannes Berg 104262ae67beSJohannes Berg IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; 1043145b6d1aSMing Lei kfree(buf); 1044a619a4c0SJuuso Oikarinen 1045a619a4c0SJuuso Oikarinen return skb; 1046a619a4c0SJuuso Oikarinen } 1047a619a4c0SJuuso Oikarinen 1048a619a4c0SJuuso Oikarinen void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, 1049a619a4c0SJuuso Oikarinen const u8 *ssid, size_t ssid_len, 1050a806c558SPaul Stewart const u8 *ie, size_t ie_len, 1051aad14cebSRajkumar Manoharan u32 ratemask, bool directed, bool no_cck) 1052a619a4c0SJuuso Oikarinen { 1053a619a4c0SJuuso Oikarinen struct sk_buff *skb; 1054a619a4c0SJuuso Oikarinen 105585a237feSJohannes Berg skb = ieee80211_build_probe_req(sdata, dst, ratemask, ssid, ssid_len, 105685a237feSJohannes Berg ie, ie_len, directed); 1057aad14cebSRajkumar Manoharan if (skb) { 1058aad14cebSRajkumar Manoharan if (no_cck) 1059aad14cebSRajkumar Manoharan IEEE80211_SKB_CB(skb)->flags |= 1060aad14cebSRajkumar Manoharan IEEE80211_TX_CTL_NO_CCK_RATE; 1061a619a4c0SJuuso Oikarinen ieee80211_tx_skb(sdata, skb); 106246900298SJohannes Berg } 1063aad14cebSRajkumar Manoharan } 106446900298SJohannes Berg 106546900298SJohannes Berg u32 ieee80211_sta_get_rates(struct ieee80211_local *local, 106646900298SJohannes Berg struct ieee802_11_elems *elems, 106746900298SJohannes Berg enum ieee80211_band band) 106846900298SJohannes Berg { 106946900298SJohannes Berg struct ieee80211_supported_band *sband; 107046900298SJohannes Berg struct ieee80211_rate *bitrates; 107146900298SJohannes Berg size_t num_rates; 107246900298SJohannes Berg u32 supp_rates; 107346900298SJohannes Berg int i, j; 107446900298SJohannes Berg sband = local->hw.wiphy->bands[band]; 107546900298SJohannes Berg 107646900298SJohannes Berg if (!sband) { 107746900298SJohannes Berg WARN_ON(1); 107846900298SJohannes Berg sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; 107946900298SJohannes Berg } 108046900298SJohannes Berg 108146900298SJohannes Berg bitrates = sband->bitrates; 108246900298SJohannes Berg num_rates = sband->n_bitrates; 108346900298SJohannes Berg supp_rates = 0; 108446900298SJohannes Berg for (i = 0; i < elems->supp_rates_len + 108546900298SJohannes Berg elems->ext_supp_rates_len; i++) { 108646900298SJohannes Berg u8 rate = 0; 108746900298SJohannes Berg int own_rate; 108846900298SJohannes Berg if (i < elems->supp_rates_len) 108946900298SJohannes Berg rate = elems->supp_rates[i]; 109046900298SJohannes Berg else if (elems->ext_supp_rates) 109146900298SJohannes Berg rate = elems->ext_supp_rates 109246900298SJohannes Berg [i - elems->supp_rates_len]; 109346900298SJohannes Berg own_rate = 5 * (rate & 0x7f); 109446900298SJohannes Berg for (j = 0; j < num_rates; j++) 109546900298SJohannes Berg if (bitrates[j].bitrate == own_rate) 109646900298SJohannes Berg supp_rates |= BIT(j); 109746900298SJohannes Berg } 109846900298SJohannes Berg return supp_rates; 109946900298SJohannes Berg } 1100f2753ddbSJohannes Berg 110184f6a01cSJohannes Berg void ieee80211_stop_device(struct ieee80211_local *local) 110284f6a01cSJohannes Berg { 110384f6a01cSJohannes Berg ieee80211_led_radio(local, false); 110467408c8cSJohannes Berg ieee80211_mod_tpt_led_trig(local, 0, IEEE80211_TPT_LEDTRIG_FL_RADIO); 110584f6a01cSJohannes Berg 110684f6a01cSJohannes Berg cancel_work_sync(&local->reconfig_filter); 110784f6a01cSJohannes Berg 110884f6a01cSJohannes Berg flush_workqueue(local->workqueue); 1109678f415fSLennert Buytenhek drv_stop(local); 111084f6a01cSJohannes Berg } 111184f6a01cSJohannes Berg 1112f2753ddbSJohannes Berg int ieee80211_reconfig(struct ieee80211_local *local) 1113f2753ddbSJohannes Berg { 1114f2753ddbSJohannes Berg struct ieee80211_hw *hw = &local->hw; 1115f2753ddbSJohannes Berg struct ieee80211_sub_if_data *sdata; 1116f2753ddbSJohannes Berg struct sta_info *sta; 11172683d65bSEliad Peller int res, i; 11185bb644a0SJohannes Berg 1119eecc4800SJohannes Berg #ifdef CONFIG_PM 1120ceb99fe0SJohannes Berg if (local->suspended) 1121ceb99fe0SJohannes Berg local->resuming = true; 1122f2753ddbSJohannes Berg 1123eecc4800SJohannes Berg if (local->wowlan) { 1124eecc4800SJohannes Berg local->wowlan = false; 1125eecc4800SJohannes Berg res = drv_resume(local); 1126eecc4800SJohannes Berg if (res < 0) { 1127eecc4800SJohannes Berg local->resuming = false; 1128eecc4800SJohannes Berg return res; 1129eecc4800SJohannes Berg } 1130eecc4800SJohannes Berg if (res == 0) 1131eecc4800SJohannes Berg goto wake_up; 1132eecc4800SJohannes Berg WARN_ON(res > 1); 1133eecc4800SJohannes Berg /* 1134eecc4800SJohannes Berg * res is 1, which means the driver requested 1135eecc4800SJohannes Berg * to go through a regular reset on wakeup. 1136eecc4800SJohannes Berg */ 1137eecc4800SJohannes Berg } 1138eecc4800SJohannes Berg #endif 1139eecc4800SJohannes Berg 114094f9b97bSJohannes Berg /* setup fragmentation threshold */ 114194f9b97bSJohannes Berg drv_set_frag_threshold(local, hw->wiphy->frag_threshold); 114294f9b97bSJohannes Berg 114394f9b97bSJohannes Berg /* setup RTS threshold */ 114494f9b97bSJohannes Berg drv_set_rts_threshold(local, hw->wiphy->rts_threshold); 114594f9b97bSJohannes Berg 114694f9b97bSJohannes Berg /* reset coverage class */ 114794f9b97bSJohannes Berg drv_set_coverage_class(local, hw->wiphy->coverage_class); 114894f9b97bSJohannes Berg 114994f9b97bSJohannes Berg /* everything else happens only if HW was up & running */ 115094f9b97bSJohannes Berg if (!local->open_count) 115194f9b97bSJohannes Berg goto wake_up; 115294f9b97bSJohannes Berg 115324feda00SLuis R. Rodriguez /* 115424feda00SLuis R. Rodriguez * Upon resume hardware can sometimes be goofy due to 115524feda00SLuis R. Rodriguez * various platform / driver / bus issues, so restarting 115624feda00SLuis R. Rodriguez * the device may at times not work immediately. Propagate 115724feda00SLuis R. Rodriguez * the error. 115824feda00SLuis R. Rodriguez */ 115924487981SJohannes Berg res = drv_start(local); 116024feda00SLuis R. Rodriguez if (res) { 1161c7a00dc7SJohn W. Linville WARN(local->suspended, "Hardware became unavailable " 1162c7a00dc7SJohn W. Linville "upon resume. This could be a software issue " 1163c7a00dc7SJohn W. Linville "prior to suspend or a hardware issue.\n"); 116424feda00SLuis R. Rodriguez return res; 116524feda00SLuis R. Rodriguez } 1166f2753ddbSJohannes Berg 11671f87f7d3SJohannes Berg ieee80211_led_radio(local, true); 116867408c8cSJohannes Berg ieee80211_mod_tpt_led_trig(local, 116967408c8cSJohannes Berg IEEE80211_TPT_LEDTRIG_FL_RADIO, 0); 1170f2753ddbSJohannes Berg 1171f2753ddbSJohannes Berg /* add interfaces */ 1172f2753ddbSJohannes Berg list_for_each_entry(sdata, &local->interfaces, list) { 1173f2753ddbSJohannes Berg if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && 1174f2753ddbSJohannes Berg sdata->vif.type != NL80211_IFTYPE_MONITOR && 11751ed32e4fSJohannes Berg ieee80211_sdata_running(sdata)) 11767b7eab6fSJohannes Berg res = drv_add_interface(local, sdata); 1177f2753ddbSJohannes Berg } 1178f2753ddbSJohannes Berg 1179f2753ddbSJohannes Berg /* add STAs back */ 118034e89507SJohannes Berg mutex_lock(&local->sta_mtx); 1181f2753ddbSJohannes Berg list_for_each_entry(sta, &local->sta_list, list) { 118234e89507SJohannes Berg if (sta->uploaded) { 11835bb644a0SJohannes Berg sdata = sta->sdata; 1184f2753ddbSJohannes Berg if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) 1185f2753ddbSJohannes Berg sdata = container_of(sdata->bss, 1186f2753ddbSJohannes Berg struct ieee80211_sub_if_data, 1187f2753ddbSJohannes Berg u.ap); 1188f2753ddbSJohannes Berg 1189f785d83aSEliad Peller memset(&sta->sta.drv_priv, 0, hw->sta_data_size); 119034e89507SJohannes Berg WARN_ON(drv_sta_add(local, sdata, &sta->sta)); 1191f2753ddbSJohannes Berg } 1192f2753ddbSJohannes Berg } 119334e89507SJohannes Berg mutex_unlock(&local->sta_mtx); 1194f2753ddbSJohannes Berg 11952683d65bSEliad Peller /* reconfigure tx conf */ 1196f6f3def3SEliad Peller list_for_each_entry(sdata, &local->interfaces, list) { 1197f6f3def3SEliad Peller if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN || 1198f6f3def3SEliad Peller sdata->vif.type == NL80211_IFTYPE_MONITOR || 1199f6f3def3SEliad Peller !ieee80211_sdata_running(sdata)) 1200f6f3def3SEliad Peller continue; 1201f6f3def3SEliad Peller 12022683d65bSEliad Peller for (i = 0; i < hw->queues; i++) 1203f6f3def3SEliad Peller drv_conf_tx(local, sdata, i, &sdata->tx_conf[i]); 1204f6f3def3SEliad Peller } 12052683d65bSEliad Peller 1206f2753ddbSJohannes Berg /* reconfigure hardware */ 1207f2753ddbSJohannes Berg ieee80211_hw_config(local, ~0); 1208f2753ddbSJohannes Berg 1209f2753ddbSJohannes Berg ieee80211_configure_filter(local); 1210f2753ddbSJohannes Berg 1211f2753ddbSJohannes Berg /* Finally also reconfigure all the BSS information */ 1212f2753ddbSJohannes Berg list_for_each_entry(sdata, &local->interfaces, list) { 1213ac8dd506SJohannes Berg u32 changed; 1214ac8dd506SJohannes Berg 12159607e6b6SJohannes Berg if (!ieee80211_sdata_running(sdata)) 1216f2753ddbSJohannes Berg continue; 1217ac8dd506SJohannes Berg 1218ac8dd506SJohannes Berg /* common change flags for all interface types */ 1219ac8dd506SJohannes Berg changed = BSS_CHANGED_ERP_CTS_PROT | 1220ac8dd506SJohannes Berg BSS_CHANGED_ERP_PREAMBLE | 1221ac8dd506SJohannes Berg BSS_CHANGED_ERP_SLOT | 1222ac8dd506SJohannes Berg BSS_CHANGED_HT | 1223ac8dd506SJohannes Berg BSS_CHANGED_BASIC_RATES | 1224ac8dd506SJohannes Berg BSS_CHANGED_BEACON_INT | 1225ac8dd506SJohannes Berg BSS_CHANGED_BSSID | 12264ced3f74SJohannes Berg BSS_CHANGED_CQM | 122755de47f6SEliad Peller BSS_CHANGED_QOS | 122855de47f6SEliad Peller BSS_CHANGED_IDLE; 1229ac8dd506SJohannes Berg 1230f2753ddbSJohannes Berg switch (sdata->vif.type) { 1231f2753ddbSJohannes Berg case NL80211_IFTYPE_STATION: 1232ac8dd506SJohannes Berg changed |= BSS_CHANGED_ASSOC; 1233a7b545f7SEliad Peller mutex_lock(&sdata->u.mgd.mtx); 1234ac8dd506SJohannes Berg ieee80211_bss_info_change_notify(sdata, changed); 1235a7b545f7SEliad Peller mutex_unlock(&sdata->u.mgd.mtx); 1236ac8dd506SJohannes Berg break; 1237f2753ddbSJohannes Berg case NL80211_IFTYPE_ADHOC: 1238ac8dd506SJohannes Berg changed |= BSS_CHANGED_IBSS; 1239ac8dd506SJohannes Berg /* fall through */ 1240f2753ddbSJohannes Berg case NL80211_IFTYPE_AP: 124102945821SArik Nemtsov changed |= BSS_CHANGED_SSID | 124202945821SArik Nemtsov BSS_CHANGED_AP_PROBE_RESP; 12437827493bSArik Nemtsov /* fall through */ 1244f2753ddbSJohannes Berg case NL80211_IFTYPE_MESH_POINT: 1245ac8dd506SJohannes Berg changed |= BSS_CHANGED_BEACON | 1246ac8dd506SJohannes Berg BSS_CHANGED_BEACON_ENABLED; 12472d0ddec5SJohannes Berg ieee80211_bss_info_change_notify(sdata, changed); 1248f2753ddbSJohannes Berg break; 1249f2753ddbSJohannes Berg case NL80211_IFTYPE_WDS: 1250f2753ddbSJohannes Berg break; 1251f2753ddbSJohannes Berg case NL80211_IFTYPE_AP_VLAN: 1252f2753ddbSJohannes Berg case NL80211_IFTYPE_MONITOR: 1253f2753ddbSJohannes Berg /* ignore virtual */ 1254f2753ddbSJohannes Berg break; 1255f2753ddbSJohannes Berg case NL80211_IFTYPE_UNSPECIFIED: 12562e161f78SJohannes Berg case NUM_NL80211_IFTYPES: 12572ca27bcfSJohannes Berg case NL80211_IFTYPE_P2P_CLIENT: 12582ca27bcfSJohannes Berg case NL80211_IFTYPE_P2P_GO: 1259f2753ddbSJohannes Berg WARN_ON(1); 1260f2753ddbSJohannes Berg break; 1261f2753ddbSJohannes Berg } 1262f2753ddbSJohannes Berg } 1263f2753ddbSJohannes Berg 12648e1b23b9SEyal Shapira ieee80211_recalc_ps(local, -1); 12658e1b23b9SEyal Shapira 12662a419056SJohannes Berg /* 12672a419056SJohannes Berg * Clear the WLAN_STA_BLOCK_BA flag so new aggregation 12682a419056SJohannes Berg * sessions can be established after a resume. 12692a419056SJohannes Berg * 12702a419056SJohannes Berg * Also tear down aggregation sessions since reconfiguring 12712a419056SJohannes Berg * them in a hardware restart scenario is not easily done 12722a419056SJohannes Berg * right now, and the hardware will have lost information 12732a419056SJohannes Berg * about the sessions, but we and the AP still think they 12742a419056SJohannes Berg * are active. This is really a workaround though. 12752a419056SJohannes Berg */ 127674e2bd1fSWey-Yi Guy if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { 12772a419056SJohannes Berg mutex_lock(&local->sta_mtx); 12782a419056SJohannes Berg 12792a419056SJohannes Berg list_for_each_entry(sta, &local->sta_list, list) { 128053f73c09SJohannes Berg ieee80211_sta_tear_down_BA_sessions(sta, true); 1281c2c98fdeSJohannes Berg clear_sta_flag(sta, WLAN_STA_BLOCK_BA); 128274e2bd1fSWey-Yi Guy } 12832a419056SJohannes Berg 12842a419056SJohannes Berg mutex_unlock(&local->sta_mtx); 128574e2bd1fSWey-Yi Guy } 128674e2bd1fSWey-Yi Guy 1287f2753ddbSJohannes Berg /* add back keys */ 1288f2753ddbSJohannes Berg list_for_each_entry(sdata, &local->interfaces, list) 12899607e6b6SJohannes Berg if (ieee80211_sdata_running(sdata)) 1290f2753ddbSJohannes Berg ieee80211_enable_keys(sdata); 1291f2753ddbSJohannes Berg 1292eecc4800SJohannes Berg wake_up: 1293f2753ddbSJohannes Berg ieee80211_wake_queues_by_reason(hw, 1294f2753ddbSJohannes Berg IEEE80211_QUEUE_STOP_REASON_SUSPEND); 1295f2753ddbSJohannes Berg 12965bb644a0SJohannes Berg /* 12975bb644a0SJohannes Berg * If this is for hw restart things are still running. 12985bb644a0SJohannes Berg * We may want to change that later, however. 12995bb644a0SJohannes Berg */ 1300ceb99fe0SJohannes Berg if (!local->suspended) 13015bb644a0SJohannes Berg return 0; 13025bb644a0SJohannes Berg 13035bb644a0SJohannes Berg #ifdef CONFIG_PM 1304ceb99fe0SJohannes Berg /* first set suspended false, then resuming */ 13055bb644a0SJohannes Berg local->suspended = false; 1306ceb99fe0SJohannes Berg mb(); 1307ceb99fe0SJohannes Berg local->resuming = false; 13085bb644a0SJohannes Berg 13095bb644a0SJohannes Berg list_for_each_entry(sdata, &local->interfaces, list) { 13105bb644a0SJohannes Berg switch(sdata->vif.type) { 13115bb644a0SJohannes Berg case NL80211_IFTYPE_STATION: 13125bb644a0SJohannes Berg ieee80211_sta_restart(sdata); 13135bb644a0SJohannes Berg break; 13145bb644a0SJohannes Berg case NL80211_IFTYPE_ADHOC: 13155bb644a0SJohannes Berg ieee80211_ibss_restart(sdata); 13165bb644a0SJohannes Berg break; 13175bb644a0SJohannes Berg case NL80211_IFTYPE_MESH_POINT: 13185bb644a0SJohannes Berg ieee80211_mesh_restart(sdata); 13195bb644a0SJohannes Berg break; 13205bb644a0SJohannes Berg default: 13215bb644a0SJohannes Berg break; 13225bb644a0SJohannes Berg } 13235bb644a0SJohannes Berg } 13245bb644a0SJohannes Berg 132526d59535SJohannes Berg mod_timer(&local->sta_cleanup, jiffies + 1); 13265bb644a0SJohannes Berg 132734e89507SJohannes Berg mutex_lock(&local->sta_mtx); 13285bb644a0SJohannes Berg list_for_each_entry(sta, &local->sta_list, list) 13295bb644a0SJohannes Berg mesh_plink_restart(sta); 133034e89507SJohannes Berg mutex_unlock(&local->sta_mtx); 13315bb644a0SJohannes Berg #else 13325bb644a0SJohannes Berg WARN_ON(1); 13335bb644a0SJohannes Berg #endif 1334f2753ddbSJohannes Berg return 0; 1335f2753ddbSJohannes Berg } 133642935ecaSLuis R. Rodriguez 133795acac61SJohannes Berg void ieee80211_resume_disconnect(struct ieee80211_vif *vif) 133895acac61SJohannes Berg { 133995acac61SJohannes Berg struct ieee80211_sub_if_data *sdata; 134095acac61SJohannes Berg struct ieee80211_local *local; 134195acac61SJohannes Berg struct ieee80211_key *key; 134295acac61SJohannes Berg 134395acac61SJohannes Berg if (WARN_ON(!vif)) 134495acac61SJohannes Berg return; 134595acac61SJohannes Berg 134695acac61SJohannes Berg sdata = vif_to_sdata(vif); 134795acac61SJohannes Berg local = sdata->local; 134895acac61SJohannes Berg 134995acac61SJohannes Berg if (WARN_ON(!local->resuming)) 135095acac61SJohannes Berg return; 135195acac61SJohannes Berg 135295acac61SJohannes Berg if (WARN_ON(vif->type != NL80211_IFTYPE_STATION)) 135395acac61SJohannes Berg return; 135495acac61SJohannes Berg 135595acac61SJohannes Berg sdata->flags |= IEEE80211_SDATA_DISCONNECT_RESUME; 135695acac61SJohannes Berg 135795acac61SJohannes Berg mutex_lock(&local->key_mtx); 135895acac61SJohannes Berg list_for_each_entry(key, &sdata->key_list, list) 135995acac61SJohannes Berg key->flags |= KEY_FLAG_TAINTED; 136095acac61SJohannes Berg mutex_unlock(&local->key_mtx); 136195acac61SJohannes Berg } 136295acac61SJohannes Berg EXPORT_SYMBOL_GPL(ieee80211_resume_disconnect); 136395acac61SJohannes Berg 13640f78231bSJohannes Berg static int check_mgd_smps(struct ieee80211_if_managed *ifmgd, 13650f78231bSJohannes Berg enum ieee80211_smps_mode *smps_mode) 13660f78231bSJohannes Berg { 13670f78231bSJohannes Berg if (ifmgd->associated) { 13680f78231bSJohannes Berg *smps_mode = ifmgd->ap_smps; 13690f78231bSJohannes Berg 13700f78231bSJohannes Berg if (*smps_mode == IEEE80211_SMPS_AUTOMATIC) { 13710f78231bSJohannes Berg if (ifmgd->powersave) 13720f78231bSJohannes Berg *smps_mode = IEEE80211_SMPS_DYNAMIC; 13730f78231bSJohannes Berg else 13740f78231bSJohannes Berg *smps_mode = IEEE80211_SMPS_OFF; 13750f78231bSJohannes Berg } 13760f78231bSJohannes Berg 13770f78231bSJohannes Berg return 1; 13780f78231bSJohannes Berg } 13790f78231bSJohannes Berg 13800f78231bSJohannes Berg return 0; 13810f78231bSJohannes Berg } 13820f78231bSJohannes Berg 13830f78231bSJohannes Berg /* must hold iflist_mtx */ 1384025e6be2SJohannes Berg void ieee80211_recalc_smps(struct ieee80211_local *local) 13850f78231bSJohannes Berg { 13860f78231bSJohannes Berg struct ieee80211_sub_if_data *sdata; 13870f78231bSJohannes Berg enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_OFF; 13880f78231bSJohannes Berg int count = 0; 13890f78231bSJohannes Berg 139046a5ebafSJohannes Berg lockdep_assert_held(&local->iflist_mtx); 13910f78231bSJohannes Berg 13920f78231bSJohannes Berg /* 13930f78231bSJohannes Berg * This function could be improved to handle multiple 13940f78231bSJohannes Berg * interfaces better, but right now it makes any 13950f78231bSJohannes Berg * non-station interfaces force SM PS to be turned 13960f78231bSJohannes Berg * off. If there are multiple station interfaces it 13970f78231bSJohannes Berg * could also use the best possible mode, e.g. if 13980f78231bSJohannes Berg * one is in static and the other in dynamic then 13990f78231bSJohannes Berg * dynamic is ok. 14000f78231bSJohannes Berg */ 14010f78231bSJohannes Berg 14020f78231bSJohannes Berg list_for_each_entry(sdata, &local->interfaces, list) { 140326a58456SJohannes Berg if (!ieee80211_sdata_running(sdata)) 14040f78231bSJohannes Berg continue; 14050f78231bSJohannes Berg if (sdata->vif.type != NL80211_IFTYPE_STATION) 14060f78231bSJohannes Berg goto set; 1407025e6be2SJohannes Berg 14080f78231bSJohannes Berg count += check_mgd_smps(&sdata->u.mgd, &smps_mode); 14090f78231bSJohannes Berg 14100f78231bSJohannes Berg if (count > 1) { 14110f78231bSJohannes Berg smps_mode = IEEE80211_SMPS_OFF; 14120f78231bSJohannes Berg break; 14130f78231bSJohannes Berg } 14140f78231bSJohannes Berg } 14150f78231bSJohannes Berg 14160f78231bSJohannes Berg if (smps_mode == local->smps_mode) 14170f78231bSJohannes Berg return; 14180f78231bSJohannes Berg 14190f78231bSJohannes Berg set: 14200f78231bSJohannes Berg local->smps_mode = smps_mode; 14210f78231bSJohannes Berg /* changed flag is auto-detected for this */ 14220f78231bSJohannes Berg ieee80211_hw_config(local, 0); 14230f78231bSJohannes Berg } 14248e664fb3SJohannes Berg 14258e664fb3SJohannes Berg static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id) 14268e664fb3SJohannes Berg { 14278e664fb3SJohannes Berg int i; 14288e664fb3SJohannes Berg 14298e664fb3SJohannes Berg for (i = 0; i < n_ids; i++) 14308e664fb3SJohannes Berg if (ids[i] == id) 14318e664fb3SJohannes Berg return true; 14328e664fb3SJohannes Berg return false; 14338e664fb3SJohannes Berg } 14348e664fb3SJohannes Berg 14358e664fb3SJohannes Berg /** 14368e664fb3SJohannes Berg * ieee80211_ie_split - split an IE buffer according to ordering 14378e664fb3SJohannes Berg * 14388e664fb3SJohannes Berg * @ies: the IE buffer 14398e664fb3SJohannes Berg * @ielen: the length of the IE buffer 14408e664fb3SJohannes Berg * @ids: an array with element IDs that are allowed before 14418e664fb3SJohannes Berg * the split 14428e664fb3SJohannes Berg * @n_ids: the size of the element ID array 14438e664fb3SJohannes Berg * @offset: offset where to start splitting in the buffer 14448e664fb3SJohannes Berg * 14458e664fb3SJohannes Berg * This function splits an IE buffer by updating the @offset 14468e664fb3SJohannes Berg * variable to point to the location where the buffer should be 14478e664fb3SJohannes Berg * split. 14488e664fb3SJohannes Berg * 14498e664fb3SJohannes Berg * It assumes that the given IE buffer is well-formed, this 14508e664fb3SJohannes Berg * has to be guaranteed by the caller! 14518e664fb3SJohannes Berg * 14528e664fb3SJohannes Berg * It also assumes that the IEs in the buffer are ordered 14538e664fb3SJohannes Berg * correctly, if not the result of using this function will not 14548e664fb3SJohannes Berg * be ordered correctly either, i.e. it does no reordering. 14558e664fb3SJohannes Berg * 14568e664fb3SJohannes Berg * The function returns the offset where the next part of the 14578e664fb3SJohannes Berg * buffer starts, which may be @ielen if the entire (remainder) 14588e664fb3SJohannes Berg * of the buffer should be used. 14598e664fb3SJohannes Berg */ 14608e664fb3SJohannes Berg size_t ieee80211_ie_split(const u8 *ies, size_t ielen, 14618e664fb3SJohannes Berg const u8 *ids, int n_ids, size_t offset) 14628e664fb3SJohannes Berg { 14638e664fb3SJohannes Berg size_t pos = offset; 14648e664fb3SJohannes Berg 14658e664fb3SJohannes Berg while (pos < ielen && ieee80211_id_in_list(ids, n_ids, ies[pos])) 14668e664fb3SJohannes Berg pos += 2 + ies[pos + 1]; 14678e664fb3SJohannes Berg 14688e664fb3SJohannes Berg return pos; 14698e664fb3SJohannes Berg } 14708e664fb3SJohannes Berg 14718e664fb3SJohannes Berg size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset) 14728e664fb3SJohannes Berg { 14738e664fb3SJohannes Berg size_t pos = offset; 14748e664fb3SJohannes Berg 14758e664fb3SJohannes Berg while (pos < ielen && ies[pos] != WLAN_EID_VENDOR_SPECIFIC) 14768e664fb3SJohannes Berg pos += 2 + ies[pos + 1]; 14778e664fb3SJohannes Berg 14788e664fb3SJohannes Berg return pos; 14798e664fb3SJohannes Berg } 1480615f7b9bSMeenakshi Venkataraman 1481615f7b9bSMeenakshi Venkataraman static void _ieee80211_enable_rssi_reports(struct ieee80211_sub_if_data *sdata, 1482615f7b9bSMeenakshi Venkataraman int rssi_min_thold, 1483615f7b9bSMeenakshi Venkataraman int rssi_max_thold) 1484615f7b9bSMeenakshi Venkataraman { 1485615f7b9bSMeenakshi Venkataraman trace_api_enable_rssi_reports(sdata, rssi_min_thold, rssi_max_thold); 1486615f7b9bSMeenakshi Venkataraman 1487615f7b9bSMeenakshi Venkataraman if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) 1488615f7b9bSMeenakshi Venkataraman return; 1489615f7b9bSMeenakshi Venkataraman 1490615f7b9bSMeenakshi Venkataraman /* 1491615f7b9bSMeenakshi Venkataraman * Scale up threshold values before storing it, as the RSSI averaging 1492615f7b9bSMeenakshi Venkataraman * algorithm uses a scaled up value as well. Change this scaling 1493615f7b9bSMeenakshi Venkataraman * factor if the RSSI averaging algorithm changes. 1494615f7b9bSMeenakshi Venkataraman */ 1495615f7b9bSMeenakshi Venkataraman sdata->u.mgd.rssi_min_thold = rssi_min_thold*16; 1496615f7b9bSMeenakshi Venkataraman sdata->u.mgd.rssi_max_thold = rssi_max_thold*16; 1497615f7b9bSMeenakshi Venkataraman } 1498615f7b9bSMeenakshi Venkataraman 1499615f7b9bSMeenakshi Venkataraman void ieee80211_enable_rssi_reports(struct ieee80211_vif *vif, 1500615f7b9bSMeenakshi Venkataraman int rssi_min_thold, 1501615f7b9bSMeenakshi Venkataraman int rssi_max_thold) 1502615f7b9bSMeenakshi Venkataraman { 1503615f7b9bSMeenakshi Venkataraman struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); 1504615f7b9bSMeenakshi Venkataraman 1505615f7b9bSMeenakshi Venkataraman WARN_ON(rssi_min_thold == rssi_max_thold || 1506615f7b9bSMeenakshi Venkataraman rssi_min_thold > rssi_max_thold); 1507615f7b9bSMeenakshi Venkataraman 1508615f7b9bSMeenakshi Venkataraman _ieee80211_enable_rssi_reports(sdata, rssi_min_thold, 1509615f7b9bSMeenakshi Venkataraman rssi_max_thold); 1510615f7b9bSMeenakshi Venkataraman } 1511615f7b9bSMeenakshi Venkataraman EXPORT_SYMBOL(ieee80211_enable_rssi_reports); 1512615f7b9bSMeenakshi Venkataraman 1513615f7b9bSMeenakshi Venkataraman void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif) 1514615f7b9bSMeenakshi Venkataraman { 1515615f7b9bSMeenakshi Venkataraman struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); 1516615f7b9bSMeenakshi Venkataraman 1517615f7b9bSMeenakshi Venkataraman _ieee80211_enable_rssi_reports(sdata, 0, 0); 1518615f7b9bSMeenakshi Venkataraman } 1519615f7b9bSMeenakshi Venkataraman EXPORT_SYMBOL(ieee80211_disable_rssi_reports); 1520768db343SArik Nemtsov 152142e7aa77SAlexander Simon u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_supported_band *sband, 152242e7aa77SAlexander Simon u16 cap) 152342e7aa77SAlexander Simon { 152442e7aa77SAlexander Simon __le16 tmp; 152542e7aa77SAlexander Simon 152642e7aa77SAlexander Simon *pos++ = WLAN_EID_HT_CAPABILITY; 152742e7aa77SAlexander Simon *pos++ = sizeof(struct ieee80211_ht_cap); 152842e7aa77SAlexander Simon memset(pos, 0, sizeof(struct ieee80211_ht_cap)); 152942e7aa77SAlexander Simon 153042e7aa77SAlexander Simon /* capability flags */ 153142e7aa77SAlexander Simon tmp = cpu_to_le16(cap); 153242e7aa77SAlexander Simon memcpy(pos, &tmp, sizeof(u16)); 153342e7aa77SAlexander Simon pos += sizeof(u16); 153442e7aa77SAlexander Simon 153542e7aa77SAlexander Simon /* AMPDU parameters */ 153642e7aa77SAlexander Simon *pos++ = sband->ht_cap.ampdu_factor | 153742e7aa77SAlexander Simon (sband->ht_cap.ampdu_density << 153842e7aa77SAlexander Simon IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT); 153942e7aa77SAlexander Simon 154042e7aa77SAlexander Simon /* MCS set */ 154142e7aa77SAlexander Simon memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); 154242e7aa77SAlexander Simon pos += sizeof(sband->ht_cap.mcs); 154342e7aa77SAlexander Simon 154442e7aa77SAlexander Simon /* extended capabilities */ 154542e7aa77SAlexander Simon pos += sizeof(__le16); 154642e7aa77SAlexander Simon 154742e7aa77SAlexander Simon /* BF capabilities */ 154842e7aa77SAlexander Simon pos += sizeof(__le32); 154942e7aa77SAlexander Simon 155042e7aa77SAlexander Simon /* antenna selection */ 155142e7aa77SAlexander Simon pos += sizeof(u8); 155242e7aa77SAlexander Simon 155342e7aa77SAlexander Simon return pos; 155442e7aa77SAlexander Simon } 155542e7aa77SAlexander Simon 155642e7aa77SAlexander Simon u8 *ieee80211_ie_build_ht_info(u8 *pos, 155742e7aa77SAlexander Simon struct ieee80211_sta_ht_cap *ht_cap, 155842e7aa77SAlexander Simon struct ieee80211_channel *channel, 155942e7aa77SAlexander Simon enum nl80211_channel_type channel_type) 156042e7aa77SAlexander Simon { 156142e7aa77SAlexander Simon struct ieee80211_ht_info *ht_info; 156242e7aa77SAlexander Simon /* Build HT Information */ 156342e7aa77SAlexander Simon *pos++ = WLAN_EID_HT_INFORMATION; 156442e7aa77SAlexander Simon *pos++ = sizeof(struct ieee80211_ht_info); 156542e7aa77SAlexander Simon ht_info = (struct ieee80211_ht_info *)pos; 156642e7aa77SAlexander Simon ht_info->control_chan = 156742e7aa77SAlexander Simon ieee80211_frequency_to_channel(channel->center_freq); 156842e7aa77SAlexander Simon switch (channel_type) { 156942e7aa77SAlexander Simon case NL80211_CHAN_HT40MINUS: 157042e7aa77SAlexander Simon ht_info->ht_param = IEEE80211_HT_PARAM_CHA_SEC_BELOW; 157142e7aa77SAlexander Simon break; 157242e7aa77SAlexander Simon case NL80211_CHAN_HT40PLUS: 157342e7aa77SAlexander Simon ht_info->ht_param = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; 157442e7aa77SAlexander Simon break; 157542e7aa77SAlexander Simon case NL80211_CHAN_HT20: 157642e7aa77SAlexander Simon default: 157742e7aa77SAlexander Simon ht_info->ht_param = IEEE80211_HT_PARAM_CHA_SEC_NONE; 157842e7aa77SAlexander Simon break; 157942e7aa77SAlexander Simon } 158042e7aa77SAlexander Simon if (ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) 158142e7aa77SAlexander Simon ht_info->ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY; 158242e7aa77SAlexander Simon ht_info->operation_mode = 0x0000; 158342e7aa77SAlexander Simon ht_info->stbc_param = 0x0000; 158442e7aa77SAlexander Simon 158542e7aa77SAlexander Simon /* It seems that Basic MCS set and Supported MCS set 158642e7aa77SAlexander Simon are identical for the first 10 bytes */ 158742e7aa77SAlexander Simon memset(&ht_info->basic_set, 0, 16); 158842e7aa77SAlexander Simon memcpy(&ht_info->basic_set, &ht_cap->mcs, 10); 158942e7aa77SAlexander Simon 159042e7aa77SAlexander Simon return pos + sizeof(struct ieee80211_ht_info); 159142e7aa77SAlexander Simon } 159242e7aa77SAlexander Simon 159342e7aa77SAlexander Simon enum nl80211_channel_type 159442e7aa77SAlexander Simon ieee80211_ht_info_to_channel_type(struct ieee80211_ht_info *ht_info) 159542e7aa77SAlexander Simon { 159642e7aa77SAlexander Simon enum nl80211_channel_type channel_type; 159742e7aa77SAlexander Simon 159842e7aa77SAlexander Simon if (!ht_info) 159942e7aa77SAlexander Simon return NL80211_CHAN_NO_HT; 160042e7aa77SAlexander Simon 160142e7aa77SAlexander Simon switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { 160242e7aa77SAlexander Simon case IEEE80211_HT_PARAM_CHA_SEC_NONE: 160342e7aa77SAlexander Simon channel_type = NL80211_CHAN_HT20; 160442e7aa77SAlexander Simon break; 160542e7aa77SAlexander Simon case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: 160642e7aa77SAlexander Simon channel_type = NL80211_CHAN_HT40PLUS; 160742e7aa77SAlexander Simon break; 160842e7aa77SAlexander Simon case IEEE80211_HT_PARAM_CHA_SEC_BELOW: 160942e7aa77SAlexander Simon channel_type = NL80211_CHAN_HT40MINUS; 161042e7aa77SAlexander Simon break; 161142e7aa77SAlexander Simon default: 161242e7aa77SAlexander Simon channel_type = NL80211_CHAN_NO_HT; 161342e7aa77SAlexander Simon } 161442e7aa77SAlexander Simon 161542e7aa77SAlexander Simon return channel_type; 161642e7aa77SAlexander Simon } 161742e7aa77SAlexander Simon 1618768db343SArik Nemtsov int ieee80211_add_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb) 1619768db343SArik Nemtsov { 1620768db343SArik Nemtsov struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); 1621768db343SArik Nemtsov struct ieee80211_local *local = sdata->local; 1622768db343SArik Nemtsov struct ieee80211_supported_band *sband; 1623768db343SArik Nemtsov int rate; 1624768db343SArik Nemtsov u8 i, rates, *pos; 1625768db343SArik Nemtsov 1626768db343SArik Nemtsov sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; 1627768db343SArik Nemtsov rates = sband->n_bitrates; 1628768db343SArik Nemtsov if (rates > 8) 1629768db343SArik Nemtsov rates = 8; 1630768db343SArik Nemtsov 1631768db343SArik Nemtsov if (skb_tailroom(skb) < rates + 2) 1632768db343SArik Nemtsov return -ENOMEM; 1633768db343SArik Nemtsov 1634768db343SArik Nemtsov pos = skb_put(skb, rates + 2); 1635768db343SArik Nemtsov *pos++ = WLAN_EID_SUPP_RATES; 1636768db343SArik Nemtsov *pos++ = rates; 1637768db343SArik Nemtsov for (i = 0; i < rates; i++) { 1638768db343SArik Nemtsov rate = sband->bitrates[i].bitrate; 1639768db343SArik Nemtsov *pos++ = (u8) (rate / 5); 1640768db343SArik Nemtsov } 1641768db343SArik Nemtsov 1642768db343SArik Nemtsov return 0; 1643768db343SArik Nemtsov } 1644768db343SArik Nemtsov 1645768db343SArik Nemtsov int ieee80211_add_ext_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb) 1646768db343SArik Nemtsov { 1647768db343SArik Nemtsov struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); 1648768db343SArik Nemtsov struct ieee80211_local *local = sdata->local; 1649768db343SArik Nemtsov struct ieee80211_supported_band *sband; 1650768db343SArik Nemtsov int rate; 1651768db343SArik Nemtsov u8 i, exrates, *pos; 1652768db343SArik Nemtsov 1653768db343SArik Nemtsov sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; 1654768db343SArik Nemtsov exrates = sband->n_bitrates; 1655768db343SArik Nemtsov if (exrates > 8) 1656768db343SArik Nemtsov exrates -= 8; 1657768db343SArik Nemtsov else 1658768db343SArik Nemtsov exrates = 0; 1659768db343SArik Nemtsov 1660768db343SArik Nemtsov if (skb_tailroom(skb) < exrates + 2) 1661768db343SArik Nemtsov return -ENOMEM; 1662768db343SArik Nemtsov 1663768db343SArik Nemtsov if (exrates) { 1664768db343SArik Nemtsov pos = skb_put(skb, exrates + 2); 1665768db343SArik Nemtsov *pos++ = WLAN_EID_EXT_SUPP_RATES; 1666768db343SArik Nemtsov *pos++ = exrates; 1667768db343SArik Nemtsov for (i = 8; i < sband->n_bitrates; i++) { 1668768db343SArik Nemtsov rate = sband->bitrates[i].bitrate; 1669768db343SArik Nemtsov *pos++ = (u8) (rate / 5); 1670768db343SArik Nemtsov } 1671768db343SArik Nemtsov } 1672768db343SArik Nemtsov return 0; 1673768db343SArik Nemtsov } 1674