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> 23d91f36dbSJohannes 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 { 1002de8e0d9SJohannes Berg struct sk_buff *skb = tx->skb; 1012de8e0d9SJohannes Berg struct ieee80211_hdr *hdr; 102c2d1560aSJohannes Berg 1032de8e0d9SJohannes Berg do { 1042de8e0d9SJohannes Berg hdr = (struct ieee80211_hdr *) skb->data; 105c2d1560aSJohannes Berg hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); 1062de8e0d9SJohannes Berg } while ((skb = skb->next)); 107c2d1560aSJohannes Berg } 108c2d1560aSJohannes Berg 109c2d1560aSJohannes Berg int ieee80211_frame_duration(struct ieee80211_local *local, 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 1238318d78aSJohannes Berg if (local->hw.conf.channel->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, 1658318d78aSJohannes Berg size_t frame_len, 1668318d78aSJohannes Berg struct ieee80211_rate *rate) 167c2d1560aSJohannes Berg { 168c2d1560aSJohannes Berg struct ieee80211_local *local = hw_to_local(hw); 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 1828318d78aSJohannes Berg dur = ieee80211_frame_duration(local, 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 2012e92e6f2SJohannes Berg sband = local->hw.wiphy->bands[local->hw.conf.channel->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 */ 2168318d78aSJohannes Berg dur = ieee80211_frame_duration(local, 10, rate->bitrate, 217c2d1560aSJohannes Berg erp, short_preamble); 218c2d1560aSJohannes Berg /* Data frame duration */ 2198318d78aSJohannes Berg dur += ieee80211_frame_duration(local, frame_len, rate->bitrate, 220c2d1560aSJohannes Berg erp, short_preamble); 221c2d1560aSJohannes Berg /* ACK duration */ 2228318d78aSJohannes Berg dur += ieee80211_frame_duration(local, 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 2422e92e6f2SJohannes Berg sband = local->hw.wiphy->bands[local->hw.conf.channel->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 */ 2568318d78aSJohannes Berg dur = ieee80211_frame_duration(local, frame_len, rate->bitrate, 257c2d1560aSJohannes Berg erp, short_preamble); 258e039fa4aSJohannes Berg if (!(frame_txctl->flags & IEEE80211_TX_CTL_NO_ACK)) { 259c2d1560aSJohannes Berg /* ACK duration */ 2608318d78aSJohannes Berg dur += ieee80211_frame_duration(local, 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 268ce7c9111SKalle Valo static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, 269ce7c9111SKalle Valo enum queue_stop_reason reason) 270c2d1560aSJohannes Berg { 271c2d1560aSJohannes Berg struct ieee80211_local *local = hw_to_local(hw); 272c2d1560aSJohannes Berg 273e4e72fb4SJohannes Berg if (WARN_ON(queue >= hw->queues)) 27496f5e66eSJohannes Berg return; 27596f5e66eSJohannes Berg 276ce7c9111SKalle Valo __clear_bit(reason, &local->queue_stop_reasons[queue]); 277ce7c9111SKalle Valo 278ce7c9111SKalle Valo if (local->queue_stop_reasons[queue] != 0) 279ce7c9111SKalle Valo /* someone still has this queue stopped */ 280ce7c9111SKalle Valo return; 281ce7c9111SKalle Valo 2823b8d81e0SJohannes Berg if (!skb_queue_empty(&local->pending[queue])) 2833b8d81e0SJohannes Berg tasklet_schedule(&local->tx_pending_tasklet); 284c2d1560aSJohannes Berg } 285ce7c9111SKalle Valo 28696f5e66eSJohannes Berg void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, 287ce7c9111SKalle Valo enum queue_stop_reason reason) 288ce7c9111SKalle Valo { 289ce7c9111SKalle Valo struct ieee80211_local *local = hw_to_local(hw); 290ce7c9111SKalle Valo unsigned long flags; 291ce7c9111SKalle Valo 292ce7c9111SKalle Valo spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 293ce7c9111SKalle Valo __ieee80211_wake_queue(hw, queue, reason); 294ce7c9111SKalle Valo spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 295ce7c9111SKalle Valo } 296ce7c9111SKalle Valo 297ce7c9111SKalle Valo void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue) 298ce7c9111SKalle Valo { 299ce7c9111SKalle Valo ieee80211_wake_queue_by_reason(hw, queue, 300ce7c9111SKalle Valo IEEE80211_QUEUE_STOP_REASON_DRIVER); 301ce7c9111SKalle Valo } 302c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_wake_queue); 303c2d1560aSJohannes Berg 304ce7c9111SKalle Valo static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, 305ce7c9111SKalle Valo enum queue_stop_reason reason) 306c2d1560aSJohannes Berg { 307c2d1560aSJohannes Berg struct ieee80211_local *local = hw_to_local(hw); 308c2d1560aSJohannes Berg 309e4e72fb4SJohannes Berg if (WARN_ON(queue >= hw->queues)) 31096f5e66eSJohannes Berg return; 31196f5e66eSJohannes Berg 3122a577d98SJohannes Berg __set_bit(reason, &local->queue_stop_reasons[queue]); 313c2d1560aSJohannes Berg } 314ce7c9111SKalle Valo 31596f5e66eSJohannes Berg void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, 316ce7c9111SKalle Valo enum queue_stop_reason reason) 317ce7c9111SKalle Valo { 318ce7c9111SKalle Valo struct ieee80211_local *local = hw_to_local(hw); 319ce7c9111SKalle Valo unsigned long flags; 320ce7c9111SKalle Valo 321ce7c9111SKalle Valo spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 322ce7c9111SKalle Valo __ieee80211_stop_queue(hw, queue, reason); 323ce7c9111SKalle Valo spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 324ce7c9111SKalle Valo } 325ce7c9111SKalle Valo 326ce7c9111SKalle Valo void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue) 327ce7c9111SKalle Valo { 328ce7c9111SKalle Valo ieee80211_stop_queue_by_reason(hw, queue, 329ce7c9111SKalle Valo IEEE80211_QUEUE_STOP_REASON_DRIVER); 330ce7c9111SKalle Valo } 331c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_stop_queue); 332c2d1560aSJohannes Berg 3338f77f384SJohannes Berg void ieee80211_add_pending_skb(struct ieee80211_local *local, 3348f77f384SJohannes Berg struct sk_buff *skb) 3358f77f384SJohannes Berg { 3368f77f384SJohannes Berg struct ieee80211_hw *hw = &local->hw; 3378f77f384SJohannes Berg unsigned long flags; 3388f77f384SJohannes Berg int queue = skb_get_queue_mapping(skb); 339a7bc376cSJohannes Berg struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 340a7bc376cSJohannes Berg 341a7bc376cSJohannes Berg if (WARN_ON(!info->control.vif)) { 342a7bc376cSJohannes Berg kfree(skb); 343a7bc376cSJohannes Berg return; 344a7bc376cSJohannes Berg } 3458f77f384SJohannes Berg 3468f77f384SJohannes Berg spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 3478f77f384SJohannes Berg __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD); 3483b8d81e0SJohannes Berg __skb_queue_tail(&local->pending[queue], skb); 3498f77f384SJohannes Berg __ieee80211_wake_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD); 3508f77f384SJohannes Berg spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 3518f77f384SJohannes Berg } 3528f77f384SJohannes Berg 3538f77f384SJohannes Berg int ieee80211_add_pending_skbs(struct ieee80211_local *local, 3548f77f384SJohannes Berg struct sk_buff_head *skbs) 3558f77f384SJohannes Berg { 3568f77f384SJohannes Berg struct ieee80211_hw *hw = &local->hw; 3578f77f384SJohannes Berg struct sk_buff *skb; 3588f77f384SJohannes Berg unsigned long flags; 3598f77f384SJohannes Berg int queue, ret = 0, i; 3608f77f384SJohannes Berg 3618f77f384SJohannes Berg spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 3628f77f384SJohannes Berg for (i = 0; i < hw->queues; i++) 3638f77f384SJohannes Berg __ieee80211_stop_queue(hw, i, 3648f77f384SJohannes Berg IEEE80211_QUEUE_STOP_REASON_SKB_ADD); 3658f77f384SJohannes Berg 3668f77f384SJohannes Berg while ((skb = skb_dequeue(skbs))) { 367a7bc376cSJohannes Berg struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 368a7bc376cSJohannes Berg 369a7bc376cSJohannes Berg if (WARN_ON(!info->control.vif)) { 370a7bc376cSJohannes Berg kfree(skb); 371a7bc376cSJohannes Berg continue; 372a7bc376cSJohannes Berg } 373a7bc376cSJohannes Berg 3748f77f384SJohannes Berg ret++; 3758f77f384SJohannes Berg queue = skb_get_queue_mapping(skb); 3763b8d81e0SJohannes Berg __skb_queue_tail(&local->pending[queue], skb); 3778f77f384SJohannes Berg } 3788f77f384SJohannes Berg 3793b8d81e0SJohannes Berg for (i = 0; i < hw->queues; i++) 3808f77f384SJohannes Berg __ieee80211_wake_queue(hw, i, 3818f77f384SJohannes Berg IEEE80211_QUEUE_STOP_REASON_SKB_ADD); 3828f77f384SJohannes Berg spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 3838f77f384SJohannes Berg 3848f77f384SJohannes Berg return ret; 3858f77f384SJohannes Berg } 3868f77f384SJohannes Berg 387ce7c9111SKalle Valo void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, 388ce7c9111SKalle Valo enum queue_stop_reason reason) 389c2d1560aSJohannes Berg { 390ce7c9111SKalle Valo struct ieee80211_local *local = hw_to_local(hw); 391ce7c9111SKalle Valo unsigned long flags; 392c2d1560aSJohannes Berg int i; 393c2d1560aSJohannes Berg 394ce7c9111SKalle Valo spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 395ce7c9111SKalle Valo 39696f5e66eSJohannes Berg for (i = 0; i < hw->queues; i++) 397ce7c9111SKalle Valo __ieee80211_stop_queue(hw, i, reason); 398ce7c9111SKalle Valo 399ce7c9111SKalle Valo spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 400ce7c9111SKalle Valo } 401ce7c9111SKalle Valo 402ce7c9111SKalle Valo void ieee80211_stop_queues(struct ieee80211_hw *hw) 403ce7c9111SKalle Valo { 404ce7c9111SKalle Valo ieee80211_stop_queues_by_reason(hw, 405ce7c9111SKalle Valo IEEE80211_QUEUE_STOP_REASON_DRIVER); 406c2d1560aSJohannes Berg } 407c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_stop_queues); 408c2d1560aSJohannes Berg 40992ab8535STomas Winkler int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue) 41092ab8535STomas Winkler { 41192ab8535STomas Winkler struct ieee80211_local *local = hw_to_local(hw); 4123b8d81e0SJohannes Berg unsigned long flags; 4133b8d81e0SJohannes Berg int ret; 41496f5e66eSJohannes Berg 415e4e72fb4SJohannes Berg if (WARN_ON(queue >= hw->queues)) 41696f5e66eSJohannes Berg return true; 41796f5e66eSJohannes Berg 4183b8d81e0SJohannes Berg spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 4193b8d81e0SJohannes Berg ret = !!local->queue_stop_reasons[queue]; 4203b8d81e0SJohannes Berg spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 4213b8d81e0SJohannes Berg return ret; 42292ab8535STomas Winkler } 42392ab8535STomas Winkler EXPORT_SYMBOL(ieee80211_queue_stopped); 42492ab8535STomas Winkler 425ce7c9111SKalle Valo void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, 426ce7c9111SKalle Valo enum queue_stop_reason reason) 427c2d1560aSJohannes Berg { 428ce7c9111SKalle Valo struct ieee80211_local *local = hw_to_local(hw); 429ce7c9111SKalle Valo unsigned long flags; 430c2d1560aSJohannes Berg int i; 431c2d1560aSJohannes Berg 432ce7c9111SKalle Valo spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 433ce7c9111SKalle Valo 434e4e72fb4SJohannes Berg for (i = 0; i < hw->queues; i++) 435ce7c9111SKalle Valo __ieee80211_wake_queue(hw, i, reason); 436ce7c9111SKalle Valo 437ce7c9111SKalle Valo spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 438ce7c9111SKalle Valo } 439ce7c9111SKalle Valo 440ce7c9111SKalle Valo void ieee80211_wake_queues(struct ieee80211_hw *hw) 441ce7c9111SKalle Valo { 442ce7c9111SKalle Valo ieee80211_wake_queues_by_reason(hw, IEEE80211_QUEUE_STOP_REASON_DRIVER); 443c2d1560aSJohannes Berg } 444c2d1560aSJohannes Berg EXPORT_SYMBOL(ieee80211_wake_queues); 445dabeb344SJohannes Berg 44632bfd35dSJohannes Berg void ieee80211_iterate_active_interfaces( 44732bfd35dSJohannes Berg struct ieee80211_hw *hw, 448dabeb344SJohannes Berg void (*iterator)(void *data, u8 *mac, 44932bfd35dSJohannes Berg struct ieee80211_vif *vif), 450dabeb344SJohannes Berg void *data) 451dabeb344SJohannes Berg { 452dabeb344SJohannes Berg struct ieee80211_local *local = hw_to_local(hw); 453dabeb344SJohannes Berg struct ieee80211_sub_if_data *sdata; 454dabeb344SJohannes Berg 455c771c9d8SJohannes Berg mutex_lock(&local->iflist_mtx); 4562f561febSIvo van Doorn 4572f561febSIvo van Doorn list_for_each_entry(sdata, &local->interfaces, list) { 4582f561febSIvo van Doorn switch (sdata->vif.type) { 45905c914feSJohannes Berg case __NL80211_IFTYPE_AFTER_LAST: 46005c914feSJohannes Berg case NL80211_IFTYPE_UNSPECIFIED: 46105c914feSJohannes Berg case NL80211_IFTYPE_MONITOR: 46205c914feSJohannes Berg case NL80211_IFTYPE_AP_VLAN: 4632f561febSIvo van Doorn continue; 46405c914feSJohannes Berg case NL80211_IFTYPE_AP: 46505c914feSJohannes Berg case NL80211_IFTYPE_STATION: 46605c914feSJohannes Berg case NL80211_IFTYPE_ADHOC: 46705c914feSJohannes Berg case NL80211_IFTYPE_WDS: 46805c914feSJohannes Berg case NL80211_IFTYPE_MESH_POINT: 4692f561febSIvo van Doorn break; 4702f561febSIvo van Doorn } 4712f561febSIvo van Doorn if (netif_running(sdata->dev)) 4722f561febSIvo van Doorn iterator(data, sdata->dev->dev_addr, 4732f561febSIvo van Doorn &sdata->vif); 4742f561febSIvo van Doorn } 4752f561febSIvo van Doorn 476c771c9d8SJohannes Berg mutex_unlock(&local->iflist_mtx); 4772f561febSIvo van Doorn } 4782f561febSIvo van Doorn EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces); 4792f561febSIvo van Doorn 4802f561febSIvo van Doorn void ieee80211_iterate_active_interfaces_atomic( 4812f561febSIvo van Doorn struct ieee80211_hw *hw, 4822f561febSIvo van Doorn void (*iterator)(void *data, u8 *mac, 4832f561febSIvo van Doorn struct ieee80211_vif *vif), 4842f561febSIvo van Doorn void *data) 4852f561febSIvo van Doorn { 4862f561febSIvo van Doorn struct ieee80211_local *local = hw_to_local(hw); 4872f561febSIvo van Doorn struct ieee80211_sub_if_data *sdata; 4882f561febSIvo van Doorn 489e38bad47SJohannes Berg rcu_read_lock(); 490dabeb344SJohannes Berg 491e38bad47SJohannes Berg list_for_each_entry_rcu(sdata, &local->interfaces, list) { 49251fb61e7SJohannes Berg switch (sdata->vif.type) { 49305c914feSJohannes Berg case __NL80211_IFTYPE_AFTER_LAST: 49405c914feSJohannes Berg case NL80211_IFTYPE_UNSPECIFIED: 49505c914feSJohannes Berg case NL80211_IFTYPE_MONITOR: 49605c914feSJohannes Berg case NL80211_IFTYPE_AP_VLAN: 497dabeb344SJohannes Berg continue; 49805c914feSJohannes Berg case NL80211_IFTYPE_AP: 49905c914feSJohannes Berg case NL80211_IFTYPE_STATION: 50005c914feSJohannes Berg case NL80211_IFTYPE_ADHOC: 50105c914feSJohannes Berg case NL80211_IFTYPE_WDS: 50205c914feSJohannes Berg case NL80211_IFTYPE_MESH_POINT: 503dabeb344SJohannes Berg break; 504dabeb344SJohannes Berg } 505dabeb344SJohannes Berg if (netif_running(sdata->dev)) 506dabeb344SJohannes Berg iterator(data, sdata->dev->dev_addr, 50732bfd35dSJohannes Berg &sdata->vif); 508dabeb344SJohannes Berg } 509e38bad47SJohannes Berg 510e38bad47SJohannes Berg rcu_read_unlock(); 511dabeb344SJohannes Berg } 5122f561febSIvo van Doorn EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic); 51337ffc8daSJohannes Berg 51437ffc8daSJohannes Berg void ieee802_11_parse_elems(u8 *start, size_t len, 51537ffc8daSJohannes Berg struct ieee802_11_elems *elems) 51637ffc8daSJohannes Berg { 517d91f36dbSJohannes Berg ieee802_11_parse_elems_crc(start, len, elems, 0, 0); 518d91f36dbSJohannes Berg } 519d91f36dbSJohannes Berg 520d91f36dbSJohannes Berg u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, 521d91f36dbSJohannes Berg struct ieee802_11_elems *elems, 522d91f36dbSJohannes Berg u64 filter, u32 crc) 523d91f36dbSJohannes Berg { 52437ffc8daSJohannes Berg size_t left = len; 52537ffc8daSJohannes Berg u8 *pos = start; 526d91f36dbSJohannes Berg bool calc_crc = filter != 0; 52737ffc8daSJohannes Berg 52837ffc8daSJohannes Berg memset(elems, 0, sizeof(*elems)); 52937ffc8daSJohannes Berg elems->ie_start = start; 53037ffc8daSJohannes Berg elems->total_len = len; 53137ffc8daSJohannes Berg 53237ffc8daSJohannes Berg while (left >= 2) { 53337ffc8daSJohannes Berg u8 id, elen; 53437ffc8daSJohannes Berg 53537ffc8daSJohannes Berg id = *pos++; 53637ffc8daSJohannes Berg elen = *pos++; 53737ffc8daSJohannes Berg left -= 2; 53837ffc8daSJohannes Berg 53937ffc8daSJohannes Berg if (elen > left) 540d91f36dbSJohannes Berg break; 541d91f36dbSJohannes Berg 542d91f36dbSJohannes Berg if (calc_crc && id < 64 && (filter & BIT(id))) 543d91f36dbSJohannes Berg crc = crc32_be(crc, pos - 2, elen + 2); 54437ffc8daSJohannes Berg 54537ffc8daSJohannes Berg switch (id) { 54637ffc8daSJohannes Berg case WLAN_EID_SSID: 54737ffc8daSJohannes Berg elems->ssid = pos; 54837ffc8daSJohannes Berg elems->ssid_len = elen; 54937ffc8daSJohannes Berg break; 55037ffc8daSJohannes Berg case WLAN_EID_SUPP_RATES: 55137ffc8daSJohannes Berg elems->supp_rates = pos; 55237ffc8daSJohannes Berg elems->supp_rates_len = elen; 55337ffc8daSJohannes Berg break; 55437ffc8daSJohannes Berg case WLAN_EID_FH_PARAMS: 55537ffc8daSJohannes Berg elems->fh_params = pos; 55637ffc8daSJohannes Berg elems->fh_params_len = elen; 55737ffc8daSJohannes Berg break; 55837ffc8daSJohannes Berg case WLAN_EID_DS_PARAMS: 55937ffc8daSJohannes Berg elems->ds_params = pos; 56037ffc8daSJohannes Berg elems->ds_params_len = elen; 56137ffc8daSJohannes Berg break; 56237ffc8daSJohannes Berg case WLAN_EID_CF_PARAMS: 56337ffc8daSJohannes Berg elems->cf_params = pos; 56437ffc8daSJohannes Berg elems->cf_params_len = elen; 56537ffc8daSJohannes Berg break; 56637ffc8daSJohannes Berg case WLAN_EID_TIM: 567e7ec86f5SJohannes Berg if (elen >= sizeof(struct ieee80211_tim_ie)) { 568e7ec86f5SJohannes Berg elems->tim = (void *)pos; 56937ffc8daSJohannes Berg elems->tim_len = elen; 570e7ec86f5SJohannes Berg } 57137ffc8daSJohannes Berg break; 57237ffc8daSJohannes Berg case WLAN_EID_IBSS_PARAMS: 57337ffc8daSJohannes Berg elems->ibss_params = pos; 57437ffc8daSJohannes Berg elems->ibss_params_len = elen; 57537ffc8daSJohannes Berg break; 57637ffc8daSJohannes Berg case WLAN_EID_CHALLENGE: 57737ffc8daSJohannes Berg elems->challenge = pos; 57837ffc8daSJohannes Berg elems->challenge_len = elen; 57937ffc8daSJohannes Berg break; 580d91f36dbSJohannes Berg case WLAN_EID_VENDOR_SPECIFIC: 58137ffc8daSJohannes Berg if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 && 58237ffc8daSJohannes Berg pos[2] == 0xf2) { 58337ffc8daSJohannes Berg /* Microsoft OUI (00:50:F2) */ 584d91f36dbSJohannes Berg 585d91f36dbSJohannes Berg if (calc_crc) 586d91f36dbSJohannes Berg crc = crc32_be(crc, pos - 2, elen + 2); 587d91f36dbSJohannes Berg 58837ffc8daSJohannes Berg if (pos[3] == 1) { 58937ffc8daSJohannes Berg /* OUI Type 1 - WPA IE */ 59037ffc8daSJohannes Berg elems->wpa = pos; 59137ffc8daSJohannes Berg elems->wpa_len = elen; 59237ffc8daSJohannes Berg } else if (elen >= 5 && pos[3] == 2) { 593d91f36dbSJohannes Berg /* OUI Type 2 - WMM IE */ 59437ffc8daSJohannes Berg if (pos[4] == 0) { 59537ffc8daSJohannes Berg elems->wmm_info = pos; 59637ffc8daSJohannes Berg elems->wmm_info_len = elen; 59737ffc8daSJohannes Berg } else if (pos[4] == 1) { 59837ffc8daSJohannes Berg elems->wmm_param = pos; 59937ffc8daSJohannes Berg elems->wmm_param_len = elen; 60037ffc8daSJohannes Berg } 60137ffc8daSJohannes Berg } 60237ffc8daSJohannes Berg } 60337ffc8daSJohannes Berg break; 60437ffc8daSJohannes Berg case WLAN_EID_RSN: 60537ffc8daSJohannes Berg elems->rsn = pos; 60637ffc8daSJohannes Berg elems->rsn_len = elen; 60737ffc8daSJohannes Berg break; 60837ffc8daSJohannes Berg case WLAN_EID_ERP_INFO: 60937ffc8daSJohannes Berg elems->erp_info = pos; 61037ffc8daSJohannes Berg elems->erp_info_len = elen; 61137ffc8daSJohannes Berg break; 61237ffc8daSJohannes Berg case WLAN_EID_EXT_SUPP_RATES: 61337ffc8daSJohannes Berg elems->ext_supp_rates = pos; 61437ffc8daSJohannes Berg elems->ext_supp_rates_len = elen; 61537ffc8daSJohannes Berg break; 61637ffc8daSJohannes Berg case WLAN_EID_HT_CAPABILITY: 61709914813SJohannes Berg if (elen >= sizeof(struct ieee80211_ht_cap)) 61809914813SJohannes Berg elems->ht_cap_elem = (void *)pos; 61937ffc8daSJohannes Berg break; 620d9fe60deSJohannes Berg case WLAN_EID_HT_INFORMATION: 621d9fe60deSJohannes Berg if (elen >= sizeof(struct ieee80211_ht_info)) 62209914813SJohannes Berg elems->ht_info_elem = (void *)pos; 62337ffc8daSJohannes Berg break; 62437ffc8daSJohannes Berg case WLAN_EID_MESH_ID: 62537ffc8daSJohannes Berg elems->mesh_id = pos; 62637ffc8daSJohannes Berg elems->mesh_id_len = elen; 62737ffc8daSJohannes Berg break; 62837ffc8daSJohannes Berg case WLAN_EID_MESH_CONFIG: 62937ffc8daSJohannes Berg elems->mesh_config = pos; 63037ffc8daSJohannes Berg elems->mesh_config_len = elen; 63137ffc8daSJohannes Berg break; 63237ffc8daSJohannes Berg case WLAN_EID_PEER_LINK: 63337ffc8daSJohannes Berg elems->peer_link = pos; 63437ffc8daSJohannes Berg elems->peer_link_len = elen; 63537ffc8daSJohannes Berg break; 63637ffc8daSJohannes Berg case WLAN_EID_PREQ: 63737ffc8daSJohannes Berg elems->preq = pos; 63837ffc8daSJohannes Berg elems->preq_len = elen; 63937ffc8daSJohannes Berg break; 64037ffc8daSJohannes Berg case WLAN_EID_PREP: 64137ffc8daSJohannes Berg elems->prep = pos; 64237ffc8daSJohannes Berg elems->prep_len = elen; 64337ffc8daSJohannes Berg break; 64437ffc8daSJohannes Berg case WLAN_EID_PERR: 64537ffc8daSJohannes Berg elems->perr = pos; 64637ffc8daSJohannes Berg elems->perr_len = elen; 64737ffc8daSJohannes Berg break; 64837ffc8daSJohannes Berg case WLAN_EID_CHANNEL_SWITCH: 64937ffc8daSJohannes Berg elems->ch_switch_elem = pos; 65037ffc8daSJohannes Berg elems->ch_switch_elem_len = elen; 65137ffc8daSJohannes Berg break; 65237ffc8daSJohannes Berg case WLAN_EID_QUIET: 65337ffc8daSJohannes Berg if (!elems->quiet_elem) { 65437ffc8daSJohannes Berg elems->quiet_elem = pos; 65537ffc8daSJohannes Berg elems->quiet_elem_len = elen; 65637ffc8daSJohannes Berg } 65737ffc8daSJohannes Berg elems->num_of_quiet_elem++; 65837ffc8daSJohannes Berg break; 65937ffc8daSJohannes Berg case WLAN_EID_COUNTRY: 66037ffc8daSJohannes Berg elems->country_elem = pos; 66137ffc8daSJohannes Berg elems->country_elem_len = elen; 66237ffc8daSJohannes Berg break; 66337ffc8daSJohannes Berg case WLAN_EID_PWR_CONSTRAINT: 66437ffc8daSJohannes Berg elems->pwr_constr_elem = pos; 66537ffc8daSJohannes Berg elems->pwr_constr_elem_len = elen; 66637ffc8daSJohannes Berg break; 667f797eb7eSJouni Malinen case WLAN_EID_TIMEOUT_INTERVAL: 668f797eb7eSJouni Malinen elems->timeout_int = pos; 669f797eb7eSJouni Malinen elems->timeout_int_len = elen; 67063a5ab82SJouni Malinen break; 67137ffc8daSJohannes Berg default: 67237ffc8daSJohannes Berg break; 67337ffc8daSJohannes Berg } 67437ffc8daSJohannes Berg 67537ffc8daSJohannes Berg left -= elen; 67637ffc8daSJohannes Berg pos += elen; 67737ffc8daSJohannes Berg } 678d91f36dbSJohannes Berg 679d91f36dbSJohannes Berg return crc; 68037ffc8daSJohannes Berg } 6815825fe10SJohannes Berg 6825825fe10SJohannes Berg void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata) 6835825fe10SJohannes Berg { 6845825fe10SJohannes Berg struct ieee80211_local *local = sdata->local; 6855825fe10SJohannes Berg struct ieee80211_tx_queue_params qparam; 686aa837e1dSJohannes Berg int queue; 687aa837e1dSJohannes Berg bool use_11b; 688aa837e1dSJohannes Berg int aCWmin, aCWmax; 6895825fe10SJohannes Berg 6905825fe10SJohannes Berg if (!local->ops->conf_tx) 6915825fe10SJohannes Berg return; 6925825fe10SJohannes Berg 6935825fe10SJohannes Berg memset(&qparam, 0, sizeof(qparam)); 6945825fe10SJohannes Berg 695aa837e1dSJohannes Berg use_11b = (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) && 696aa837e1dSJohannes Berg !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE); 6975825fe10SJohannes Berg 698aa837e1dSJohannes Berg for (queue = 0; queue < local_to_hw(local)->queues; queue++) { 699aa837e1dSJohannes Berg /* Set defaults according to 802.11-2007 Table 7-37 */ 700aa837e1dSJohannes Berg aCWmax = 1023; 701aa837e1dSJohannes Berg if (use_11b) 702aa837e1dSJohannes Berg aCWmin = 31; 7035825fe10SJohannes Berg else 704aa837e1dSJohannes Berg aCWmin = 15; 7055825fe10SJohannes Berg 706aa837e1dSJohannes Berg switch (queue) { 707aa837e1dSJohannes Berg case 3: /* AC_BK */ 7087ba10a8eSJohannes Berg qparam.cw_max = aCWmax; 7097ba10a8eSJohannes Berg qparam.cw_min = aCWmin; 7105825fe10SJohannes Berg qparam.txop = 0; 711aa837e1dSJohannes Berg qparam.aifs = 7; 712aa837e1dSJohannes Berg break; 713aa837e1dSJohannes Berg default: /* never happens but let's not leave undefined */ 714aa837e1dSJohannes Berg case 2: /* AC_BE */ 7157ba10a8eSJohannes Berg qparam.cw_max = aCWmax; 7167ba10a8eSJohannes Berg qparam.cw_min = aCWmin; 717aa837e1dSJohannes Berg qparam.txop = 0; 718aa837e1dSJohannes Berg qparam.aifs = 3; 719aa837e1dSJohannes Berg break; 720aa837e1dSJohannes Berg case 1: /* AC_VI */ 721aa837e1dSJohannes Berg qparam.cw_max = aCWmin; 722aa837e1dSJohannes Berg qparam.cw_min = (aCWmin + 1) / 2 - 1; 723aa837e1dSJohannes Berg if (use_11b) 724aa837e1dSJohannes Berg qparam.txop = 6016/32; 725aa837e1dSJohannes Berg else 726aa837e1dSJohannes Berg qparam.txop = 3008/32; 727aa837e1dSJohannes Berg qparam.aifs = 2; 728aa837e1dSJohannes Berg break; 729aa837e1dSJohannes Berg case 0: /* AC_VO */ 730aa837e1dSJohannes Berg qparam.cw_max = (aCWmin + 1) / 2 - 1; 731aa837e1dSJohannes Berg qparam.cw_min = (aCWmin + 1) / 4 - 1; 732aa837e1dSJohannes Berg if (use_11b) 733aa837e1dSJohannes Berg qparam.txop = 3264/32; 734aa837e1dSJohannes Berg else 735aa837e1dSJohannes Berg qparam.txop = 1504/32; 736aa837e1dSJohannes Berg qparam.aifs = 2; 737aa837e1dSJohannes Berg break; 738aa837e1dSJohannes Berg } 7395825fe10SJohannes Berg 740aa837e1dSJohannes Berg drv_conf_tx(local, queue, &qparam); 741aa837e1dSJohannes Berg } 7425825fe10SJohannes Berg } 743e50db65cSJohannes Berg 74446900298SJohannes Berg void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, 74546900298SJohannes Berg const size_t supp_rates_len, 74646900298SJohannes Berg const u8 *supp_rates) 74746900298SJohannes Berg { 74846900298SJohannes Berg struct ieee80211_local *local = sdata->local; 74946900298SJohannes Berg int i, have_higher_than_11mbit = 0; 75046900298SJohannes Berg 75146900298SJohannes Berg /* cf. IEEE 802.11 9.2.12 */ 75246900298SJohannes Berg for (i = 0; i < supp_rates_len; i++) 75346900298SJohannes Berg if ((supp_rates[i] & 0x7f) * 5 > 110) 75446900298SJohannes Berg have_higher_than_11mbit = 1; 75546900298SJohannes Berg 75646900298SJohannes Berg if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && 75746900298SJohannes Berg have_higher_than_11mbit) 75846900298SJohannes Berg sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; 75946900298SJohannes Berg else 76046900298SJohannes Berg sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; 76146900298SJohannes Berg 76246900298SJohannes Berg ieee80211_set_wmm_default(sdata); 76346900298SJohannes Berg } 76446900298SJohannes Berg 765881d948cSJohannes Berg u32 ieee80211_mandatory_rates(struct ieee80211_local *local, 76696dd22acSJohannes Berg enum ieee80211_band band) 76796dd22acSJohannes Berg { 76896dd22acSJohannes Berg struct ieee80211_supported_band *sband; 76996dd22acSJohannes Berg struct ieee80211_rate *bitrates; 770881d948cSJohannes Berg u32 mandatory_rates; 77196dd22acSJohannes Berg enum ieee80211_rate_flags mandatory_flag; 77296dd22acSJohannes Berg int i; 77396dd22acSJohannes Berg 77496dd22acSJohannes Berg sband = local->hw.wiphy->bands[band]; 77596dd22acSJohannes Berg if (!sband) { 77696dd22acSJohannes Berg WARN_ON(1); 77796dd22acSJohannes Berg sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; 77896dd22acSJohannes Berg } 77996dd22acSJohannes Berg 78096dd22acSJohannes Berg if (band == IEEE80211_BAND_2GHZ) 78196dd22acSJohannes Berg mandatory_flag = IEEE80211_RATE_MANDATORY_B; 78296dd22acSJohannes Berg else 78396dd22acSJohannes Berg mandatory_flag = IEEE80211_RATE_MANDATORY_A; 78496dd22acSJohannes Berg 78596dd22acSJohannes Berg bitrates = sband->bitrates; 78696dd22acSJohannes Berg mandatory_rates = 0; 78796dd22acSJohannes Berg for (i = 0; i < sband->n_bitrates; i++) 78896dd22acSJohannes Berg if (bitrates[i].flags & mandatory_flag) 78996dd22acSJohannes Berg mandatory_rates |= BIT(i); 79096dd22acSJohannes Berg return mandatory_rates; 79196dd22acSJohannes Berg } 79246900298SJohannes Berg 79346900298SJohannes Berg void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, 79446900298SJohannes Berg u16 transaction, u16 auth_alg, 795fffd0934SJohannes Berg u8 *extra, size_t extra_len, const u8 *bssid, 796fffd0934SJohannes Berg const u8 *key, u8 key_len, u8 key_idx) 79746900298SJohannes Berg { 79846900298SJohannes Berg struct ieee80211_local *local = sdata->local; 79946900298SJohannes Berg struct sk_buff *skb; 80046900298SJohannes Berg struct ieee80211_mgmt *mgmt; 801fffd0934SJohannes Berg int err; 80246900298SJohannes Berg 80346900298SJohannes Berg skb = dev_alloc_skb(local->hw.extra_tx_headroom + 80465fc73acSJouni Malinen sizeof(*mgmt) + 6 + extra_len); 80546900298SJohannes Berg if (!skb) { 80646900298SJohannes Berg printk(KERN_DEBUG "%s: failed to allocate buffer for auth " 80746900298SJohannes Berg "frame\n", sdata->dev->name); 80846900298SJohannes Berg return; 80946900298SJohannes Berg } 81046900298SJohannes Berg skb_reserve(skb, local->hw.extra_tx_headroom); 81146900298SJohannes Berg 81246900298SJohannes Berg mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6); 81346900298SJohannes Berg memset(mgmt, 0, 24 + 6); 81446900298SJohannes Berg mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | 81546900298SJohannes Berg IEEE80211_STYPE_AUTH); 81646900298SJohannes Berg memcpy(mgmt->da, bssid, ETH_ALEN); 81746900298SJohannes Berg memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); 81846900298SJohannes Berg memcpy(mgmt->bssid, bssid, ETH_ALEN); 81946900298SJohannes Berg mgmt->u.auth.auth_alg = cpu_to_le16(auth_alg); 82046900298SJohannes Berg mgmt->u.auth.auth_transaction = cpu_to_le16(transaction); 82146900298SJohannes Berg mgmt->u.auth.status_code = cpu_to_le16(0); 82246900298SJohannes Berg if (extra) 82346900298SJohannes Berg memcpy(skb_put(skb, extra_len), extra, extra_len); 82446900298SJohannes Berg 825fffd0934SJohannes Berg if (auth_alg == WLAN_AUTH_SHARED_KEY && transaction == 3) { 826fffd0934SJohannes Berg mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); 827fffd0934SJohannes Berg err = ieee80211_wep_encrypt(local, skb, key, key_len, key_idx); 828fffd0934SJohannes Berg WARN_ON(err); 829fffd0934SJohannes Berg } 830fffd0934SJohannes Berg 831fffd0934SJohannes Berg ieee80211_tx_skb(sdata, skb, 0); 83246900298SJohannes Berg } 83346900298SJohannes Berg 834de95a54bSJohannes Berg int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, 835de95a54bSJohannes Berg const u8 *ie, size_t ie_len) 836de95a54bSJohannes Berg { 837de95a54bSJohannes Berg struct ieee80211_supported_band *sband; 838de95a54bSJohannes Berg u8 *pos, *supp_rates_len, *esupp_rates_len = NULL; 839de95a54bSJohannes Berg int i; 840de95a54bSJohannes Berg 841de95a54bSJohannes Berg sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; 842de95a54bSJohannes Berg 843de95a54bSJohannes Berg pos = buffer; 844de95a54bSJohannes Berg 845de95a54bSJohannes Berg *pos++ = WLAN_EID_SUPP_RATES; 846de95a54bSJohannes Berg supp_rates_len = pos; 847de95a54bSJohannes Berg *pos++ = 0; 848de95a54bSJohannes Berg 849de95a54bSJohannes Berg for (i = 0; i < sband->n_bitrates; i++) { 850de95a54bSJohannes Berg struct ieee80211_rate *rate = &sband->bitrates[i]; 851de95a54bSJohannes Berg 852de95a54bSJohannes Berg if (esupp_rates_len) { 853de95a54bSJohannes Berg *esupp_rates_len += 1; 854de95a54bSJohannes Berg } else if (*supp_rates_len == 8) { 855de95a54bSJohannes Berg *pos++ = WLAN_EID_EXT_SUPP_RATES; 856de95a54bSJohannes Berg esupp_rates_len = pos; 857de95a54bSJohannes Berg *pos++ = 1; 858de95a54bSJohannes Berg } else 859de95a54bSJohannes Berg *supp_rates_len += 1; 860de95a54bSJohannes Berg 861de95a54bSJohannes Berg *pos++ = rate->bitrate / 5; 862de95a54bSJohannes Berg } 863de95a54bSJohannes Berg 8645ef2d41aSJohannes Berg if (sband->ht_cap.ht_supported) { 8655ef2d41aSJohannes Berg __le16 tmp = cpu_to_le16(sband->ht_cap.cap); 8665ef2d41aSJohannes Berg 8675ef2d41aSJohannes Berg *pos++ = WLAN_EID_HT_CAPABILITY; 8685ef2d41aSJohannes Berg *pos++ = sizeof(struct ieee80211_ht_cap); 8695ef2d41aSJohannes Berg memset(pos, 0, sizeof(struct ieee80211_ht_cap)); 8705ef2d41aSJohannes Berg memcpy(pos, &tmp, sizeof(u16)); 8715ef2d41aSJohannes Berg pos += sizeof(u16); 8725ef2d41aSJohannes Berg /* TODO: needs a define here for << 2 */ 8735ef2d41aSJohannes Berg *pos++ = sband->ht_cap.ampdu_factor | 8745ef2d41aSJohannes Berg (sband->ht_cap.ampdu_density << 2); 8755ef2d41aSJohannes Berg memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); 8765ef2d41aSJohannes Berg pos += sizeof(sband->ht_cap.mcs); 8775ef2d41aSJohannes Berg pos += 2 + 4 + 1; /* ext info, BF cap, antsel */ 8785ef2d41aSJohannes Berg } 8795ef2d41aSJohannes Berg 880de95a54bSJohannes Berg /* 881de95a54bSJohannes Berg * If adding more here, adjust code in main.c 882de95a54bSJohannes Berg * that calculates local->scan_ies_len. 883de95a54bSJohannes Berg */ 884de95a54bSJohannes Berg 885de95a54bSJohannes Berg if (ie) { 886de95a54bSJohannes Berg memcpy(pos, ie, ie_len); 887de95a54bSJohannes Berg pos += ie_len; 888de95a54bSJohannes Berg } 889de95a54bSJohannes Berg 890de95a54bSJohannes Berg return pos - buffer; 891de95a54bSJohannes Berg } 892de95a54bSJohannes Berg 89346900298SJohannes Berg void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, 894de95a54bSJohannes Berg const u8 *ssid, size_t ssid_len, 895de95a54bSJohannes Berg const u8 *ie, size_t ie_len) 89646900298SJohannes Berg { 89746900298SJohannes Berg struct ieee80211_local *local = sdata->local; 89846900298SJohannes Berg struct sk_buff *skb; 89946900298SJohannes Berg struct ieee80211_mgmt *mgmt; 900de95a54bSJohannes Berg u8 *pos; 90146900298SJohannes Berg 90246900298SJohannes Berg skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 + 90365fc73acSJouni Malinen ie_len); 90446900298SJohannes Berg if (!skb) { 90546900298SJohannes Berg printk(KERN_DEBUG "%s: failed to allocate buffer for probe " 90646900298SJohannes Berg "request\n", sdata->dev->name); 90746900298SJohannes Berg return; 90846900298SJohannes Berg } 90946900298SJohannes Berg skb_reserve(skb, local->hw.extra_tx_headroom); 91046900298SJohannes Berg 91146900298SJohannes Berg mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); 91246900298SJohannes Berg memset(mgmt, 0, 24); 91346900298SJohannes Berg mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | 91446900298SJohannes Berg IEEE80211_STYPE_PROBE_REQ); 91546900298SJohannes Berg memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); 91646900298SJohannes Berg if (dst) { 91746900298SJohannes Berg memcpy(mgmt->da, dst, ETH_ALEN); 91846900298SJohannes Berg memcpy(mgmt->bssid, dst, ETH_ALEN); 91946900298SJohannes Berg } else { 92046900298SJohannes Berg memset(mgmt->da, 0xff, ETH_ALEN); 92146900298SJohannes Berg memset(mgmt->bssid, 0xff, ETH_ALEN); 92246900298SJohannes Berg } 92346900298SJohannes Berg pos = skb_put(skb, 2 + ssid_len); 92446900298SJohannes Berg *pos++ = WLAN_EID_SSID; 92546900298SJohannes Berg *pos++ = ssid_len; 92646900298SJohannes Berg memcpy(pos, ssid, ssid_len); 927de95a54bSJohannes Berg pos += ssid_len; 92846900298SJohannes Berg 929de95a54bSJohannes Berg skb_put(skb, ieee80211_build_preq_ies(local, pos, ie, ie_len)); 93046900298SJohannes Berg 93146900298SJohannes Berg ieee80211_tx_skb(sdata, skb, 0); 93246900298SJohannes Berg } 93346900298SJohannes Berg 93446900298SJohannes Berg u32 ieee80211_sta_get_rates(struct ieee80211_local *local, 93546900298SJohannes Berg struct ieee802_11_elems *elems, 93646900298SJohannes Berg enum ieee80211_band band) 93746900298SJohannes Berg { 93846900298SJohannes Berg struct ieee80211_supported_band *sband; 93946900298SJohannes Berg struct ieee80211_rate *bitrates; 94046900298SJohannes Berg size_t num_rates; 94146900298SJohannes Berg u32 supp_rates; 94246900298SJohannes Berg int i, j; 94346900298SJohannes Berg sband = local->hw.wiphy->bands[band]; 94446900298SJohannes Berg 94546900298SJohannes Berg if (!sband) { 94646900298SJohannes Berg WARN_ON(1); 94746900298SJohannes Berg sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; 94846900298SJohannes Berg } 94946900298SJohannes Berg 95046900298SJohannes Berg bitrates = sband->bitrates; 95146900298SJohannes Berg num_rates = sband->n_bitrates; 95246900298SJohannes Berg supp_rates = 0; 95346900298SJohannes Berg for (i = 0; i < elems->supp_rates_len + 95446900298SJohannes Berg elems->ext_supp_rates_len; i++) { 95546900298SJohannes Berg u8 rate = 0; 95646900298SJohannes Berg int own_rate; 95746900298SJohannes Berg if (i < elems->supp_rates_len) 95846900298SJohannes Berg rate = elems->supp_rates[i]; 95946900298SJohannes Berg else if (elems->ext_supp_rates) 96046900298SJohannes Berg rate = elems->ext_supp_rates 96146900298SJohannes Berg [i - elems->supp_rates_len]; 96246900298SJohannes Berg own_rate = 5 * (rate & 0x7f); 96346900298SJohannes Berg for (j = 0; j < num_rates; j++) 96446900298SJohannes Berg if (bitrates[j].bitrate == own_rate) 96546900298SJohannes Berg supp_rates |= BIT(j); 96646900298SJohannes Berg } 96746900298SJohannes Berg return supp_rates; 96846900298SJohannes Berg } 969f2753ddbSJohannes Berg 970f2753ddbSJohannes Berg int ieee80211_reconfig(struct ieee80211_local *local) 971f2753ddbSJohannes Berg { 972f2753ddbSJohannes Berg struct ieee80211_hw *hw = &local->hw; 973f2753ddbSJohannes Berg struct ieee80211_sub_if_data *sdata; 974f2753ddbSJohannes Berg struct ieee80211_if_init_conf conf; 975f2753ddbSJohannes Berg struct sta_info *sta; 976f2753ddbSJohannes Berg unsigned long flags; 977f2753ddbSJohannes Berg int res; 9785bb644a0SJohannes Berg bool from_suspend = local->suspended; 9795bb644a0SJohannes Berg 9805bb644a0SJohannes Berg /* 9815bb644a0SJohannes Berg * We're going to start the hardware, at that point 9825bb644a0SJohannes Berg * we are no longer suspended and can RX frames. 9835bb644a0SJohannes Berg */ 9845bb644a0SJohannes Berg local->suspended = false; 985f2753ddbSJohannes Berg 986f2753ddbSJohannes Berg /* restart hardware */ 987f2753ddbSJohannes Berg if (local->open_count) { 98824487981SJohannes Berg res = drv_start(local); 989f2753ddbSJohannes Berg 9901f87f7d3SJohannes Berg ieee80211_led_radio(local, true); 991f2753ddbSJohannes Berg } 992f2753ddbSJohannes Berg 993f2753ddbSJohannes Berg /* add interfaces */ 994f2753ddbSJohannes Berg list_for_each_entry(sdata, &local->interfaces, list) { 995f2753ddbSJohannes Berg if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && 996f2753ddbSJohannes Berg sdata->vif.type != NL80211_IFTYPE_MONITOR && 997f2753ddbSJohannes Berg netif_running(sdata->dev)) { 998f2753ddbSJohannes Berg conf.vif = &sdata->vif; 999f2753ddbSJohannes Berg conf.type = sdata->vif.type; 1000f2753ddbSJohannes Berg conf.mac_addr = sdata->dev->dev_addr; 100124487981SJohannes Berg res = drv_add_interface(local, &conf); 1002f2753ddbSJohannes Berg } 1003f2753ddbSJohannes Berg } 1004f2753ddbSJohannes Berg 1005f2753ddbSJohannes Berg /* add STAs back */ 1006f2753ddbSJohannes Berg if (local->ops->sta_notify) { 1007f2753ddbSJohannes Berg spin_lock_irqsave(&local->sta_lock, flags); 1008f2753ddbSJohannes Berg list_for_each_entry(sta, &local->sta_list, list) { 10095bb644a0SJohannes Berg sdata = sta->sdata; 1010f2753ddbSJohannes Berg if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) 1011f2753ddbSJohannes Berg sdata = container_of(sdata->bss, 1012f2753ddbSJohannes Berg struct ieee80211_sub_if_data, 1013f2753ddbSJohannes Berg u.ap); 1014f2753ddbSJohannes Berg 101524487981SJohannes Berg drv_sta_notify(local, &sdata->vif, STA_NOTIFY_ADD, 101624487981SJohannes Berg &sta->sta); 1017f2753ddbSJohannes Berg } 1018f2753ddbSJohannes Berg spin_unlock_irqrestore(&local->sta_lock, flags); 1019f2753ddbSJohannes Berg } 1020f2753ddbSJohannes Berg 1021f2753ddbSJohannes Berg /* Clear Suspend state so that ADDBA requests can be processed */ 1022f2753ddbSJohannes Berg 1023f2753ddbSJohannes Berg rcu_read_lock(); 1024f2753ddbSJohannes Berg 1025f2753ddbSJohannes Berg if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { 1026f2753ddbSJohannes Berg list_for_each_entry_rcu(sta, &local->sta_list, list) { 1027f2753ddbSJohannes Berg clear_sta_flags(sta, WLAN_STA_SUSPEND); 1028f2753ddbSJohannes Berg } 1029f2753ddbSJohannes Berg } 1030f2753ddbSJohannes Berg 1031f2753ddbSJohannes Berg rcu_read_unlock(); 1032f2753ddbSJohannes Berg 1033f2753ddbSJohannes Berg /* setup RTS threshold */ 103424487981SJohannes Berg drv_set_rts_threshold(local, hw->wiphy->rts_threshold); 1035f2753ddbSJohannes Berg 1036f2753ddbSJohannes Berg /* reconfigure hardware */ 1037f2753ddbSJohannes Berg ieee80211_hw_config(local, ~0); 1038f2753ddbSJohannes Berg 10393b8d81e0SJohannes Berg spin_lock_bh(&local->filter_lock); 1040f2753ddbSJohannes Berg ieee80211_configure_filter(local); 10413b8d81e0SJohannes Berg spin_unlock_bh(&local->filter_lock); 1042f2753ddbSJohannes Berg 1043f2753ddbSJohannes Berg /* Finally also reconfigure all the BSS information */ 1044f2753ddbSJohannes Berg list_for_each_entry(sdata, &local->interfaces, list) { 1045f2753ddbSJohannes Berg u32 changed = ~0; 1046f2753ddbSJohannes Berg if (!netif_running(sdata->dev)) 1047f2753ddbSJohannes Berg continue; 1048f2753ddbSJohannes Berg switch (sdata->vif.type) { 1049f2753ddbSJohannes Berg case NL80211_IFTYPE_STATION: 1050f2753ddbSJohannes Berg /* disable beacon change bits */ 10512d0ddec5SJohannes Berg changed &= ~(BSS_CHANGED_BEACON | 10522d0ddec5SJohannes Berg BSS_CHANGED_BEACON_ENABLED); 1053f2753ddbSJohannes Berg /* fall through */ 1054f2753ddbSJohannes Berg case NL80211_IFTYPE_ADHOC: 1055f2753ddbSJohannes Berg case NL80211_IFTYPE_AP: 1056f2753ddbSJohannes Berg case NL80211_IFTYPE_MESH_POINT: 10572d0ddec5SJohannes Berg ieee80211_bss_info_change_notify(sdata, changed); 1058f2753ddbSJohannes Berg break; 1059f2753ddbSJohannes Berg case NL80211_IFTYPE_WDS: 1060f2753ddbSJohannes Berg break; 1061f2753ddbSJohannes Berg case NL80211_IFTYPE_AP_VLAN: 1062f2753ddbSJohannes Berg case NL80211_IFTYPE_MONITOR: 1063f2753ddbSJohannes Berg /* ignore virtual */ 1064f2753ddbSJohannes Berg break; 1065f2753ddbSJohannes Berg case NL80211_IFTYPE_UNSPECIFIED: 1066f2753ddbSJohannes Berg case __NL80211_IFTYPE_AFTER_LAST: 1067f2753ddbSJohannes Berg WARN_ON(1); 1068f2753ddbSJohannes Berg break; 1069f2753ddbSJohannes Berg } 1070f2753ddbSJohannes Berg } 1071f2753ddbSJohannes Berg 1072f2753ddbSJohannes Berg /* add back keys */ 1073f2753ddbSJohannes Berg list_for_each_entry(sdata, &local->interfaces, list) 1074f2753ddbSJohannes Berg if (netif_running(sdata->dev)) 1075f2753ddbSJohannes Berg ieee80211_enable_keys(sdata); 1076f2753ddbSJohannes Berg 1077f2753ddbSJohannes Berg ieee80211_wake_queues_by_reason(hw, 1078f2753ddbSJohannes Berg IEEE80211_QUEUE_STOP_REASON_SUSPEND); 1079f2753ddbSJohannes Berg 10805bb644a0SJohannes Berg /* 10815bb644a0SJohannes Berg * If this is for hw restart things are still running. 10825bb644a0SJohannes Berg * We may want to change that later, however. 10835bb644a0SJohannes Berg */ 10845bb644a0SJohannes Berg if (!from_suspend) 10855bb644a0SJohannes Berg return 0; 10865bb644a0SJohannes Berg 10875bb644a0SJohannes Berg #ifdef CONFIG_PM 10885bb644a0SJohannes Berg local->suspended = false; 10895bb644a0SJohannes Berg 10905bb644a0SJohannes Berg list_for_each_entry(sdata, &local->interfaces, list) { 10915bb644a0SJohannes Berg switch(sdata->vif.type) { 10925bb644a0SJohannes Berg case NL80211_IFTYPE_STATION: 10935bb644a0SJohannes Berg ieee80211_sta_restart(sdata); 10945bb644a0SJohannes Berg break; 10955bb644a0SJohannes Berg case NL80211_IFTYPE_ADHOC: 10965bb644a0SJohannes Berg ieee80211_ibss_restart(sdata); 10975bb644a0SJohannes Berg break; 10985bb644a0SJohannes Berg case NL80211_IFTYPE_MESH_POINT: 10995bb644a0SJohannes Berg ieee80211_mesh_restart(sdata); 11005bb644a0SJohannes Berg break; 11015bb644a0SJohannes Berg default: 11025bb644a0SJohannes Berg break; 11035bb644a0SJohannes Berg } 11045bb644a0SJohannes Berg } 11055bb644a0SJohannes Berg 11065bb644a0SJohannes Berg add_timer(&local->sta_cleanup); 11075bb644a0SJohannes Berg 11085bb644a0SJohannes Berg spin_lock_irqsave(&local->sta_lock, flags); 11095bb644a0SJohannes Berg list_for_each_entry(sta, &local->sta_list, list) 11105bb644a0SJohannes Berg mesh_plink_restart(sta); 11115bb644a0SJohannes Berg spin_unlock_irqrestore(&local->sta_lock, flags); 11125bb644a0SJohannes Berg #else 11135bb644a0SJohannes Berg WARN_ON(1); 11145bb644a0SJohannes Berg #endif 1115f2753ddbSJohannes Berg return 0; 1116f2753ddbSJohannes Berg } 1117