1c2d1560aSJohannes Berg /* 2c2d1560aSJohannes Berg * Copyright 2002-2005, Instant802 Networks, Inc. 3c2d1560aSJohannes Berg * Copyright 2005-2006, Devicescape Software, Inc. 4c2d1560aSJohannes Berg * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> 5c2d1560aSJohannes Berg * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> 6c2d1560aSJohannes Berg * 7c2d1560aSJohannes Berg * This program is free software; you can redistribute it and/or modify 8c2d1560aSJohannes Berg * it under the terms of the GNU General Public License version 2 as 9c2d1560aSJohannes Berg * published by the Free Software Foundation. 10c2d1560aSJohannes Berg * 11c2d1560aSJohannes Berg * utilities for mac80211 12c2d1560aSJohannes Berg */ 13c2d1560aSJohannes Berg 14c2d1560aSJohannes Berg #include <net/mac80211.h> 15c2d1560aSJohannes Berg #include <linux/netdevice.h> 16c2d1560aSJohannes Berg #include <linux/types.h> 17c2d1560aSJohannes Berg #include <linux/slab.h> 18c2d1560aSJohannes Berg #include <linux/skbuff.h> 19c2d1560aSJohannes Berg #include <linux/etherdevice.h> 20c2d1560aSJohannes Berg #include <linux/if_arp.h> 21c2d1560aSJohannes Berg #include <linux/wireless.h> 22c2d1560aSJohannes Berg #include <linux/bitmap.h> 23881d966bSEric W. Biederman #include <net/net_namespace.h> 24c2d1560aSJohannes Berg #include <net/cfg80211.h> 25dabeb344SJohannes Berg #include <net/rtnetlink.h> 26c2d1560aSJohannes Berg 27c2d1560aSJohannes Berg #include "ieee80211_i.h" 282c8dccc7SJohannes Berg #include "rate.h" 29ee385855SLuis Carlos Cobo #include "mesh.h" 30c2d1560aSJohannes Berg #include "wme.h" 31c2d1560aSJohannes Berg 32c2d1560aSJohannes Berg /* privid for wiphys to determine whether they belong to us or not */ 33c2d1560aSJohannes Berg void *mac80211_wiphy_privid = &mac80211_wiphy_privid; 34c2d1560aSJohannes Berg 35c2d1560aSJohannes Berg /* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ 36c2d1560aSJohannes Berg /* Ethernet-II snap header (RFC1042 for most EtherTypes) */ 37c97c23e3SSenthil Balasubramanian const unsigned char rfc1042_header[] __aligned(2) = 38c2d1560aSJohannes Berg { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; 39c2d1560aSJohannes Berg 40c2d1560aSJohannes Berg /* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ 41c97c23e3SSenthil Balasubramanian const unsigned char bridge_tunnel_header[] __aligned(2) = 42c2d1560aSJohannes Berg { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; 43c2d1560aSJohannes Berg 449a95371aSLuis R. Rodriguez struct ieee80211_hw *wiphy_to_ieee80211_hw(struct wiphy *wiphy) 459a95371aSLuis R. Rodriguez { 469a95371aSLuis R. Rodriguez struct ieee80211_local *local; 479a95371aSLuis R. Rodriguez BUG_ON(!wiphy); 489a95371aSLuis R. Rodriguez 499a95371aSLuis R. Rodriguez local = wiphy_priv(wiphy); 509a95371aSLuis R. Rodriguez return &local->hw; 519a95371aSLuis R. Rodriguez } 529a95371aSLuis R. Rodriguez EXPORT_SYMBOL(wiphy_to_ieee80211_hw); 53c2d1560aSJohannes Berg 5471364716SRon Rindjunsky u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, 5505c914feSJohannes Berg enum nl80211_iftype type) 56c2d1560aSJohannes Berg { 57a494bb1cSHarvey Harrison __le16 fc = hdr->frame_control; 58c2d1560aSJohannes Berg 5998f0b0a3SRon Rindjunsky /* drop ACK/CTS frames and incorrect hdr len (ctrl) */ 6098f0b0a3SRon Rindjunsky if (len < 16) 61c2d1560aSJohannes Berg return NULL; 62c2d1560aSJohannes Berg 63a494bb1cSHarvey Harrison if (ieee80211_is_data(fc)) { 6498f0b0a3SRon Rindjunsky if (len < 24) /* drop incorrect hdr len (data) */ 6598f0b0a3SRon Rindjunsky return NULL; 66a494bb1cSHarvey Harrison 67a494bb1cSHarvey Harrison if (ieee80211_has_a4(fc)) 68c2d1560aSJohannes Berg return NULL; 69a494bb1cSHarvey Harrison if (ieee80211_has_tods(fc)) 70a494bb1cSHarvey Harrison return hdr->addr1; 71a494bb1cSHarvey Harrison if (ieee80211_has_fromds(fc)) 72c2d1560aSJohannes Berg return hdr->addr2; 73a494bb1cSHarvey Harrison 74c2d1560aSJohannes Berg return hdr->addr3; 75c2d1560aSJohannes Berg } 76a494bb1cSHarvey Harrison 77a494bb1cSHarvey Harrison if (ieee80211_is_mgmt(fc)) { 7898f0b0a3SRon Rindjunsky if (len < 24) /* drop incorrect hdr len (mgmt) */ 7998f0b0a3SRon Rindjunsky return NULL; 80c2d1560aSJohannes Berg return hdr->addr3; 81a494bb1cSHarvey Harrison } 82a494bb1cSHarvey Harrison 83a494bb1cSHarvey Harrison if (ieee80211_is_ctl(fc)) { 84a494bb1cSHarvey Harrison if(ieee80211_is_pspoll(fc)) 85c2d1560aSJohannes Berg return hdr->addr1; 86a494bb1cSHarvey Harrison 87a494bb1cSHarvey Harrison if (ieee80211_is_back_req(fc)) { 8871364716SRon Rindjunsky switch (type) { 8905c914feSJohannes Berg case NL80211_IFTYPE_STATION: 9071364716SRon Rindjunsky return hdr->addr2; 9105c914feSJohannes Berg case NL80211_IFTYPE_AP: 9205c914feSJohannes Berg case NL80211_IFTYPE_AP_VLAN: 9371364716SRon Rindjunsky return hdr->addr1; 9471364716SRon Rindjunsky default: 95a494bb1cSHarvey Harrison break; /* fall through to the return */ 9671364716SRon Rindjunsky } 9771364716SRon Rindjunsky } 98c2d1560aSJohannes Berg } 99c2d1560aSJohannes Berg 100c2d1560aSJohannes Berg return NULL; 101c2d1560aSJohannes Berg } 102c2d1560aSJohannes Berg 1036693be71SHarvey Harrison unsigned int ieee80211_hdrlen(__le16 fc) 1046693be71SHarvey Harrison { 1056693be71SHarvey Harrison unsigned int hdrlen = 24; 1066693be71SHarvey Harrison 1076693be71SHarvey Harrison if (ieee80211_is_data(fc)) { 1086693be71SHarvey Harrison if (ieee80211_has_a4(fc)) 1096693be71SHarvey Harrison hdrlen = 30; 1106693be71SHarvey Harrison if (ieee80211_is_data_qos(fc)) 1116693be71SHarvey Harrison hdrlen += IEEE80211_QOS_CTL_LEN; 1126693be71SHarvey Harrison goto out; 1136693be71SHarvey Harrison } 1146693be71SHarvey Harrison 1156693be71SHarvey Harrison if (ieee80211_is_ctl(fc)) { 1166693be71SHarvey Harrison /* 1176693be71SHarvey Harrison * ACK and CTS are 10 bytes, all others 16. To see how 1186693be71SHarvey Harrison * to get this condition consider 1196693be71SHarvey Harrison * subtype mask: 0b0000000011110000 (0x00F0) 1206693be71SHarvey Harrison * ACK subtype: 0b0000000011010000 (0x00D0) 1216693be71SHarvey Harrison * CTS subtype: 0b0000000011000000 (0x00C0) 1226693be71SHarvey Harrison * bits that matter: ^^^ (0x00E0) 1236693be71SHarvey Harrison * value of those: 0b0000000011000000 (0x00C0) 1246693be71SHarvey Harrison */ 1256693be71SHarvey Harrison if ((fc & cpu_to_le16(0x00E0)) == cpu_to_le16(0x00C0)) 1266693be71SHarvey Harrison hdrlen = 10; 1276693be71SHarvey Harrison else 1286693be71SHarvey Harrison hdrlen = 16; 1296693be71SHarvey Harrison } 1306693be71SHarvey Harrison out: 1316693be71SHarvey Harrison return hdrlen; 1326693be71SHarvey Harrison } 1336693be71SHarvey Harrison EXPORT_SYMBOL(ieee80211_hdrlen); 1346693be71SHarvey Harrison 135c9c6950cSHarvey Harrison unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb) 136c2d1560aSJohannes Berg { 137c2d1560aSJohannes Berg const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *)skb->data; 138c9c6950cSHarvey Harrison unsigned int hdrlen; 139c2d1560aSJohannes Berg 140c2d1560aSJohannes Berg if (unlikely(skb->len < 10)) 141c2d1560aSJohannes Berg return 0; 142c9c6950cSHarvey Harrison hdrlen = ieee80211_hdrlen(hdr->frame_control); 143c2d1560aSJohannes Berg if (unlikely(hdrlen > skb->len)) 144c2d1560aSJohannes Berg return 0; 145c2d1560aSJohannes Berg return hdrlen; 146c2d1560aSJohannes Berg } 147c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); 148c2d1560aSJohannes Berg 149ee385855SLuis Carlos Cobo int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) 150ee385855SLuis Carlos Cobo { 151ee385855SLuis Carlos Cobo int ae = meshhdr->flags & IEEE80211S_FLAGS_AE; 152ee385855SLuis Carlos Cobo /* 7.1.3.5a.2 */ 153ee385855SLuis Carlos Cobo switch (ae) { 154ee385855SLuis Carlos Cobo case 0: 155ef269254SLuis Carlos Cobo return 6; 156ee385855SLuis Carlos Cobo case 1: 157ef269254SLuis Carlos Cobo return 12; 158ee385855SLuis Carlos Cobo case 2: 159ef269254SLuis Carlos Cobo return 18; 160ee385855SLuis Carlos Cobo case 3: 161ef269254SLuis Carlos Cobo return 24; 162ee385855SLuis Carlos Cobo default: 163ef269254SLuis Carlos Cobo return 6; 164ee385855SLuis Carlos Cobo } 165ee385855SLuis Carlos Cobo } 166ee385855SLuis Carlos Cobo 1675cf121c3SJohannes Berg void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx) 168c2d1560aSJohannes Berg { 169c2d1560aSJohannes Berg struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; 170c2d1560aSJohannes Berg 171c2d1560aSJohannes Berg hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); 1725cf121c3SJohannes Berg if (tx->extra_frag) { 173c2d1560aSJohannes Berg struct ieee80211_hdr *fhdr; 174c2d1560aSJohannes Berg int i; 1755cf121c3SJohannes Berg for (i = 0; i < tx->num_extra_frag; i++) { 176c2d1560aSJohannes Berg fhdr = (struct ieee80211_hdr *) 1775cf121c3SJohannes Berg tx->extra_frag[i]->data; 178c2d1560aSJohannes Berg fhdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); 179c2d1560aSJohannes Berg } 180c2d1560aSJohannes Berg } 181c2d1560aSJohannes Berg } 182c2d1560aSJohannes Berg 183c2d1560aSJohannes Berg int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, 184c2d1560aSJohannes Berg int rate, int erp, int short_preamble) 185c2d1560aSJohannes Berg { 186c2d1560aSJohannes Berg int dur; 187c2d1560aSJohannes Berg 188c2d1560aSJohannes Berg /* calculate duration (in microseconds, rounded up to next higher 189c2d1560aSJohannes Berg * integer if it includes a fractional microsecond) to send frame of 190c2d1560aSJohannes Berg * len bytes (does not include FCS) at the given rate. Duration will 191c2d1560aSJohannes Berg * also include SIFS. 192c2d1560aSJohannes Berg * 193c2d1560aSJohannes Berg * rate is in 100 kbps, so divident is multiplied by 10 in the 194c2d1560aSJohannes Berg * DIV_ROUND_UP() operations. 195c2d1560aSJohannes Berg */ 196c2d1560aSJohannes Berg 1978318d78aSJohannes Berg if (local->hw.conf.channel->band == IEEE80211_BAND_5GHZ || erp) { 198c2d1560aSJohannes Berg /* 199c2d1560aSJohannes Berg * OFDM: 200c2d1560aSJohannes Berg * 201c2d1560aSJohannes Berg * N_DBPS = DATARATE x 4 202c2d1560aSJohannes Berg * N_SYM = Ceiling((16+8xLENGTH+6) / N_DBPS) 203c2d1560aSJohannes Berg * (16 = SIGNAL time, 6 = tail bits) 204c2d1560aSJohannes Berg * TXTIME = T_PREAMBLE + T_SIGNAL + T_SYM x N_SYM + Signal Ext 205c2d1560aSJohannes Berg * 206c2d1560aSJohannes Berg * T_SYM = 4 usec 207c2d1560aSJohannes Berg * 802.11a - 17.5.2: aSIFSTime = 16 usec 208c2d1560aSJohannes Berg * 802.11g - 19.8.4: aSIFSTime = 10 usec + 209c2d1560aSJohannes Berg * signal ext = 6 usec 210c2d1560aSJohannes Berg */ 211c2d1560aSJohannes Berg dur = 16; /* SIFS + signal ext */ 212c2d1560aSJohannes Berg dur += 16; /* 17.3.2.3: T_PREAMBLE = 16 usec */ 213c2d1560aSJohannes Berg dur += 4; /* 17.3.2.3: T_SIGNAL = 4 usec */ 214c2d1560aSJohannes Berg dur += 4 * DIV_ROUND_UP((16 + 8 * (len + 4) + 6) * 10, 215c2d1560aSJohannes Berg 4 * rate); /* T_SYM x N_SYM */ 216c2d1560aSJohannes Berg } else { 217c2d1560aSJohannes Berg /* 218c2d1560aSJohannes Berg * 802.11b or 802.11g with 802.11b compatibility: 219c2d1560aSJohannes Berg * 18.3.4: TXTIME = PreambleLength + PLCPHeaderTime + 220c2d1560aSJohannes Berg * Ceiling(((LENGTH+PBCC)x8)/DATARATE). PBCC=0. 221c2d1560aSJohannes Berg * 222c2d1560aSJohannes Berg * 802.11 (DS): 15.3.3, 802.11b: 18.3.4 223c2d1560aSJohannes Berg * aSIFSTime = 10 usec 224c2d1560aSJohannes Berg * aPreambleLength = 144 usec or 72 usec with short preamble 225c2d1560aSJohannes Berg * aPLCPHeaderLength = 48 usec or 24 usec with short preamble 226c2d1560aSJohannes Berg */ 227c2d1560aSJohannes Berg dur = 10; /* aSIFSTime = 10 usec */ 228c2d1560aSJohannes Berg dur += short_preamble ? (72 + 24) : (144 + 48); 229c2d1560aSJohannes Berg 230c2d1560aSJohannes Berg dur += DIV_ROUND_UP(8 * (len + 4) * 10, rate); 231c2d1560aSJohannes Berg } 232c2d1560aSJohannes Berg 233c2d1560aSJohannes Berg return dur; 234c2d1560aSJohannes Berg } 235c2d1560aSJohannes Berg 236c2d1560aSJohannes Berg /* Exported duration function for driver use */ 23732bfd35dSJohannes Berg __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, 23832bfd35dSJohannes Berg struct ieee80211_vif *vif, 2398318d78aSJohannes Berg size_t frame_len, 2408318d78aSJohannes Berg struct ieee80211_rate *rate) 241c2d1560aSJohannes Berg { 242c2d1560aSJohannes Berg struct ieee80211_local *local = hw_to_local(hw); 24325d834e1SJohannes Berg struct ieee80211_sub_if_data *sdata; 244c2d1560aSJohannes Berg u16 dur; 245c2d1560aSJohannes Berg int erp; 24625d834e1SJohannes Berg bool short_preamble = false; 247c2d1560aSJohannes Berg 2488318d78aSJohannes Berg erp = 0; 24925d834e1SJohannes Berg if (vif) { 25025d834e1SJohannes Berg sdata = vif_to_sdata(vif); 251bda3933aSJohannes Berg short_preamble = sdata->vif.bss_conf.use_short_preamble; 2528318d78aSJohannes Berg if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) 2538318d78aSJohannes Berg erp = rate->flags & IEEE80211_RATE_ERP_G; 25425d834e1SJohannes Berg } 2558318d78aSJohannes Berg 2568318d78aSJohannes Berg dur = ieee80211_frame_duration(local, frame_len, rate->bitrate, erp, 25725d834e1SJohannes Berg short_preamble); 258c2d1560aSJohannes Berg 259c2d1560aSJohannes Berg return cpu_to_le16(dur); 260c2d1560aSJohannes Berg } 261c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_generic_frame_duration); 262c2d1560aSJohannes Berg 26332bfd35dSJohannes Berg __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, 26432bfd35dSJohannes Berg struct ieee80211_vif *vif, size_t frame_len, 265e039fa4aSJohannes Berg const struct ieee80211_tx_info *frame_txctl) 266c2d1560aSJohannes Berg { 267c2d1560aSJohannes Berg struct ieee80211_local *local = hw_to_local(hw); 268c2d1560aSJohannes Berg struct ieee80211_rate *rate; 26925d834e1SJohannes Berg struct ieee80211_sub_if_data *sdata; 270471b3efdSJohannes Berg bool short_preamble; 271c2d1560aSJohannes Berg int erp; 272c2d1560aSJohannes Berg u16 dur; 2732e92e6f2SJohannes Berg struct ieee80211_supported_band *sband; 2742e92e6f2SJohannes Berg 2752e92e6f2SJohannes Berg sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; 276c2d1560aSJohannes Berg 27725d834e1SJohannes Berg short_preamble = false; 2787e9ed188SDaniel Drake 279e039fa4aSJohannes Berg rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx]; 2808318d78aSJohannes Berg 2818318d78aSJohannes Berg erp = 0; 28225d834e1SJohannes Berg if (vif) { 28325d834e1SJohannes Berg sdata = vif_to_sdata(vif); 284bda3933aSJohannes Berg short_preamble = sdata->vif.bss_conf.use_short_preamble; 2858318d78aSJohannes Berg if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) 2868318d78aSJohannes Berg erp = rate->flags & IEEE80211_RATE_ERP_G; 28725d834e1SJohannes Berg } 288c2d1560aSJohannes Berg 289c2d1560aSJohannes Berg /* CTS duration */ 2908318d78aSJohannes Berg dur = ieee80211_frame_duration(local, 10, rate->bitrate, 291c2d1560aSJohannes Berg erp, short_preamble); 292c2d1560aSJohannes Berg /* Data frame duration */ 2938318d78aSJohannes Berg dur += ieee80211_frame_duration(local, frame_len, rate->bitrate, 294c2d1560aSJohannes Berg erp, short_preamble); 295c2d1560aSJohannes Berg /* ACK duration */ 2968318d78aSJohannes Berg dur += ieee80211_frame_duration(local, 10, rate->bitrate, 297c2d1560aSJohannes Berg erp, short_preamble); 298c2d1560aSJohannes Berg 299c2d1560aSJohannes Berg return cpu_to_le16(dur); 300c2d1560aSJohannes Berg } 301c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_rts_duration); 302c2d1560aSJohannes Berg 30332bfd35dSJohannes Berg __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, 30432bfd35dSJohannes Berg struct ieee80211_vif *vif, 305c2d1560aSJohannes Berg size_t frame_len, 306e039fa4aSJohannes Berg const struct ieee80211_tx_info *frame_txctl) 307c2d1560aSJohannes Berg { 308c2d1560aSJohannes Berg struct ieee80211_local *local = hw_to_local(hw); 309c2d1560aSJohannes Berg struct ieee80211_rate *rate; 31025d834e1SJohannes Berg struct ieee80211_sub_if_data *sdata; 311471b3efdSJohannes Berg bool short_preamble; 312c2d1560aSJohannes Berg int erp; 313c2d1560aSJohannes Berg u16 dur; 3142e92e6f2SJohannes Berg struct ieee80211_supported_band *sband; 3152e92e6f2SJohannes Berg 3162e92e6f2SJohannes Berg sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; 317c2d1560aSJohannes Berg 31825d834e1SJohannes Berg short_preamble = false; 3197e9ed188SDaniel Drake 320e039fa4aSJohannes Berg rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx]; 3218318d78aSJohannes Berg erp = 0; 32225d834e1SJohannes Berg if (vif) { 32325d834e1SJohannes Berg sdata = vif_to_sdata(vif); 324bda3933aSJohannes Berg short_preamble = sdata->vif.bss_conf.use_short_preamble; 3258318d78aSJohannes Berg if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) 3268318d78aSJohannes Berg erp = rate->flags & IEEE80211_RATE_ERP_G; 32725d834e1SJohannes Berg } 328c2d1560aSJohannes Berg 329c2d1560aSJohannes Berg /* Data frame duration */ 3308318d78aSJohannes Berg dur = ieee80211_frame_duration(local, frame_len, rate->bitrate, 331c2d1560aSJohannes Berg erp, short_preamble); 332e039fa4aSJohannes Berg if (!(frame_txctl->flags & IEEE80211_TX_CTL_NO_ACK)) { 333c2d1560aSJohannes Berg /* ACK duration */ 3348318d78aSJohannes Berg dur += ieee80211_frame_duration(local, 10, rate->bitrate, 335c2d1560aSJohannes Berg erp, short_preamble); 336c2d1560aSJohannes Berg } 337c2d1560aSJohannes Berg 338c2d1560aSJohannes Berg return cpu_to_le16(dur); 339c2d1560aSJohannes Berg } 340c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_ctstoself_duration); 341c2d1560aSJohannes Berg 342ce7c9111SKalle Valo static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, 343ce7c9111SKalle Valo enum queue_stop_reason reason) 344c2d1560aSJohannes Berg { 345c2d1560aSJohannes Berg struct ieee80211_local *local = hw_to_local(hw); 346c2d1560aSJohannes Berg 34796f5e66eSJohannes Berg if (queue >= hw->queues) { 34896f5e66eSJohannes Berg if (local->ampdu_ac_queue[queue - hw->queues] < 0) 34996f5e66eSJohannes Berg return; 35096f5e66eSJohannes Berg 35196f5e66eSJohannes Berg /* 35296f5e66eSJohannes Berg * for virtual aggregation queues, we need to refcount the 35396f5e66eSJohannes Berg * internal mac80211 disable (multiple times!), keep track of 35496f5e66eSJohannes Berg * driver disable _and_ make sure the regular queue is 35596f5e66eSJohannes Berg * actually enabled. 35696f5e66eSJohannes Berg */ 35796f5e66eSJohannes Berg if (reason == IEEE80211_QUEUE_STOP_REASON_AGGREGATION) 35896f5e66eSJohannes Berg local->amdpu_ac_stop_refcnt[queue - hw->queues]--; 35996f5e66eSJohannes Berg else 36096f5e66eSJohannes Berg __clear_bit(reason, &local->queue_stop_reasons[queue]); 36196f5e66eSJohannes Berg 36296f5e66eSJohannes Berg if (local->queue_stop_reasons[queue] || 36396f5e66eSJohannes Berg local->amdpu_ac_stop_refcnt[queue - hw->queues]) 36496f5e66eSJohannes Berg return; 36596f5e66eSJohannes Berg 36696f5e66eSJohannes Berg /* now go on to treat the corresponding regular queue */ 36796f5e66eSJohannes Berg queue = local->ampdu_ac_queue[queue - hw->queues]; 36896f5e66eSJohannes Berg reason = IEEE80211_QUEUE_STOP_REASON_AGGREGATION; 36996f5e66eSJohannes Berg } 37096f5e66eSJohannes Berg 371ce7c9111SKalle Valo __clear_bit(reason, &local->queue_stop_reasons[queue]); 372ce7c9111SKalle Valo 373ce7c9111SKalle Valo if (local->queue_stop_reasons[queue] != 0) 374ce7c9111SKalle Valo /* someone still has this queue stopped */ 375ce7c9111SKalle Valo return; 376ce7c9111SKalle Valo 377e2530083SJohannes Berg if (test_bit(queue, local->queues_pending)) { 378f8e79dddSTomas Winkler set_bit(queue, local->queues_pending_run); 379c2d1560aSJohannes Berg tasklet_schedule(&local->tx_pending_tasklet); 380e2530083SJohannes Berg } else { 381e2530083SJohannes Berg netif_wake_subqueue(local->mdev, queue); 382c2d1560aSJohannes Berg } 383c2d1560aSJohannes Berg } 384ce7c9111SKalle Valo 38596f5e66eSJohannes Berg void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, 386ce7c9111SKalle Valo enum queue_stop_reason reason) 387ce7c9111SKalle Valo { 388ce7c9111SKalle Valo struct ieee80211_local *local = hw_to_local(hw); 389ce7c9111SKalle Valo unsigned long flags; 390ce7c9111SKalle Valo 391ce7c9111SKalle Valo spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 392ce7c9111SKalle Valo __ieee80211_wake_queue(hw, queue, reason); 393ce7c9111SKalle Valo spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 394ce7c9111SKalle Valo } 395ce7c9111SKalle Valo 396ce7c9111SKalle Valo void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue) 397ce7c9111SKalle Valo { 398ce7c9111SKalle Valo ieee80211_wake_queue_by_reason(hw, queue, 399ce7c9111SKalle Valo IEEE80211_QUEUE_STOP_REASON_DRIVER); 400ce7c9111SKalle Valo } 401c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_wake_queue); 402c2d1560aSJohannes Berg 403ce7c9111SKalle Valo static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, 404ce7c9111SKalle Valo enum queue_stop_reason reason) 405c2d1560aSJohannes Berg { 406c2d1560aSJohannes Berg struct ieee80211_local *local = hw_to_local(hw); 407c2d1560aSJohannes Berg 40896f5e66eSJohannes Berg if (queue >= hw->queues) { 40996f5e66eSJohannes Berg if (local->ampdu_ac_queue[queue - hw->queues] < 0) 41096f5e66eSJohannes Berg return; 41196f5e66eSJohannes Berg 41296f5e66eSJohannes Berg /* 41396f5e66eSJohannes Berg * for virtual aggregation queues, we need to refcount the 41496f5e66eSJohannes Berg * internal mac80211 disable (multiple times!), keep track of 41596f5e66eSJohannes Berg * driver disable _and_ make sure the regular queue is 41696f5e66eSJohannes Berg * actually enabled. 41796f5e66eSJohannes Berg */ 41896f5e66eSJohannes Berg if (reason == IEEE80211_QUEUE_STOP_REASON_AGGREGATION) 41996f5e66eSJohannes Berg local->amdpu_ac_stop_refcnt[queue - hw->queues]++; 42096f5e66eSJohannes Berg else 42196f5e66eSJohannes Berg __set_bit(reason, &local->queue_stop_reasons[queue]); 42296f5e66eSJohannes Berg 42396f5e66eSJohannes Berg /* now go on to treat the corresponding regular queue */ 42496f5e66eSJohannes Berg queue = local->ampdu_ac_queue[queue - hw->queues]; 42596f5e66eSJohannes Berg reason = IEEE80211_QUEUE_STOP_REASON_AGGREGATION; 42696f5e66eSJohannes Berg } 42796f5e66eSJohannes Berg 428ce7c9111SKalle Valo __set_bit(reason, &local->queue_stop_reasons[queue]); 429ce7c9111SKalle Valo 430e2530083SJohannes Berg netif_stop_subqueue(local->mdev, queue); 431c2d1560aSJohannes Berg } 432ce7c9111SKalle Valo 43396f5e66eSJohannes Berg void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, 434ce7c9111SKalle Valo enum queue_stop_reason reason) 435ce7c9111SKalle Valo { 436ce7c9111SKalle Valo struct ieee80211_local *local = hw_to_local(hw); 437ce7c9111SKalle Valo unsigned long flags; 438ce7c9111SKalle Valo 439ce7c9111SKalle Valo spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 440ce7c9111SKalle Valo __ieee80211_stop_queue(hw, queue, reason); 441ce7c9111SKalle Valo spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 442ce7c9111SKalle Valo } 443ce7c9111SKalle Valo 444ce7c9111SKalle Valo void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue) 445ce7c9111SKalle Valo { 446ce7c9111SKalle Valo ieee80211_stop_queue_by_reason(hw, queue, 447ce7c9111SKalle Valo IEEE80211_QUEUE_STOP_REASON_DRIVER); 448ce7c9111SKalle Valo } 449c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_stop_queue); 450c2d1560aSJohannes Berg 451ce7c9111SKalle Valo void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, 452ce7c9111SKalle Valo enum queue_stop_reason reason) 453c2d1560aSJohannes Berg { 454ce7c9111SKalle Valo struct ieee80211_local *local = hw_to_local(hw); 455ce7c9111SKalle Valo unsigned long flags; 456c2d1560aSJohannes Berg int i; 457c2d1560aSJohannes Berg 458ce7c9111SKalle Valo spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 459ce7c9111SKalle Valo 46096f5e66eSJohannes Berg for (i = 0; i < hw->queues; i++) 461ce7c9111SKalle Valo __ieee80211_stop_queue(hw, i, reason); 462ce7c9111SKalle Valo 463ce7c9111SKalle Valo spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 464ce7c9111SKalle Valo } 465ce7c9111SKalle Valo 466ce7c9111SKalle Valo void ieee80211_stop_queues(struct ieee80211_hw *hw) 467ce7c9111SKalle Valo { 468ce7c9111SKalle Valo ieee80211_stop_queues_by_reason(hw, 469ce7c9111SKalle Valo IEEE80211_QUEUE_STOP_REASON_DRIVER); 470c2d1560aSJohannes Berg } 471c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_stop_queues); 472c2d1560aSJohannes Berg 47392ab8535STomas Winkler int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue) 47492ab8535STomas Winkler { 47592ab8535STomas Winkler struct ieee80211_local *local = hw_to_local(hw); 47696f5e66eSJohannes Berg unsigned long flags; 47796f5e66eSJohannes Berg 47896f5e66eSJohannes Berg if (queue >= hw->queues) { 47996f5e66eSJohannes Berg spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 48096f5e66eSJohannes Berg queue = local->ampdu_ac_queue[queue - hw->queues]; 48196f5e66eSJohannes Berg spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 48296f5e66eSJohannes Berg if (queue < 0) 48396f5e66eSJohannes Berg return true; 48496f5e66eSJohannes Berg } 48596f5e66eSJohannes Berg 48692ab8535STomas Winkler return __netif_subqueue_stopped(local->mdev, queue); 48792ab8535STomas Winkler } 48892ab8535STomas Winkler EXPORT_SYMBOL(ieee80211_queue_stopped); 48992ab8535STomas Winkler 490ce7c9111SKalle Valo void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, 491ce7c9111SKalle Valo enum queue_stop_reason reason) 492c2d1560aSJohannes Berg { 493ce7c9111SKalle Valo struct ieee80211_local *local = hw_to_local(hw); 494ce7c9111SKalle Valo unsigned long flags; 495c2d1560aSJohannes Berg int i; 496c2d1560aSJohannes Berg 497ce7c9111SKalle Valo spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 498ce7c9111SKalle Valo 499c4680470SJohannes Berg for (i = 0; i < hw->queues + hw->ampdu_queues; i++) 500ce7c9111SKalle Valo __ieee80211_wake_queue(hw, i, reason); 501ce7c9111SKalle Valo 502ce7c9111SKalle Valo spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 503ce7c9111SKalle Valo } 504ce7c9111SKalle Valo 505ce7c9111SKalle Valo void ieee80211_wake_queues(struct ieee80211_hw *hw) 506ce7c9111SKalle Valo { 507ce7c9111SKalle Valo ieee80211_wake_queues_by_reason(hw, IEEE80211_QUEUE_STOP_REASON_DRIVER); 508c2d1560aSJohannes Berg } 509c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_wake_queues); 510dabeb344SJohannes Berg 51132bfd35dSJohannes Berg void ieee80211_iterate_active_interfaces( 51232bfd35dSJohannes Berg struct ieee80211_hw *hw, 513dabeb344SJohannes Berg void (*iterator)(void *data, u8 *mac, 51432bfd35dSJohannes Berg struct ieee80211_vif *vif), 515dabeb344SJohannes Berg void *data) 516dabeb344SJohannes Berg { 517dabeb344SJohannes Berg struct ieee80211_local *local = hw_to_local(hw); 518dabeb344SJohannes Berg struct ieee80211_sub_if_data *sdata; 519dabeb344SJohannes Berg 520c771c9d8SJohannes Berg mutex_lock(&local->iflist_mtx); 5212f561febSIvo van Doorn 5222f561febSIvo van Doorn list_for_each_entry(sdata, &local->interfaces, list) { 5232f561febSIvo van Doorn switch (sdata->vif.type) { 52405c914feSJohannes Berg case __NL80211_IFTYPE_AFTER_LAST: 52505c914feSJohannes Berg case NL80211_IFTYPE_UNSPECIFIED: 52605c914feSJohannes Berg case NL80211_IFTYPE_MONITOR: 52705c914feSJohannes Berg case NL80211_IFTYPE_AP_VLAN: 5282f561febSIvo van Doorn continue; 52905c914feSJohannes Berg case NL80211_IFTYPE_AP: 53005c914feSJohannes Berg case NL80211_IFTYPE_STATION: 53105c914feSJohannes Berg case NL80211_IFTYPE_ADHOC: 53205c914feSJohannes Berg case NL80211_IFTYPE_WDS: 53305c914feSJohannes Berg case NL80211_IFTYPE_MESH_POINT: 5342f561febSIvo van Doorn break; 5352f561febSIvo van Doorn } 5362f561febSIvo van Doorn if (netif_running(sdata->dev)) 5372f561febSIvo van Doorn iterator(data, sdata->dev->dev_addr, 5382f561febSIvo van Doorn &sdata->vif); 5392f561febSIvo van Doorn } 5402f561febSIvo van Doorn 541c771c9d8SJohannes Berg mutex_unlock(&local->iflist_mtx); 5422f561febSIvo van Doorn } 5432f561febSIvo van Doorn EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces); 5442f561febSIvo van Doorn 5452f561febSIvo van Doorn void ieee80211_iterate_active_interfaces_atomic( 5462f561febSIvo van Doorn struct ieee80211_hw *hw, 5472f561febSIvo van Doorn void (*iterator)(void *data, u8 *mac, 5482f561febSIvo van Doorn struct ieee80211_vif *vif), 5492f561febSIvo van Doorn void *data) 5502f561febSIvo van Doorn { 5512f561febSIvo van Doorn struct ieee80211_local *local = hw_to_local(hw); 5522f561febSIvo van Doorn struct ieee80211_sub_if_data *sdata; 5532f561febSIvo van Doorn 554e38bad47SJohannes Berg rcu_read_lock(); 555dabeb344SJohannes Berg 556e38bad47SJohannes Berg list_for_each_entry_rcu(sdata, &local->interfaces, list) { 55751fb61e7SJohannes Berg switch (sdata->vif.type) { 55805c914feSJohannes Berg case __NL80211_IFTYPE_AFTER_LAST: 55905c914feSJohannes Berg case NL80211_IFTYPE_UNSPECIFIED: 56005c914feSJohannes Berg case NL80211_IFTYPE_MONITOR: 56105c914feSJohannes Berg case NL80211_IFTYPE_AP_VLAN: 562dabeb344SJohannes Berg continue; 56305c914feSJohannes Berg case NL80211_IFTYPE_AP: 56405c914feSJohannes Berg case NL80211_IFTYPE_STATION: 56505c914feSJohannes Berg case NL80211_IFTYPE_ADHOC: 56605c914feSJohannes Berg case NL80211_IFTYPE_WDS: 56705c914feSJohannes Berg case NL80211_IFTYPE_MESH_POINT: 568dabeb344SJohannes Berg break; 569dabeb344SJohannes Berg } 570dabeb344SJohannes Berg if (netif_running(sdata->dev)) 571dabeb344SJohannes Berg iterator(data, sdata->dev->dev_addr, 57232bfd35dSJohannes Berg &sdata->vif); 573dabeb344SJohannes Berg } 574e38bad47SJohannes Berg 575e38bad47SJohannes Berg rcu_read_unlock(); 576dabeb344SJohannes Berg } 5772f561febSIvo van Doorn EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic); 57837ffc8daSJohannes Berg 57937ffc8daSJohannes Berg void ieee802_11_parse_elems(u8 *start, size_t len, 58037ffc8daSJohannes Berg struct ieee802_11_elems *elems) 58137ffc8daSJohannes Berg { 58237ffc8daSJohannes Berg size_t left = len; 58337ffc8daSJohannes Berg u8 *pos = start; 58437ffc8daSJohannes Berg 58537ffc8daSJohannes Berg memset(elems, 0, sizeof(*elems)); 58637ffc8daSJohannes Berg elems->ie_start = start; 58737ffc8daSJohannes Berg elems->total_len = len; 58837ffc8daSJohannes Berg 58937ffc8daSJohannes Berg while (left >= 2) { 59037ffc8daSJohannes Berg u8 id, elen; 59137ffc8daSJohannes Berg 59237ffc8daSJohannes Berg id = *pos++; 59337ffc8daSJohannes Berg elen = *pos++; 59437ffc8daSJohannes Berg left -= 2; 59537ffc8daSJohannes Berg 59637ffc8daSJohannes Berg if (elen > left) 59737ffc8daSJohannes Berg return; 59837ffc8daSJohannes Berg 59937ffc8daSJohannes Berg switch (id) { 60037ffc8daSJohannes Berg case WLAN_EID_SSID: 60137ffc8daSJohannes Berg elems->ssid = pos; 60237ffc8daSJohannes Berg elems->ssid_len = elen; 60337ffc8daSJohannes Berg break; 60437ffc8daSJohannes Berg case WLAN_EID_SUPP_RATES: 60537ffc8daSJohannes Berg elems->supp_rates = pos; 60637ffc8daSJohannes Berg elems->supp_rates_len = elen; 60737ffc8daSJohannes Berg break; 60837ffc8daSJohannes Berg case WLAN_EID_FH_PARAMS: 60937ffc8daSJohannes Berg elems->fh_params = pos; 61037ffc8daSJohannes Berg elems->fh_params_len = elen; 61137ffc8daSJohannes Berg break; 61237ffc8daSJohannes Berg case WLAN_EID_DS_PARAMS: 61337ffc8daSJohannes Berg elems->ds_params = pos; 61437ffc8daSJohannes Berg elems->ds_params_len = elen; 61537ffc8daSJohannes Berg break; 61637ffc8daSJohannes Berg case WLAN_EID_CF_PARAMS: 61737ffc8daSJohannes Berg elems->cf_params = pos; 61837ffc8daSJohannes Berg elems->cf_params_len = elen; 61937ffc8daSJohannes Berg break; 62037ffc8daSJohannes Berg case WLAN_EID_TIM: 62137ffc8daSJohannes Berg elems->tim = pos; 62237ffc8daSJohannes Berg elems->tim_len = elen; 62337ffc8daSJohannes Berg break; 62437ffc8daSJohannes Berg case WLAN_EID_IBSS_PARAMS: 62537ffc8daSJohannes Berg elems->ibss_params = pos; 62637ffc8daSJohannes Berg elems->ibss_params_len = elen; 62737ffc8daSJohannes Berg break; 62837ffc8daSJohannes Berg case WLAN_EID_CHALLENGE: 62937ffc8daSJohannes Berg elems->challenge = pos; 63037ffc8daSJohannes Berg elems->challenge_len = elen; 63137ffc8daSJohannes Berg break; 63237ffc8daSJohannes Berg case WLAN_EID_WPA: 63337ffc8daSJohannes Berg if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 && 63437ffc8daSJohannes Berg pos[2] == 0xf2) { 63537ffc8daSJohannes Berg /* Microsoft OUI (00:50:F2) */ 63637ffc8daSJohannes Berg if (pos[3] == 1) { 63737ffc8daSJohannes Berg /* OUI Type 1 - WPA IE */ 63837ffc8daSJohannes Berg elems->wpa = pos; 63937ffc8daSJohannes Berg elems->wpa_len = elen; 64037ffc8daSJohannes Berg } else if (elen >= 5 && pos[3] == 2) { 64137ffc8daSJohannes Berg if (pos[4] == 0) { 64237ffc8daSJohannes Berg elems->wmm_info = pos; 64337ffc8daSJohannes Berg elems->wmm_info_len = elen; 64437ffc8daSJohannes Berg } else if (pos[4] == 1) { 64537ffc8daSJohannes Berg elems->wmm_param = pos; 64637ffc8daSJohannes Berg elems->wmm_param_len = elen; 64737ffc8daSJohannes Berg } 64837ffc8daSJohannes Berg } 64937ffc8daSJohannes Berg } 65037ffc8daSJohannes Berg break; 65137ffc8daSJohannes Berg case WLAN_EID_RSN: 65237ffc8daSJohannes Berg elems->rsn = pos; 65337ffc8daSJohannes Berg elems->rsn_len = elen; 65437ffc8daSJohannes Berg break; 65537ffc8daSJohannes Berg case WLAN_EID_ERP_INFO: 65637ffc8daSJohannes Berg elems->erp_info = pos; 65737ffc8daSJohannes Berg elems->erp_info_len = elen; 65837ffc8daSJohannes Berg break; 65937ffc8daSJohannes Berg case WLAN_EID_EXT_SUPP_RATES: 66037ffc8daSJohannes Berg elems->ext_supp_rates = pos; 66137ffc8daSJohannes Berg elems->ext_supp_rates_len = elen; 66237ffc8daSJohannes Berg break; 66337ffc8daSJohannes Berg case WLAN_EID_HT_CAPABILITY: 66409914813SJohannes Berg if (elen >= sizeof(struct ieee80211_ht_cap)) 66509914813SJohannes Berg elems->ht_cap_elem = (void *)pos; 66637ffc8daSJohannes Berg break; 667d9fe60deSJohannes Berg case WLAN_EID_HT_INFORMATION: 668d9fe60deSJohannes Berg if (elen >= sizeof(struct ieee80211_ht_info)) 66909914813SJohannes Berg elems->ht_info_elem = (void *)pos; 67037ffc8daSJohannes Berg break; 67137ffc8daSJohannes Berg case WLAN_EID_MESH_ID: 67237ffc8daSJohannes Berg elems->mesh_id = pos; 67337ffc8daSJohannes Berg elems->mesh_id_len = elen; 67437ffc8daSJohannes Berg break; 67537ffc8daSJohannes Berg case WLAN_EID_MESH_CONFIG: 67637ffc8daSJohannes Berg elems->mesh_config = pos; 67737ffc8daSJohannes Berg elems->mesh_config_len = elen; 67837ffc8daSJohannes Berg break; 67937ffc8daSJohannes Berg case WLAN_EID_PEER_LINK: 68037ffc8daSJohannes Berg elems->peer_link = pos; 68137ffc8daSJohannes Berg elems->peer_link_len = elen; 68237ffc8daSJohannes Berg break; 68337ffc8daSJohannes Berg case WLAN_EID_PREQ: 68437ffc8daSJohannes Berg elems->preq = pos; 68537ffc8daSJohannes Berg elems->preq_len = elen; 68637ffc8daSJohannes Berg break; 68737ffc8daSJohannes Berg case WLAN_EID_PREP: 68837ffc8daSJohannes Berg elems->prep = pos; 68937ffc8daSJohannes Berg elems->prep_len = elen; 69037ffc8daSJohannes Berg break; 69137ffc8daSJohannes Berg case WLAN_EID_PERR: 69237ffc8daSJohannes Berg elems->perr = pos; 69337ffc8daSJohannes Berg elems->perr_len = elen; 69437ffc8daSJohannes Berg break; 69537ffc8daSJohannes Berg case WLAN_EID_CHANNEL_SWITCH: 69637ffc8daSJohannes Berg elems->ch_switch_elem = pos; 69737ffc8daSJohannes Berg elems->ch_switch_elem_len = elen; 69837ffc8daSJohannes Berg break; 69937ffc8daSJohannes Berg case WLAN_EID_QUIET: 70037ffc8daSJohannes Berg if (!elems->quiet_elem) { 70137ffc8daSJohannes Berg elems->quiet_elem = pos; 70237ffc8daSJohannes Berg elems->quiet_elem_len = elen; 70337ffc8daSJohannes Berg } 70437ffc8daSJohannes Berg elems->num_of_quiet_elem++; 70537ffc8daSJohannes Berg break; 70637ffc8daSJohannes Berg case WLAN_EID_COUNTRY: 70737ffc8daSJohannes Berg elems->country_elem = pos; 70837ffc8daSJohannes Berg elems->country_elem_len = elen; 70937ffc8daSJohannes Berg break; 71037ffc8daSJohannes Berg case WLAN_EID_PWR_CONSTRAINT: 71137ffc8daSJohannes Berg elems->pwr_constr_elem = pos; 71237ffc8daSJohannes Berg elems->pwr_constr_elem_len = elen; 71337ffc8daSJohannes Berg break; 714f797eb7eSJouni Malinen case WLAN_EID_TIMEOUT_INTERVAL: 715f797eb7eSJouni Malinen elems->timeout_int = pos; 716f797eb7eSJouni Malinen elems->timeout_int_len = elen; 71763a5ab82SJouni Malinen break; 71837ffc8daSJohannes Berg default: 71937ffc8daSJohannes Berg break; 72037ffc8daSJohannes Berg } 72137ffc8daSJohannes Berg 72237ffc8daSJohannes Berg left -= elen; 72337ffc8daSJohannes Berg pos += elen; 72437ffc8daSJohannes Berg } 72537ffc8daSJohannes Berg } 7265825fe10SJohannes Berg 7275825fe10SJohannes Berg void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata) 7285825fe10SJohannes Berg { 7295825fe10SJohannes Berg struct ieee80211_local *local = sdata->local; 7305825fe10SJohannes Berg struct ieee80211_tx_queue_params qparam; 7315825fe10SJohannes Berg int i; 7325825fe10SJohannes Berg 7335825fe10SJohannes Berg if (!local->ops->conf_tx) 7345825fe10SJohannes Berg return; 7355825fe10SJohannes Berg 7365825fe10SJohannes Berg memset(&qparam, 0, sizeof(qparam)); 7375825fe10SJohannes Berg 7385825fe10SJohannes Berg qparam.aifs = 2; 7395825fe10SJohannes Berg 7405825fe10SJohannes Berg if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && 7415825fe10SJohannes Berg !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)) 7425825fe10SJohannes Berg qparam.cw_min = 31; 7435825fe10SJohannes Berg else 7445825fe10SJohannes Berg qparam.cw_min = 15; 7455825fe10SJohannes Berg 7465825fe10SJohannes Berg qparam.cw_max = 1023; 7475825fe10SJohannes Berg qparam.txop = 0; 7485825fe10SJohannes Berg 7495825fe10SJohannes Berg for (i = 0; i < local_to_hw(local)->queues; i++) 7505825fe10SJohannes Berg local->ops->conf_tx(local_to_hw(local), i, &qparam); 7515825fe10SJohannes Berg } 752e50db65cSJohannes Berg 75346900298SJohannes Berg void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, 75446900298SJohannes Berg const size_t supp_rates_len, 75546900298SJohannes Berg const u8 *supp_rates) 75646900298SJohannes Berg { 75746900298SJohannes Berg struct ieee80211_local *local = sdata->local; 75846900298SJohannes Berg int i, have_higher_than_11mbit = 0; 75946900298SJohannes Berg 76046900298SJohannes Berg /* cf. IEEE 802.11 9.2.12 */ 76146900298SJohannes Berg for (i = 0; i < supp_rates_len; i++) 76246900298SJohannes Berg if ((supp_rates[i] & 0x7f) * 5 > 110) 76346900298SJohannes Berg have_higher_than_11mbit = 1; 76446900298SJohannes Berg 76546900298SJohannes Berg if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && 76646900298SJohannes Berg have_higher_than_11mbit) 76746900298SJohannes Berg sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; 76846900298SJohannes Berg else 76946900298SJohannes Berg sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; 77046900298SJohannes Berg 77146900298SJohannes Berg ieee80211_set_wmm_default(sdata); 77246900298SJohannes Berg } 77346900298SJohannes Berg 774e50db65cSJohannes Berg void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, 775e50db65cSJohannes Berg int encrypt) 776e50db65cSJohannes Berg { 777e50db65cSJohannes Berg skb->dev = sdata->local->mdev; 778e50db65cSJohannes Berg skb_set_mac_header(skb, 0); 779e50db65cSJohannes Berg skb_set_network_header(skb, 0); 780e50db65cSJohannes Berg skb_set_transport_header(skb, 0); 781e50db65cSJohannes Berg 782e50db65cSJohannes Berg skb->iif = sdata->dev->ifindex; 783e50db65cSJohannes Berg skb->do_not_encrypt = !encrypt; 784e50db65cSJohannes Berg 785e50db65cSJohannes Berg dev_queue_xmit(skb); 786e50db65cSJohannes Berg } 787e16751c3SJohannes Berg 788e16751c3SJohannes Berg int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freqMHz) 789e16751c3SJohannes Berg { 790e16751c3SJohannes Berg int ret = -EINVAL; 791e16751c3SJohannes Berg struct ieee80211_channel *chan; 792e16751c3SJohannes Berg struct ieee80211_local *local = sdata->local; 793e16751c3SJohannes Berg 794e16751c3SJohannes Berg chan = ieee80211_get_channel(local->hw.wiphy, freqMHz); 795e16751c3SJohannes Berg 796e16751c3SJohannes Berg if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) { 79705c914feSJohannes Berg if (sdata->vif.type == NL80211_IFTYPE_ADHOC && 798d73782fdSJohannes Berg chan->flags & IEEE80211_CHAN_NO_IBSS) 799e16751c3SJohannes Berg return ret; 800e16751c3SJohannes Berg local->oper_channel = chan; 801094d05dcSSujith local->oper_channel_type = NL80211_CHAN_NO_HT; 802e16751c3SJohannes Berg 803c2b13452SJohannes Berg if (local->sw_scanning || local->hw_scanning) 804e16751c3SJohannes Berg ret = 0; 805e16751c3SJohannes Berg else 806e8975581SJohannes Berg ret = ieee80211_hw_config( 807e8975581SJohannes Berg local, IEEE80211_CONF_CHANGE_CHANNEL); 808e16751c3SJohannes Berg } 809e16751c3SJohannes Berg 810e16751c3SJohannes Berg return ret; 811e16751c3SJohannes Berg } 81296dd22acSJohannes Berg 813881d948cSJohannes Berg u32 ieee80211_mandatory_rates(struct ieee80211_local *local, 81496dd22acSJohannes Berg enum ieee80211_band band) 81596dd22acSJohannes Berg { 81696dd22acSJohannes Berg struct ieee80211_supported_band *sband; 81796dd22acSJohannes Berg struct ieee80211_rate *bitrates; 818881d948cSJohannes Berg u32 mandatory_rates; 81996dd22acSJohannes Berg enum ieee80211_rate_flags mandatory_flag; 82096dd22acSJohannes Berg int i; 82196dd22acSJohannes Berg 82296dd22acSJohannes Berg sband = local->hw.wiphy->bands[band]; 82396dd22acSJohannes Berg if (!sband) { 82496dd22acSJohannes Berg WARN_ON(1); 82596dd22acSJohannes Berg sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; 82696dd22acSJohannes Berg } 82796dd22acSJohannes Berg 82896dd22acSJohannes Berg if (band == IEEE80211_BAND_2GHZ) 82996dd22acSJohannes Berg mandatory_flag = IEEE80211_RATE_MANDATORY_B; 83096dd22acSJohannes Berg else 83196dd22acSJohannes Berg mandatory_flag = IEEE80211_RATE_MANDATORY_A; 83296dd22acSJohannes Berg 83396dd22acSJohannes Berg bitrates = sband->bitrates; 83496dd22acSJohannes Berg mandatory_rates = 0; 83596dd22acSJohannes Berg for (i = 0; i < sband->n_bitrates; i++) 83696dd22acSJohannes Berg if (bitrates[i].flags & mandatory_flag) 83796dd22acSJohannes Berg mandatory_rates |= BIT(i); 83896dd22acSJohannes Berg return mandatory_rates; 83996dd22acSJohannes Berg } 84046900298SJohannes Berg 84146900298SJohannes Berg void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, 84246900298SJohannes Berg u16 transaction, u16 auth_alg, 84346900298SJohannes Berg u8 *extra, size_t extra_len, 84446900298SJohannes Berg const u8 *bssid, int encrypt) 84546900298SJohannes Berg { 84646900298SJohannes Berg struct ieee80211_local *local = sdata->local; 84746900298SJohannes Berg struct sk_buff *skb; 84846900298SJohannes Berg struct ieee80211_mgmt *mgmt; 84946900298SJohannes Berg 85046900298SJohannes Berg skb = dev_alloc_skb(local->hw.extra_tx_headroom + 85165fc73acSJouni Malinen sizeof(*mgmt) + 6 + extra_len); 85246900298SJohannes Berg if (!skb) { 85346900298SJohannes Berg printk(KERN_DEBUG "%s: failed to allocate buffer for auth " 85446900298SJohannes Berg "frame\n", sdata->dev->name); 85546900298SJohannes Berg return; 85646900298SJohannes Berg } 85746900298SJohannes Berg skb_reserve(skb, local->hw.extra_tx_headroom); 85846900298SJohannes Berg 85946900298SJohannes Berg mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6); 86046900298SJohannes Berg memset(mgmt, 0, 24 + 6); 86146900298SJohannes Berg mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | 86246900298SJohannes Berg IEEE80211_STYPE_AUTH); 86346900298SJohannes Berg if (encrypt) 86446900298SJohannes Berg mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); 86546900298SJohannes Berg memcpy(mgmt->da, bssid, ETH_ALEN); 86646900298SJohannes Berg memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); 86746900298SJohannes Berg memcpy(mgmt->bssid, bssid, ETH_ALEN); 86846900298SJohannes Berg mgmt->u.auth.auth_alg = cpu_to_le16(auth_alg); 86946900298SJohannes Berg mgmt->u.auth.auth_transaction = cpu_to_le16(transaction); 87046900298SJohannes Berg mgmt->u.auth.status_code = cpu_to_le16(0); 87146900298SJohannes Berg if (extra) 87246900298SJohannes Berg memcpy(skb_put(skb, extra_len), extra, extra_len); 87346900298SJohannes Berg 87446900298SJohannes Berg ieee80211_tx_skb(sdata, skb, encrypt); 87546900298SJohannes Berg } 87646900298SJohannes Berg 87746900298SJohannes Berg void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, 87870692ad2SJouni Malinen u8 *ssid, size_t ssid_len, 87970692ad2SJouni Malinen u8 *ie, size_t ie_len) 88046900298SJohannes Berg { 88146900298SJohannes Berg struct ieee80211_local *local = sdata->local; 88246900298SJohannes Berg struct ieee80211_supported_band *sband; 88346900298SJohannes Berg struct sk_buff *skb; 88446900298SJohannes Berg struct ieee80211_mgmt *mgmt; 88565fc73acSJouni Malinen u8 *pos, *supp_rates, *esupp_rates = NULL; 88665fc73acSJouni Malinen int i; 88746900298SJohannes Berg 88846900298SJohannes Berg skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 + 88965fc73acSJouni Malinen ie_len); 89046900298SJohannes Berg if (!skb) { 89146900298SJohannes Berg printk(KERN_DEBUG "%s: failed to allocate buffer for probe " 89246900298SJohannes Berg "request\n", sdata->dev->name); 89346900298SJohannes Berg return; 89446900298SJohannes Berg } 89546900298SJohannes Berg skb_reserve(skb, local->hw.extra_tx_headroom); 89646900298SJohannes Berg 89746900298SJohannes Berg mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); 89846900298SJohannes Berg memset(mgmt, 0, 24); 89946900298SJohannes Berg mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | 90046900298SJohannes Berg IEEE80211_STYPE_PROBE_REQ); 90146900298SJohannes Berg memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); 90246900298SJohannes Berg if (dst) { 90346900298SJohannes Berg memcpy(mgmt->da, dst, ETH_ALEN); 90446900298SJohannes Berg memcpy(mgmt->bssid, dst, ETH_ALEN); 90546900298SJohannes Berg } else { 90646900298SJohannes Berg memset(mgmt->da, 0xff, ETH_ALEN); 90746900298SJohannes Berg memset(mgmt->bssid, 0xff, ETH_ALEN); 90846900298SJohannes Berg } 90946900298SJohannes Berg pos = skb_put(skb, 2 + ssid_len); 91046900298SJohannes Berg *pos++ = WLAN_EID_SSID; 91146900298SJohannes Berg *pos++ = ssid_len; 91246900298SJohannes Berg memcpy(pos, ssid, ssid_len); 91346900298SJohannes Berg 91446900298SJohannes Berg supp_rates = skb_put(skb, 2); 91546900298SJohannes Berg supp_rates[0] = WLAN_EID_SUPP_RATES; 91646900298SJohannes Berg supp_rates[1] = 0; 91746900298SJohannes Berg sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; 91846900298SJohannes Berg 91946900298SJohannes Berg for (i = 0; i < sband->n_bitrates; i++) { 92046900298SJohannes Berg struct ieee80211_rate *rate = &sband->bitrates[i]; 92146900298SJohannes Berg if (esupp_rates) { 92246900298SJohannes Berg pos = skb_put(skb, 1); 92346900298SJohannes Berg esupp_rates[1]++; 92446900298SJohannes Berg } else if (supp_rates[1] == 8) { 92546900298SJohannes Berg esupp_rates = skb_put(skb, 3); 92646900298SJohannes Berg esupp_rates[0] = WLAN_EID_EXT_SUPP_RATES; 92746900298SJohannes Berg esupp_rates[1] = 1; 92846900298SJohannes Berg pos = &esupp_rates[2]; 92946900298SJohannes Berg } else { 93046900298SJohannes Berg pos = skb_put(skb, 1); 93146900298SJohannes Berg supp_rates[1]++; 93246900298SJohannes Berg } 93346900298SJohannes Berg *pos = rate->bitrate / 5; 93446900298SJohannes Berg } 93546900298SJohannes Berg 93670692ad2SJouni Malinen if (ie) 93770692ad2SJouni Malinen memcpy(skb_put(skb, ie_len), ie, ie_len); 93846900298SJohannes Berg 93946900298SJohannes Berg ieee80211_tx_skb(sdata, skb, 0); 94046900298SJohannes Berg } 94146900298SJohannes Berg 94246900298SJohannes Berg u32 ieee80211_sta_get_rates(struct ieee80211_local *local, 94346900298SJohannes Berg struct ieee802_11_elems *elems, 94446900298SJohannes Berg enum ieee80211_band band) 94546900298SJohannes Berg { 94646900298SJohannes Berg struct ieee80211_supported_band *sband; 94746900298SJohannes Berg struct ieee80211_rate *bitrates; 94846900298SJohannes Berg size_t num_rates; 94946900298SJohannes Berg u32 supp_rates; 95046900298SJohannes Berg int i, j; 95146900298SJohannes Berg sband = local->hw.wiphy->bands[band]; 95246900298SJohannes Berg 95346900298SJohannes Berg if (!sband) { 95446900298SJohannes Berg WARN_ON(1); 95546900298SJohannes Berg sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; 95646900298SJohannes Berg } 95746900298SJohannes Berg 95846900298SJohannes Berg bitrates = sband->bitrates; 95946900298SJohannes Berg num_rates = sband->n_bitrates; 96046900298SJohannes Berg supp_rates = 0; 96146900298SJohannes Berg for (i = 0; i < elems->supp_rates_len + 96246900298SJohannes Berg elems->ext_supp_rates_len; i++) { 96346900298SJohannes Berg u8 rate = 0; 96446900298SJohannes Berg int own_rate; 96546900298SJohannes Berg if (i < elems->supp_rates_len) 96646900298SJohannes Berg rate = elems->supp_rates[i]; 96746900298SJohannes Berg else if (elems->ext_supp_rates) 96846900298SJohannes Berg rate = elems->ext_supp_rates 96946900298SJohannes Berg [i - elems->supp_rates_len]; 97046900298SJohannes Berg own_rate = 5 * (rate & 0x7f); 97146900298SJohannes Berg for (j = 0; j < num_rates; j++) 97246900298SJohannes Berg if (bitrates[j].bitrate == own_rate) 97346900298SJohannes Berg supp_rates |= BIT(j); 97446900298SJohannes Berg } 97546900298SJohannes Berg return supp_rates; 97646900298SJohannes Berg } 977