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> 16bc3b2d7fSPaul Gortmaker #include <linux/export.h> 17c2d1560aSJohannes Berg #include <linux/types.h> 18c2d1560aSJohannes Berg #include <linux/slab.h> 19c2d1560aSJohannes Berg #include <linux/skbuff.h> 20c2d1560aSJohannes Berg #include <linux/etherdevice.h> 21c2d1560aSJohannes Berg #include <linux/if_arp.h> 22c2d1560aSJohannes Berg #include <linux/bitmap.h> 23dd76986bSJohannes Berg #include <linux/crc32.h> 24881d966bSEric W. Biederman #include <net/net_namespace.h> 25c2d1560aSJohannes Berg #include <net/cfg80211.h> 26dabeb344SJohannes Berg #include <net/rtnetlink.h> 27c2d1560aSJohannes Berg 28c2d1560aSJohannes Berg #include "ieee80211_i.h" 2924487981SJohannes Berg #include "driver-ops.h" 302c8dccc7SJohannes Berg #include "rate.h" 31ee385855SLuis Carlos Cobo #include "mesh.h" 32c2d1560aSJohannes Berg #include "wme.h" 33f2753ddbSJohannes Berg #include "led.h" 34fffd0934SJohannes Berg #include "wep.h" 35c2d1560aSJohannes Berg 36c2d1560aSJohannes Berg /* privid for wiphys to determine whether they belong to us or not */ 37c2d1560aSJohannes Berg void *mac80211_wiphy_privid = &mac80211_wiphy_privid; 38c2d1560aSJohannes Berg 399a95371aSLuis R. Rodriguez struct ieee80211_hw *wiphy_to_ieee80211_hw(struct wiphy *wiphy) 409a95371aSLuis R. Rodriguez { 419a95371aSLuis R. Rodriguez struct ieee80211_local *local; 429a95371aSLuis R. Rodriguez BUG_ON(!wiphy); 439a95371aSLuis R. Rodriguez 449a95371aSLuis R. Rodriguez local = wiphy_priv(wiphy); 459a95371aSLuis R. Rodriguez return &local->hw; 469a95371aSLuis R. Rodriguez } 479a95371aSLuis R. Rodriguez EXPORT_SYMBOL(wiphy_to_ieee80211_hw); 48c2d1560aSJohannes Berg 4971364716SRon Rindjunsky u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, 5005c914feSJohannes Berg enum nl80211_iftype type) 51c2d1560aSJohannes Berg { 52a494bb1cSHarvey Harrison __le16 fc = hdr->frame_control; 53c2d1560aSJohannes Berg 5498f0b0a3SRon Rindjunsky /* drop ACK/CTS frames and incorrect hdr len (ctrl) */ 5598f0b0a3SRon Rindjunsky if (len < 16) 56c2d1560aSJohannes Berg return NULL; 57c2d1560aSJohannes Berg 58a494bb1cSHarvey Harrison if (ieee80211_is_data(fc)) { 5998f0b0a3SRon Rindjunsky if (len < 24) /* drop incorrect hdr len (data) */ 6098f0b0a3SRon Rindjunsky return NULL; 61a494bb1cSHarvey Harrison 62a494bb1cSHarvey Harrison if (ieee80211_has_a4(fc)) 63c2d1560aSJohannes Berg return NULL; 64a494bb1cSHarvey Harrison if (ieee80211_has_tods(fc)) 65a494bb1cSHarvey Harrison return hdr->addr1; 66a494bb1cSHarvey Harrison if (ieee80211_has_fromds(fc)) 67c2d1560aSJohannes Berg return hdr->addr2; 68a494bb1cSHarvey Harrison 69c2d1560aSJohannes Berg return hdr->addr3; 70c2d1560aSJohannes Berg } 71a494bb1cSHarvey Harrison 72a494bb1cSHarvey Harrison if (ieee80211_is_mgmt(fc)) { 7398f0b0a3SRon Rindjunsky if (len < 24) /* drop incorrect hdr len (mgmt) */ 7498f0b0a3SRon Rindjunsky return NULL; 75c2d1560aSJohannes Berg return hdr->addr3; 76a494bb1cSHarvey Harrison } 77a494bb1cSHarvey Harrison 78a494bb1cSHarvey Harrison if (ieee80211_is_ctl(fc)) { 79a494bb1cSHarvey Harrison if(ieee80211_is_pspoll(fc)) 80c2d1560aSJohannes Berg return hdr->addr1; 81a494bb1cSHarvey Harrison 82a494bb1cSHarvey Harrison if (ieee80211_is_back_req(fc)) { 8371364716SRon Rindjunsky switch (type) { 8405c914feSJohannes Berg case NL80211_IFTYPE_STATION: 8571364716SRon Rindjunsky return hdr->addr2; 8605c914feSJohannes Berg case NL80211_IFTYPE_AP: 8705c914feSJohannes Berg case NL80211_IFTYPE_AP_VLAN: 8871364716SRon Rindjunsky return hdr->addr1; 8971364716SRon Rindjunsky default: 90a494bb1cSHarvey Harrison break; /* fall through to the return */ 9171364716SRon Rindjunsky } 9271364716SRon Rindjunsky } 93c2d1560aSJohannes Berg } 94c2d1560aSJohannes Berg 95c2d1560aSJohannes Berg return NULL; 96c2d1560aSJohannes Berg } 97c2d1560aSJohannes Berg 985cf121c3SJohannes Berg void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx) 99c2d1560aSJohannes Berg { 100252b86c4SJohannes Berg struct sk_buff *skb; 1012de8e0d9SJohannes Berg struct ieee80211_hdr *hdr; 102c2d1560aSJohannes Berg 103252b86c4SJohannes Berg skb_queue_walk(&tx->skbs, skb) { 1042de8e0d9SJohannes Berg hdr = (struct ieee80211_hdr *) skb->data; 105c2d1560aSJohannes Berg hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); 106252b86c4SJohannes Berg } 107c2d1560aSJohannes Berg } 108c2d1560aSJohannes Berg 1094ee73f33SMichal Kazior int ieee80211_frame_duration(enum ieee80211_band band, size_t len, 110c2d1560aSJohannes Berg int rate, int erp, int short_preamble) 111c2d1560aSJohannes Berg { 112c2d1560aSJohannes Berg int dur; 113c2d1560aSJohannes Berg 114c2d1560aSJohannes Berg /* calculate duration (in microseconds, rounded up to next higher 115c2d1560aSJohannes Berg * integer if it includes a fractional microsecond) to send frame of 116c2d1560aSJohannes Berg * len bytes (does not include FCS) at the given rate. Duration will 117c2d1560aSJohannes Berg * also include SIFS. 118c2d1560aSJohannes Berg * 119c2d1560aSJohannes Berg * rate is in 100 kbps, so divident is multiplied by 10 in the 120c2d1560aSJohannes Berg * DIV_ROUND_UP() operations. 121c2d1560aSJohannes Berg */ 122c2d1560aSJohannes Berg 1234ee73f33SMichal Kazior if (band == IEEE80211_BAND_5GHZ || erp) { 124c2d1560aSJohannes Berg /* 125c2d1560aSJohannes Berg * OFDM: 126c2d1560aSJohannes Berg * 127c2d1560aSJohannes Berg * N_DBPS = DATARATE x 4 128c2d1560aSJohannes Berg * N_SYM = Ceiling((16+8xLENGTH+6) / N_DBPS) 129c2d1560aSJohannes Berg * (16 = SIGNAL time, 6 = tail bits) 130c2d1560aSJohannes Berg * TXTIME = T_PREAMBLE + T_SIGNAL + T_SYM x N_SYM + Signal Ext 131c2d1560aSJohannes Berg * 132c2d1560aSJohannes Berg * T_SYM = 4 usec 133c2d1560aSJohannes Berg * 802.11a - 17.5.2: aSIFSTime = 16 usec 134c2d1560aSJohannes Berg * 802.11g - 19.8.4: aSIFSTime = 10 usec + 135c2d1560aSJohannes Berg * signal ext = 6 usec 136c2d1560aSJohannes Berg */ 137c2d1560aSJohannes Berg dur = 16; /* SIFS + signal ext */ 138c2d1560aSJohannes Berg dur += 16; /* 17.3.2.3: T_PREAMBLE = 16 usec */ 139c2d1560aSJohannes Berg dur += 4; /* 17.3.2.3: T_SIGNAL = 4 usec */ 140c2d1560aSJohannes Berg dur += 4 * DIV_ROUND_UP((16 + 8 * (len + 4) + 6) * 10, 141c2d1560aSJohannes Berg 4 * rate); /* T_SYM x N_SYM */ 142c2d1560aSJohannes Berg } else { 143c2d1560aSJohannes Berg /* 144c2d1560aSJohannes Berg * 802.11b or 802.11g with 802.11b compatibility: 145c2d1560aSJohannes Berg * 18.3.4: TXTIME = PreambleLength + PLCPHeaderTime + 146c2d1560aSJohannes Berg * Ceiling(((LENGTH+PBCC)x8)/DATARATE). PBCC=0. 147c2d1560aSJohannes Berg * 148c2d1560aSJohannes Berg * 802.11 (DS): 15.3.3, 802.11b: 18.3.4 149c2d1560aSJohannes Berg * aSIFSTime = 10 usec 150c2d1560aSJohannes Berg * aPreambleLength = 144 usec or 72 usec with short preamble 151c2d1560aSJohannes Berg * aPLCPHeaderLength = 48 usec or 24 usec with short preamble 152c2d1560aSJohannes Berg */ 153c2d1560aSJohannes Berg dur = 10; /* aSIFSTime = 10 usec */ 154c2d1560aSJohannes Berg dur += short_preamble ? (72 + 24) : (144 + 48); 155c2d1560aSJohannes Berg 156c2d1560aSJohannes Berg dur += DIV_ROUND_UP(8 * (len + 4) * 10, rate); 157c2d1560aSJohannes Berg } 158c2d1560aSJohannes Berg 159c2d1560aSJohannes Berg return dur; 160c2d1560aSJohannes Berg } 161c2d1560aSJohannes Berg 162c2d1560aSJohannes Berg /* Exported duration function for driver use */ 16332bfd35dSJohannes Berg __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, 16432bfd35dSJohannes Berg struct ieee80211_vif *vif, 1654ee73f33SMichal Kazior enum ieee80211_band band, 1668318d78aSJohannes Berg size_t frame_len, 1678318d78aSJohannes Berg struct ieee80211_rate *rate) 168c2d1560aSJohannes Berg { 16925d834e1SJohannes Berg struct ieee80211_sub_if_data *sdata; 170c2d1560aSJohannes Berg u16 dur; 171c2d1560aSJohannes Berg int erp; 17225d834e1SJohannes Berg bool short_preamble = false; 173c2d1560aSJohannes Berg 1748318d78aSJohannes Berg erp = 0; 17525d834e1SJohannes Berg if (vif) { 17625d834e1SJohannes Berg sdata = vif_to_sdata(vif); 177bda3933aSJohannes Berg short_preamble = sdata->vif.bss_conf.use_short_preamble; 1788318d78aSJohannes Berg if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) 1798318d78aSJohannes Berg erp = rate->flags & IEEE80211_RATE_ERP_G; 18025d834e1SJohannes Berg } 1818318d78aSJohannes Berg 1824ee73f33SMichal Kazior dur = ieee80211_frame_duration(band, frame_len, rate->bitrate, erp, 18325d834e1SJohannes Berg short_preamble); 184c2d1560aSJohannes Berg 185c2d1560aSJohannes Berg return cpu_to_le16(dur); 186c2d1560aSJohannes Berg } 187c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_generic_frame_duration); 188c2d1560aSJohannes Berg 18932bfd35dSJohannes Berg __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, 19032bfd35dSJohannes Berg struct ieee80211_vif *vif, size_t frame_len, 191e039fa4aSJohannes Berg const struct ieee80211_tx_info *frame_txctl) 192c2d1560aSJohannes Berg { 193c2d1560aSJohannes Berg struct ieee80211_local *local = hw_to_local(hw); 194c2d1560aSJohannes Berg struct ieee80211_rate *rate; 19525d834e1SJohannes Berg struct ieee80211_sub_if_data *sdata; 196471b3efdSJohannes Berg bool short_preamble; 197c2d1560aSJohannes Berg int erp; 198c2d1560aSJohannes Berg u16 dur; 1992e92e6f2SJohannes Berg struct ieee80211_supported_band *sband; 2002e92e6f2SJohannes Berg 2014ee73f33SMichal Kazior sband = local->hw.wiphy->bands[frame_txctl->band]; 202c2d1560aSJohannes Berg 20325d834e1SJohannes Berg short_preamble = false; 2047e9ed188SDaniel Drake 205e039fa4aSJohannes Berg rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx]; 2068318d78aSJohannes Berg 2078318d78aSJohannes Berg erp = 0; 20825d834e1SJohannes Berg if (vif) { 20925d834e1SJohannes Berg sdata = vif_to_sdata(vif); 210bda3933aSJohannes Berg short_preamble = sdata->vif.bss_conf.use_short_preamble; 2118318d78aSJohannes Berg if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) 2128318d78aSJohannes Berg erp = rate->flags & IEEE80211_RATE_ERP_G; 21325d834e1SJohannes Berg } 214c2d1560aSJohannes Berg 215c2d1560aSJohannes Berg /* CTS duration */ 2164ee73f33SMichal Kazior dur = ieee80211_frame_duration(sband->band, 10, rate->bitrate, 217c2d1560aSJohannes Berg erp, short_preamble); 218c2d1560aSJohannes Berg /* Data frame duration */ 2194ee73f33SMichal Kazior dur += ieee80211_frame_duration(sband->band, frame_len, rate->bitrate, 220c2d1560aSJohannes Berg erp, short_preamble); 221c2d1560aSJohannes Berg /* ACK duration */ 2224ee73f33SMichal Kazior dur += ieee80211_frame_duration(sband->band, 10, rate->bitrate, 223c2d1560aSJohannes Berg erp, short_preamble); 224c2d1560aSJohannes Berg 225c2d1560aSJohannes Berg return cpu_to_le16(dur); 226c2d1560aSJohannes Berg } 227c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_rts_duration); 228c2d1560aSJohannes Berg 22932bfd35dSJohannes Berg __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, 23032bfd35dSJohannes Berg struct ieee80211_vif *vif, 231c2d1560aSJohannes Berg size_t frame_len, 232e039fa4aSJohannes Berg const struct ieee80211_tx_info *frame_txctl) 233c2d1560aSJohannes Berg { 234c2d1560aSJohannes Berg struct ieee80211_local *local = hw_to_local(hw); 235c2d1560aSJohannes Berg struct ieee80211_rate *rate; 23625d834e1SJohannes Berg struct ieee80211_sub_if_data *sdata; 237471b3efdSJohannes Berg bool short_preamble; 238c2d1560aSJohannes Berg int erp; 239c2d1560aSJohannes Berg u16 dur; 2402e92e6f2SJohannes Berg struct ieee80211_supported_band *sband; 2412e92e6f2SJohannes Berg 2424ee73f33SMichal Kazior sband = local->hw.wiphy->bands[frame_txctl->band]; 243c2d1560aSJohannes Berg 24425d834e1SJohannes Berg short_preamble = false; 2457e9ed188SDaniel Drake 246e039fa4aSJohannes Berg rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx]; 2478318d78aSJohannes Berg erp = 0; 24825d834e1SJohannes Berg if (vif) { 24925d834e1SJohannes Berg sdata = vif_to_sdata(vif); 250bda3933aSJohannes Berg short_preamble = sdata->vif.bss_conf.use_short_preamble; 2518318d78aSJohannes Berg if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) 2528318d78aSJohannes Berg erp = rate->flags & IEEE80211_RATE_ERP_G; 25325d834e1SJohannes Berg } 254c2d1560aSJohannes Berg 255c2d1560aSJohannes Berg /* Data frame duration */ 2564ee73f33SMichal Kazior dur = ieee80211_frame_duration(sband->band, frame_len, rate->bitrate, 257c2d1560aSJohannes Berg erp, short_preamble); 258e039fa4aSJohannes Berg if (!(frame_txctl->flags & IEEE80211_TX_CTL_NO_ACK)) { 259c2d1560aSJohannes Berg /* ACK duration */ 2604ee73f33SMichal Kazior dur += ieee80211_frame_duration(sband->band, 10, rate->bitrate, 261c2d1560aSJohannes Berg erp, short_preamble); 262c2d1560aSJohannes Berg } 263c2d1560aSJohannes Berg 264c2d1560aSJohannes Berg return cpu_to_le16(dur); 265c2d1560aSJohannes Berg } 266c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_ctstoself_duration); 267c2d1560aSJohannes Berg 2683a25a8c8SJohannes Berg void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue) 2693a25a8c8SJohannes Berg { 2703a25a8c8SJohannes Berg struct ieee80211_sub_if_data *sdata; 271a6f38ac3SJohannes Berg int n_acs = IEEE80211_NUM_ACS; 272a6f38ac3SJohannes Berg 273a6f38ac3SJohannes Berg if (local->hw.queues < IEEE80211_NUM_ACS) 274a6f38ac3SJohannes Berg n_acs = 1; 2753a25a8c8SJohannes Berg 2763a25a8c8SJohannes Berg list_for_each_entry_rcu(sdata, &local->interfaces, list) { 2773a25a8c8SJohannes Berg int ac; 2783a25a8c8SJohannes Berg 279f142c6b9SJohannes Berg if (!sdata->dev) 280f142c6b9SJohannes Berg continue; 281f142c6b9SJohannes Berg 2823a25a8c8SJohannes Berg if (test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state)) 2833a25a8c8SJohannes Berg continue; 2843a25a8c8SJohannes Berg 2853a25a8c8SJohannes Berg if (sdata->vif.cab_queue != IEEE80211_INVAL_HW_QUEUE && 2863a25a8c8SJohannes Berg local->queue_stop_reasons[sdata->vif.cab_queue] != 0) 2873a25a8c8SJohannes Berg continue; 2883a25a8c8SJohannes Berg 289a6f38ac3SJohannes Berg for (ac = 0; ac < n_acs; ac++) { 2903a25a8c8SJohannes Berg int ac_queue = sdata->vif.hw_queue[ac]; 2913a25a8c8SJohannes Berg 2923a25a8c8SJohannes Berg if (ac_queue == queue || 2933a25a8c8SJohannes Berg (sdata->vif.cab_queue == queue && 2943a25a8c8SJohannes Berg local->queue_stop_reasons[ac_queue] == 0 && 2953a25a8c8SJohannes Berg skb_queue_empty(&local->pending[ac_queue]))) 2963a25a8c8SJohannes Berg netif_wake_subqueue(sdata->dev, ac); 2973a25a8c8SJohannes Berg } 2983a25a8c8SJohannes Berg } 2993a25a8c8SJohannes Berg } 3003a25a8c8SJohannes Berg 301ce7c9111SKalle Valo static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, 302ce7c9111SKalle Valo enum queue_stop_reason reason) 303c2d1560aSJohannes Berg { 304c2d1560aSJohannes Berg struct ieee80211_local *local = hw_to_local(hw); 305c2d1560aSJohannes Berg 306b5878a2dSJohannes Berg trace_wake_queue(local, queue, reason); 307b5878a2dSJohannes Berg 308e4e72fb4SJohannes Berg if (WARN_ON(queue >= hw->queues)) 30996f5e66eSJohannes Berg return; 31096f5e66eSJohannes Berg 311ada15125SJohannes Berg if (!test_bit(reason, &local->queue_stop_reasons[queue])) 312ada15125SJohannes Berg return; 313ada15125SJohannes Berg 314ce7c9111SKalle Valo __clear_bit(reason, &local->queue_stop_reasons[queue]); 315ce7c9111SKalle Valo 316ce7c9111SKalle Valo if (local->queue_stop_reasons[queue] != 0) 317ce7c9111SKalle Valo /* someone still has this queue stopped */ 318ce7c9111SKalle Valo return; 319ce7c9111SKalle Valo 3207236fe29SJohannes Berg if (skb_queue_empty(&local->pending[queue])) { 321cf0277e7SJohannes Berg rcu_read_lock(); 3223a25a8c8SJohannes Berg ieee80211_propagate_queue_wake(local, queue); 323cf0277e7SJohannes Berg rcu_read_unlock(); 3247236fe29SJohannes Berg } else 3257236fe29SJohannes Berg tasklet_schedule(&local->tx_pending_tasklet); 326c2d1560aSJohannes Berg } 327ce7c9111SKalle Valo 32896f5e66eSJohannes Berg void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, 329ce7c9111SKalle Valo enum queue_stop_reason reason) 330ce7c9111SKalle Valo { 331ce7c9111SKalle Valo struct ieee80211_local *local = hw_to_local(hw); 332ce7c9111SKalle Valo unsigned long flags; 333ce7c9111SKalle Valo 334ce7c9111SKalle Valo spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 335ce7c9111SKalle Valo __ieee80211_wake_queue(hw, queue, reason); 336ce7c9111SKalle Valo spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 337ce7c9111SKalle Valo } 338ce7c9111SKalle Valo 339ce7c9111SKalle Valo void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue) 340ce7c9111SKalle Valo { 341ce7c9111SKalle Valo ieee80211_wake_queue_by_reason(hw, queue, 342ce7c9111SKalle Valo IEEE80211_QUEUE_STOP_REASON_DRIVER); 343ce7c9111SKalle Valo } 344c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_wake_queue); 345c2d1560aSJohannes Berg 346ce7c9111SKalle Valo static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, 347ce7c9111SKalle Valo enum queue_stop_reason reason) 348c2d1560aSJohannes Berg { 349c2d1560aSJohannes Berg struct ieee80211_local *local = hw_to_local(hw); 350cf0277e7SJohannes Berg struct ieee80211_sub_if_data *sdata; 351a6f38ac3SJohannes Berg int n_acs = IEEE80211_NUM_ACS; 352c2d1560aSJohannes Berg 353b5878a2dSJohannes Berg trace_stop_queue(local, queue, reason); 354b5878a2dSJohannes Berg 355e4e72fb4SJohannes Berg if (WARN_ON(queue >= hw->queues)) 35696f5e66eSJohannes Berg return; 35796f5e66eSJohannes Berg 358ada15125SJohannes Berg if (test_bit(reason, &local->queue_stop_reasons[queue])) 359ada15125SJohannes Berg return; 360ada15125SJohannes Berg 3612a577d98SJohannes Berg __set_bit(reason, &local->queue_stop_reasons[queue]); 362cf0277e7SJohannes Berg 363a6f38ac3SJohannes Berg if (local->hw.queues < IEEE80211_NUM_ACS) 364a6f38ac3SJohannes Berg n_acs = 1; 365a6f38ac3SJohannes Berg 366cf0277e7SJohannes Berg rcu_read_lock(); 3673a25a8c8SJohannes Berg list_for_each_entry_rcu(sdata, &local->interfaces, list) { 3683a25a8c8SJohannes Berg int ac; 3693a25a8c8SJohannes Berg 370f142c6b9SJohannes Berg if (!sdata->dev) 371f142c6b9SJohannes Berg continue; 372f142c6b9SJohannes Berg 373a6f38ac3SJohannes Berg for (ac = 0; ac < n_acs; ac++) { 3743a25a8c8SJohannes Berg if (sdata->vif.hw_queue[ac] == queue || 3753a25a8c8SJohannes Berg sdata->vif.cab_queue == queue) 3763a25a8c8SJohannes Berg netif_stop_subqueue(sdata->dev, ac); 3773a25a8c8SJohannes Berg } 3783a25a8c8SJohannes Berg } 379cf0277e7SJohannes Berg rcu_read_unlock(); 380c2d1560aSJohannes Berg } 381ce7c9111SKalle Valo 38296f5e66eSJohannes Berg void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, 383ce7c9111SKalle Valo enum queue_stop_reason reason) 384ce7c9111SKalle Valo { 385ce7c9111SKalle Valo struct ieee80211_local *local = hw_to_local(hw); 386ce7c9111SKalle Valo unsigned long flags; 387ce7c9111SKalle Valo 388ce7c9111SKalle Valo spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 389ce7c9111SKalle Valo __ieee80211_stop_queue(hw, queue, reason); 390ce7c9111SKalle Valo spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 391ce7c9111SKalle Valo } 392ce7c9111SKalle Valo 393ce7c9111SKalle Valo void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue) 394ce7c9111SKalle Valo { 395ce7c9111SKalle Valo ieee80211_stop_queue_by_reason(hw, queue, 396ce7c9111SKalle Valo IEEE80211_QUEUE_STOP_REASON_DRIVER); 397ce7c9111SKalle Valo } 398c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_stop_queue); 399c2d1560aSJohannes Berg 4008f77f384SJohannes Berg void ieee80211_add_pending_skb(struct ieee80211_local *local, 4018f77f384SJohannes Berg struct sk_buff *skb) 4028f77f384SJohannes Berg { 4038f77f384SJohannes Berg struct ieee80211_hw *hw = &local->hw; 4048f77f384SJohannes Berg unsigned long flags; 405a7bc376cSJohannes Berg struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 4063a25a8c8SJohannes Berg int queue = info->hw_queue; 407a7bc376cSJohannes Berg 408a7bc376cSJohannes Berg if (WARN_ON(!info->control.vif)) { 4090819663dSRoel Kluin kfree_skb(skb); 410a7bc376cSJohannes Berg return; 411a7bc376cSJohannes Berg } 4128f77f384SJohannes Berg 4138f77f384SJohannes Berg spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 4148f77f384SJohannes Berg __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD); 4153b8d81e0SJohannes Berg __skb_queue_tail(&local->pending[queue], skb); 4168f77f384SJohannes Berg __ieee80211_wake_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD); 4178f77f384SJohannes Berg spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 4188f77f384SJohannes Berg } 4198f77f384SJohannes Berg 420b0b97a8aSJohannes Berg void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local, 42150a9432dSJohannes Berg struct sk_buff_head *skbs, 42250a9432dSJohannes Berg void (*fn)(void *data), void *data) 4238f77f384SJohannes Berg { 4248f77f384SJohannes Berg struct ieee80211_hw *hw = &local->hw; 4258f77f384SJohannes Berg struct sk_buff *skb; 4268f77f384SJohannes Berg unsigned long flags; 427b0b97a8aSJohannes Berg int queue, i; 4288f77f384SJohannes Berg 4298f77f384SJohannes Berg spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 4308f77f384SJohannes Berg while ((skb = skb_dequeue(skbs))) { 431a7bc376cSJohannes Berg struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 432a7bc376cSJohannes Berg 433a7bc376cSJohannes Berg if (WARN_ON(!info->control.vif)) { 4340819663dSRoel Kluin kfree_skb(skb); 435a7bc376cSJohannes Berg continue; 436a7bc376cSJohannes Berg } 437a7bc376cSJohannes Berg 4383a25a8c8SJohannes Berg queue = info->hw_queue; 4394644ae89SJohannes Berg 4404644ae89SJohannes Berg __ieee80211_stop_queue(hw, queue, 4414644ae89SJohannes Berg IEEE80211_QUEUE_STOP_REASON_SKB_ADD); 4424644ae89SJohannes Berg 4433b8d81e0SJohannes Berg __skb_queue_tail(&local->pending[queue], skb); 4448f77f384SJohannes Berg } 4458f77f384SJohannes Berg 44650a9432dSJohannes Berg if (fn) 44750a9432dSJohannes Berg fn(data); 44850a9432dSJohannes Berg 4493b8d81e0SJohannes Berg for (i = 0; i < hw->queues; i++) 4508f77f384SJohannes Berg __ieee80211_wake_queue(hw, i, 4518f77f384SJohannes Berg IEEE80211_QUEUE_STOP_REASON_SKB_ADD); 4528f77f384SJohannes Berg spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 4538f77f384SJohannes Berg } 4548f77f384SJohannes Berg 455ce7c9111SKalle Valo void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, 456ce7c9111SKalle Valo enum queue_stop_reason reason) 457c2d1560aSJohannes Berg { 458ce7c9111SKalle Valo struct ieee80211_local *local = hw_to_local(hw); 459ce7c9111SKalle Valo unsigned long flags; 460c2d1560aSJohannes Berg int i; 461c2d1560aSJohannes Berg 462ce7c9111SKalle Valo spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 463ce7c9111SKalle Valo 46496f5e66eSJohannes Berg for (i = 0; i < hw->queues; i++) 465ce7c9111SKalle Valo __ieee80211_stop_queue(hw, i, reason); 466ce7c9111SKalle Valo 467ce7c9111SKalle Valo spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 468ce7c9111SKalle Valo } 469ce7c9111SKalle Valo 470ce7c9111SKalle Valo void ieee80211_stop_queues(struct ieee80211_hw *hw) 471ce7c9111SKalle Valo { 472ce7c9111SKalle Valo ieee80211_stop_queues_by_reason(hw, 473ce7c9111SKalle Valo IEEE80211_QUEUE_STOP_REASON_DRIVER); 474c2d1560aSJohannes Berg } 475c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_stop_queues); 476c2d1560aSJohannes Berg 47792ab8535STomas Winkler int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue) 47892ab8535STomas Winkler { 47992ab8535STomas Winkler struct ieee80211_local *local = hw_to_local(hw); 4803b8d81e0SJohannes Berg unsigned long flags; 4813b8d81e0SJohannes Berg int ret; 48296f5e66eSJohannes Berg 483e4e72fb4SJohannes Berg if (WARN_ON(queue >= hw->queues)) 48496f5e66eSJohannes Berg return true; 48596f5e66eSJohannes Berg 4863b8d81e0SJohannes Berg spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 4873b8d81e0SJohannes Berg ret = !!local->queue_stop_reasons[queue]; 4883b8d81e0SJohannes Berg spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 4893b8d81e0SJohannes Berg return ret; 49092ab8535STomas Winkler } 49192ab8535STomas Winkler EXPORT_SYMBOL(ieee80211_queue_stopped); 49292ab8535STomas Winkler 493ce7c9111SKalle Valo void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, 494ce7c9111SKalle Valo enum queue_stop_reason reason) 495c2d1560aSJohannes Berg { 496ce7c9111SKalle Valo struct ieee80211_local *local = hw_to_local(hw); 497ce7c9111SKalle Valo unsigned long flags; 498c2d1560aSJohannes Berg int i; 499c2d1560aSJohannes Berg 500ce7c9111SKalle Valo spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 501ce7c9111SKalle Valo 502e4e72fb4SJohannes Berg for (i = 0; i < hw->queues; i++) 503ce7c9111SKalle Valo __ieee80211_wake_queue(hw, i, reason); 504ce7c9111SKalle Valo 505ce7c9111SKalle Valo spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 506ce7c9111SKalle Valo } 507ce7c9111SKalle Valo 508ce7c9111SKalle Valo void ieee80211_wake_queues(struct ieee80211_hw *hw) 509ce7c9111SKalle Valo { 510ce7c9111SKalle Valo ieee80211_wake_queues_by_reason(hw, IEEE80211_QUEUE_STOP_REASON_DRIVER); 511c2d1560aSJohannes Berg } 512c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_wake_queues); 513dabeb344SJohannes Berg 51432bfd35dSJohannes Berg void ieee80211_iterate_active_interfaces( 51532bfd35dSJohannes Berg struct ieee80211_hw *hw, 516dabeb344SJohannes Berg void (*iterator)(void *data, u8 *mac, 51732bfd35dSJohannes Berg struct ieee80211_vif *vif), 518dabeb344SJohannes Berg void *data) 519dabeb344SJohannes Berg { 520dabeb344SJohannes Berg struct ieee80211_local *local = hw_to_local(hw); 521dabeb344SJohannes Berg struct ieee80211_sub_if_data *sdata; 522dabeb344SJohannes Berg 523c771c9d8SJohannes Berg mutex_lock(&local->iflist_mtx); 5242f561febSIvo van Doorn 5252f561febSIvo van Doorn list_for_each_entry(sdata, &local->interfaces, list) { 5262f561febSIvo van Doorn switch (sdata->vif.type) { 52705c914feSJohannes Berg case NL80211_IFTYPE_MONITOR: 52805c914feSJohannes Berg case NL80211_IFTYPE_AP_VLAN: 5292f561febSIvo van Doorn continue; 5302ca27bcfSJohannes Berg default: 5312f561febSIvo van Doorn break; 5322f561febSIvo van Doorn } 5339607e6b6SJohannes Berg if (ieee80211_sdata_running(sdata)) 53447846c9bSJohannes Berg iterator(data, sdata->vif.addr, 5352f561febSIvo van Doorn &sdata->vif); 5362f561febSIvo van Doorn } 5372f561febSIvo van Doorn 538685fb72bSJohannes Berg sdata = rcu_dereference_protected(local->monitor_sdata, 539685fb72bSJohannes Berg lockdep_is_held(&local->iflist_mtx)); 540685fb72bSJohannes Berg if (sdata) 541685fb72bSJohannes Berg iterator(data, sdata->vif.addr, &sdata->vif); 542685fb72bSJohannes Berg 543c771c9d8SJohannes Berg mutex_unlock(&local->iflist_mtx); 5442f561febSIvo van Doorn } 5452f561febSIvo van Doorn EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces); 5462f561febSIvo van Doorn 5472f561febSIvo van Doorn void ieee80211_iterate_active_interfaces_atomic( 5482f561febSIvo van Doorn struct ieee80211_hw *hw, 5492f561febSIvo van Doorn void (*iterator)(void *data, u8 *mac, 5502f561febSIvo van Doorn struct ieee80211_vif *vif), 5512f561febSIvo van Doorn void *data) 5522f561febSIvo van Doorn { 5532f561febSIvo van Doorn struct ieee80211_local *local = hw_to_local(hw); 5542f561febSIvo van Doorn struct ieee80211_sub_if_data *sdata; 5552f561febSIvo van Doorn 556e38bad47SJohannes Berg rcu_read_lock(); 557dabeb344SJohannes Berg 558e38bad47SJohannes Berg list_for_each_entry_rcu(sdata, &local->interfaces, list) { 55951fb61e7SJohannes Berg switch (sdata->vif.type) { 56005c914feSJohannes Berg case NL80211_IFTYPE_MONITOR: 56105c914feSJohannes Berg case NL80211_IFTYPE_AP_VLAN: 562dabeb344SJohannes Berg continue; 5632ca27bcfSJohannes Berg default: 564dabeb344SJohannes Berg break; 565dabeb344SJohannes Berg } 5669607e6b6SJohannes Berg if (ieee80211_sdata_running(sdata)) 56747846c9bSJohannes Berg iterator(data, sdata->vif.addr, 56832bfd35dSJohannes Berg &sdata->vif); 569dabeb344SJohannes Berg } 570e38bad47SJohannes Berg 571685fb72bSJohannes Berg sdata = rcu_dereference(local->monitor_sdata); 572685fb72bSJohannes Berg if (sdata) 573685fb72bSJohannes Berg iterator(data, sdata->vif.addr, &sdata->vif); 574685fb72bSJohannes Berg 575e38bad47SJohannes Berg rcu_read_unlock(); 576dabeb344SJohannes Berg } 5772f561febSIvo van Doorn EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic); 57837ffc8daSJohannes Berg 57942935ecaSLuis R. Rodriguez /* 58042935ecaSLuis R. Rodriguez * Nothing should have been stuffed into the workqueue during 58142935ecaSLuis R. Rodriguez * the suspend->resume cycle. If this WARN is seen then there 58242935ecaSLuis R. Rodriguez * is a bug with either the driver suspend or something in 58342935ecaSLuis R. Rodriguez * mac80211 stuffing into the workqueue which we haven't yet 58442935ecaSLuis R. Rodriguez * cleared during mac80211's suspend cycle. 58542935ecaSLuis R. Rodriguez */ 58642935ecaSLuis R. Rodriguez static bool ieee80211_can_queue_work(struct ieee80211_local *local) 58742935ecaSLuis R. Rodriguez { 588ceb99fe0SJohannes Berg if (WARN(local->suspended && !local->resuming, 589ceb99fe0SJohannes Berg "queueing ieee80211 work while going to suspend\n")) 59042935ecaSLuis R. Rodriguez return false; 59142935ecaSLuis R. Rodriguez 59242935ecaSLuis R. Rodriguez return true; 59342935ecaSLuis R. Rodriguez } 59442935ecaSLuis R. Rodriguez 59542935ecaSLuis R. Rodriguez void ieee80211_queue_work(struct ieee80211_hw *hw, struct work_struct *work) 59642935ecaSLuis R. Rodriguez { 59742935ecaSLuis R. Rodriguez struct ieee80211_local *local = hw_to_local(hw); 59842935ecaSLuis R. Rodriguez 59942935ecaSLuis R. Rodriguez if (!ieee80211_can_queue_work(local)) 60042935ecaSLuis R. Rodriguez return; 60142935ecaSLuis R. Rodriguez 60242935ecaSLuis R. Rodriguez queue_work(local->workqueue, work); 60342935ecaSLuis R. Rodriguez } 60442935ecaSLuis R. Rodriguez EXPORT_SYMBOL(ieee80211_queue_work); 60542935ecaSLuis R. Rodriguez 60642935ecaSLuis R. Rodriguez void ieee80211_queue_delayed_work(struct ieee80211_hw *hw, 60742935ecaSLuis R. Rodriguez struct delayed_work *dwork, 60842935ecaSLuis R. Rodriguez unsigned long delay) 60942935ecaSLuis R. Rodriguez { 61042935ecaSLuis R. Rodriguez struct ieee80211_local *local = hw_to_local(hw); 61142935ecaSLuis R. Rodriguez 61242935ecaSLuis R. Rodriguez if (!ieee80211_can_queue_work(local)) 61342935ecaSLuis R. Rodriguez return; 61442935ecaSLuis R. Rodriguez 61542935ecaSLuis R. Rodriguez queue_delayed_work(local->workqueue, dwork, delay); 61642935ecaSLuis R. Rodriguez } 61742935ecaSLuis R. Rodriguez EXPORT_SYMBOL(ieee80211_queue_delayed_work); 61842935ecaSLuis R. Rodriguez 619dd76986bSJohannes Berg u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, 620dd76986bSJohannes Berg struct ieee802_11_elems *elems, 621dd76986bSJohannes Berg u64 filter, u32 crc) 622dd76986bSJohannes Berg { 623dd76986bSJohannes Berg size_t left = len; 624dd76986bSJohannes Berg u8 *pos = start; 625dd76986bSJohannes Berg bool calc_crc = filter != 0; 626fcff4f10SPaul Stewart DECLARE_BITMAP(seen_elems, 256); 627dd76986bSJohannes Berg 628fcff4f10SPaul Stewart bitmap_zero(seen_elems, 256); 629dd76986bSJohannes Berg memset(elems, 0, sizeof(*elems)); 630dd76986bSJohannes Berg elems->ie_start = start; 631dd76986bSJohannes Berg elems->total_len = len; 632dd76986bSJohannes Berg 633dd76986bSJohannes Berg while (left >= 2) { 634dd76986bSJohannes Berg u8 id, elen; 635fcff4f10SPaul Stewart bool elem_parse_failed; 636dd76986bSJohannes Berg 637dd76986bSJohannes Berg id = *pos++; 638dd76986bSJohannes Berg elen = *pos++; 639dd76986bSJohannes Berg left -= 2; 640dd76986bSJohannes Berg 641fcff4f10SPaul Stewart if (elen > left) { 642fcff4f10SPaul Stewart elems->parse_error = true; 643dd76986bSJohannes Berg break; 644fcff4f10SPaul Stewart } 645fcff4f10SPaul Stewart 6469690fb16SJohannes Berg switch (id) { 6479690fb16SJohannes Berg case WLAN_EID_SSID: 6489690fb16SJohannes Berg case WLAN_EID_SUPP_RATES: 6499690fb16SJohannes Berg case WLAN_EID_FH_PARAMS: 6509690fb16SJohannes Berg case WLAN_EID_DS_PARAMS: 6519690fb16SJohannes Berg case WLAN_EID_CF_PARAMS: 6529690fb16SJohannes Berg case WLAN_EID_TIM: 6539690fb16SJohannes Berg case WLAN_EID_IBSS_PARAMS: 6549690fb16SJohannes Berg case WLAN_EID_CHALLENGE: 6559690fb16SJohannes Berg case WLAN_EID_RSN: 6569690fb16SJohannes Berg case WLAN_EID_ERP_INFO: 6579690fb16SJohannes Berg case WLAN_EID_EXT_SUPP_RATES: 6589690fb16SJohannes Berg case WLAN_EID_HT_CAPABILITY: 6599690fb16SJohannes Berg case WLAN_EID_HT_OPERATION: 6609690fb16SJohannes Berg case WLAN_EID_VHT_CAPABILITY: 6619690fb16SJohannes Berg case WLAN_EID_VHT_OPERATION: 6629690fb16SJohannes Berg case WLAN_EID_MESH_ID: 6639690fb16SJohannes Berg case WLAN_EID_MESH_CONFIG: 6649690fb16SJohannes Berg case WLAN_EID_PEER_MGMT: 6659690fb16SJohannes Berg case WLAN_EID_PREQ: 6669690fb16SJohannes Berg case WLAN_EID_PREP: 6679690fb16SJohannes Berg case WLAN_EID_PERR: 6689690fb16SJohannes Berg case WLAN_EID_RANN: 6699690fb16SJohannes Berg case WLAN_EID_CHANNEL_SWITCH: 6709690fb16SJohannes Berg case WLAN_EID_EXT_CHANSWITCH_ANN: 6719690fb16SJohannes Berg case WLAN_EID_COUNTRY: 6729690fb16SJohannes Berg case WLAN_EID_PWR_CONSTRAINT: 6739690fb16SJohannes Berg case WLAN_EID_TIMEOUT_INTERVAL: 6749690fb16SJohannes Berg if (test_bit(id, seen_elems)) { 675fcff4f10SPaul Stewart elems->parse_error = true; 676fcff4f10SPaul Stewart left -= elen; 677fcff4f10SPaul Stewart pos += elen; 678fcff4f10SPaul Stewart continue; 679fcff4f10SPaul Stewart } 6809690fb16SJohannes Berg break; 6819690fb16SJohannes Berg } 682dd76986bSJohannes Berg 683dd76986bSJohannes Berg if (calc_crc && id < 64 && (filter & (1ULL << id))) 684dd76986bSJohannes Berg crc = crc32_be(crc, pos - 2, elen + 2); 685dd76986bSJohannes Berg 686fcff4f10SPaul Stewart elem_parse_failed = false; 687fcff4f10SPaul Stewart 688dd76986bSJohannes Berg switch (id) { 689dd76986bSJohannes Berg case WLAN_EID_SSID: 690dd76986bSJohannes Berg elems->ssid = pos; 691dd76986bSJohannes Berg elems->ssid_len = elen; 692dd76986bSJohannes Berg break; 693dd76986bSJohannes Berg case WLAN_EID_SUPP_RATES: 694dd76986bSJohannes Berg elems->supp_rates = pos; 695dd76986bSJohannes Berg elems->supp_rates_len = elen; 696dd76986bSJohannes Berg break; 697dd76986bSJohannes Berg case WLAN_EID_FH_PARAMS: 698dd76986bSJohannes Berg elems->fh_params = pos; 699dd76986bSJohannes Berg elems->fh_params_len = elen; 700dd76986bSJohannes Berg break; 701dd76986bSJohannes Berg case WLAN_EID_DS_PARAMS: 702dd76986bSJohannes Berg elems->ds_params = pos; 703dd76986bSJohannes Berg elems->ds_params_len = elen; 704dd76986bSJohannes Berg break; 705dd76986bSJohannes Berg case WLAN_EID_CF_PARAMS: 706dd76986bSJohannes Berg elems->cf_params = pos; 707dd76986bSJohannes Berg elems->cf_params_len = elen; 708dd76986bSJohannes Berg break; 709dd76986bSJohannes Berg case WLAN_EID_TIM: 710dd76986bSJohannes Berg if (elen >= sizeof(struct ieee80211_tim_ie)) { 711dd76986bSJohannes Berg elems->tim = (void *)pos; 712dd76986bSJohannes Berg elems->tim_len = elen; 713fcff4f10SPaul Stewart } else 714fcff4f10SPaul Stewart elem_parse_failed = true; 715dd76986bSJohannes Berg break; 716dd76986bSJohannes Berg case WLAN_EID_IBSS_PARAMS: 717dd76986bSJohannes Berg elems->ibss_params = pos; 718dd76986bSJohannes Berg elems->ibss_params_len = elen; 719dd76986bSJohannes Berg break; 720dd76986bSJohannes Berg case WLAN_EID_CHALLENGE: 721dd76986bSJohannes Berg elems->challenge = pos; 722dd76986bSJohannes Berg elems->challenge_len = elen; 723dd76986bSJohannes Berg break; 724dd76986bSJohannes Berg case WLAN_EID_VENDOR_SPECIFIC: 725dd76986bSJohannes Berg if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 && 726dd76986bSJohannes Berg pos[2] == 0xf2) { 727dd76986bSJohannes Berg /* Microsoft OUI (00:50:F2) */ 728dd76986bSJohannes Berg 729dd76986bSJohannes Berg if (calc_crc) 730dd76986bSJohannes Berg crc = crc32_be(crc, pos - 2, elen + 2); 731dd76986bSJohannes Berg 732dd76986bSJohannes Berg if (pos[3] == 1) { 733dd76986bSJohannes Berg /* OUI Type 1 - WPA IE */ 734dd76986bSJohannes Berg elems->wpa = pos; 735dd76986bSJohannes Berg elems->wpa_len = elen; 736dd76986bSJohannes Berg } else if (elen >= 5 && pos[3] == 2) { 737dd76986bSJohannes Berg /* OUI Type 2 - WMM IE */ 738dd76986bSJohannes Berg if (pos[4] == 0) { 739dd76986bSJohannes Berg elems->wmm_info = pos; 740dd76986bSJohannes Berg elems->wmm_info_len = elen; 741dd76986bSJohannes Berg } else if (pos[4] == 1) { 742dd76986bSJohannes Berg elems->wmm_param = pos; 743dd76986bSJohannes Berg elems->wmm_param_len = elen; 744dd76986bSJohannes Berg } 745dd76986bSJohannes Berg } 746dd76986bSJohannes Berg } 747dd76986bSJohannes Berg break; 748dd76986bSJohannes Berg case WLAN_EID_RSN: 749dd76986bSJohannes Berg elems->rsn = pos; 750dd76986bSJohannes Berg elems->rsn_len = elen; 751dd76986bSJohannes Berg break; 752dd76986bSJohannes Berg case WLAN_EID_ERP_INFO: 753dd76986bSJohannes Berg elems->erp_info = pos; 754dd76986bSJohannes Berg elems->erp_info_len = elen; 755dd76986bSJohannes Berg break; 756dd76986bSJohannes Berg case WLAN_EID_EXT_SUPP_RATES: 757dd76986bSJohannes Berg elems->ext_supp_rates = pos; 758dd76986bSJohannes Berg elems->ext_supp_rates_len = elen; 759dd76986bSJohannes Berg break; 760dd76986bSJohannes Berg case WLAN_EID_HT_CAPABILITY: 761dd76986bSJohannes Berg if (elen >= sizeof(struct ieee80211_ht_cap)) 762dd76986bSJohannes Berg elems->ht_cap_elem = (void *)pos; 763fcff4f10SPaul Stewart else 764fcff4f10SPaul Stewart elem_parse_failed = true; 765dd76986bSJohannes Berg break; 766074d46d1SJohannes Berg case WLAN_EID_HT_OPERATION: 767074d46d1SJohannes Berg if (elen >= sizeof(struct ieee80211_ht_operation)) 768074d46d1SJohannes Berg elems->ht_operation = (void *)pos; 769fcff4f10SPaul Stewart else 770fcff4f10SPaul Stewart elem_parse_failed = true; 771dd76986bSJohannes Berg break; 772dd76986bSJohannes Berg case WLAN_EID_MESH_ID: 773dd76986bSJohannes Berg elems->mesh_id = pos; 774dd76986bSJohannes Berg elems->mesh_id_len = elen; 775dd76986bSJohannes Berg break; 776dd76986bSJohannes Berg case WLAN_EID_MESH_CONFIG: 777dd76986bSJohannes Berg if (elen >= sizeof(struct ieee80211_meshconf_ie)) 778dd76986bSJohannes Berg elems->mesh_config = (void *)pos; 779fcff4f10SPaul Stewart else 780fcff4f10SPaul Stewart elem_parse_failed = true; 781dd76986bSJohannes Berg break; 782dd76986bSJohannes Berg case WLAN_EID_PEER_MGMT: 783dd76986bSJohannes Berg elems->peering = pos; 784dd76986bSJohannes Berg elems->peering_len = elen; 785dd76986bSJohannes Berg break; 786dd76986bSJohannes Berg case WLAN_EID_PREQ: 787dd76986bSJohannes Berg elems->preq = pos; 788dd76986bSJohannes Berg elems->preq_len = elen; 789dd76986bSJohannes Berg break; 790dd76986bSJohannes Berg case WLAN_EID_PREP: 791dd76986bSJohannes Berg elems->prep = pos; 792dd76986bSJohannes Berg elems->prep_len = elen; 793dd76986bSJohannes Berg break; 794dd76986bSJohannes Berg case WLAN_EID_PERR: 795dd76986bSJohannes Berg elems->perr = pos; 796dd76986bSJohannes Berg elems->perr_len = elen; 797dd76986bSJohannes Berg break; 798dd76986bSJohannes Berg case WLAN_EID_RANN: 799dd76986bSJohannes Berg if (elen >= sizeof(struct ieee80211_rann_ie)) 800dd76986bSJohannes Berg elems->rann = (void *)pos; 801fcff4f10SPaul Stewart else 802fcff4f10SPaul Stewart elem_parse_failed = true; 803dd76986bSJohannes Berg break; 804dd76986bSJohannes Berg case WLAN_EID_CHANNEL_SWITCH: 8055bc1420bSJohannes Berg if (elen != sizeof(struct ieee80211_channel_sw_ie)) { 8065bc1420bSJohannes Berg elem_parse_failed = true; 8075bc1420bSJohannes Berg break; 8085bc1420bSJohannes Berg } 8095bc1420bSJohannes Berg elems->ch_switch_ie = (void *)pos; 810dd76986bSJohannes Berg break; 811dd76986bSJohannes Berg case WLAN_EID_QUIET: 812dd76986bSJohannes Berg if (!elems->quiet_elem) { 813dd76986bSJohannes Berg elems->quiet_elem = pos; 814dd76986bSJohannes Berg elems->quiet_elem_len = elen; 815dd76986bSJohannes Berg } 816dd76986bSJohannes Berg elems->num_of_quiet_elem++; 817dd76986bSJohannes Berg break; 818dd76986bSJohannes Berg case WLAN_EID_COUNTRY: 819dd76986bSJohannes Berg elems->country_elem = pos; 820dd76986bSJohannes Berg elems->country_elem_len = elen; 821dd76986bSJohannes Berg break; 822dd76986bSJohannes Berg case WLAN_EID_PWR_CONSTRAINT: 823761a48d2SJohannes Berg if (elen != 1) { 824761a48d2SJohannes Berg elem_parse_failed = true; 825761a48d2SJohannes Berg break; 826761a48d2SJohannes Berg } 827dd76986bSJohannes Berg elems->pwr_constr_elem = pos; 828dd76986bSJohannes Berg break; 829dd76986bSJohannes Berg case WLAN_EID_TIMEOUT_INTERVAL: 830dd76986bSJohannes Berg elems->timeout_int = pos; 831dd76986bSJohannes Berg elems->timeout_int_len = elen; 832dd76986bSJohannes Berg break; 833dd76986bSJohannes Berg default: 834dd76986bSJohannes Berg break; 835dd76986bSJohannes Berg } 836dd76986bSJohannes Berg 837fcff4f10SPaul Stewart if (elem_parse_failed) 838fcff4f10SPaul Stewart elems->parse_error = true; 839fcff4f10SPaul Stewart else 840fcff4f10SPaul Stewart set_bit(id, seen_elems); 841fcff4f10SPaul Stewart 842dd76986bSJohannes Berg left -= elen; 843dd76986bSJohannes Berg pos += elen; 844dd76986bSJohannes Berg } 845dd76986bSJohannes Berg 846fcff4f10SPaul Stewart if (left != 0) 847fcff4f10SPaul Stewart elems->parse_error = true; 848fcff4f10SPaul Stewart 849dd76986bSJohannes Berg return crc; 850dd76986bSJohannes Berg } 851dd76986bSJohannes Berg 85237ffc8daSJohannes Berg void ieee802_11_parse_elems(u8 *start, size_t len, 85337ffc8daSJohannes Berg struct ieee802_11_elems *elems) 85437ffc8daSJohannes Berg { 855d91f36dbSJohannes Berg ieee802_11_parse_elems_crc(start, len, elems, 0, 0); 856d91f36dbSJohannes Berg } 857d91f36dbSJohannes Berg 8583abead59SJohannes Berg void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, 8593abead59SJohannes Berg bool bss_notify) 8605825fe10SJohannes Berg { 8615825fe10SJohannes Berg struct ieee80211_local *local = sdata->local; 8625825fe10SJohannes Berg struct ieee80211_tx_queue_params qparam; 86354bcbc69SJohannes Berg int ac; 864a8ce8544SStanislaw Gruszka bool use_11b, enable_qos; 865aa837e1dSJohannes Berg int aCWmin, aCWmax; 8665825fe10SJohannes Berg 8675825fe10SJohannes Berg if (!local->ops->conf_tx) 8685825fe10SJohannes Berg return; 8695825fe10SJohannes Berg 87054bcbc69SJohannes Berg if (local->hw.queues < IEEE80211_NUM_ACS) 87154bcbc69SJohannes Berg return; 87254bcbc69SJohannes Berg 8735825fe10SJohannes Berg memset(&qparam, 0, sizeof(qparam)); 8745825fe10SJohannes Berg 875679ef4eaSJohannes Berg use_11b = (local->oper_channel->band == IEEE80211_BAND_2GHZ) && 876aa837e1dSJohannes Berg !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE); 8775825fe10SJohannes Berg 878a8ce8544SStanislaw Gruszka /* 879a8ce8544SStanislaw Gruszka * By default disable QoS in STA mode for old access points, which do 880a8ce8544SStanislaw Gruszka * not support 802.11e. New APs will provide proper queue parameters, 881a8ce8544SStanislaw Gruszka * that we will configure later. 882a8ce8544SStanislaw Gruszka */ 883a8ce8544SStanislaw Gruszka enable_qos = (sdata->vif.type != NL80211_IFTYPE_STATION); 884a8ce8544SStanislaw Gruszka 88554bcbc69SJohannes Berg for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { 886aa837e1dSJohannes Berg /* Set defaults according to 802.11-2007 Table 7-37 */ 887aa837e1dSJohannes Berg aCWmax = 1023; 888aa837e1dSJohannes Berg if (use_11b) 889aa837e1dSJohannes Berg aCWmin = 31; 8905825fe10SJohannes Berg else 891aa837e1dSJohannes Berg aCWmin = 15; 8925825fe10SJohannes Berg 893a8ce8544SStanislaw Gruszka if (enable_qos) { 89454bcbc69SJohannes Berg switch (ac) { 8951d98fb12SJohannes Berg case IEEE80211_AC_BK: 8967ba10a8eSJohannes Berg qparam.cw_max = aCWmax; 8977ba10a8eSJohannes Berg qparam.cw_min = aCWmin; 8985825fe10SJohannes Berg qparam.txop = 0; 899aa837e1dSJohannes Berg qparam.aifs = 7; 900aa837e1dSJohannes Berg break; 901a8ce8544SStanislaw Gruszka /* never happens but let's not leave undefined */ 902a8ce8544SStanislaw Gruszka default: 9031d98fb12SJohannes Berg case IEEE80211_AC_BE: 9047ba10a8eSJohannes Berg qparam.cw_max = aCWmax; 9057ba10a8eSJohannes Berg qparam.cw_min = aCWmin; 906aa837e1dSJohannes Berg qparam.txop = 0; 907aa837e1dSJohannes Berg qparam.aifs = 3; 908aa837e1dSJohannes Berg break; 9091d98fb12SJohannes Berg case IEEE80211_AC_VI: 910aa837e1dSJohannes Berg qparam.cw_max = aCWmin; 911aa837e1dSJohannes Berg qparam.cw_min = (aCWmin + 1) / 2 - 1; 912aa837e1dSJohannes Berg if (use_11b) 913aa837e1dSJohannes Berg qparam.txop = 6016/32; 914aa837e1dSJohannes Berg else 915aa837e1dSJohannes Berg qparam.txop = 3008/32; 916aa837e1dSJohannes Berg qparam.aifs = 2; 917aa837e1dSJohannes Berg break; 9181d98fb12SJohannes Berg case IEEE80211_AC_VO: 919aa837e1dSJohannes Berg qparam.cw_max = (aCWmin + 1) / 2 - 1; 920aa837e1dSJohannes Berg qparam.cw_min = (aCWmin + 1) / 4 - 1; 921aa837e1dSJohannes Berg if (use_11b) 922aa837e1dSJohannes Berg qparam.txop = 3264/32; 923aa837e1dSJohannes Berg else 924aa837e1dSJohannes Berg qparam.txop = 1504/32; 925aa837e1dSJohannes Berg qparam.aifs = 2; 926aa837e1dSJohannes Berg break; 927aa837e1dSJohannes Berg } 928a8ce8544SStanislaw Gruszka } else { 929a8ce8544SStanislaw Gruszka /* Confiure old 802.11b/g medium access rules. */ 930a8ce8544SStanislaw Gruszka qparam.cw_max = aCWmax; 931a8ce8544SStanislaw Gruszka qparam.cw_min = aCWmin; 932a8ce8544SStanislaw Gruszka qparam.txop = 0; 933a8ce8544SStanislaw Gruszka qparam.aifs = 2; 934a8ce8544SStanislaw Gruszka } 9355825fe10SJohannes Berg 936ab13315aSKalle Valo qparam.uapsd = false; 937ab13315aSKalle Valo 93854bcbc69SJohannes Berg sdata->tx_conf[ac] = qparam; 93954bcbc69SJohannes Berg drv_conf_tx(local, sdata, ac, &qparam); 940aa837e1dSJohannes Berg } 941e1b3ec1aSStanislaw Gruszka 942f142c6b9SJohannes Berg if (sdata->vif.type != NL80211_IFTYPE_MONITOR && 943f142c6b9SJohannes Berg sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE) { 944a8ce8544SStanislaw Gruszka sdata->vif.bss_conf.qos = enable_qos; 9453abead59SJohannes Berg if (bss_notify) 9463abead59SJohannes Berg ieee80211_bss_info_change_notify(sdata, 9473abead59SJohannes Berg BSS_CHANGED_QOS); 9485825fe10SJohannes Berg } 949d9734979SSujith } 950e50db65cSJohannes Berg 95146900298SJohannes Berg void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, 95246900298SJohannes Berg const size_t supp_rates_len, 95346900298SJohannes Berg const u8 *supp_rates) 95446900298SJohannes Berg { 95546900298SJohannes Berg struct ieee80211_local *local = sdata->local; 95646900298SJohannes Berg int i, have_higher_than_11mbit = 0; 95746900298SJohannes Berg 95846900298SJohannes Berg /* cf. IEEE 802.11 9.2.12 */ 95946900298SJohannes Berg for (i = 0; i < supp_rates_len; i++) 96046900298SJohannes Berg if ((supp_rates[i] & 0x7f) * 5 > 110) 96146900298SJohannes Berg have_higher_than_11mbit = 1; 96246900298SJohannes Berg 963679ef4eaSJohannes Berg if (local->oper_channel->band == IEEE80211_BAND_2GHZ && 96446900298SJohannes Berg have_higher_than_11mbit) 96546900298SJohannes Berg sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; 96646900298SJohannes Berg else 96746900298SJohannes Berg sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; 96846900298SJohannes Berg 9693abead59SJohannes Berg ieee80211_set_wmm_default(sdata, true); 97046900298SJohannes Berg } 97146900298SJohannes Berg 972881d948cSJohannes Berg u32 ieee80211_mandatory_rates(struct ieee80211_local *local, 97396dd22acSJohannes Berg enum ieee80211_band band) 97496dd22acSJohannes Berg { 97596dd22acSJohannes Berg struct ieee80211_supported_band *sband; 97696dd22acSJohannes Berg struct ieee80211_rate *bitrates; 977881d948cSJohannes Berg u32 mandatory_rates; 97896dd22acSJohannes Berg enum ieee80211_rate_flags mandatory_flag; 97996dd22acSJohannes Berg int i; 98096dd22acSJohannes Berg 98196dd22acSJohannes Berg sband = local->hw.wiphy->bands[band]; 9824ee73f33SMichal Kazior if (WARN_ON(!sband)) 9834ee73f33SMichal Kazior return 1; 98496dd22acSJohannes Berg 98596dd22acSJohannes Berg if (band == IEEE80211_BAND_2GHZ) 98696dd22acSJohannes Berg mandatory_flag = IEEE80211_RATE_MANDATORY_B; 98796dd22acSJohannes Berg else 98896dd22acSJohannes Berg mandatory_flag = IEEE80211_RATE_MANDATORY_A; 98996dd22acSJohannes Berg 99096dd22acSJohannes Berg bitrates = sband->bitrates; 99196dd22acSJohannes Berg mandatory_rates = 0; 99296dd22acSJohannes Berg for (i = 0; i < sband->n_bitrates; i++) 99396dd22acSJohannes Berg if (bitrates[i].flags & mandatory_flag) 99496dd22acSJohannes Berg mandatory_rates |= BIT(i); 99596dd22acSJohannes Berg return mandatory_rates; 99696dd22acSJohannes Berg } 99746900298SJohannes Berg 99846900298SJohannes Berg void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, 99946900298SJohannes Berg u16 transaction, u16 auth_alg, 1000efa6a09dSAntonio Quartulli u8 *extra, size_t extra_len, const u8 *da, 1001efa6a09dSAntonio Quartulli const u8 *bssid, const u8 *key, u8 key_len, u8 key_idx) 100246900298SJohannes Berg { 100346900298SJohannes Berg struct ieee80211_local *local = sdata->local; 100446900298SJohannes Berg struct sk_buff *skb; 100546900298SJohannes Berg struct ieee80211_mgmt *mgmt; 1006fffd0934SJohannes Berg int err; 100746900298SJohannes Berg 100846900298SJohannes Berg skb = dev_alloc_skb(local->hw.extra_tx_headroom + 100965fc73acSJouni Malinen sizeof(*mgmt) + 6 + extra_len); 1010d15b8459SJoe Perches if (!skb) 101146900298SJohannes Berg return; 1012d15b8459SJoe Perches 101346900298SJohannes Berg skb_reserve(skb, local->hw.extra_tx_headroom); 101446900298SJohannes Berg 101546900298SJohannes Berg mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6); 101646900298SJohannes Berg memset(mgmt, 0, 24 + 6); 101746900298SJohannes Berg mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | 101846900298SJohannes Berg IEEE80211_STYPE_AUTH); 1019efa6a09dSAntonio Quartulli memcpy(mgmt->da, da, ETH_ALEN); 102047846c9bSJohannes Berg memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); 102146900298SJohannes Berg memcpy(mgmt->bssid, bssid, ETH_ALEN); 102246900298SJohannes Berg mgmt->u.auth.auth_alg = cpu_to_le16(auth_alg); 102346900298SJohannes Berg mgmt->u.auth.auth_transaction = cpu_to_le16(transaction); 102446900298SJohannes Berg mgmt->u.auth.status_code = cpu_to_le16(0); 102546900298SJohannes Berg if (extra) 102646900298SJohannes Berg memcpy(skb_put(skb, extra_len), extra, extra_len); 102746900298SJohannes Berg 1028fffd0934SJohannes Berg if (auth_alg == WLAN_AUTH_SHARED_KEY && transaction == 3) { 1029fffd0934SJohannes Berg mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); 1030fffd0934SJohannes Berg err = ieee80211_wep_encrypt(local, skb, key, key_len, key_idx); 1031fffd0934SJohannes Berg WARN_ON(err); 1032fffd0934SJohannes Berg } 1033fffd0934SJohannes Berg 103462ae67beSJohannes Berg IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; 103562ae67beSJohannes Berg ieee80211_tx_skb(sdata, skb); 103646900298SJohannes Berg } 103746900298SJohannes Berg 10386ae16775SAntonio Quartulli void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, 10396ae16775SAntonio Quartulli const u8 *bssid, u16 stype, u16 reason, 10406ae16775SAntonio Quartulli bool send_frame, u8 *frame_buf) 10416ae16775SAntonio Quartulli { 10426ae16775SAntonio Quartulli struct ieee80211_local *local = sdata->local; 10436ae16775SAntonio Quartulli struct sk_buff *skb; 10446ae16775SAntonio Quartulli struct ieee80211_mgmt *mgmt = (void *)frame_buf; 10456ae16775SAntonio Quartulli 10466ae16775SAntonio Quartulli /* build frame */ 10476ae16775SAntonio Quartulli mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype); 10486ae16775SAntonio Quartulli mgmt->duration = 0; /* initialize only */ 10496ae16775SAntonio Quartulli mgmt->seq_ctrl = 0; /* initialize only */ 10506ae16775SAntonio Quartulli memcpy(mgmt->da, bssid, ETH_ALEN); 10516ae16775SAntonio Quartulli memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); 10526ae16775SAntonio Quartulli memcpy(mgmt->bssid, bssid, ETH_ALEN); 10536ae16775SAntonio Quartulli /* u.deauth.reason_code == u.disassoc.reason_code */ 10546ae16775SAntonio Quartulli mgmt->u.deauth.reason_code = cpu_to_le16(reason); 10556ae16775SAntonio Quartulli 10566ae16775SAntonio Quartulli if (send_frame) { 10576ae16775SAntonio Quartulli skb = dev_alloc_skb(local->hw.extra_tx_headroom + 10586ae16775SAntonio Quartulli IEEE80211_DEAUTH_FRAME_LEN); 10596ae16775SAntonio Quartulli if (!skb) 10606ae16775SAntonio Quartulli return; 10616ae16775SAntonio Quartulli 10626ae16775SAntonio Quartulli skb_reserve(skb, local->hw.extra_tx_headroom); 10636ae16775SAntonio Quartulli 10646ae16775SAntonio Quartulli /* copy in frame */ 10656ae16775SAntonio Quartulli memcpy(skb_put(skb, IEEE80211_DEAUTH_FRAME_LEN), 10666ae16775SAntonio Quartulli mgmt, IEEE80211_DEAUTH_FRAME_LEN); 10676ae16775SAntonio Quartulli 10686ae16775SAntonio Quartulli if (sdata->vif.type != NL80211_IFTYPE_STATION || 10696ae16775SAntonio Quartulli !(sdata->u.mgd.flags & IEEE80211_STA_MFP_ENABLED)) 10706ae16775SAntonio Quartulli IEEE80211_SKB_CB(skb)->flags |= 10716ae16775SAntonio Quartulli IEEE80211_TX_INTFL_DONT_ENCRYPT; 10726ae16775SAntonio Quartulli 10736ae16775SAntonio Quartulli ieee80211_tx_skb(sdata, skb); 10746ae16775SAntonio Quartulli } 10756ae16775SAntonio Quartulli } 10766ae16775SAntonio Quartulli 1077de95a54bSJohannes Berg int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, 10784d36ec58SJohannes Berg const u8 *ie, size_t ie_len, 1079651b5225SJouni Malinen enum ieee80211_band band, u32 rate_mask, 1080651b5225SJouni Malinen u8 channel) 1081de95a54bSJohannes Berg { 1082de95a54bSJohannes Berg struct ieee80211_supported_band *sband; 10838e664fb3SJohannes Berg u8 *pos; 10848e664fb3SJohannes Berg size_t offset = 0, noffset; 10858e664fb3SJohannes Berg int supp_rates_len, i; 10868dcb2003SJouni Malinen u8 rates[32]; 10878dcb2003SJouni Malinen int num_rates; 10888dcb2003SJouni Malinen int ext_rates_len; 1089de95a54bSJohannes Berg 10904d36ec58SJohannes Berg sband = local->hw.wiphy->bands[band]; 1091d811b3d5SArik Nemtsov if (WARN_ON_ONCE(!sband)) 1092d811b3d5SArik Nemtsov return 0; 1093de95a54bSJohannes Berg 1094de95a54bSJohannes Berg pos = buffer; 1095de95a54bSJohannes Berg 10968dcb2003SJouni Malinen num_rates = 0; 10978dcb2003SJouni Malinen for (i = 0; i < sband->n_bitrates; i++) { 10988dcb2003SJouni Malinen if ((BIT(i) & rate_mask) == 0) 10998dcb2003SJouni Malinen continue; /* skip rate */ 11008dcb2003SJouni Malinen rates[num_rates++] = (u8) (sband->bitrates[i].bitrate / 5); 11018dcb2003SJouni Malinen } 11028dcb2003SJouni Malinen 11038dcb2003SJouni Malinen supp_rates_len = min_t(int, num_rates, 8); 11048e664fb3SJohannes Berg 1105de95a54bSJohannes Berg *pos++ = WLAN_EID_SUPP_RATES; 11068e664fb3SJohannes Berg *pos++ = supp_rates_len; 11078dcb2003SJouni Malinen memcpy(pos, rates, supp_rates_len); 11088dcb2003SJouni Malinen pos += supp_rates_len; 1109de95a54bSJohannes Berg 11108e664fb3SJohannes Berg /* insert "request information" if in custom IEs */ 11118e664fb3SJohannes Berg if (ie && ie_len) { 11128e664fb3SJohannes Berg static const u8 before_extrates[] = { 11138e664fb3SJohannes Berg WLAN_EID_SSID, 11148e664fb3SJohannes Berg WLAN_EID_SUPP_RATES, 11158e664fb3SJohannes Berg WLAN_EID_REQUEST, 11168e664fb3SJohannes Berg }; 11178e664fb3SJohannes Berg noffset = ieee80211_ie_split(ie, ie_len, 11188e664fb3SJohannes Berg before_extrates, 11198e664fb3SJohannes Berg ARRAY_SIZE(before_extrates), 11208e664fb3SJohannes Berg offset); 11218e664fb3SJohannes Berg memcpy(pos, ie + offset, noffset - offset); 11228e664fb3SJohannes Berg pos += noffset - offset; 11238e664fb3SJohannes Berg offset = noffset; 11248e664fb3SJohannes Berg } 11258e664fb3SJohannes Berg 11268dcb2003SJouni Malinen ext_rates_len = num_rates - supp_rates_len; 11278dcb2003SJouni Malinen if (ext_rates_len > 0) { 1128de95a54bSJohannes Berg *pos++ = WLAN_EID_EXT_SUPP_RATES; 11298dcb2003SJouni Malinen *pos++ = ext_rates_len; 11308dcb2003SJouni Malinen memcpy(pos, rates + supp_rates_len, ext_rates_len); 11318dcb2003SJouni Malinen pos += ext_rates_len; 11328e664fb3SJohannes Berg } 11338e664fb3SJohannes Berg 1134651b5225SJouni Malinen if (channel && sband->band == IEEE80211_BAND_2GHZ) { 1135651b5225SJouni Malinen *pos++ = WLAN_EID_DS_PARAMS; 1136651b5225SJouni Malinen *pos++ = 1; 1137651b5225SJouni Malinen *pos++ = channel; 1138651b5225SJouni Malinen } 1139651b5225SJouni Malinen 11408e664fb3SJohannes Berg /* insert custom IEs that go before HT */ 11418e664fb3SJohannes Berg if (ie && ie_len) { 11428e664fb3SJohannes Berg static const u8 before_ht[] = { 11438e664fb3SJohannes Berg WLAN_EID_SSID, 11448e664fb3SJohannes Berg WLAN_EID_SUPP_RATES, 11458e664fb3SJohannes Berg WLAN_EID_REQUEST, 11468e664fb3SJohannes Berg WLAN_EID_EXT_SUPP_RATES, 11478e664fb3SJohannes Berg WLAN_EID_DS_PARAMS, 11488e664fb3SJohannes Berg WLAN_EID_SUPPORTED_REGULATORY_CLASSES, 11498e664fb3SJohannes Berg }; 11508e664fb3SJohannes Berg noffset = ieee80211_ie_split(ie, ie_len, 11518e664fb3SJohannes Berg before_ht, ARRAY_SIZE(before_ht), 11528e664fb3SJohannes Berg offset); 11538e664fb3SJohannes Berg memcpy(pos, ie + offset, noffset - offset); 11548e664fb3SJohannes Berg pos += noffset - offset; 11558e664fb3SJohannes Berg offset = noffset; 1156de95a54bSJohannes Berg } 1157de95a54bSJohannes Berg 115842e7aa77SAlexander Simon if (sband->ht_cap.ht_supported) 1159ef96a842SBen Greear pos = ieee80211_ie_build_ht_cap(pos, &sband->ht_cap, 1160ef96a842SBen Greear sband->ht_cap.cap); 11615ef2d41aSJohannes Berg 1162de95a54bSJohannes Berg /* 1163de95a54bSJohannes Berg * If adding more here, adjust code in main.c 1164de95a54bSJohannes Berg * that calculates local->scan_ies_len. 1165de95a54bSJohannes Berg */ 1166de95a54bSJohannes Berg 11678e664fb3SJohannes Berg /* add any remaining custom IEs */ 11688e664fb3SJohannes Berg if (ie && ie_len) { 11698e664fb3SJohannes Berg noffset = ie_len; 11708e664fb3SJohannes Berg memcpy(pos, ie + offset, noffset - offset); 11718e664fb3SJohannes Berg pos += noffset - offset; 1172de95a54bSJohannes Berg } 1173de95a54bSJohannes Berg 1174ba0afa2fSMahesh Palivela if (sband->vht_cap.vht_supported) 1175ba0afa2fSMahesh Palivela pos = ieee80211_ie_build_vht_cap(pos, &sband->vht_cap, 1176ba0afa2fSMahesh Palivela sband->vht_cap.cap); 1177ba0afa2fSMahesh Palivela 1178de95a54bSJohannes Berg return pos - buffer; 1179de95a54bSJohannes Berg } 1180de95a54bSJohannes Berg 1181a619a4c0SJuuso Oikarinen struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, 118285a237feSJohannes Berg u8 *dst, u32 ratemask, 11836b77863bSJohannes Berg struct ieee80211_channel *chan, 1184de95a54bSJohannes Berg const u8 *ssid, size_t ssid_len, 1185a806c558SPaul Stewart const u8 *ie, size_t ie_len, 1186a806c558SPaul Stewart bool directed) 118746900298SJohannes Berg { 118846900298SJohannes Berg struct ieee80211_local *local = sdata->local; 118946900298SJohannes Berg struct sk_buff *skb; 119046900298SJohannes Berg struct ieee80211_mgmt *mgmt; 11917c12ce8bSKalle Valo size_t buf_len; 11927c12ce8bSKalle Valo u8 *buf; 11936b77863bSJohannes Berg u8 chan_no; 119446900298SJohannes Berg 11957c12ce8bSKalle Valo /* FIXME: come up with a proper value */ 11967c12ce8bSKalle Valo buf = kmalloc(200 + ie_len, GFP_KERNEL); 1197d15b8459SJoe Perches if (!buf) 1198a619a4c0SJuuso Oikarinen return NULL; 119946900298SJohannes Berg 1200a806c558SPaul Stewart /* 1201a806c558SPaul Stewart * Do not send DS Channel parameter for directed probe requests 1202a806c558SPaul Stewart * in order to maximize the chance that we get a response. Some 1203a806c558SPaul Stewart * badly-behaved APs don't respond when this parameter is included. 1204a806c558SPaul Stewart */ 1205a806c558SPaul Stewart if (directed) 12066b77863bSJohannes Berg chan_no = 0; 1207a806c558SPaul Stewart else 12086b77863bSJohannes Berg chan_no = ieee80211_frequency_to_channel(chan->center_freq); 1209651b5225SJouni Malinen 12106b77863bSJohannes Berg buf_len = ieee80211_build_preq_ies(local, buf, ie, ie_len, chan->band, 12116b77863bSJohannes Berg ratemask, chan_no); 12127c12ce8bSKalle Valo 12137c12ce8bSKalle Valo skb = ieee80211_probereq_get(&local->hw, &sdata->vif, 12147c12ce8bSKalle Valo ssid, ssid_len, 12157c12ce8bSKalle Valo buf, buf_len); 12165b2bbf75SJohannes Berg if (!skb) 12175b2bbf75SJohannes Berg goto out; 12187c12ce8bSKalle Valo 121946900298SJohannes Berg if (dst) { 12207c12ce8bSKalle Valo mgmt = (struct ieee80211_mgmt *) skb->data; 122146900298SJohannes Berg memcpy(mgmt->da, dst, ETH_ALEN); 122246900298SJohannes Berg memcpy(mgmt->bssid, dst, ETH_ALEN); 122346900298SJohannes Berg } 122446900298SJohannes Berg 122562ae67beSJohannes Berg IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; 12265b2bbf75SJohannes Berg 12275b2bbf75SJohannes Berg out: 1228145b6d1aSMing Lei kfree(buf); 1229a619a4c0SJuuso Oikarinen 1230a619a4c0SJuuso Oikarinen return skb; 1231a619a4c0SJuuso Oikarinen } 1232a619a4c0SJuuso Oikarinen 1233a619a4c0SJuuso Oikarinen void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, 1234a619a4c0SJuuso Oikarinen const u8 *ssid, size_t ssid_len, 1235a806c558SPaul Stewart const u8 *ie, size_t ie_len, 1236fe94fe05SJohannes Berg u32 ratemask, bool directed, bool no_cck, 1237fe94fe05SJohannes Berg struct ieee80211_channel *channel) 1238a619a4c0SJuuso Oikarinen { 1239a619a4c0SJuuso Oikarinen struct sk_buff *skb; 1240a619a4c0SJuuso Oikarinen 1241fe94fe05SJohannes Berg skb = ieee80211_build_probe_req(sdata, dst, ratemask, channel, 12426b77863bSJohannes Berg ssid, ssid_len, 124385a237feSJohannes Berg ie, ie_len, directed); 1244aad14cebSRajkumar Manoharan if (skb) { 1245aad14cebSRajkumar Manoharan if (no_cck) 1246aad14cebSRajkumar Manoharan IEEE80211_SKB_CB(skb)->flags |= 1247aad14cebSRajkumar Manoharan IEEE80211_TX_CTL_NO_CCK_RATE; 1248a619a4c0SJuuso Oikarinen ieee80211_tx_skb(sdata, skb); 124946900298SJohannes Berg } 1250aad14cebSRajkumar Manoharan } 125146900298SJohannes Berg 125246900298SJohannes Berg u32 ieee80211_sta_get_rates(struct ieee80211_local *local, 125346900298SJohannes Berg struct ieee802_11_elems *elems, 12549ebb61a2SAshok Nagarajan enum ieee80211_band band, u32 *basic_rates) 125546900298SJohannes Berg { 125646900298SJohannes Berg struct ieee80211_supported_band *sband; 125746900298SJohannes Berg struct ieee80211_rate *bitrates; 125846900298SJohannes Berg size_t num_rates; 125946900298SJohannes Berg u32 supp_rates; 126046900298SJohannes Berg int i, j; 126146900298SJohannes Berg sband = local->hw.wiphy->bands[band]; 126246900298SJohannes Berg 12634ee73f33SMichal Kazior if (WARN_ON(!sband)) 12644ee73f33SMichal Kazior return 1; 126546900298SJohannes Berg 126646900298SJohannes Berg bitrates = sband->bitrates; 126746900298SJohannes Berg num_rates = sband->n_bitrates; 126846900298SJohannes Berg supp_rates = 0; 126946900298SJohannes Berg for (i = 0; i < elems->supp_rates_len + 127046900298SJohannes Berg elems->ext_supp_rates_len; i++) { 127146900298SJohannes Berg u8 rate = 0; 127246900298SJohannes Berg int own_rate; 12739ebb61a2SAshok Nagarajan bool is_basic; 127446900298SJohannes Berg if (i < elems->supp_rates_len) 127546900298SJohannes Berg rate = elems->supp_rates[i]; 127646900298SJohannes Berg else if (elems->ext_supp_rates) 127746900298SJohannes Berg rate = elems->ext_supp_rates 127846900298SJohannes Berg [i - elems->supp_rates_len]; 127946900298SJohannes Berg own_rate = 5 * (rate & 0x7f); 12809ebb61a2SAshok Nagarajan is_basic = !!(rate & 0x80); 12819ebb61a2SAshok Nagarajan 12829ebb61a2SAshok Nagarajan if (is_basic && (rate & 0x7f) == BSS_MEMBERSHIP_SELECTOR_HT_PHY) 12839ebb61a2SAshok Nagarajan continue; 12849ebb61a2SAshok Nagarajan 12859ebb61a2SAshok Nagarajan for (j = 0; j < num_rates; j++) { 12869ebb61a2SAshok Nagarajan if (bitrates[j].bitrate == own_rate) { 128746900298SJohannes Berg supp_rates |= BIT(j); 12889ebb61a2SAshok Nagarajan if (basic_rates && is_basic) 12899ebb61a2SAshok Nagarajan *basic_rates |= BIT(j); 12909ebb61a2SAshok Nagarajan } 12919ebb61a2SAshok Nagarajan } 129246900298SJohannes Berg } 129346900298SJohannes Berg return supp_rates; 129446900298SJohannes Berg } 1295f2753ddbSJohannes Berg 129684f6a01cSJohannes Berg void ieee80211_stop_device(struct ieee80211_local *local) 129784f6a01cSJohannes Berg { 129884f6a01cSJohannes Berg ieee80211_led_radio(local, false); 129967408c8cSJohannes Berg ieee80211_mod_tpt_led_trig(local, 0, IEEE80211_TPT_LEDTRIG_FL_RADIO); 130084f6a01cSJohannes Berg 130184f6a01cSJohannes Berg cancel_work_sync(&local->reconfig_filter); 130284f6a01cSJohannes Berg 130384f6a01cSJohannes Berg flush_workqueue(local->workqueue); 1304678f415fSLennert Buytenhek drv_stop(local); 130584f6a01cSJohannes Berg } 130684f6a01cSJohannes Berg 1307f2753ddbSJohannes Berg int ieee80211_reconfig(struct ieee80211_local *local) 1308f2753ddbSJohannes Berg { 1309f2753ddbSJohannes Berg struct ieee80211_hw *hw = &local->hw; 1310f2753ddbSJohannes Berg struct ieee80211_sub_if_data *sdata; 1311f2753ddbSJohannes Berg struct sta_info *sta; 13122683d65bSEliad Peller int res, i; 13135bb644a0SJohannes Berg 1314eecc4800SJohannes Berg #ifdef CONFIG_PM 1315ceb99fe0SJohannes Berg if (local->suspended) 1316ceb99fe0SJohannes Berg local->resuming = true; 1317f2753ddbSJohannes Berg 1318eecc4800SJohannes Berg if (local->wowlan) { 1319eecc4800SJohannes Berg local->wowlan = false; 1320eecc4800SJohannes Berg res = drv_resume(local); 1321eecc4800SJohannes Berg if (res < 0) { 1322eecc4800SJohannes Berg local->resuming = false; 1323eecc4800SJohannes Berg return res; 1324eecc4800SJohannes Berg } 1325eecc4800SJohannes Berg if (res == 0) 1326eecc4800SJohannes Berg goto wake_up; 1327eecc4800SJohannes Berg WARN_ON(res > 1); 1328eecc4800SJohannes Berg /* 1329eecc4800SJohannes Berg * res is 1, which means the driver requested 1330eecc4800SJohannes Berg * to go through a regular reset on wakeup. 1331eecc4800SJohannes Berg */ 1332eecc4800SJohannes Berg } 1333eecc4800SJohannes Berg #endif 133494f9b97bSJohannes Berg /* everything else happens only if HW was up & running */ 133594f9b97bSJohannes Berg if (!local->open_count) 133694f9b97bSJohannes Berg goto wake_up; 133794f9b97bSJohannes Berg 133824feda00SLuis R. Rodriguez /* 133924feda00SLuis R. Rodriguez * Upon resume hardware can sometimes be goofy due to 134024feda00SLuis R. Rodriguez * various platform / driver / bus issues, so restarting 134124feda00SLuis R. Rodriguez * the device may at times not work immediately. Propagate 134224feda00SLuis R. Rodriguez * the error. 134324feda00SLuis R. Rodriguez */ 134424487981SJohannes Berg res = drv_start(local); 134524feda00SLuis R. Rodriguez if (res) { 1346c7a00dc7SJohn W. Linville WARN(local->suspended, "Hardware became unavailable " 1347c7a00dc7SJohn W. Linville "upon resume. This could be a software issue " 1348c7a00dc7SJohn W. Linville "prior to suspend or a hardware issue.\n"); 134924feda00SLuis R. Rodriguez return res; 135024feda00SLuis R. Rodriguez } 1351f2753ddbSJohannes Berg 13527f281975SYogesh Ashok Powar /* setup fragmentation threshold */ 13537f281975SYogesh Ashok Powar drv_set_frag_threshold(local, hw->wiphy->frag_threshold); 13547f281975SYogesh Ashok Powar 13557f281975SYogesh Ashok Powar /* setup RTS threshold */ 13567f281975SYogesh Ashok Powar drv_set_rts_threshold(local, hw->wiphy->rts_threshold); 13577f281975SYogesh Ashok Powar 13587f281975SYogesh Ashok Powar /* reset coverage class */ 13597f281975SYogesh Ashok Powar drv_set_coverage_class(local, hw->wiphy->coverage_class); 13607f281975SYogesh Ashok Powar 13611f87f7d3SJohannes Berg ieee80211_led_radio(local, true); 136267408c8cSJohannes Berg ieee80211_mod_tpt_led_trig(local, 136367408c8cSJohannes Berg IEEE80211_TPT_LEDTRIG_FL_RADIO, 0); 1364f2753ddbSJohannes Berg 1365f2753ddbSJohannes Berg /* add interfaces */ 13664b6f1dd6SJohannes Berg sdata = rtnl_dereference(local->monitor_sdata); 13674b6f1dd6SJohannes Berg if (sdata) { 13684b6f1dd6SJohannes Berg res = drv_add_interface(local, sdata); 13694b6f1dd6SJohannes Berg if (WARN_ON(res)) { 13704b6f1dd6SJohannes Berg rcu_assign_pointer(local->monitor_sdata, NULL); 13714b6f1dd6SJohannes Berg synchronize_net(); 13724b6f1dd6SJohannes Berg kfree(sdata); 13734b6f1dd6SJohannes Berg } 13744b6f1dd6SJohannes Berg } 13754b6f1dd6SJohannes Berg 1376f2753ddbSJohannes Berg list_for_each_entry(sdata, &local->interfaces, list) { 1377f2753ddbSJohannes Berg if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && 1378f2753ddbSJohannes Berg sdata->vif.type != NL80211_IFTYPE_MONITOR && 13791ed32e4fSJohannes Berg ieee80211_sdata_running(sdata)) 13807b7eab6fSJohannes Berg res = drv_add_interface(local, sdata); 1381f2753ddbSJohannes Berg } 1382f2753ddbSJohannes Berg 1383f2753ddbSJohannes Berg /* add STAs back */ 138434e89507SJohannes Berg mutex_lock(&local->sta_mtx); 1385f2753ddbSJohannes Berg list_for_each_entry(sta, &local->sta_list, list) { 1386f09603a2SJohannes Berg enum ieee80211_sta_state state; 1387f09603a2SJohannes Berg 13882e8d397eSArik Nemtsov if (!sta->uploaded) 13892e8d397eSArik Nemtsov continue; 13902e8d397eSArik Nemtsov 13912e8d397eSArik Nemtsov /* AP-mode stations will be added later */ 13922e8d397eSArik Nemtsov if (sta->sdata->vif.type == NL80211_IFTYPE_AP) 13932e8d397eSArik Nemtsov continue; 13942e8d397eSArik Nemtsov 1395f09603a2SJohannes Berg for (state = IEEE80211_STA_NOTEXIST; 1396bd34ab62SMeenakshi Venkataraman state < sta->sta_state; state++) 13972e8d397eSArik Nemtsov WARN_ON(drv_sta_state(local, sta->sdata, sta, state, 13982e8d397eSArik Nemtsov state + 1)); 1399f2753ddbSJohannes Berg } 140034e89507SJohannes Berg mutex_unlock(&local->sta_mtx); 1401f2753ddbSJohannes Berg 14022683d65bSEliad Peller /* reconfigure tx conf */ 140354bcbc69SJohannes Berg if (hw->queues >= IEEE80211_NUM_ACS) { 1404f6f3def3SEliad Peller list_for_each_entry(sdata, &local->interfaces, list) { 1405f6f3def3SEliad Peller if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN || 1406f6f3def3SEliad Peller sdata->vif.type == NL80211_IFTYPE_MONITOR || 1407f6f3def3SEliad Peller !ieee80211_sdata_running(sdata)) 1408f6f3def3SEliad Peller continue; 1409f6f3def3SEliad Peller 141054bcbc69SJohannes Berg for (i = 0; i < IEEE80211_NUM_ACS; i++) 141154bcbc69SJohannes Berg drv_conf_tx(local, sdata, i, 141254bcbc69SJohannes Berg &sdata->tx_conf[i]); 141354bcbc69SJohannes Berg } 1414f6f3def3SEliad Peller } 14152683d65bSEliad Peller 1416f2753ddbSJohannes Berg /* reconfigure hardware */ 1417f2753ddbSJohannes Berg ieee80211_hw_config(local, ~0); 1418f2753ddbSJohannes Berg 1419f2753ddbSJohannes Berg ieee80211_configure_filter(local); 1420f2753ddbSJohannes Berg 1421f2753ddbSJohannes Berg /* Finally also reconfigure all the BSS information */ 1422f2753ddbSJohannes Berg list_for_each_entry(sdata, &local->interfaces, list) { 1423ac8dd506SJohannes Berg u32 changed; 1424ac8dd506SJohannes Berg 14259607e6b6SJohannes Berg if (!ieee80211_sdata_running(sdata)) 1426f2753ddbSJohannes Berg continue; 1427ac8dd506SJohannes Berg 1428ac8dd506SJohannes Berg /* common change flags for all interface types */ 1429ac8dd506SJohannes Berg changed = BSS_CHANGED_ERP_CTS_PROT | 1430ac8dd506SJohannes Berg BSS_CHANGED_ERP_PREAMBLE | 1431ac8dd506SJohannes Berg BSS_CHANGED_ERP_SLOT | 1432ac8dd506SJohannes Berg BSS_CHANGED_HT | 1433ac8dd506SJohannes Berg BSS_CHANGED_BASIC_RATES | 1434ac8dd506SJohannes Berg BSS_CHANGED_BEACON_INT | 1435ac8dd506SJohannes Berg BSS_CHANGED_BSSID | 14364ced3f74SJohannes Berg BSS_CHANGED_CQM | 143755de47f6SEliad Peller BSS_CHANGED_QOS | 143855de47f6SEliad Peller BSS_CHANGED_IDLE; 1439ac8dd506SJohannes Berg 1440f2753ddbSJohannes Berg switch (sdata->vif.type) { 1441f2753ddbSJohannes Berg case NL80211_IFTYPE_STATION: 14420d392e93SEliad Peller changed |= BSS_CHANGED_ASSOC | 1443ab095877SEliad Peller BSS_CHANGED_ARP_FILTER | 1444ab095877SEliad Peller BSS_CHANGED_PS; 1445a7b545f7SEliad Peller mutex_lock(&sdata->u.mgd.mtx); 1446ac8dd506SJohannes Berg ieee80211_bss_info_change_notify(sdata, changed); 1447a7b545f7SEliad Peller mutex_unlock(&sdata->u.mgd.mtx); 1448ac8dd506SJohannes Berg break; 1449f2753ddbSJohannes Berg case NL80211_IFTYPE_ADHOC: 1450ac8dd506SJohannes Berg changed |= BSS_CHANGED_IBSS; 1451ac8dd506SJohannes Berg /* fall through */ 1452f2753ddbSJohannes Berg case NL80211_IFTYPE_AP: 1453e7979ac7SArik Nemtsov changed |= BSS_CHANGED_SSID; 1454e7979ac7SArik Nemtsov 1455e7979ac7SArik Nemtsov if (sdata->vif.type == NL80211_IFTYPE_AP) 1456e7979ac7SArik Nemtsov changed |= BSS_CHANGED_AP_PROBE_RESP; 1457e7979ac7SArik Nemtsov 14587827493bSArik Nemtsov /* fall through */ 1459f2753ddbSJohannes Berg case NL80211_IFTYPE_MESH_POINT: 1460ac8dd506SJohannes Berg changed |= BSS_CHANGED_BEACON | 1461ac8dd506SJohannes Berg BSS_CHANGED_BEACON_ENABLED; 14622d0ddec5SJohannes Berg ieee80211_bss_info_change_notify(sdata, changed); 1463f2753ddbSJohannes Berg break; 1464f2753ddbSJohannes Berg case NL80211_IFTYPE_WDS: 1465f2753ddbSJohannes Berg break; 1466f2753ddbSJohannes Berg case NL80211_IFTYPE_AP_VLAN: 1467f2753ddbSJohannes Berg case NL80211_IFTYPE_MONITOR: 1468f2753ddbSJohannes Berg /* ignore virtual */ 1469f2753ddbSJohannes Berg break; 147098104fdeSJohannes Berg case NL80211_IFTYPE_P2P_DEVICE: 1471f142c6b9SJohannes Berg changed = BSS_CHANGED_IDLE; 1472f142c6b9SJohannes Berg break; 1473f2753ddbSJohannes Berg case NL80211_IFTYPE_UNSPECIFIED: 14742e161f78SJohannes Berg case NUM_NL80211_IFTYPES: 14752ca27bcfSJohannes Berg case NL80211_IFTYPE_P2P_CLIENT: 14762ca27bcfSJohannes Berg case NL80211_IFTYPE_P2P_GO: 1477f2753ddbSJohannes Berg WARN_ON(1); 1478f2753ddbSJohannes Berg break; 1479f2753ddbSJohannes Berg } 1480f2753ddbSJohannes Berg } 1481f2753ddbSJohannes Berg 14828e1b23b9SEyal Shapira ieee80211_recalc_ps(local, -1); 14838e1b23b9SEyal Shapira 14842a419056SJohannes Berg /* 14856e1b1b24SEliad Peller * The sta might be in psm against the ap (e.g. because 14866e1b1b24SEliad Peller * this was the state before a hw restart), so we 14876e1b1b24SEliad Peller * explicitly send a null packet in order to make sure 14886e1b1b24SEliad Peller * it'll sync against the ap (and get out of psm). 14896e1b1b24SEliad Peller */ 14906e1b1b24SEliad Peller if (!(local->hw.conf.flags & IEEE80211_CONF_PS)) { 14916e1b1b24SEliad Peller list_for_each_entry(sdata, &local->interfaces, list) { 14926e1b1b24SEliad Peller if (sdata->vif.type != NL80211_IFTYPE_STATION) 14936e1b1b24SEliad Peller continue; 149420f544eeSJohannes Berg if (!sdata->u.mgd.associated) 149520f544eeSJohannes Berg continue; 14966e1b1b24SEliad Peller 14976e1b1b24SEliad Peller ieee80211_send_nullfunc(local, sdata, 0); 14986e1b1b24SEliad Peller } 14996e1b1b24SEliad Peller } 15006e1b1b24SEliad Peller 15012e8d397eSArik Nemtsov /* APs are now beaconing, add back stations */ 15022e8d397eSArik Nemtsov mutex_lock(&local->sta_mtx); 15032e8d397eSArik Nemtsov list_for_each_entry(sta, &local->sta_list, list) { 15042e8d397eSArik Nemtsov enum ieee80211_sta_state state; 15052e8d397eSArik Nemtsov 15062e8d397eSArik Nemtsov if (!sta->uploaded) 15072e8d397eSArik Nemtsov continue; 15082e8d397eSArik Nemtsov 15092e8d397eSArik Nemtsov if (sta->sdata->vif.type != NL80211_IFTYPE_AP) 15102e8d397eSArik Nemtsov continue; 15112e8d397eSArik Nemtsov 15122e8d397eSArik Nemtsov for (state = IEEE80211_STA_NOTEXIST; 15132e8d397eSArik Nemtsov state < sta->sta_state; state++) 15142e8d397eSArik Nemtsov WARN_ON(drv_sta_state(local, sta->sdata, sta, state, 15152e8d397eSArik Nemtsov state + 1)); 15162e8d397eSArik Nemtsov } 15172e8d397eSArik Nemtsov mutex_unlock(&local->sta_mtx); 15182e8d397eSArik Nemtsov 15197b21aea0SEyal Shapira /* add back keys */ 15207b21aea0SEyal Shapira list_for_each_entry(sdata, &local->interfaces, list) 15217b21aea0SEyal Shapira if (ieee80211_sdata_running(sdata)) 15227b21aea0SEyal Shapira ieee80211_enable_keys(sdata); 15237b21aea0SEyal Shapira 1524c6209488SEliad Peller wake_up: 152504800adaSArik Nemtsov local->in_reconfig = false; 152604800adaSArik Nemtsov barrier(); 152704800adaSArik Nemtsov 15286e1b1b24SEliad Peller /* 15292a419056SJohannes Berg * Clear the WLAN_STA_BLOCK_BA flag so new aggregation 15302a419056SJohannes Berg * sessions can be established after a resume. 15312a419056SJohannes Berg * 15322a419056SJohannes Berg * Also tear down aggregation sessions since reconfiguring 15332a419056SJohannes Berg * them in a hardware restart scenario is not easily done 15342a419056SJohannes Berg * right now, and the hardware will have lost information 15352a419056SJohannes Berg * about the sessions, but we and the AP still think they 15362a419056SJohannes Berg * are active. This is really a workaround though. 15372a419056SJohannes Berg */ 153874e2bd1fSWey-Yi Guy if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { 15392a419056SJohannes Berg mutex_lock(&local->sta_mtx); 15402a419056SJohannes Berg 15412a419056SJohannes Berg list_for_each_entry(sta, &local->sta_list, list) { 154253f73c09SJohannes Berg ieee80211_sta_tear_down_BA_sessions(sta, true); 1543c2c98fdeSJohannes Berg clear_sta_flag(sta, WLAN_STA_BLOCK_BA); 154474e2bd1fSWey-Yi Guy } 15452a419056SJohannes Berg 15462a419056SJohannes Berg mutex_unlock(&local->sta_mtx); 154774e2bd1fSWey-Yi Guy } 154874e2bd1fSWey-Yi Guy 1549f2753ddbSJohannes Berg ieee80211_wake_queues_by_reason(hw, 1550f2753ddbSJohannes Berg IEEE80211_QUEUE_STOP_REASON_SUSPEND); 1551f2753ddbSJohannes Berg 15525bb644a0SJohannes Berg /* 15535bb644a0SJohannes Berg * If this is for hw restart things are still running. 15545bb644a0SJohannes Berg * We may want to change that later, however. 15555bb644a0SJohannes Berg */ 1556ceb99fe0SJohannes Berg if (!local->suspended) 15575bb644a0SJohannes Berg return 0; 15585bb644a0SJohannes Berg 15595bb644a0SJohannes Berg #ifdef CONFIG_PM 1560ceb99fe0SJohannes Berg /* first set suspended false, then resuming */ 15615bb644a0SJohannes Berg local->suspended = false; 1562ceb99fe0SJohannes Berg mb(); 1563ceb99fe0SJohannes Berg local->resuming = false; 15645bb644a0SJohannes Berg 15655bb644a0SJohannes Berg list_for_each_entry(sdata, &local->interfaces, list) { 15665bb644a0SJohannes Berg switch(sdata->vif.type) { 15675bb644a0SJohannes Berg case NL80211_IFTYPE_STATION: 15685bb644a0SJohannes Berg ieee80211_sta_restart(sdata); 15695bb644a0SJohannes Berg break; 15705bb644a0SJohannes Berg case NL80211_IFTYPE_ADHOC: 15715bb644a0SJohannes Berg ieee80211_ibss_restart(sdata); 15725bb644a0SJohannes Berg break; 15735bb644a0SJohannes Berg case NL80211_IFTYPE_MESH_POINT: 15745bb644a0SJohannes Berg ieee80211_mesh_restart(sdata); 15755bb644a0SJohannes Berg break; 15765bb644a0SJohannes Berg default: 15775bb644a0SJohannes Berg break; 15785bb644a0SJohannes Berg } 15795bb644a0SJohannes Berg } 15805bb644a0SJohannes Berg 158126d59535SJohannes Berg mod_timer(&local->sta_cleanup, jiffies + 1); 15825bb644a0SJohannes Berg 158334e89507SJohannes Berg mutex_lock(&local->sta_mtx); 15845bb644a0SJohannes Berg list_for_each_entry(sta, &local->sta_list, list) 15855bb644a0SJohannes Berg mesh_plink_restart(sta); 158634e89507SJohannes Berg mutex_unlock(&local->sta_mtx); 15875bb644a0SJohannes Berg #else 15885bb644a0SJohannes Berg WARN_ON(1); 15895bb644a0SJohannes Berg #endif 1590f2753ddbSJohannes Berg return 0; 1591f2753ddbSJohannes Berg } 159242935ecaSLuis R. Rodriguez 159395acac61SJohannes Berg void ieee80211_resume_disconnect(struct ieee80211_vif *vif) 159495acac61SJohannes Berg { 159595acac61SJohannes Berg struct ieee80211_sub_if_data *sdata; 159695acac61SJohannes Berg struct ieee80211_local *local; 159795acac61SJohannes Berg struct ieee80211_key *key; 159895acac61SJohannes Berg 159995acac61SJohannes Berg if (WARN_ON(!vif)) 160095acac61SJohannes Berg return; 160195acac61SJohannes Berg 160295acac61SJohannes Berg sdata = vif_to_sdata(vif); 160395acac61SJohannes Berg local = sdata->local; 160495acac61SJohannes Berg 160595acac61SJohannes Berg if (WARN_ON(!local->resuming)) 160695acac61SJohannes Berg return; 160795acac61SJohannes Berg 160895acac61SJohannes Berg if (WARN_ON(vif->type != NL80211_IFTYPE_STATION)) 160995acac61SJohannes Berg return; 161095acac61SJohannes Berg 161195acac61SJohannes Berg sdata->flags |= IEEE80211_SDATA_DISCONNECT_RESUME; 161295acac61SJohannes Berg 161395acac61SJohannes Berg mutex_lock(&local->key_mtx); 161495acac61SJohannes Berg list_for_each_entry(key, &sdata->key_list, list) 161595acac61SJohannes Berg key->flags |= KEY_FLAG_TAINTED; 161695acac61SJohannes Berg mutex_unlock(&local->key_mtx); 161795acac61SJohannes Berg } 161895acac61SJohannes Berg EXPORT_SYMBOL_GPL(ieee80211_resume_disconnect); 161995acac61SJohannes Berg 16200f78231bSJohannes Berg static int check_mgd_smps(struct ieee80211_if_managed *ifmgd, 16210f78231bSJohannes Berg enum ieee80211_smps_mode *smps_mode) 16220f78231bSJohannes Berg { 16230f78231bSJohannes Berg if (ifmgd->associated) { 16240f78231bSJohannes Berg *smps_mode = ifmgd->ap_smps; 16250f78231bSJohannes Berg 16260f78231bSJohannes Berg if (*smps_mode == IEEE80211_SMPS_AUTOMATIC) { 16270f78231bSJohannes Berg if (ifmgd->powersave) 16280f78231bSJohannes Berg *smps_mode = IEEE80211_SMPS_DYNAMIC; 16290f78231bSJohannes Berg else 16300f78231bSJohannes Berg *smps_mode = IEEE80211_SMPS_OFF; 16310f78231bSJohannes Berg } 16320f78231bSJohannes Berg 16330f78231bSJohannes Berg return 1; 16340f78231bSJohannes Berg } 16350f78231bSJohannes Berg 16360f78231bSJohannes Berg return 0; 16370f78231bSJohannes Berg } 16380f78231bSJohannes Berg 1639025e6be2SJohannes Berg void ieee80211_recalc_smps(struct ieee80211_local *local) 16400f78231bSJohannes Berg { 16410f78231bSJohannes Berg struct ieee80211_sub_if_data *sdata; 16420f78231bSJohannes Berg enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_OFF; 16430f78231bSJohannes Berg int count = 0; 16440f78231bSJohannes Berg 16455d8e4237SJohannes Berg mutex_lock(&local->iflist_mtx); 16460f78231bSJohannes Berg 16470f78231bSJohannes Berg /* 16480f78231bSJohannes Berg * This function could be improved to handle multiple 16490f78231bSJohannes Berg * interfaces better, but right now it makes any 16500f78231bSJohannes Berg * non-station interfaces force SM PS to be turned 16510f78231bSJohannes Berg * off. If there are multiple station interfaces it 16520f78231bSJohannes Berg * could also use the best possible mode, e.g. if 16530f78231bSJohannes Berg * one is in static and the other in dynamic then 16540f78231bSJohannes Berg * dynamic is ok. 16550f78231bSJohannes Berg */ 16560f78231bSJohannes Berg 16570f78231bSJohannes Berg list_for_each_entry(sdata, &local->interfaces, list) { 165826a58456SJohannes Berg if (!ieee80211_sdata_running(sdata)) 16590f78231bSJohannes Berg continue; 1660f142c6b9SJohannes Berg if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) 1661f142c6b9SJohannes Berg continue; 16620f78231bSJohannes Berg if (sdata->vif.type != NL80211_IFTYPE_STATION) 16630f78231bSJohannes Berg goto set; 1664025e6be2SJohannes Berg 16650f78231bSJohannes Berg count += check_mgd_smps(&sdata->u.mgd, &smps_mode); 16660f78231bSJohannes Berg 16670f78231bSJohannes Berg if (count > 1) { 16680f78231bSJohannes Berg smps_mode = IEEE80211_SMPS_OFF; 16690f78231bSJohannes Berg break; 16700f78231bSJohannes Berg } 16710f78231bSJohannes Berg } 16720f78231bSJohannes Berg 16730f78231bSJohannes Berg if (smps_mode == local->smps_mode) 16745d8e4237SJohannes Berg goto unlock; 16750f78231bSJohannes Berg 16760f78231bSJohannes Berg set: 16770f78231bSJohannes Berg local->smps_mode = smps_mode; 16780f78231bSJohannes Berg /* changed flag is auto-detected for this */ 16790f78231bSJohannes Berg ieee80211_hw_config(local, 0); 16805d8e4237SJohannes Berg unlock: 16815d8e4237SJohannes Berg mutex_unlock(&local->iflist_mtx); 16820f78231bSJohannes Berg } 16838e664fb3SJohannes Berg 16848e664fb3SJohannes Berg static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id) 16858e664fb3SJohannes Berg { 16868e664fb3SJohannes Berg int i; 16878e664fb3SJohannes Berg 16888e664fb3SJohannes Berg for (i = 0; i < n_ids; i++) 16898e664fb3SJohannes Berg if (ids[i] == id) 16908e664fb3SJohannes Berg return true; 16918e664fb3SJohannes Berg return false; 16928e664fb3SJohannes Berg } 16938e664fb3SJohannes Berg 16948e664fb3SJohannes Berg /** 16958e664fb3SJohannes Berg * ieee80211_ie_split - split an IE buffer according to ordering 16968e664fb3SJohannes Berg * 16978e664fb3SJohannes Berg * @ies: the IE buffer 16988e664fb3SJohannes Berg * @ielen: the length of the IE buffer 16998e664fb3SJohannes Berg * @ids: an array with element IDs that are allowed before 17008e664fb3SJohannes Berg * the split 17018e664fb3SJohannes Berg * @n_ids: the size of the element ID array 17028e664fb3SJohannes Berg * @offset: offset where to start splitting in the buffer 17038e664fb3SJohannes Berg * 17048e664fb3SJohannes Berg * This function splits an IE buffer by updating the @offset 17058e664fb3SJohannes Berg * variable to point to the location where the buffer should be 17068e664fb3SJohannes Berg * split. 17078e664fb3SJohannes Berg * 17088e664fb3SJohannes Berg * It assumes that the given IE buffer is well-formed, this 17098e664fb3SJohannes Berg * has to be guaranteed by the caller! 17108e664fb3SJohannes Berg * 17118e664fb3SJohannes Berg * It also assumes that the IEs in the buffer are ordered 17128e664fb3SJohannes Berg * correctly, if not the result of using this function will not 17138e664fb3SJohannes Berg * be ordered correctly either, i.e. it does no reordering. 17148e664fb3SJohannes Berg * 17158e664fb3SJohannes Berg * The function returns the offset where the next part of the 17168e664fb3SJohannes Berg * buffer starts, which may be @ielen if the entire (remainder) 17178e664fb3SJohannes Berg * of the buffer should be used. 17188e664fb3SJohannes Berg */ 17198e664fb3SJohannes Berg size_t ieee80211_ie_split(const u8 *ies, size_t ielen, 17208e664fb3SJohannes Berg const u8 *ids, int n_ids, size_t offset) 17218e664fb3SJohannes Berg { 17228e664fb3SJohannes Berg size_t pos = offset; 17238e664fb3SJohannes Berg 17248e664fb3SJohannes Berg while (pos < ielen && ieee80211_id_in_list(ids, n_ids, ies[pos])) 17258e664fb3SJohannes Berg pos += 2 + ies[pos + 1]; 17268e664fb3SJohannes Berg 17278e664fb3SJohannes Berg return pos; 17288e664fb3SJohannes Berg } 17298e664fb3SJohannes Berg 17308e664fb3SJohannes Berg size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset) 17318e664fb3SJohannes Berg { 17328e664fb3SJohannes Berg size_t pos = offset; 17338e664fb3SJohannes Berg 17348e664fb3SJohannes Berg while (pos < ielen && ies[pos] != WLAN_EID_VENDOR_SPECIFIC) 17358e664fb3SJohannes Berg pos += 2 + ies[pos + 1]; 17368e664fb3SJohannes Berg 17378e664fb3SJohannes Berg return pos; 17388e664fb3SJohannes Berg } 1739615f7b9bSMeenakshi Venkataraman 1740615f7b9bSMeenakshi Venkataraman static void _ieee80211_enable_rssi_reports(struct ieee80211_sub_if_data *sdata, 1741615f7b9bSMeenakshi Venkataraman int rssi_min_thold, 1742615f7b9bSMeenakshi Venkataraman int rssi_max_thold) 1743615f7b9bSMeenakshi Venkataraman { 1744615f7b9bSMeenakshi Venkataraman trace_api_enable_rssi_reports(sdata, rssi_min_thold, rssi_max_thold); 1745615f7b9bSMeenakshi Venkataraman 1746615f7b9bSMeenakshi Venkataraman if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) 1747615f7b9bSMeenakshi Venkataraman return; 1748615f7b9bSMeenakshi Venkataraman 1749615f7b9bSMeenakshi Venkataraman /* 1750615f7b9bSMeenakshi Venkataraman * Scale up threshold values before storing it, as the RSSI averaging 1751615f7b9bSMeenakshi Venkataraman * algorithm uses a scaled up value as well. Change this scaling 1752615f7b9bSMeenakshi Venkataraman * factor if the RSSI averaging algorithm changes. 1753615f7b9bSMeenakshi Venkataraman */ 1754615f7b9bSMeenakshi Venkataraman sdata->u.mgd.rssi_min_thold = rssi_min_thold*16; 1755615f7b9bSMeenakshi Venkataraman sdata->u.mgd.rssi_max_thold = rssi_max_thold*16; 1756615f7b9bSMeenakshi Venkataraman } 1757615f7b9bSMeenakshi Venkataraman 1758615f7b9bSMeenakshi Venkataraman void ieee80211_enable_rssi_reports(struct ieee80211_vif *vif, 1759615f7b9bSMeenakshi Venkataraman int rssi_min_thold, 1760615f7b9bSMeenakshi Venkataraman int rssi_max_thold) 1761615f7b9bSMeenakshi Venkataraman { 1762615f7b9bSMeenakshi Venkataraman struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); 1763615f7b9bSMeenakshi Venkataraman 1764615f7b9bSMeenakshi Venkataraman WARN_ON(rssi_min_thold == rssi_max_thold || 1765615f7b9bSMeenakshi Venkataraman rssi_min_thold > rssi_max_thold); 1766615f7b9bSMeenakshi Venkataraman 1767615f7b9bSMeenakshi Venkataraman _ieee80211_enable_rssi_reports(sdata, rssi_min_thold, 1768615f7b9bSMeenakshi Venkataraman rssi_max_thold); 1769615f7b9bSMeenakshi Venkataraman } 1770615f7b9bSMeenakshi Venkataraman EXPORT_SYMBOL(ieee80211_enable_rssi_reports); 1771615f7b9bSMeenakshi Venkataraman 1772615f7b9bSMeenakshi Venkataraman void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif) 1773615f7b9bSMeenakshi Venkataraman { 1774615f7b9bSMeenakshi Venkataraman struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); 1775615f7b9bSMeenakshi Venkataraman 1776615f7b9bSMeenakshi Venkataraman _ieee80211_enable_rssi_reports(sdata, 0, 0); 1777615f7b9bSMeenakshi Venkataraman } 1778615f7b9bSMeenakshi Venkataraman EXPORT_SYMBOL(ieee80211_disable_rssi_reports); 1779768db343SArik Nemtsov 1780ef96a842SBen Greear u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, 178142e7aa77SAlexander Simon u16 cap) 178242e7aa77SAlexander Simon { 178342e7aa77SAlexander Simon __le16 tmp; 178442e7aa77SAlexander Simon 178542e7aa77SAlexander Simon *pos++ = WLAN_EID_HT_CAPABILITY; 178642e7aa77SAlexander Simon *pos++ = sizeof(struct ieee80211_ht_cap); 178742e7aa77SAlexander Simon memset(pos, 0, sizeof(struct ieee80211_ht_cap)); 178842e7aa77SAlexander Simon 178942e7aa77SAlexander Simon /* capability flags */ 179042e7aa77SAlexander Simon tmp = cpu_to_le16(cap); 179142e7aa77SAlexander Simon memcpy(pos, &tmp, sizeof(u16)); 179242e7aa77SAlexander Simon pos += sizeof(u16); 179342e7aa77SAlexander Simon 179442e7aa77SAlexander Simon /* AMPDU parameters */ 1795ef96a842SBen Greear *pos++ = ht_cap->ampdu_factor | 1796ef96a842SBen Greear (ht_cap->ampdu_density << 179742e7aa77SAlexander Simon IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT); 179842e7aa77SAlexander Simon 179942e7aa77SAlexander Simon /* MCS set */ 1800ef96a842SBen Greear memcpy(pos, &ht_cap->mcs, sizeof(ht_cap->mcs)); 1801ef96a842SBen Greear pos += sizeof(ht_cap->mcs); 180242e7aa77SAlexander Simon 180342e7aa77SAlexander Simon /* extended capabilities */ 180442e7aa77SAlexander Simon pos += sizeof(__le16); 180542e7aa77SAlexander Simon 180642e7aa77SAlexander Simon /* BF capabilities */ 180742e7aa77SAlexander Simon pos += sizeof(__le32); 180842e7aa77SAlexander Simon 180942e7aa77SAlexander Simon /* antenna selection */ 181042e7aa77SAlexander Simon pos += sizeof(u8); 181142e7aa77SAlexander Simon 181242e7aa77SAlexander Simon return pos; 181342e7aa77SAlexander Simon } 181442e7aa77SAlexander Simon 1815ba0afa2fSMahesh Palivela u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, 1816ba0afa2fSMahesh Palivela u32 cap) 1817ba0afa2fSMahesh Palivela { 1818ba0afa2fSMahesh Palivela __le32 tmp; 1819ba0afa2fSMahesh Palivela 1820ba0afa2fSMahesh Palivela *pos++ = WLAN_EID_VHT_CAPABILITY; 1821ba0afa2fSMahesh Palivela *pos++ = sizeof(struct ieee80211_vht_capabilities); 1822ba0afa2fSMahesh Palivela memset(pos, 0, sizeof(struct ieee80211_vht_capabilities)); 1823ba0afa2fSMahesh Palivela 1824ba0afa2fSMahesh Palivela /* capability flags */ 1825ba0afa2fSMahesh Palivela tmp = cpu_to_le32(cap); 1826ba0afa2fSMahesh Palivela memcpy(pos, &tmp, sizeof(u32)); 1827ba0afa2fSMahesh Palivela pos += sizeof(u32); 1828ba0afa2fSMahesh Palivela 1829ba0afa2fSMahesh Palivela /* VHT MCS set */ 1830ba0afa2fSMahesh Palivela memcpy(pos, &vht_cap->vht_mcs, sizeof(vht_cap->vht_mcs)); 1831ba0afa2fSMahesh Palivela pos += sizeof(vht_cap->vht_mcs); 1832ba0afa2fSMahesh Palivela 1833ba0afa2fSMahesh Palivela return pos; 1834ba0afa2fSMahesh Palivela } 1835ba0afa2fSMahesh Palivela 1836074d46d1SJohannes Berg u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, 183742e7aa77SAlexander Simon struct ieee80211_channel *channel, 1838431e3154SAshok Nagarajan enum nl80211_channel_type channel_type, 1839431e3154SAshok Nagarajan u16 prot_mode) 184042e7aa77SAlexander Simon { 1841074d46d1SJohannes Berg struct ieee80211_ht_operation *ht_oper; 184242e7aa77SAlexander Simon /* Build HT Information */ 1843074d46d1SJohannes Berg *pos++ = WLAN_EID_HT_OPERATION; 1844074d46d1SJohannes Berg *pos++ = sizeof(struct ieee80211_ht_operation); 1845074d46d1SJohannes Berg ht_oper = (struct ieee80211_ht_operation *)pos; 1846074d46d1SJohannes Berg ht_oper->primary_chan = 184742e7aa77SAlexander Simon ieee80211_frequency_to_channel(channel->center_freq); 184842e7aa77SAlexander Simon switch (channel_type) { 184942e7aa77SAlexander Simon case NL80211_CHAN_HT40MINUS: 1850074d46d1SJohannes Berg ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_BELOW; 185142e7aa77SAlexander Simon break; 185242e7aa77SAlexander Simon case NL80211_CHAN_HT40PLUS: 1853074d46d1SJohannes Berg ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; 185442e7aa77SAlexander Simon break; 185542e7aa77SAlexander Simon case NL80211_CHAN_HT20: 185642e7aa77SAlexander Simon default: 1857074d46d1SJohannes Berg ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_NONE; 185842e7aa77SAlexander Simon break; 185942e7aa77SAlexander Simon } 1860aee286c2SThomas Pedersen if (ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 && 1861aee286c2SThomas Pedersen channel_type != NL80211_CHAN_NO_HT && 1862aee286c2SThomas Pedersen channel_type != NL80211_CHAN_HT20) 1863074d46d1SJohannes Berg ht_oper->ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY; 1864ff3cc5f4SSimon Wunderlich 1865431e3154SAshok Nagarajan ht_oper->operation_mode = cpu_to_le16(prot_mode); 1866074d46d1SJohannes Berg ht_oper->stbc_param = 0x0000; 186742e7aa77SAlexander Simon 186842e7aa77SAlexander Simon /* It seems that Basic MCS set and Supported MCS set 186942e7aa77SAlexander Simon are identical for the first 10 bytes */ 1870074d46d1SJohannes Berg memset(&ht_oper->basic_set, 0, 16); 1871074d46d1SJohannes Berg memcpy(&ht_oper->basic_set, &ht_cap->mcs, 10); 187242e7aa77SAlexander Simon 1873074d46d1SJohannes Berg return pos + sizeof(struct ieee80211_ht_operation); 187442e7aa77SAlexander Simon } 187542e7aa77SAlexander Simon 187642e7aa77SAlexander Simon enum nl80211_channel_type 1877074d46d1SJohannes Berg ieee80211_ht_oper_to_channel_type(struct ieee80211_ht_operation *ht_oper) 187842e7aa77SAlexander Simon { 187942e7aa77SAlexander Simon enum nl80211_channel_type channel_type; 188042e7aa77SAlexander Simon 1881074d46d1SJohannes Berg if (!ht_oper) 188242e7aa77SAlexander Simon return NL80211_CHAN_NO_HT; 188342e7aa77SAlexander Simon 1884074d46d1SJohannes Berg switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { 188542e7aa77SAlexander Simon case IEEE80211_HT_PARAM_CHA_SEC_NONE: 188642e7aa77SAlexander Simon channel_type = NL80211_CHAN_HT20; 188742e7aa77SAlexander Simon break; 188842e7aa77SAlexander Simon case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: 188942e7aa77SAlexander Simon channel_type = NL80211_CHAN_HT40PLUS; 189042e7aa77SAlexander Simon break; 189142e7aa77SAlexander Simon case IEEE80211_HT_PARAM_CHA_SEC_BELOW: 189242e7aa77SAlexander Simon channel_type = NL80211_CHAN_HT40MINUS; 189342e7aa77SAlexander Simon break; 189442e7aa77SAlexander Simon default: 189542e7aa77SAlexander Simon channel_type = NL80211_CHAN_NO_HT; 189642e7aa77SAlexander Simon } 189742e7aa77SAlexander Simon 189842e7aa77SAlexander Simon return channel_type; 189942e7aa77SAlexander Simon } 190042e7aa77SAlexander Simon 1901fc8a7321SJohannes Berg int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata, 19026b77863bSJohannes Berg struct sk_buff *skb, bool need_basic, 19036b77863bSJohannes Berg enum ieee80211_band band) 1904768db343SArik Nemtsov { 1905768db343SArik Nemtsov struct ieee80211_local *local = sdata->local; 1906768db343SArik Nemtsov struct ieee80211_supported_band *sband; 1907768db343SArik Nemtsov int rate; 1908768db343SArik Nemtsov u8 i, rates, *pos; 1909fc8a7321SJohannes Berg u32 basic_rates = sdata->vif.bss_conf.basic_rates; 1910768db343SArik Nemtsov 19116b77863bSJohannes Berg sband = local->hw.wiphy->bands[band]; 1912768db343SArik Nemtsov rates = sband->n_bitrates; 1913768db343SArik Nemtsov if (rates > 8) 1914768db343SArik Nemtsov rates = 8; 1915768db343SArik Nemtsov 1916768db343SArik Nemtsov if (skb_tailroom(skb) < rates + 2) 1917768db343SArik Nemtsov return -ENOMEM; 1918768db343SArik Nemtsov 1919768db343SArik Nemtsov pos = skb_put(skb, rates + 2); 1920768db343SArik Nemtsov *pos++ = WLAN_EID_SUPP_RATES; 1921768db343SArik Nemtsov *pos++ = rates; 1922768db343SArik Nemtsov for (i = 0; i < rates; i++) { 1923657c3e0cSAshok Nagarajan u8 basic = 0; 1924657c3e0cSAshok Nagarajan if (need_basic && basic_rates & BIT(i)) 1925657c3e0cSAshok Nagarajan basic = 0x80; 1926768db343SArik Nemtsov rate = sband->bitrates[i].bitrate; 1927657c3e0cSAshok Nagarajan *pos++ = basic | (u8) (rate / 5); 1928768db343SArik Nemtsov } 1929768db343SArik Nemtsov 1930768db343SArik Nemtsov return 0; 1931768db343SArik Nemtsov } 1932768db343SArik Nemtsov 1933fc8a7321SJohannes Berg int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata, 19346b77863bSJohannes Berg struct sk_buff *skb, bool need_basic, 19356b77863bSJohannes Berg enum ieee80211_band band) 1936768db343SArik Nemtsov { 1937768db343SArik Nemtsov struct ieee80211_local *local = sdata->local; 1938768db343SArik Nemtsov struct ieee80211_supported_band *sband; 1939768db343SArik Nemtsov int rate; 1940768db343SArik Nemtsov u8 i, exrates, *pos; 1941fc8a7321SJohannes Berg u32 basic_rates = sdata->vif.bss_conf.basic_rates; 1942768db343SArik Nemtsov 19436b77863bSJohannes Berg sband = local->hw.wiphy->bands[band]; 1944768db343SArik Nemtsov exrates = sband->n_bitrates; 1945768db343SArik Nemtsov if (exrates > 8) 1946768db343SArik Nemtsov exrates -= 8; 1947768db343SArik Nemtsov else 1948768db343SArik Nemtsov exrates = 0; 1949768db343SArik Nemtsov 1950768db343SArik Nemtsov if (skb_tailroom(skb) < exrates + 2) 1951768db343SArik Nemtsov return -ENOMEM; 1952768db343SArik Nemtsov 1953768db343SArik Nemtsov if (exrates) { 1954768db343SArik Nemtsov pos = skb_put(skb, exrates + 2); 1955768db343SArik Nemtsov *pos++ = WLAN_EID_EXT_SUPP_RATES; 1956768db343SArik Nemtsov *pos++ = exrates; 1957768db343SArik Nemtsov for (i = 8; i < sband->n_bitrates; i++) { 1958657c3e0cSAshok Nagarajan u8 basic = 0; 1959657c3e0cSAshok Nagarajan if (need_basic && basic_rates & BIT(i)) 1960657c3e0cSAshok Nagarajan basic = 0x80; 1961768db343SArik Nemtsov rate = sband->bitrates[i].bitrate; 1962657c3e0cSAshok Nagarajan *pos++ = basic | (u8) (rate / 5); 1963768db343SArik Nemtsov } 1964768db343SArik Nemtsov } 1965768db343SArik Nemtsov return 0; 1966768db343SArik Nemtsov } 19671dae27f8SWey-Yi Guy 19681dae27f8SWey-Yi Guy int ieee80211_ave_rssi(struct ieee80211_vif *vif) 19691dae27f8SWey-Yi Guy { 19701dae27f8SWey-Yi Guy struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); 19711dae27f8SWey-Yi Guy struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 19721dae27f8SWey-Yi Guy 1973be6bcabcSWey-Yi Guy if (WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_STATION)) { 1974be6bcabcSWey-Yi Guy /* non-managed type inferfaces */ 1975be6bcabcSWey-Yi Guy return 0; 1976be6bcabcSWey-Yi Guy } 19771dae27f8SWey-Yi Guy return ifmgd->ave_beacon_signal; 19781dae27f8SWey-Yi Guy } 19790d8a0a17SWey-Yi Guy EXPORT_SYMBOL_GPL(ieee80211_ave_rssi); 1980