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 3718f77f384SJohannes Berg int ieee80211_add_pending_skbs(struct ieee80211_local *local, 3728f77f384SJohannes Berg struct sk_buff_head *skbs) 3738f77f384SJohannes Berg { 3748f77f384SJohannes Berg struct ieee80211_hw *hw = &local->hw; 3758f77f384SJohannes Berg struct sk_buff *skb; 3768f77f384SJohannes Berg unsigned long flags; 3778f77f384SJohannes Berg int queue, ret = 0, i; 3788f77f384SJohannes Berg 3798f77f384SJohannes Berg spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 3808f77f384SJohannes Berg for (i = 0; i < hw->queues; i++) 3818f77f384SJohannes Berg __ieee80211_stop_queue(hw, i, 3828f77f384SJohannes Berg IEEE80211_QUEUE_STOP_REASON_SKB_ADD); 3838f77f384SJohannes Berg 3848f77f384SJohannes Berg while ((skb = skb_dequeue(skbs))) { 385a7bc376cSJohannes Berg struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 386a7bc376cSJohannes Berg 387a7bc376cSJohannes Berg if (WARN_ON(!info->control.vif)) { 3880819663dSRoel Kluin kfree_skb(skb); 389a7bc376cSJohannes Berg continue; 390a7bc376cSJohannes Berg } 391a7bc376cSJohannes Berg 3928f77f384SJohannes Berg ret++; 3938f77f384SJohannes Berg queue = skb_get_queue_mapping(skb); 3943b8d81e0SJohannes Berg __skb_queue_tail(&local->pending[queue], skb); 3958f77f384SJohannes Berg } 3968f77f384SJohannes Berg 3973b8d81e0SJohannes Berg for (i = 0; i < hw->queues; i++) 3988f77f384SJohannes Berg __ieee80211_wake_queue(hw, i, 3998f77f384SJohannes Berg IEEE80211_QUEUE_STOP_REASON_SKB_ADD); 4008f77f384SJohannes Berg spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 4018f77f384SJohannes Berg 4028f77f384SJohannes Berg return ret; 4038f77f384SJohannes Berg } 4048f77f384SJohannes Berg 405ce7c9111SKalle Valo void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, 406ce7c9111SKalle Valo enum queue_stop_reason reason) 407c2d1560aSJohannes Berg { 408ce7c9111SKalle Valo struct ieee80211_local *local = hw_to_local(hw); 409ce7c9111SKalle Valo unsigned long flags; 410c2d1560aSJohannes Berg int i; 411c2d1560aSJohannes Berg 412ce7c9111SKalle Valo spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 413ce7c9111SKalle Valo 41496f5e66eSJohannes Berg for (i = 0; i < hw->queues; i++) 415ce7c9111SKalle Valo __ieee80211_stop_queue(hw, i, reason); 416ce7c9111SKalle Valo 417ce7c9111SKalle Valo spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 418ce7c9111SKalle Valo } 419ce7c9111SKalle Valo 420ce7c9111SKalle Valo void ieee80211_stop_queues(struct ieee80211_hw *hw) 421ce7c9111SKalle Valo { 422ce7c9111SKalle Valo ieee80211_stop_queues_by_reason(hw, 423ce7c9111SKalle Valo IEEE80211_QUEUE_STOP_REASON_DRIVER); 424c2d1560aSJohannes Berg } 425c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_stop_queues); 426c2d1560aSJohannes Berg 42792ab8535STomas Winkler int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue) 42892ab8535STomas Winkler { 42992ab8535STomas Winkler struct ieee80211_local *local = hw_to_local(hw); 4303b8d81e0SJohannes Berg unsigned long flags; 4313b8d81e0SJohannes Berg int ret; 43296f5e66eSJohannes Berg 433e4e72fb4SJohannes Berg if (WARN_ON(queue >= hw->queues)) 43496f5e66eSJohannes Berg return true; 43596f5e66eSJohannes Berg 4363b8d81e0SJohannes Berg spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 4373b8d81e0SJohannes Berg ret = !!local->queue_stop_reasons[queue]; 4383b8d81e0SJohannes Berg spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 4393b8d81e0SJohannes Berg return ret; 44092ab8535STomas Winkler } 44192ab8535STomas Winkler EXPORT_SYMBOL(ieee80211_queue_stopped); 44292ab8535STomas Winkler 443ce7c9111SKalle Valo void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, 444ce7c9111SKalle Valo enum queue_stop_reason reason) 445c2d1560aSJohannes Berg { 446ce7c9111SKalle Valo struct ieee80211_local *local = hw_to_local(hw); 447ce7c9111SKalle Valo unsigned long flags; 448c2d1560aSJohannes Berg int i; 449c2d1560aSJohannes Berg 450ce7c9111SKalle Valo spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 451ce7c9111SKalle Valo 452e4e72fb4SJohannes Berg for (i = 0; i < hw->queues; i++) 453ce7c9111SKalle Valo __ieee80211_wake_queue(hw, i, reason); 454ce7c9111SKalle Valo 455ce7c9111SKalle Valo spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 456ce7c9111SKalle Valo } 457ce7c9111SKalle Valo 458ce7c9111SKalle Valo void ieee80211_wake_queues(struct ieee80211_hw *hw) 459ce7c9111SKalle Valo { 460ce7c9111SKalle Valo ieee80211_wake_queues_by_reason(hw, IEEE80211_QUEUE_STOP_REASON_DRIVER); 461c2d1560aSJohannes Berg } 462c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_wake_queues); 463dabeb344SJohannes Berg 46432bfd35dSJohannes Berg void ieee80211_iterate_active_interfaces( 46532bfd35dSJohannes Berg struct ieee80211_hw *hw, 466dabeb344SJohannes Berg void (*iterator)(void *data, u8 *mac, 46732bfd35dSJohannes Berg struct ieee80211_vif *vif), 468dabeb344SJohannes Berg void *data) 469dabeb344SJohannes Berg { 470dabeb344SJohannes Berg struct ieee80211_local *local = hw_to_local(hw); 471dabeb344SJohannes Berg struct ieee80211_sub_if_data *sdata; 472dabeb344SJohannes Berg 473c771c9d8SJohannes Berg mutex_lock(&local->iflist_mtx); 4742f561febSIvo van Doorn 4752f561febSIvo van Doorn list_for_each_entry(sdata, &local->interfaces, list) { 4762f561febSIvo van Doorn switch (sdata->vif.type) { 47705c914feSJohannes Berg case NL80211_IFTYPE_MONITOR: 47805c914feSJohannes Berg case NL80211_IFTYPE_AP_VLAN: 4792f561febSIvo van Doorn continue; 4802ca27bcfSJohannes Berg default: 4812f561febSIvo van Doorn break; 4822f561febSIvo van Doorn } 4839607e6b6SJohannes Berg if (ieee80211_sdata_running(sdata)) 48447846c9bSJohannes Berg iterator(data, sdata->vif.addr, 4852f561febSIvo van Doorn &sdata->vif); 4862f561febSIvo van Doorn } 4872f561febSIvo van Doorn 488c771c9d8SJohannes Berg mutex_unlock(&local->iflist_mtx); 4892f561febSIvo van Doorn } 4902f561febSIvo van Doorn EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces); 4912f561febSIvo van Doorn 4922f561febSIvo van Doorn void ieee80211_iterate_active_interfaces_atomic( 4932f561febSIvo van Doorn struct ieee80211_hw *hw, 4942f561febSIvo van Doorn void (*iterator)(void *data, u8 *mac, 4952f561febSIvo van Doorn struct ieee80211_vif *vif), 4962f561febSIvo van Doorn void *data) 4972f561febSIvo van Doorn { 4982f561febSIvo van Doorn struct ieee80211_local *local = hw_to_local(hw); 4992f561febSIvo van Doorn struct ieee80211_sub_if_data *sdata; 5002f561febSIvo van Doorn 501e38bad47SJohannes Berg rcu_read_lock(); 502dabeb344SJohannes Berg 503e38bad47SJohannes Berg list_for_each_entry_rcu(sdata, &local->interfaces, list) { 50451fb61e7SJohannes Berg switch (sdata->vif.type) { 50505c914feSJohannes Berg case NL80211_IFTYPE_MONITOR: 50605c914feSJohannes Berg case NL80211_IFTYPE_AP_VLAN: 507dabeb344SJohannes Berg continue; 5082ca27bcfSJohannes Berg default: 509dabeb344SJohannes Berg break; 510dabeb344SJohannes Berg } 5119607e6b6SJohannes Berg if (ieee80211_sdata_running(sdata)) 51247846c9bSJohannes Berg iterator(data, sdata->vif.addr, 51332bfd35dSJohannes Berg &sdata->vif); 514dabeb344SJohannes Berg } 515e38bad47SJohannes Berg 516e38bad47SJohannes Berg rcu_read_unlock(); 517dabeb344SJohannes Berg } 5182f561febSIvo van Doorn EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic); 51937ffc8daSJohannes Berg 52042935ecaSLuis R. Rodriguez /* 52142935ecaSLuis R. Rodriguez * Nothing should have been stuffed into the workqueue during 52242935ecaSLuis R. Rodriguez * the suspend->resume cycle. If this WARN is seen then there 52342935ecaSLuis R. Rodriguez * is a bug with either the driver suspend or something in 52442935ecaSLuis R. Rodriguez * mac80211 stuffing into the workqueue which we haven't yet 52542935ecaSLuis R. Rodriguez * cleared during mac80211's suspend cycle. 52642935ecaSLuis R. Rodriguez */ 52742935ecaSLuis R. Rodriguez static bool ieee80211_can_queue_work(struct ieee80211_local *local) 52842935ecaSLuis R. Rodriguez { 529ceb99fe0SJohannes Berg if (WARN(local->suspended && !local->resuming, 530ceb99fe0SJohannes Berg "queueing ieee80211 work while going to suspend\n")) 53142935ecaSLuis R. Rodriguez return false; 53242935ecaSLuis R. Rodriguez 53342935ecaSLuis R. Rodriguez return true; 53442935ecaSLuis R. Rodriguez } 53542935ecaSLuis R. Rodriguez 53642935ecaSLuis R. Rodriguez void ieee80211_queue_work(struct ieee80211_hw *hw, struct work_struct *work) 53742935ecaSLuis R. Rodriguez { 53842935ecaSLuis R. Rodriguez struct ieee80211_local *local = hw_to_local(hw); 53942935ecaSLuis R. Rodriguez 54042935ecaSLuis R. Rodriguez if (!ieee80211_can_queue_work(local)) 54142935ecaSLuis R. Rodriguez return; 54242935ecaSLuis R. Rodriguez 54342935ecaSLuis R. Rodriguez queue_work(local->workqueue, work); 54442935ecaSLuis R. Rodriguez } 54542935ecaSLuis R. Rodriguez EXPORT_SYMBOL(ieee80211_queue_work); 54642935ecaSLuis R. Rodriguez 54742935ecaSLuis R. Rodriguez void ieee80211_queue_delayed_work(struct ieee80211_hw *hw, 54842935ecaSLuis R. Rodriguez struct delayed_work *dwork, 54942935ecaSLuis R. Rodriguez unsigned long delay) 55042935ecaSLuis R. Rodriguez { 55142935ecaSLuis R. Rodriguez struct ieee80211_local *local = hw_to_local(hw); 55242935ecaSLuis R. Rodriguez 55342935ecaSLuis R. Rodriguez if (!ieee80211_can_queue_work(local)) 55442935ecaSLuis R. Rodriguez return; 55542935ecaSLuis R. Rodriguez 55642935ecaSLuis R. Rodriguez queue_delayed_work(local->workqueue, dwork, delay); 55742935ecaSLuis R. Rodriguez } 55842935ecaSLuis R. Rodriguez EXPORT_SYMBOL(ieee80211_queue_delayed_work); 55942935ecaSLuis R. Rodriguez 56037ffc8daSJohannes Berg void ieee802_11_parse_elems(u8 *start, size_t len, 56137ffc8daSJohannes Berg struct ieee802_11_elems *elems) 56237ffc8daSJohannes Berg { 563d91f36dbSJohannes Berg ieee802_11_parse_elems_crc(start, len, elems, 0, 0); 564d91f36dbSJohannes Berg } 565d91f36dbSJohannes Berg 566d91f36dbSJohannes Berg u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, 567d91f36dbSJohannes Berg struct ieee802_11_elems *elems, 568d91f36dbSJohannes Berg u64 filter, u32 crc) 569d91f36dbSJohannes Berg { 57037ffc8daSJohannes Berg size_t left = len; 57137ffc8daSJohannes Berg u8 *pos = start; 572d91f36dbSJohannes Berg bool calc_crc = filter != 0; 57337ffc8daSJohannes Berg 57437ffc8daSJohannes Berg memset(elems, 0, sizeof(*elems)); 57537ffc8daSJohannes Berg elems->ie_start = start; 57637ffc8daSJohannes Berg elems->total_len = len; 57737ffc8daSJohannes Berg 57837ffc8daSJohannes Berg while (left >= 2) { 57937ffc8daSJohannes Berg u8 id, elen; 58037ffc8daSJohannes Berg 58137ffc8daSJohannes Berg id = *pos++; 58237ffc8daSJohannes Berg elen = *pos++; 58337ffc8daSJohannes Berg left -= 2; 58437ffc8daSJohannes Berg 58537ffc8daSJohannes Berg if (elen > left) 586d91f36dbSJohannes Berg break; 587d91f36dbSJohannes Berg 5881814077fSVasanthakumar Thiagarajan if (calc_crc && id < 64 && (filter & (1ULL << id))) 589d91f36dbSJohannes Berg crc = crc32_be(crc, pos - 2, elen + 2); 59037ffc8daSJohannes Berg 59137ffc8daSJohannes Berg switch (id) { 59237ffc8daSJohannes Berg case WLAN_EID_SSID: 59337ffc8daSJohannes Berg elems->ssid = pos; 59437ffc8daSJohannes Berg elems->ssid_len = elen; 59537ffc8daSJohannes Berg break; 59637ffc8daSJohannes Berg case WLAN_EID_SUPP_RATES: 59737ffc8daSJohannes Berg elems->supp_rates = pos; 59837ffc8daSJohannes Berg elems->supp_rates_len = elen; 59937ffc8daSJohannes Berg break; 60037ffc8daSJohannes Berg case WLAN_EID_FH_PARAMS: 60137ffc8daSJohannes Berg elems->fh_params = pos; 60237ffc8daSJohannes Berg elems->fh_params_len = elen; 60337ffc8daSJohannes Berg break; 60437ffc8daSJohannes Berg case WLAN_EID_DS_PARAMS: 60537ffc8daSJohannes Berg elems->ds_params = pos; 60637ffc8daSJohannes Berg elems->ds_params_len = elen; 60737ffc8daSJohannes Berg break; 60837ffc8daSJohannes Berg case WLAN_EID_CF_PARAMS: 60937ffc8daSJohannes Berg elems->cf_params = pos; 61037ffc8daSJohannes Berg elems->cf_params_len = elen; 61137ffc8daSJohannes Berg break; 61237ffc8daSJohannes Berg case WLAN_EID_TIM: 613e7ec86f5SJohannes Berg if (elen >= sizeof(struct ieee80211_tim_ie)) { 614e7ec86f5SJohannes Berg elems->tim = (void *)pos; 61537ffc8daSJohannes Berg elems->tim_len = elen; 616e7ec86f5SJohannes Berg } 61737ffc8daSJohannes Berg break; 61837ffc8daSJohannes Berg case WLAN_EID_IBSS_PARAMS: 61937ffc8daSJohannes Berg elems->ibss_params = pos; 62037ffc8daSJohannes Berg elems->ibss_params_len = elen; 62137ffc8daSJohannes Berg break; 62237ffc8daSJohannes Berg case WLAN_EID_CHALLENGE: 62337ffc8daSJohannes Berg elems->challenge = pos; 62437ffc8daSJohannes Berg elems->challenge_len = elen; 62537ffc8daSJohannes Berg break; 626d91f36dbSJohannes Berg case WLAN_EID_VENDOR_SPECIFIC: 62737ffc8daSJohannes Berg if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 && 62837ffc8daSJohannes Berg pos[2] == 0xf2) { 62937ffc8daSJohannes Berg /* Microsoft OUI (00:50:F2) */ 630d91f36dbSJohannes Berg 631d91f36dbSJohannes Berg if (calc_crc) 632d91f36dbSJohannes Berg crc = crc32_be(crc, pos - 2, elen + 2); 633d91f36dbSJohannes Berg 63437ffc8daSJohannes Berg if (pos[3] == 1) { 63537ffc8daSJohannes Berg /* OUI Type 1 - WPA IE */ 63637ffc8daSJohannes Berg elems->wpa = pos; 63737ffc8daSJohannes Berg elems->wpa_len = elen; 63837ffc8daSJohannes Berg } else if (elen >= 5 && pos[3] == 2) { 639d91f36dbSJohannes Berg /* OUI Type 2 - WMM IE */ 64037ffc8daSJohannes Berg if (pos[4] == 0) { 64137ffc8daSJohannes Berg elems->wmm_info = pos; 64237ffc8daSJohannes Berg elems->wmm_info_len = elen; 64337ffc8daSJohannes Berg } else if (pos[4] == 1) { 64437ffc8daSJohannes Berg elems->wmm_param = pos; 64537ffc8daSJohannes Berg elems->wmm_param_len = elen; 64637ffc8daSJohannes Berg } 64737ffc8daSJohannes Berg } 64837ffc8daSJohannes Berg } 64937ffc8daSJohannes Berg break; 65037ffc8daSJohannes Berg case WLAN_EID_RSN: 65137ffc8daSJohannes Berg elems->rsn = pos; 65237ffc8daSJohannes Berg elems->rsn_len = elen; 65337ffc8daSJohannes Berg break; 65437ffc8daSJohannes Berg case WLAN_EID_ERP_INFO: 65537ffc8daSJohannes Berg elems->erp_info = pos; 65637ffc8daSJohannes Berg elems->erp_info_len = elen; 65737ffc8daSJohannes Berg break; 65837ffc8daSJohannes Berg case WLAN_EID_EXT_SUPP_RATES: 65937ffc8daSJohannes Berg elems->ext_supp_rates = pos; 66037ffc8daSJohannes Berg elems->ext_supp_rates_len = elen; 66137ffc8daSJohannes Berg break; 66237ffc8daSJohannes Berg case WLAN_EID_HT_CAPABILITY: 66309914813SJohannes Berg if (elen >= sizeof(struct ieee80211_ht_cap)) 66409914813SJohannes Berg elems->ht_cap_elem = (void *)pos; 66537ffc8daSJohannes Berg break; 666d9fe60deSJohannes Berg case WLAN_EID_HT_INFORMATION: 667d9fe60deSJohannes Berg if (elen >= sizeof(struct ieee80211_ht_info)) 66809914813SJohannes Berg elems->ht_info_elem = (void *)pos; 66937ffc8daSJohannes Berg break; 67037ffc8daSJohannes Berg case WLAN_EID_MESH_ID: 67137ffc8daSJohannes Berg elems->mesh_id = pos; 67237ffc8daSJohannes Berg elems->mesh_id_len = elen; 67337ffc8daSJohannes Berg break; 67437ffc8daSJohannes Berg case WLAN_EID_MESH_CONFIG: 675136cfa28SRui Paulo if (elen >= sizeof(struct ieee80211_meshconf_ie)) 676136cfa28SRui Paulo elems->mesh_config = (void *)pos; 67737ffc8daSJohannes Berg break; 67837ffc8daSJohannes Berg case WLAN_EID_PEER_LINK: 67937ffc8daSJohannes Berg elems->peer_link = pos; 68037ffc8daSJohannes Berg elems->peer_link_len = elen; 68137ffc8daSJohannes Berg break; 68237ffc8daSJohannes Berg case WLAN_EID_PREQ: 68337ffc8daSJohannes Berg elems->preq = pos; 68437ffc8daSJohannes Berg elems->preq_len = elen; 68537ffc8daSJohannes Berg break; 68637ffc8daSJohannes Berg case WLAN_EID_PREP: 68737ffc8daSJohannes Berg elems->prep = pos; 68837ffc8daSJohannes Berg elems->prep_len = elen; 68937ffc8daSJohannes Berg break; 69037ffc8daSJohannes Berg case WLAN_EID_PERR: 69137ffc8daSJohannes Berg elems->perr = pos; 69237ffc8daSJohannes Berg elems->perr_len = elen; 69337ffc8daSJohannes Berg break; 69490a5e169SRui Paulo case WLAN_EID_RANN: 69590a5e169SRui Paulo if (elen >= sizeof(struct ieee80211_rann_ie)) 69690a5e169SRui Paulo elems->rann = (void *)pos; 69790a5e169SRui Paulo break; 69837ffc8daSJohannes Berg case WLAN_EID_CHANNEL_SWITCH: 69937ffc8daSJohannes Berg elems->ch_switch_elem = pos; 70037ffc8daSJohannes Berg elems->ch_switch_elem_len = elen; 70137ffc8daSJohannes Berg break; 70237ffc8daSJohannes Berg case WLAN_EID_QUIET: 70337ffc8daSJohannes Berg if (!elems->quiet_elem) { 70437ffc8daSJohannes Berg elems->quiet_elem = pos; 70537ffc8daSJohannes Berg elems->quiet_elem_len = elen; 70637ffc8daSJohannes Berg } 70737ffc8daSJohannes Berg elems->num_of_quiet_elem++; 70837ffc8daSJohannes Berg break; 70937ffc8daSJohannes Berg case WLAN_EID_COUNTRY: 71037ffc8daSJohannes Berg elems->country_elem = pos; 71137ffc8daSJohannes Berg elems->country_elem_len = elen; 71237ffc8daSJohannes Berg break; 71337ffc8daSJohannes Berg case WLAN_EID_PWR_CONSTRAINT: 71437ffc8daSJohannes Berg elems->pwr_constr_elem = pos; 71537ffc8daSJohannes Berg elems->pwr_constr_elem_len = elen; 71637ffc8daSJohannes Berg break; 717f797eb7eSJouni Malinen case WLAN_EID_TIMEOUT_INTERVAL: 718f797eb7eSJouni Malinen elems->timeout_int = pos; 719f797eb7eSJouni Malinen elems->timeout_int_len = elen; 72063a5ab82SJouni Malinen break; 72137ffc8daSJohannes Berg default: 72237ffc8daSJohannes Berg break; 72337ffc8daSJohannes Berg } 72437ffc8daSJohannes Berg 72537ffc8daSJohannes Berg left -= elen; 72637ffc8daSJohannes Berg pos += elen; 72737ffc8daSJohannes Berg } 728d91f36dbSJohannes Berg 729d91f36dbSJohannes Berg return crc; 73037ffc8daSJohannes Berg } 7315825fe10SJohannes Berg 7325825fe10SJohannes Berg void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata) 7335825fe10SJohannes Berg { 7345825fe10SJohannes Berg struct ieee80211_local *local = sdata->local; 7355825fe10SJohannes Berg struct ieee80211_tx_queue_params qparam; 736aa837e1dSJohannes Berg int queue; 737aa837e1dSJohannes Berg bool use_11b; 738aa837e1dSJohannes Berg int aCWmin, aCWmax; 7395825fe10SJohannes Berg 7405825fe10SJohannes Berg if (!local->ops->conf_tx) 7415825fe10SJohannes Berg return; 7425825fe10SJohannes Berg 7435825fe10SJohannes Berg memset(&qparam, 0, sizeof(qparam)); 7445825fe10SJohannes Berg 745aa837e1dSJohannes Berg use_11b = (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) && 746aa837e1dSJohannes Berg !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE); 7475825fe10SJohannes Berg 748aa837e1dSJohannes Berg for (queue = 0; queue < local_to_hw(local)->queues; queue++) { 749aa837e1dSJohannes Berg /* Set defaults according to 802.11-2007 Table 7-37 */ 750aa837e1dSJohannes Berg aCWmax = 1023; 751aa837e1dSJohannes Berg if (use_11b) 752aa837e1dSJohannes Berg aCWmin = 31; 7535825fe10SJohannes Berg else 754aa837e1dSJohannes Berg aCWmin = 15; 7555825fe10SJohannes Berg 756aa837e1dSJohannes Berg switch (queue) { 757aa837e1dSJohannes Berg case 3: /* AC_BK */ 7587ba10a8eSJohannes Berg qparam.cw_max = aCWmax; 7597ba10a8eSJohannes Berg qparam.cw_min = aCWmin; 7605825fe10SJohannes Berg qparam.txop = 0; 761aa837e1dSJohannes Berg qparam.aifs = 7; 762aa837e1dSJohannes Berg break; 763aa837e1dSJohannes Berg default: /* never happens but let's not leave undefined */ 764aa837e1dSJohannes Berg case 2: /* AC_BE */ 7657ba10a8eSJohannes Berg qparam.cw_max = aCWmax; 7667ba10a8eSJohannes Berg qparam.cw_min = aCWmin; 767aa837e1dSJohannes Berg qparam.txop = 0; 768aa837e1dSJohannes Berg qparam.aifs = 3; 769aa837e1dSJohannes Berg break; 770aa837e1dSJohannes Berg case 1: /* AC_VI */ 771aa837e1dSJohannes Berg qparam.cw_max = aCWmin; 772aa837e1dSJohannes Berg qparam.cw_min = (aCWmin + 1) / 2 - 1; 773aa837e1dSJohannes Berg if (use_11b) 774aa837e1dSJohannes Berg qparam.txop = 6016/32; 775aa837e1dSJohannes Berg else 776aa837e1dSJohannes Berg qparam.txop = 3008/32; 777aa837e1dSJohannes Berg qparam.aifs = 2; 778aa837e1dSJohannes Berg break; 779aa837e1dSJohannes Berg case 0: /* AC_VO */ 780aa837e1dSJohannes Berg qparam.cw_max = (aCWmin + 1) / 2 - 1; 781aa837e1dSJohannes Berg qparam.cw_min = (aCWmin + 1) / 4 - 1; 782aa837e1dSJohannes Berg if (use_11b) 783aa837e1dSJohannes Berg qparam.txop = 3264/32; 784aa837e1dSJohannes Berg else 785aa837e1dSJohannes Berg qparam.txop = 1504/32; 786aa837e1dSJohannes Berg qparam.aifs = 2; 787aa837e1dSJohannes Berg break; 788aa837e1dSJohannes Berg } 7895825fe10SJohannes Berg 790ab13315aSKalle Valo qparam.uapsd = false; 791ab13315aSKalle Valo 792aa837e1dSJohannes Berg drv_conf_tx(local, queue, &qparam); 793aa837e1dSJohannes Berg } 794e1b3ec1aSStanislaw Gruszka 795e1b3ec1aSStanislaw Gruszka /* after reinitialize QoS TX queues setting to default, 796e1b3ec1aSStanislaw Gruszka * disable QoS at all */ 797d9734979SSujith 798d9734979SSujith if (sdata->vif.type != NL80211_IFTYPE_MONITOR) { 799d9734979SSujith sdata->vif.bss_conf.qos = 800d9734979SSujith sdata->vif.type != NL80211_IFTYPE_STATION; 8014ced3f74SJohannes Berg ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_QOS); 8025825fe10SJohannes Berg } 803d9734979SSujith } 804e50db65cSJohannes Berg 80546900298SJohannes Berg void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, 80646900298SJohannes Berg const size_t supp_rates_len, 80746900298SJohannes Berg const u8 *supp_rates) 80846900298SJohannes Berg { 80946900298SJohannes Berg struct ieee80211_local *local = sdata->local; 81046900298SJohannes Berg int i, have_higher_than_11mbit = 0; 81146900298SJohannes Berg 81246900298SJohannes Berg /* cf. IEEE 802.11 9.2.12 */ 81346900298SJohannes Berg for (i = 0; i < supp_rates_len; i++) 81446900298SJohannes Berg if ((supp_rates[i] & 0x7f) * 5 > 110) 81546900298SJohannes Berg have_higher_than_11mbit = 1; 81646900298SJohannes Berg 81746900298SJohannes Berg if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && 81846900298SJohannes Berg have_higher_than_11mbit) 81946900298SJohannes Berg sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; 82046900298SJohannes Berg else 82146900298SJohannes Berg sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; 82246900298SJohannes Berg 82346900298SJohannes Berg ieee80211_set_wmm_default(sdata); 82446900298SJohannes Berg } 82546900298SJohannes Berg 826881d948cSJohannes Berg u32 ieee80211_mandatory_rates(struct ieee80211_local *local, 82796dd22acSJohannes Berg enum ieee80211_band band) 82896dd22acSJohannes Berg { 82996dd22acSJohannes Berg struct ieee80211_supported_band *sband; 83096dd22acSJohannes Berg struct ieee80211_rate *bitrates; 831881d948cSJohannes Berg u32 mandatory_rates; 83296dd22acSJohannes Berg enum ieee80211_rate_flags mandatory_flag; 83396dd22acSJohannes Berg int i; 83496dd22acSJohannes Berg 83596dd22acSJohannes Berg sband = local->hw.wiphy->bands[band]; 83696dd22acSJohannes Berg if (!sband) { 83796dd22acSJohannes Berg WARN_ON(1); 83896dd22acSJohannes Berg sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; 83996dd22acSJohannes Berg } 84096dd22acSJohannes Berg 84196dd22acSJohannes Berg if (band == IEEE80211_BAND_2GHZ) 84296dd22acSJohannes Berg mandatory_flag = IEEE80211_RATE_MANDATORY_B; 84396dd22acSJohannes Berg else 84496dd22acSJohannes Berg mandatory_flag = IEEE80211_RATE_MANDATORY_A; 84596dd22acSJohannes Berg 84696dd22acSJohannes Berg bitrates = sband->bitrates; 84796dd22acSJohannes Berg mandatory_rates = 0; 84896dd22acSJohannes Berg for (i = 0; i < sband->n_bitrates; i++) 84996dd22acSJohannes Berg if (bitrates[i].flags & mandatory_flag) 85096dd22acSJohannes Berg mandatory_rates |= BIT(i); 85196dd22acSJohannes Berg return mandatory_rates; 85296dd22acSJohannes Berg } 85346900298SJohannes Berg 85446900298SJohannes Berg void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, 85546900298SJohannes Berg u16 transaction, u16 auth_alg, 856fffd0934SJohannes Berg u8 *extra, size_t extra_len, const u8 *bssid, 857fffd0934SJohannes Berg const u8 *key, u8 key_len, u8 key_idx) 85846900298SJohannes Berg { 85946900298SJohannes Berg struct ieee80211_local *local = sdata->local; 86046900298SJohannes Berg struct sk_buff *skb; 86146900298SJohannes Berg struct ieee80211_mgmt *mgmt; 862fffd0934SJohannes Berg int err; 86346900298SJohannes Berg 86446900298SJohannes Berg skb = dev_alloc_skb(local->hw.extra_tx_headroom + 86565fc73acSJouni Malinen sizeof(*mgmt) + 6 + extra_len); 86646900298SJohannes Berg if (!skb) { 86746900298SJohannes Berg printk(KERN_DEBUG "%s: failed to allocate buffer for auth " 86847846c9bSJohannes Berg "frame\n", sdata->name); 86946900298SJohannes Berg return; 87046900298SJohannes Berg } 87146900298SJohannes Berg skb_reserve(skb, local->hw.extra_tx_headroom); 87246900298SJohannes Berg 87346900298SJohannes Berg mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6); 87446900298SJohannes Berg memset(mgmt, 0, 24 + 6); 87546900298SJohannes Berg mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | 87646900298SJohannes Berg IEEE80211_STYPE_AUTH); 87746900298SJohannes Berg memcpy(mgmt->da, bssid, ETH_ALEN); 87847846c9bSJohannes Berg memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); 87946900298SJohannes Berg memcpy(mgmt->bssid, bssid, ETH_ALEN); 88046900298SJohannes Berg mgmt->u.auth.auth_alg = cpu_to_le16(auth_alg); 88146900298SJohannes Berg mgmt->u.auth.auth_transaction = cpu_to_le16(transaction); 88246900298SJohannes Berg mgmt->u.auth.status_code = cpu_to_le16(0); 88346900298SJohannes Berg if (extra) 88446900298SJohannes Berg memcpy(skb_put(skb, extra_len), extra, extra_len); 88546900298SJohannes Berg 886fffd0934SJohannes Berg if (auth_alg == WLAN_AUTH_SHARED_KEY && transaction == 3) { 887fffd0934SJohannes Berg mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); 888fffd0934SJohannes Berg err = ieee80211_wep_encrypt(local, skb, key, key_len, key_idx); 889fffd0934SJohannes Berg WARN_ON(err); 890fffd0934SJohannes Berg } 891fffd0934SJohannes Berg 89262ae67beSJohannes Berg IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; 89362ae67beSJohannes Berg ieee80211_tx_skb(sdata, skb); 89446900298SJohannes Berg } 89546900298SJohannes Berg 896de95a54bSJohannes Berg int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, 8974d36ec58SJohannes Berg const u8 *ie, size_t ie_len, 898651b5225SJouni Malinen enum ieee80211_band band, u32 rate_mask, 899651b5225SJouni Malinen u8 channel) 900de95a54bSJohannes Berg { 901de95a54bSJohannes Berg struct ieee80211_supported_band *sband; 9028e664fb3SJohannes Berg u8 *pos; 9038e664fb3SJohannes Berg size_t offset = 0, noffset; 9048e664fb3SJohannes Berg int supp_rates_len, i; 9058dcb2003SJouni Malinen u8 rates[32]; 9068dcb2003SJouni Malinen int num_rates; 9078dcb2003SJouni Malinen int ext_rates_len; 908de95a54bSJohannes Berg 9094d36ec58SJohannes Berg sband = local->hw.wiphy->bands[band]; 910de95a54bSJohannes Berg 911de95a54bSJohannes Berg pos = buffer; 912de95a54bSJohannes Berg 9138dcb2003SJouni Malinen num_rates = 0; 9148dcb2003SJouni Malinen for (i = 0; i < sband->n_bitrates; i++) { 9158dcb2003SJouni Malinen if ((BIT(i) & rate_mask) == 0) 9168dcb2003SJouni Malinen continue; /* skip rate */ 9178dcb2003SJouni Malinen rates[num_rates++] = (u8) (sband->bitrates[i].bitrate / 5); 9188dcb2003SJouni Malinen } 9198dcb2003SJouni Malinen 9208dcb2003SJouni Malinen supp_rates_len = min_t(int, num_rates, 8); 9218e664fb3SJohannes Berg 922de95a54bSJohannes Berg *pos++ = WLAN_EID_SUPP_RATES; 9238e664fb3SJohannes Berg *pos++ = supp_rates_len; 9248dcb2003SJouni Malinen memcpy(pos, rates, supp_rates_len); 9258dcb2003SJouni Malinen pos += supp_rates_len; 926de95a54bSJohannes Berg 9278e664fb3SJohannes Berg /* insert "request information" if in custom IEs */ 9288e664fb3SJohannes Berg if (ie && ie_len) { 9298e664fb3SJohannes Berg static const u8 before_extrates[] = { 9308e664fb3SJohannes Berg WLAN_EID_SSID, 9318e664fb3SJohannes Berg WLAN_EID_SUPP_RATES, 9328e664fb3SJohannes Berg WLAN_EID_REQUEST, 9338e664fb3SJohannes Berg }; 9348e664fb3SJohannes Berg noffset = ieee80211_ie_split(ie, ie_len, 9358e664fb3SJohannes Berg before_extrates, 9368e664fb3SJohannes Berg ARRAY_SIZE(before_extrates), 9378e664fb3SJohannes Berg offset); 9388e664fb3SJohannes Berg memcpy(pos, ie + offset, noffset - offset); 9398e664fb3SJohannes Berg pos += noffset - offset; 9408e664fb3SJohannes Berg offset = noffset; 9418e664fb3SJohannes Berg } 9428e664fb3SJohannes Berg 9438dcb2003SJouni Malinen ext_rates_len = num_rates - supp_rates_len; 9448dcb2003SJouni Malinen if (ext_rates_len > 0) { 945de95a54bSJohannes Berg *pos++ = WLAN_EID_EXT_SUPP_RATES; 9468dcb2003SJouni Malinen *pos++ = ext_rates_len; 9478dcb2003SJouni Malinen memcpy(pos, rates + supp_rates_len, ext_rates_len); 9488dcb2003SJouni Malinen pos += ext_rates_len; 9498e664fb3SJohannes Berg } 9508e664fb3SJohannes Berg 951651b5225SJouni Malinen if (channel && sband->band == IEEE80211_BAND_2GHZ) { 952651b5225SJouni Malinen *pos++ = WLAN_EID_DS_PARAMS; 953651b5225SJouni Malinen *pos++ = 1; 954651b5225SJouni Malinen *pos++ = channel; 955651b5225SJouni Malinen } 956651b5225SJouni Malinen 9578e664fb3SJohannes Berg /* insert custom IEs that go before HT */ 9588e664fb3SJohannes Berg if (ie && ie_len) { 9598e664fb3SJohannes Berg static const u8 before_ht[] = { 9608e664fb3SJohannes Berg WLAN_EID_SSID, 9618e664fb3SJohannes Berg WLAN_EID_SUPP_RATES, 9628e664fb3SJohannes Berg WLAN_EID_REQUEST, 9638e664fb3SJohannes Berg WLAN_EID_EXT_SUPP_RATES, 9648e664fb3SJohannes Berg WLAN_EID_DS_PARAMS, 9658e664fb3SJohannes Berg WLAN_EID_SUPPORTED_REGULATORY_CLASSES, 9668e664fb3SJohannes Berg }; 9678e664fb3SJohannes Berg noffset = ieee80211_ie_split(ie, ie_len, 9688e664fb3SJohannes Berg before_ht, ARRAY_SIZE(before_ht), 9698e664fb3SJohannes Berg offset); 9708e664fb3SJohannes Berg memcpy(pos, ie + offset, noffset - offset); 9718e664fb3SJohannes Berg pos += noffset - offset; 9728e664fb3SJohannes Berg offset = noffset; 973de95a54bSJohannes Berg } 974de95a54bSJohannes Berg 9755ef2d41aSJohannes Berg if (sband->ht_cap.ht_supported) { 976f38fd12fSJohannes Berg u16 cap = sband->ht_cap.cap; 977f38fd12fSJohannes Berg __le16 tmp; 978f38fd12fSJohannes Berg 979f38fd12fSJohannes Berg if (ieee80211_disable_40mhz_24ghz && 980f38fd12fSJohannes Berg sband->band == IEEE80211_BAND_2GHZ) { 981f38fd12fSJohannes Berg cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; 982f38fd12fSJohannes Berg cap &= ~IEEE80211_HT_CAP_SGI_40; 983f38fd12fSJohannes Berg } 9845ef2d41aSJohannes Berg 9855ef2d41aSJohannes Berg *pos++ = WLAN_EID_HT_CAPABILITY; 9865ef2d41aSJohannes Berg *pos++ = sizeof(struct ieee80211_ht_cap); 9875ef2d41aSJohannes Berg memset(pos, 0, sizeof(struct ieee80211_ht_cap)); 988f38fd12fSJohannes Berg tmp = cpu_to_le16(cap); 9895ef2d41aSJohannes Berg memcpy(pos, &tmp, sizeof(u16)); 9905ef2d41aSJohannes Berg pos += sizeof(u16); 9915ef2d41aSJohannes Berg *pos++ = sband->ht_cap.ampdu_factor | 992f38fd12fSJohannes Berg (sband->ht_cap.ampdu_density << 993f38fd12fSJohannes Berg IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT); 9945ef2d41aSJohannes Berg memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); 9955ef2d41aSJohannes Berg pos += sizeof(sband->ht_cap.mcs); 9965ef2d41aSJohannes Berg pos += 2 + 4 + 1; /* ext info, BF cap, antsel */ 9975ef2d41aSJohannes Berg } 9985ef2d41aSJohannes Berg 999de95a54bSJohannes Berg /* 1000de95a54bSJohannes Berg * If adding more here, adjust code in main.c 1001de95a54bSJohannes Berg * that calculates local->scan_ies_len. 1002de95a54bSJohannes Berg */ 1003de95a54bSJohannes Berg 10048e664fb3SJohannes Berg /* add any remaining custom IEs */ 10058e664fb3SJohannes Berg if (ie && ie_len) { 10068e664fb3SJohannes Berg noffset = ie_len; 10078e664fb3SJohannes Berg memcpy(pos, ie + offset, noffset - offset); 10088e664fb3SJohannes Berg pos += noffset - offset; 1009de95a54bSJohannes Berg } 1010de95a54bSJohannes Berg 1011de95a54bSJohannes Berg return pos - buffer; 1012de95a54bSJohannes Berg } 1013de95a54bSJohannes Berg 101446900298SJohannes Berg void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, 1015de95a54bSJohannes Berg const u8 *ssid, size_t ssid_len, 1016de95a54bSJohannes Berg const u8 *ie, size_t ie_len) 101746900298SJohannes Berg { 101846900298SJohannes Berg struct ieee80211_local *local = sdata->local; 101946900298SJohannes Berg struct sk_buff *skb; 102046900298SJohannes Berg struct ieee80211_mgmt *mgmt; 10217c12ce8bSKalle Valo size_t buf_len; 10227c12ce8bSKalle Valo u8 *buf; 1023651b5225SJouni Malinen u8 chan; 102446900298SJohannes Berg 10257c12ce8bSKalle Valo /* FIXME: come up with a proper value */ 10267c12ce8bSKalle Valo buf = kmalloc(200 + ie_len, GFP_KERNEL); 10277c12ce8bSKalle Valo if (!buf) { 10287c12ce8bSKalle Valo printk(KERN_DEBUG "%s: failed to allocate temporary IE " 10297c12ce8bSKalle Valo "buffer\n", sdata->name); 103046900298SJohannes Berg return; 103146900298SJohannes Berg } 103246900298SJohannes Berg 1033651b5225SJouni Malinen chan = ieee80211_frequency_to_channel( 1034651b5225SJouni Malinen local->hw.conf.channel->center_freq); 1035651b5225SJouni Malinen 10367c12ce8bSKalle Valo buf_len = ieee80211_build_preq_ies(local, buf, ie, ie_len, 10378dcb2003SJouni Malinen local->hw.conf.channel->band, 10388dcb2003SJouni Malinen sdata->rc_rateidx_mask 1039651b5225SJouni Malinen [local->hw.conf.channel->band], 1040651b5225SJouni Malinen chan); 10417c12ce8bSKalle Valo 10427c12ce8bSKalle Valo skb = ieee80211_probereq_get(&local->hw, &sdata->vif, 10437c12ce8bSKalle Valo ssid, ssid_len, 10447c12ce8bSKalle Valo buf, buf_len); 10457c12ce8bSKalle Valo 104646900298SJohannes Berg if (dst) { 10477c12ce8bSKalle Valo mgmt = (struct ieee80211_mgmt *) skb->data; 104846900298SJohannes Berg memcpy(mgmt->da, dst, ETH_ALEN); 104946900298SJohannes Berg memcpy(mgmt->bssid, dst, ETH_ALEN); 105046900298SJohannes Berg } 105146900298SJohannes Berg 105262ae67beSJohannes Berg IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; 105362ae67beSJohannes Berg ieee80211_tx_skb(sdata, skb); 1054145b6d1aSMing Lei kfree(buf); 105546900298SJohannes Berg } 105646900298SJohannes Berg 105746900298SJohannes Berg u32 ieee80211_sta_get_rates(struct ieee80211_local *local, 105846900298SJohannes Berg struct ieee802_11_elems *elems, 105946900298SJohannes Berg enum ieee80211_band band) 106046900298SJohannes Berg { 106146900298SJohannes Berg struct ieee80211_supported_band *sband; 106246900298SJohannes Berg struct ieee80211_rate *bitrates; 106346900298SJohannes Berg size_t num_rates; 106446900298SJohannes Berg u32 supp_rates; 106546900298SJohannes Berg int i, j; 106646900298SJohannes Berg sband = local->hw.wiphy->bands[band]; 106746900298SJohannes Berg 106846900298SJohannes Berg if (!sband) { 106946900298SJohannes Berg WARN_ON(1); 107046900298SJohannes Berg sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; 107146900298SJohannes Berg } 107246900298SJohannes Berg 107346900298SJohannes Berg bitrates = sband->bitrates; 107446900298SJohannes Berg num_rates = sband->n_bitrates; 107546900298SJohannes Berg supp_rates = 0; 107646900298SJohannes Berg for (i = 0; i < elems->supp_rates_len + 107746900298SJohannes Berg elems->ext_supp_rates_len; i++) { 107846900298SJohannes Berg u8 rate = 0; 107946900298SJohannes Berg int own_rate; 108046900298SJohannes Berg if (i < elems->supp_rates_len) 108146900298SJohannes Berg rate = elems->supp_rates[i]; 108246900298SJohannes Berg else if (elems->ext_supp_rates) 108346900298SJohannes Berg rate = elems->ext_supp_rates 108446900298SJohannes Berg [i - elems->supp_rates_len]; 108546900298SJohannes Berg own_rate = 5 * (rate & 0x7f); 108646900298SJohannes Berg for (j = 0; j < num_rates; j++) 108746900298SJohannes Berg if (bitrates[j].bitrate == own_rate) 108846900298SJohannes Berg supp_rates |= BIT(j); 108946900298SJohannes Berg } 109046900298SJohannes Berg return supp_rates; 109146900298SJohannes Berg } 1092f2753ddbSJohannes Berg 109384f6a01cSJohannes Berg void ieee80211_stop_device(struct ieee80211_local *local) 109484f6a01cSJohannes Berg { 109584f6a01cSJohannes Berg ieee80211_led_radio(local, false); 109684f6a01cSJohannes Berg 109784f6a01cSJohannes Berg cancel_work_sync(&local->reconfig_filter); 109884f6a01cSJohannes Berg 109984f6a01cSJohannes Berg flush_workqueue(local->workqueue); 1100678f415fSLennert Buytenhek drv_stop(local); 110184f6a01cSJohannes Berg } 110284f6a01cSJohannes Berg 1103f2753ddbSJohannes Berg int ieee80211_reconfig(struct ieee80211_local *local) 1104f2753ddbSJohannes Berg { 1105f2753ddbSJohannes Berg struct ieee80211_hw *hw = &local->hw; 1106f2753ddbSJohannes Berg struct ieee80211_sub_if_data *sdata; 1107f2753ddbSJohannes Berg struct sta_info *sta; 1108f2753ddbSJohannes Berg int res; 11095bb644a0SJohannes Berg 1110ceb99fe0SJohannes Berg if (local->suspended) 1111ceb99fe0SJohannes Berg local->resuming = true; 1112f2753ddbSJohannes Berg 1113f2753ddbSJohannes Berg /* restart hardware */ 1114f2753ddbSJohannes Berg if (local->open_count) { 111524feda00SLuis R. Rodriguez /* 111624feda00SLuis R. Rodriguez * Upon resume hardware can sometimes be goofy due to 111724feda00SLuis R. Rodriguez * various platform / driver / bus issues, so restarting 111824feda00SLuis R. Rodriguez * the device may at times not work immediately. Propagate 111924feda00SLuis R. Rodriguez * the error. 112024feda00SLuis R. Rodriguez */ 112124487981SJohannes Berg res = drv_start(local); 112224feda00SLuis R. Rodriguez if (res) { 1123c7a00dc7SJohn W. Linville WARN(local->suspended, "Hardware became unavailable " 1124c7a00dc7SJohn W. Linville "upon resume. This could be a software issue " 1125c7a00dc7SJohn W. Linville "prior to suspend or a hardware issue.\n"); 112624feda00SLuis R. Rodriguez return res; 112724feda00SLuis R. Rodriguez } 1128f2753ddbSJohannes Berg 11291f87f7d3SJohannes Berg ieee80211_led_radio(local, true); 1130f2753ddbSJohannes Berg } 1131f2753ddbSJohannes Berg 1132f2753ddbSJohannes Berg /* add interfaces */ 1133f2753ddbSJohannes Berg list_for_each_entry(sdata, &local->interfaces, list) { 1134f2753ddbSJohannes Berg if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && 1135f2753ddbSJohannes Berg sdata->vif.type != NL80211_IFTYPE_MONITOR && 11361ed32e4fSJohannes Berg ieee80211_sdata_running(sdata)) 11371ed32e4fSJohannes Berg res = drv_add_interface(local, &sdata->vif); 1138f2753ddbSJohannes Berg } 1139f2753ddbSJohannes Berg 1140f2753ddbSJohannes Berg /* add STAs back */ 114134e89507SJohannes Berg mutex_lock(&local->sta_mtx); 1142f2753ddbSJohannes Berg list_for_each_entry(sta, &local->sta_list, list) { 114334e89507SJohannes Berg if (sta->uploaded) { 11445bb644a0SJohannes Berg sdata = sta->sdata; 1145f2753ddbSJohannes Berg if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) 1146f2753ddbSJohannes Berg sdata = container_of(sdata->bss, 1147f2753ddbSJohannes Berg struct ieee80211_sub_if_data, 1148f2753ddbSJohannes Berg u.ap); 1149f2753ddbSJohannes Berg 115034e89507SJohannes Berg WARN_ON(drv_sta_add(local, sdata, &sta->sta)); 1151f2753ddbSJohannes Berg } 1152f2753ddbSJohannes Berg } 115334e89507SJohannes Berg mutex_unlock(&local->sta_mtx); 1154f2753ddbSJohannes Berg 1155f23a4780SArik Nemtsov /* setup fragmentation threshold */ 1156f23a4780SArik Nemtsov drv_set_frag_threshold(local, hw->wiphy->frag_threshold); 1157f23a4780SArik Nemtsov 1158f2753ddbSJohannes Berg /* setup RTS threshold */ 115924487981SJohannes Berg drv_set_rts_threshold(local, hw->wiphy->rts_threshold); 1160f2753ddbSJohannes Berg 1161f2753ddbSJohannes Berg /* reconfigure hardware */ 1162f2753ddbSJohannes Berg ieee80211_hw_config(local, ~0); 1163f2753ddbSJohannes Berg 1164f2753ddbSJohannes Berg ieee80211_configure_filter(local); 1165f2753ddbSJohannes Berg 1166f2753ddbSJohannes Berg /* Finally also reconfigure all the BSS information */ 1167f2753ddbSJohannes Berg list_for_each_entry(sdata, &local->interfaces, list) { 1168ac8dd506SJohannes Berg u32 changed; 1169ac8dd506SJohannes Berg 11709607e6b6SJohannes Berg if (!ieee80211_sdata_running(sdata)) 1171f2753ddbSJohannes Berg continue; 1172ac8dd506SJohannes Berg 1173ac8dd506SJohannes Berg /* common change flags for all interface types */ 1174ac8dd506SJohannes Berg changed = BSS_CHANGED_ERP_CTS_PROT | 1175ac8dd506SJohannes Berg BSS_CHANGED_ERP_PREAMBLE | 1176ac8dd506SJohannes Berg BSS_CHANGED_ERP_SLOT | 1177ac8dd506SJohannes Berg BSS_CHANGED_HT | 1178ac8dd506SJohannes Berg BSS_CHANGED_BASIC_RATES | 1179ac8dd506SJohannes Berg BSS_CHANGED_BEACON_INT | 1180ac8dd506SJohannes Berg BSS_CHANGED_BSSID | 11814ced3f74SJohannes Berg BSS_CHANGED_CQM | 11824ced3f74SJohannes Berg BSS_CHANGED_QOS; 1183ac8dd506SJohannes Berg 1184f2753ddbSJohannes Berg switch (sdata->vif.type) { 1185f2753ddbSJohannes Berg case NL80211_IFTYPE_STATION: 1186ac8dd506SJohannes Berg changed |= BSS_CHANGED_ASSOC; 1187ac8dd506SJohannes Berg ieee80211_bss_info_change_notify(sdata, changed); 1188ac8dd506SJohannes Berg break; 1189f2753ddbSJohannes Berg case NL80211_IFTYPE_ADHOC: 1190ac8dd506SJohannes Berg changed |= BSS_CHANGED_IBSS; 1191ac8dd506SJohannes Berg /* fall through */ 1192f2753ddbSJohannes Berg case NL80211_IFTYPE_AP: 1193f2753ddbSJohannes Berg case NL80211_IFTYPE_MESH_POINT: 1194ac8dd506SJohannes Berg changed |= BSS_CHANGED_BEACON | 1195ac8dd506SJohannes Berg BSS_CHANGED_BEACON_ENABLED; 11962d0ddec5SJohannes Berg ieee80211_bss_info_change_notify(sdata, changed); 1197f2753ddbSJohannes Berg break; 1198f2753ddbSJohannes Berg case NL80211_IFTYPE_WDS: 1199f2753ddbSJohannes Berg break; 1200f2753ddbSJohannes Berg case NL80211_IFTYPE_AP_VLAN: 1201f2753ddbSJohannes Berg case NL80211_IFTYPE_MONITOR: 1202f2753ddbSJohannes Berg /* ignore virtual */ 1203f2753ddbSJohannes Berg break; 1204f2753ddbSJohannes Berg case NL80211_IFTYPE_UNSPECIFIED: 12052e161f78SJohannes Berg case NUM_NL80211_IFTYPES: 12062ca27bcfSJohannes Berg case NL80211_IFTYPE_P2P_CLIENT: 12072ca27bcfSJohannes Berg case NL80211_IFTYPE_P2P_GO: 1208f2753ddbSJohannes Berg WARN_ON(1); 1209f2753ddbSJohannes Berg break; 1210f2753ddbSJohannes Berg } 1211f2753ddbSJohannes Berg } 1212f2753ddbSJohannes Berg 12132a419056SJohannes Berg /* 12142a419056SJohannes Berg * Clear the WLAN_STA_BLOCK_BA flag so new aggregation 12152a419056SJohannes Berg * sessions can be established after a resume. 12162a419056SJohannes Berg * 12172a419056SJohannes Berg * Also tear down aggregation sessions since reconfiguring 12182a419056SJohannes Berg * them in a hardware restart scenario is not easily done 12192a419056SJohannes Berg * right now, and the hardware will have lost information 12202a419056SJohannes Berg * about the sessions, but we and the AP still think they 12212a419056SJohannes Berg * are active. This is really a workaround though. 12222a419056SJohannes Berg */ 122374e2bd1fSWey-Yi Guy if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { 12242a419056SJohannes Berg mutex_lock(&local->sta_mtx); 12252a419056SJohannes Berg 12262a419056SJohannes Berg list_for_each_entry(sta, &local->sta_list, list) { 122753f73c09SJohannes Berg ieee80211_sta_tear_down_BA_sessions(sta, true); 12282a419056SJohannes Berg clear_sta_flags(sta, WLAN_STA_BLOCK_BA); 122974e2bd1fSWey-Yi Guy } 12302a419056SJohannes Berg 12312a419056SJohannes Berg mutex_unlock(&local->sta_mtx); 123274e2bd1fSWey-Yi Guy } 123374e2bd1fSWey-Yi Guy 1234f2753ddbSJohannes Berg /* add back keys */ 1235f2753ddbSJohannes Berg list_for_each_entry(sdata, &local->interfaces, list) 12369607e6b6SJohannes Berg if (ieee80211_sdata_running(sdata)) 1237f2753ddbSJohannes Berg ieee80211_enable_keys(sdata); 1238f2753ddbSJohannes Berg 1239f2753ddbSJohannes Berg ieee80211_wake_queues_by_reason(hw, 1240f2753ddbSJohannes Berg IEEE80211_QUEUE_STOP_REASON_SUSPEND); 1241f2753ddbSJohannes Berg 12425bb644a0SJohannes Berg /* 12435bb644a0SJohannes Berg * If this is for hw restart things are still running. 12445bb644a0SJohannes Berg * We may want to change that later, however. 12455bb644a0SJohannes Berg */ 1246ceb99fe0SJohannes Berg if (!local->suspended) 12475bb644a0SJohannes Berg return 0; 12485bb644a0SJohannes Berg 12495bb644a0SJohannes Berg #ifdef CONFIG_PM 1250ceb99fe0SJohannes Berg /* first set suspended false, then resuming */ 12515bb644a0SJohannes Berg local->suspended = false; 1252ceb99fe0SJohannes Berg mb(); 1253ceb99fe0SJohannes Berg local->resuming = false; 12545bb644a0SJohannes Berg 12555bb644a0SJohannes Berg list_for_each_entry(sdata, &local->interfaces, list) { 12565bb644a0SJohannes Berg switch(sdata->vif.type) { 12575bb644a0SJohannes Berg case NL80211_IFTYPE_STATION: 12585bb644a0SJohannes Berg ieee80211_sta_restart(sdata); 12595bb644a0SJohannes Berg break; 12605bb644a0SJohannes Berg case NL80211_IFTYPE_ADHOC: 12615bb644a0SJohannes Berg ieee80211_ibss_restart(sdata); 12625bb644a0SJohannes Berg break; 12635bb644a0SJohannes Berg case NL80211_IFTYPE_MESH_POINT: 12645bb644a0SJohannes Berg ieee80211_mesh_restart(sdata); 12655bb644a0SJohannes Berg break; 12665bb644a0SJohannes Berg default: 12675bb644a0SJohannes Berg break; 12685bb644a0SJohannes Berg } 12695bb644a0SJohannes Berg } 12705bb644a0SJohannes Berg 12715bb644a0SJohannes Berg add_timer(&local->sta_cleanup); 12725bb644a0SJohannes Berg 127334e89507SJohannes Berg mutex_lock(&local->sta_mtx); 12745bb644a0SJohannes Berg list_for_each_entry(sta, &local->sta_list, list) 12755bb644a0SJohannes Berg mesh_plink_restart(sta); 127634e89507SJohannes Berg mutex_unlock(&local->sta_mtx); 12775bb644a0SJohannes Berg #else 12785bb644a0SJohannes Berg WARN_ON(1); 12795bb644a0SJohannes Berg #endif 1280f2753ddbSJohannes Berg return 0; 1281f2753ddbSJohannes Berg } 128242935ecaSLuis R. Rodriguez 12830f78231bSJohannes Berg static int check_mgd_smps(struct ieee80211_if_managed *ifmgd, 12840f78231bSJohannes Berg enum ieee80211_smps_mode *smps_mode) 12850f78231bSJohannes Berg { 12860f78231bSJohannes Berg if (ifmgd->associated) { 12870f78231bSJohannes Berg *smps_mode = ifmgd->ap_smps; 12880f78231bSJohannes Berg 12890f78231bSJohannes Berg if (*smps_mode == IEEE80211_SMPS_AUTOMATIC) { 12900f78231bSJohannes Berg if (ifmgd->powersave) 12910f78231bSJohannes Berg *smps_mode = IEEE80211_SMPS_DYNAMIC; 12920f78231bSJohannes Berg else 12930f78231bSJohannes Berg *smps_mode = IEEE80211_SMPS_OFF; 12940f78231bSJohannes Berg } 12950f78231bSJohannes Berg 12960f78231bSJohannes Berg return 1; 12970f78231bSJohannes Berg } 12980f78231bSJohannes Berg 12990f78231bSJohannes Berg return 0; 13000f78231bSJohannes Berg } 13010f78231bSJohannes Berg 13020f78231bSJohannes Berg /* must hold iflist_mtx */ 1303025e6be2SJohannes Berg void ieee80211_recalc_smps(struct ieee80211_local *local) 13040f78231bSJohannes Berg { 13050f78231bSJohannes Berg struct ieee80211_sub_if_data *sdata; 13060f78231bSJohannes Berg enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_OFF; 13070f78231bSJohannes Berg int count = 0; 13080f78231bSJohannes Berg 130946a5ebafSJohannes Berg lockdep_assert_held(&local->iflist_mtx); 13100f78231bSJohannes Berg 13110f78231bSJohannes Berg /* 13120f78231bSJohannes Berg * This function could be improved to handle multiple 13130f78231bSJohannes Berg * interfaces better, but right now it makes any 13140f78231bSJohannes Berg * non-station interfaces force SM PS to be turned 13150f78231bSJohannes Berg * off. If there are multiple station interfaces it 13160f78231bSJohannes Berg * could also use the best possible mode, e.g. if 13170f78231bSJohannes Berg * one is in static and the other in dynamic then 13180f78231bSJohannes Berg * dynamic is ok. 13190f78231bSJohannes Berg */ 13200f78231bSJohannes Berg 13210f78231bSJohannes Berg list_for_each_entry(sdata, &local->interfaces, list) { 132226a58456SJohannes Berg if (!ieee80211_sdata_running(sdata)) 13230f78231bSJohannes Berg continue; 13240f78231bSJohannes Berg if (sdata->vif.type != NL80211_IFTYPE_STATION) 13250f78231bSJohannes Berg goto set; 1326025e6be2SJohannes Berg 13270f78231bSJohannes Berg count += check_mgd_smps(&sdata->u.mgd, &smps_mode); 13280f78231bSJohannes Berg 13290f78231bSJohannes Berg if (count > 1) { 13300f78231bSJohannes Berg smps_mode = IEEE80211_SMPS_OFF; 13310f78231bSJohannes Berg break; 13320f78231bSJohannes Berg } 13330f78231bSJohannes Berg } 13340f78231bSJohannes Berg 13350f78231bSJohannes Berg if (smps_mode == local->smps_mode) 13360f78231bSJohannes Berg return; 13370f78231bSJohannes Berg 13380f78231bSJohannes Berg set: 13390f78231bSJohannes Berg local->smps_mode = smps_mode; 13400f78231bSJohannes Berg /* changed flag is auto-detected for this */ 13410f78231bSJohannes Berg ieee80211_hw_config(local, 0); 13420f78231bSJohannes Berg } 13438e664fb3SJohannes Berg 13448e664fb3SJohannes Berg static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id) 13458e664fb3SJohannes Berg { 13468e664fb3SJohannes Berg int i; 13478e664fb3SJohannes Berg 13488e664fb3SJohannes Berg for (i = 0; i < n_ids; i++) 13498e664fb3SJohannes Berg if (ids[i] == id) 13508e664fb3SJohannes Berg return true; 13518e664fb3SJohannes Berg return false; 13528e664fb3SJohannes Berg } 13538e664fb3SJohannes Berg 13548e664fb3SJohannes Berg /** 13558e664fb3SJohannes Berg * ieee80211_ie_split - split an IE buffer according to ordering 13568e664fb3SJohannes Berg * 13578e664fb3SJohannes Berg * @ies: the IE buffer 13588e664fb3SJohannes Berg * @ielen: the length of the IE buffer 13598e664fb3SJohannes Berg * @ids: an array with element IDs that are allowed before 13608e664fb3SJohannes Berg * the split 13618e664fb3SJohannes Berg * @n_ids: the size of the element ID array 13628e664fb3SJohannes Berg * @offset: offset where to start splitting in the buffer 13638e664fb3SJohannes Berg * 13648e664fb3SJohannes Berg * This function splits an IE buffer by updating the @offset 13658e664fb3SJohannes Berg * variable to point to the location where the buffer should be 13668e664fb3SJohannes Berg * split. 13678e664fb3SJohannes Berg * 13688e664fb3SJohannes Berg * It assumes that the given IE buffer is well-formed, this 13698e664fb3SJohannes Berg * has to be guaranteed by the caller! 13708e664fb3SJohannes Berg * 13718e664fb3SJohannes Berg * It also assumes that the IEs in the buffer are ordered 13728e664fb3SJohannes Berg * correctly, if not the result of using this function will not 13738e664fb3SJohannes Berg * be ordered correctly either, i.e. it does no reordering. 13748e664fb3SJohannes Berg * 13758e664fb3SJohannes Berg * The function returns the offset where the next part of the 13768e664fb3SJohannes Berg * buffer starts, which may be @ielen if the entire (remainder) 13778e664fb3SJohannes Berg * of the buffer should be used. 13788e664fb3SJohannes Berg */ 13798e664fb3SJohannes Berg size_t ieee80211_ie_split(const u8 *ies, size_t ielen, 13808e664fb3SJohannes Berg const u8 *ids, int n_ids, size_t offset) 13818e664fb3SJohannes Berg { 13828e664fb3SJohannes Berg size_t pos = offset; 13838e664fb3SJohannes Berg 13848e664fb3SJohannes Berg while (pos < ielen && ieee80211_id_in_list(ids, n_ids, ies[pos])) 13858e664fb3SJohannes Berg pos += 2 + ies[pos + 1]; 13868e664fb3SJohannes Berg 13878e664fb3SJohannes Berg return pos; 13888e664fb3SJohannes Berg } 13898e664fb3SJohannes Berg 13908e664fb3SJohannes Berg size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset) 13918e664fb3SJohannes Berg { 13928e664fb3SJohannes Berg size_t pos = offset; 13938e664fb3SJohannes Berg 13948e664fb3SJohannes Berg while (pos < ielen && ies[pos] != WLAN_EID_VENDOR_SPECIFIC) 13958e664fb3SJohannes Berg pos += 2 + ies[pos + 1]; 13968e664fb3SJohannes Berg 13978e664fb3SJohannes Berg return pos; 13988e664fb3SJohannes Berg } 1399