diff --git a/Documentation/DocBook/mac80211.tmpl b/Documentation/DocBook/mac80211.tmpl
index b651e0a4b1c0..77c3c202991b 100644
--- a/Documentation/DocBook/mac80211.tmpl
+++ b/Documentation/DocBook/mac80211.tmpl
@@ -145,7 +145,6 @@ usage should require reading the full document.
this though and the recommendation to allow only a single
interface in STA mode at first!
-!Finclude/net/mac80211.h ieee80211_if_types
!Finclude/net/mac80211.h ieee80211_if_init_conf
!Finclude/net/mac80211.h ieee80211_if_conf
@@ -177,8 +176,7 @@ usage should require reading the full document.
functions/definitions
!Finclude/net/mac80211.h ieee80211_rx_status
!Finclude/net/mac80211.h mac80211_rx_flags
-!Finclude/net/mac80211.h ieee80211_tx_control
-!Finclude/net/mac80211.h ieee80211_tx_status_flags
+!Finclude/net/mac80211.h ieee80211_tx_info
!Finclude/net/mac80211.h ieee80211_rx
!Finclude/net/mac80211.h ieee80211_rx_irqsafe
!Finclude/net/mac80211.h ieee80211_tx_status
@@ -189,12 +187,11 @@ usage should require reading the full document.
!Finclude/net/mac80211.h ieee80211_ctstoself_duration
!Finclude/net/mac80211.h ieee80211_generic_frame_duration
!Finclude/net/mac80211.h ieee80211_get_hdrlen_from_skb
-!Finclude/net/mac80211.h ieee80211_get_hdrlen
+!Finclude/net/mac80211.h ieee80211_hdrlen
!Finclude/net/mac80211.h ieee80211_wake_queue
!Finclude/net/mac80211.h ieee80211_stop_queue
-!Finclude/net/mac80211.h ieee80211_start_queues
-!Finclude/net/mac80211.h ieee80211_stop_queues
!Finclude/net/mac80211.h ieee80211_wake_queues
+!Finclude/net/mac80211.h ieee80211_stop_queues
@@ -230,8 +227,7 @@ usage should require reading the full document.
Multiple queues and QoS support
TBD
!Finclude/net/mac80211.h ieee80211_tx_queue_params
-!Finclude/net/mac80211.h ieee80211_tx_queue_stats_data
-!Finclude/net/mac80211.h ieee80211_tx_queue
+!Finclude/net/mac80211.h ieee80211_tx_queue_stats
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index eb1a47b97427..c93fcdec246d 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -6,6 +6,24 @@ be removed from this file.
---------------------------
+What: old static regulatory information and ieee80211_regdom module parameter
+When: 2.6.29
+Why: The old regulatory infrastructure has been replaced with a new one
+ which does not require statically defined regulatory domains. We do
+ not want to keep static regulatory domains in the kernel due to the
+ the dynamic nature of regulatory law and localization. We kept around
+ the old static definitions for the regulatory domains of:
+ * US
+ * JP
+ * EU
+ and used by default the US when CONFIG_WIRELESS_OLD_REGULATORY was
+ set. We also kept around the ieee80211_regdom module parameter in case
+ some applications were relying on it. Changing regulatory domains
+ can now be done instead by using nl80211, as is done with iw.
+Who: Luis R. Rodriguez
+
+---------------------------
+
What: dev->power.power_state
When: July 2007
Why: Broken design for runtime control over driver power states, confusing
diff --git a/Documentation/networking/regulatory.txt b/Documentation/networking/regulatory.txt
new file mode 100644
index 000000000000..a96989a8ff35
--- /dev/null
+++ b/Documentation/networking/regulatory.txt
@@ -0,0 +1,194 @@
+Linux wireless regulatory documentation
+---------------------------------------
+
+This document gives a brief review over how the Linux wireless
+regulatory infrastructure works.
+
+More up to date information can be obtained at the project's web page:
+
+http://wireless.kernel.org/en/developers/Regulatory
+
+Keeping regulatory domains in userspace
+---------------------------------------
+
+Due to the dynamic nature of regulatory domains we keep them
+in userspace and provide a framework for userspace to upload
+to the kernel one regulatory domain to be used as the central
+core regulatory domain all wireless devices should adhere to.
+
+How to get regulatory domains to the kernel
+-------------------------------------------
+
+Userspace gets a regulatory domain in the kernel by having
+a userspace agent build it and send it via nl80211. Only
+expected regulatory domains will be respected by the kernel.
+
+A currently available userspace agent which can accomplish this
+is CRDA - central regulatory domain agent. Its documented here:
+
+http://wireless.kernel.org/en/developers/Regulatory/CRDA
+
+Essentially the kernel will send a udev event when it knows
+it needs a new regulatory domain. A udev rule can be put in place
+to trigger crda to send the respective regulatory domain for a
+specific ISO/IEC 3166 alpha2.
+
+Below is an example udev rule which can be used:
+
+# Example file, should be put in /etc/udev/rules.d/regulatory.rules
+KERNEL=="regulatory*", ACTION=="change", SUBSYSTEM=="platform", RUN+="/sbin/crda"
+
+The alpha2 is passed as an environment variable under the variable COUNTRY.
+
+Who asks for regulatory domains?
+--------------------------------
+
+* Users
+
+Users can use iw:
+
+http://wireless.kernel.org/en/users/Documentation/iw
+
+An example:
+
+ # set regulatory domain to "Costa Rica"
+ iw reg set CR
+
+This will request the kernel to set the regulatory domain to
+the specificied alpha2. The kernel in turn will then ask userspace
+to provide a regulatory domain for the alpha2 specified by the user
+by sending a uevent.
+
+* Wireless subsystems for Country Information elements
+
+The kernel will send a uevent to inform userspace a new
+regulatory domain is required. More on this to be added
+as its integration is added.
+
+* Drivers
+
+If drivers determine they need a specific regulatory domain
+set they can inform the wireless core using regulatory_hint().
+They have two options -- they either provide an alpha2 so that
+crda can provide back a regulatory domain for that country or
+they can build their own regulatory domain based on internal
+custom knowledge so the wireless core can respect it.
+
+*Most* drivers will rely on the first mechanism of providing a
+regulatory hint with an alpha2. For these drivers there is an additional
+check that can be used to ensure compliance based on custom EEPROM
+regulatory data. This additional check can be used by drivers by
+registering on its struct wiphy a reg_notifier() callback. This notifier
+is called when the core's regulatory domain has been changed. The driver
+can use this to review the changes made and also review who made them
+(driver, user, country IE) and determine what to allow based on its
+internal EEPROM data. Devices drivers wishing to be capable of world
+roaming should use this callback. More on world roaming will be
+added to this document when its support is enabled.
+
+Device drivers who provide their own built regulatory domain
+do not need a callback as the channels registered by them are
+the only ones that will be allowed and therefore *additional*
+cannels cannot be enabled.
+
+Example code - drivers hinting an alpha2:
+------------------------------------------
+
+This example comes from the zd1211rw device driver. You can start
+by having a mapping of your device's EEPROM country/regulatory
+domain value to to a specific alpha2 as follows:
+
+static struct zd_reg_alpha2_map reg_alpha2_map[] = {
+ { ZD_REGDOMAIN_FCC, "US" },
+ { ZD_REGDOMAIN_IC, "CA" },
+ { ZD_REGDOMAIN_ETSI, "DE" }, /* Generic ETSI, use most restrictive */
+ { ZD_REGDOMAIN_JAPAN, "JP" },
+ { ZD_REGDOMAIN_JAPAN_ADD, "JP" },
+ { ZD_REGDOMAIN_SPAIN, "ES" },
+ { ZD_REGDOMAIN_FRANCE, "FR" },
+
+Then you can define a routine to map your read EEPROM value to an alpha2,
+as follows:
+
+static int zd_reg2alpha2(u8 regdomain, char *alpha2)
+{
+ unsigned int i;
+ struct zd_reg_alpha2_map *reg_map;
+ for (i = 0; i < ARRAY_SIZE(reg_alpha2_map); i++) {
+ reg_map = ®_alpha2_map[i];
+ if (regdomain == reg_map->reg) {
+ alpha2[0] = reg_map->alpha2[0];
+ alpha2[1] = reg_map->alpha2[1];
+ return 0;
+ }
+ }
+ return 1;
+}
+
+Lastly, you can then hint to the core of your discovered alpha2, if a match
+was found. You need to do this after you have registered your wiphy. You
+are expected to do this during initialization.
+
+ r = zd_reg2alpha2(mac->regdomain, alpha2);
+ if (!r)
+ regulatory_hint(hw->wiphy, alpha2, NULL);
+
+Example code - drivers providing a built in regulatory domain:
+--------------------------------------------------------------
+
+If you have regulatory information you can obtain from your
+driver and you *need* to use this we let you build a regulatory domain
+structure and pass it to the wireless core. To do this you should
+kmalloc() a structure big enough to hold your regulatory domain
+structure and you should then fill it with your data. Finally you simply
+call regulatory_hint() with the regulatory domain structure in it.
+
+Bellow is a simple example, with a regulatory domain cached using the stack.
+Your implementation may vary (read EEPROM cache instead, for example).
+
+Example cache of some regulatory domain
+
+struct ieee80211_regdomain mydriver_jp_regdom = {
+ .n_reg_rules = 3,
+ .alpha2 = "JP",
+ //.alpha2 = "99", /* If I have no alpha2 to map it to */
+ .reg_rules = {
+ /* IEEE 802.11b/g, channels 1..14 */
+ REG_RULE(2412-20, 2484+20, 40, 6, 20, 0),
+ /* IEEE 802.11a, channels 34..48 */
+ REG_RULE(5170-20, 5240+20, 40, 6, 20,
+ NL80211_RRF_PASSIVE_SCAN),
+ /* IEEE 802.11a, channels 52..64 */
+ REG_RULE(5260-20, 5320+20, 40, 6, 20,
+ NL80211_RRF_NO_IBSS |
+ NL80211_RRF_DFS),
+ }
+};
+
+Then in some part of your code after your wiphy has been registered:
+
+ int r;
+ struct ieee80211_regdomain *rd;
+ int size_of_regd;
+ int num_rules = mydriver_jp_regdom.n_reg_rules;
+ unsigned int i;
+
+ size_of_regd = sizeof(struct ieee80211_regdomain) +
+ (num_rules * sizeof(struct ieee80211_reg_rule));
+
+ rd = kzalloc(size_of_regd, GFP_KERNEL);
+ if (!rd)
+ return -ENOMEM;
+
+ memcpy(rd, &mydriver_jp_regdom, sizeof(struct ieee80211_regdomain));
+
+ for (i=0; i < num_rules; i++) {
+ memcpy(&rd->reg_rules[i], &mydriver_jp_regdom.reg_rules[i],
+ sizeof(struct ieee80211_reg_rule));
+ }
+ r = regulatory_hint(hw->wiphy, NULL, rd);
+ if (r) {
+ kfree(rd);
+ return r;
+ }
+
diff --git a/Documentation/rfkill.txt b/Documentation/rfkill.txt
index 6fcb3060dec5..b65f0799df48 100644
--- a/Documentation/rfkill.txt
+++ b/Documentation/rfkill.txt
@@ -341,6 +341,8 @@ key that does nothing by itself, as well as any hot key that is type-specific
3.1 Guidelines for wireless device drivers
------------------------------------------
+(in this text, rfkill->foo means the foo field of struct rfkill).
+
1. Each independent transmitter in a wireless device (usually there is only one
transmitter per device) should have a SINGLE rfkill class attached to it.
@@ -363,10 +365,32 @@ This rule exists because users of the rfkill subsystem expect to get (and set,
when possible) the overall transmitter rfkill state, not of a particular rfkill
line.
-5. During suspend, the rfkill class will attempt to soft-block the radio
-through a call to rfkill->toggle_radio, and will try to restore its previous
-state during resume. After a rfkill class is suspended, it will *not* call
-rfkill->toggle_radio until it is resumed.
+5. The wireless device driver MUST NOT leave the transmitter enabled during
+suspend and hibernation unless:
+
+ 5.1. The transmitter has to be enabled for some sort of functionality
+ like wake-on-wireless-packet or autonomous packed forwarding in a mesh
+ network, and that functionality is enabled for this suspend/hibernation
+ cycle.
+
+AND
+
+ 5.2. The device was not on a user-requested BLOCKED state before
+ the suspend (i.e. the driver must NOT unblock a device, not even
+ to support wake-on-wireless-packet or remain in the mesh).
+
+In other words, there is absolutely no allowed scenario where a driver can
+automatically take action to unblock a rfkill controller (obviously, this deals
+with scenarios where soft-blocking or both soft and hard blocking is happening.
+Scenarios where hardware rfkill lines are the only ones blocking the
+transmitter are outside of this rule, since the wireless device driver does not
+control its input hardware rfkill lines in the first place).
+
+6. During resume, rfkill will try to restore its previous state.
+
+7. After a rfkill class is suspended, it will *not* call rfkill->toggle_radio
+until it is resumed.
+
Example of a WLAN wireless driver connected to the rfkill subsystem:
--------------------------------------------------------------------
diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c
index c6a55cd12db9..b2c050b68890 100644
--- a/drivers/net/wireless/adm8211.c
+++ b/drivers/net/wireless/adm8211.c
@@ -765,11 +765,11 @@ static void adm8211_update_mode(struct ieee80211_hw *dev)
priv->soft_rx_crc = 0;
switch (priv->mode) {
- case IEEE80211_IF_TYPE_STA:
+ case NL80211_IFTYPE_STATION:
priv->nar &= ~(ADM8211_NAR_PR | ADM8211_NAR_EA);
priv->nar |= ADM8211_NAR_ST | ADM8211_NAR_SR;
break;
- case IEEE80211_IF_TYPE_IBSS:
+ case NL80211_IFTYPE_ADHOC:
priv->nar &= ~ADM8211_NAR_PR;
priv->nar |= ADM8211_NAR_EA | ADM8211_NAR_ST | ADM8211_NAR_SR;
@@ -777,7 +777,7 @@ static void adm8211_update_mode(struct ieee80211_hw *dev)
if (priv->pdev->revision >= ADM8211_REV_BA)
priv->soft_rx_crc = 1;
break;
- case IEEE80211_IF_TYPE_MNTR:
+ case NL80211_IFTYPE_MONITOR:
priv->nar &= ~(ADM8211_NAR_EA | ADM8211_NAR_ST);
priv->nar |= ADM8211_NAR_PR | ADM8211_NAR_SR;
break;
@@ -1410,11 +1410,11 @@ static int adm8211_add_interface(struct ieee80211_hw *dev,
struct ieee80211_if_init_conf *conf)
{
struct adm8211_priv *priv = dev->priv;
- if (priv->mode != IEEE80211_IF_TYPE_MNTR)
+ if (priv->mode != NL80211_IFTYPE_MONITOR)
return -EOPNOTSUPP;
switch (conf->type) {
- case IEEE80211_IF_TYPE_STA:
+ case NL80211_IFTYPE_STATION:
priv->mode = conf->type;
break;
default:
@@ -1437,7 +1437,7 @@ static void adm8211_remove_interface(struct ieee80211_hw *dev,
struct ieee80211_if_init_conf *conf)
{
struct adm8211_priv *priv = dev->priv;
- priv->mode = IEEE80211_IF_TYPE_MNTR;
+ priv->mode = NL80211_IFTYPE_MONITOR;
}
static int adm8211_init_rings(struct ieee80211_hw *dev)
@@ -1556,7 +1556,7 @@ static int adm8211_start(struct ieee80211_hw *dev)
ADM8211_CSR_WRITE(IER, ADM8211_IER_NIE | ADM8211_IER_AIE |
ADM8211_IER_RCIE | ADM8211_IER_TCIE |
ADM8211_IER_TDUIE | ADM8211_IER_GPTIE);
- priv->mode = IEEE80211_IF_TYPE_MNTR;
+ priv->mode = NL80211_IFTYPE_MONITOR;
adm8211_update_mode(dev);
ADM8211_CSR_WRITE(RDR, 0);
@@ -1571,7 +1571,7 @@ static void adm8211_stop(struct ieee80211_hw *dev)
{
struct adm8211_priv *priv = dev->priv;
- priv->mode = IEEE80211_IF_TYPE_INVALID;
+ priv->mode = NL80211_IFTYPE_UNSPECIFIED;
priv->nar = 0;
ADM8211_CSR_WRITE(NAR, 0);
ADM8211_CSR_WRITE(IER, 0);
@@ -1896,7 +1896,7 @@ static int __devinit adm8211_probe(struct pci_dev *pdev,
priv->tx_power = 0x40;
priv->lpf_cutoff = 0xFF;
priv->lnags_threshold = 0xFF;
- priv->mode = IEEE80211_IF_TYPE_INVALID;
+ priv->mode = NL80211_IFTYPE_UNSPECIFIED;
/* Power-on issue. EEPROM won't read correctly without */
if (pdev->revision >= ADM8211_REV_BA) {
@@ -1986,7 +1986,7 @@ static int adm8211_suspend(struct pci_dev *pdev, pm_message_t state)
struct ieee80211_hw *dev = pci_get_drvdata(pdev);
struct adm8211_priv *priv = dev->priv;
- if (priv->mode != IEEE80211_IF_TYPE_INVALID) {
+ if (priv->mode != NL80211_IFTYPE_UNSPECIFIED) {
ieee80211_stop_queues(dev);
adm8211_stop(dev);
}
@@ -2004,7 +2004,7 @@ static int adm8211_resume(struct pci_dev *pdev)
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
- if (priv->mode != IEEE80211_IF_TYPE_INVALID) {
+ if (priv->mode != NL80211_IFTYPE_UNSPECIFIED) {
adm8211_start(dev);
ieee80211_wake_queues(dev);
}
diff --git a/drivers/net/wireless/ath5k/ath5k.h b/drivers/net/wireless/ath5k/ath5k.h
index 4c0211798a7a..20018869051d 100644
--- a/drivers/net/wireless/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath5k/ath5k.h
@@ -1008,7 +1008,7 @@ struct ath5k_hw {
enum ath5k_int ah_imr;
- enum ieee80211_if_types ah_op_mode;
+ enum nl80211_iftype ah_op_mode;
enum ath5k_power_mode ah_power_mode;
struct ieee80211_channel ah_current_channel;
bool ah_turbo;
@@ -1117,7 +1117,7 @@ extern void ath5k_hw_detach(struct ath5k_hw *ah);
/* Reset Functions */
extern int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial);
-extern int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, struct ieee80211_channel *channel, bool change_channel);
+extern int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, struct ieee80211_channel *channel, bool change_channel);
/* Power management functions */
extern int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, bool set_chip, u16 sleep_duration);
diff --git a/drivers/net/wireless/ath5k/attach.c b/drivers/net/wireless/ath5k/attach.c
index 0eb2511fe147..153c4111fabe 100644
--- a/drivers/net/wireless/ath5k/attach.c
+++ b/drivers/net/wireless/ath5k/attach.c
@@ -124,7 +124,7 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
/*
* HW information
*/
- ah->ah_op_mode = IEEE80211_IF_TYPE_STA;
+ ah->ah_op_mode = NL80211_IFTYPE_STATION;
ah->ah_radar.r_enabled = AR5K_TUNE_RADAR_ALERT;
ah->ah_turbo = false;
ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER;
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c
index 85260c39aa2b..e09ed2ce6753 100644
--- a/drivers/net/wireless/ath5k/base.c
+++ b/drivers/net/wireless/ath5k/base.c
@@ -507,7 +507,7 @@ ath5k_pci_probe(struct pci_dev *pdev,
sc->iobase = mem; /* So we can unmap it on detach */
sc->cachelsz = csz * sizeof(u32); /* convert to bytes */
- sc->opmode = IEEE80211_IF_TYPE_STA;
+ sc->opmode = NL80211_IFTYPE_STATION;
mutex_init(&sc->lock);
spin_lock_init(&sc->rxbuflock);
spin_lock_init(&sc->txbuflock);
@@ -1377,8 +1377,8 @@ ath5k_beaconq_config(struct ath5k_softc *sc)
ret = ath5k_hw_get_tx_queueprops(ah, sc->bhalq, &qi);
if (ret)
return ret;
- if (sc->opmode == IEEE80211_IF_TYPE_AP ||
- sc->opmode == IEEE80211_IF_TYPE_MESH_POINT) {
+ if (sc->opmode == NL80211_IFTYPE_AP ||
+ sc->opmode == NL80211_IFTYPE_MESH_POINT) {
/*
* Always burst out beacon and CAB traffic
* (aifs = cwmin = cwmax = 0)
@@ -1386,7 +1386,7 @@ ath5k_beaconq_config(struct ath5k_softc *sc)
qi.tqi_aifs = 0;
qi.tqi_cw_min = 0;
qi.tqi_cw_max = 0;
- } else if (sc->opmode == IEEE80211_IF_TYPE_IBSS) {
+ } else if (sc->opmode == NL80211_IFTYPE_ADHOC) {
/*
* Adhoc mode; backoff between 0 and (2 * cw_min).
*/
@@ -1714,7 +1714,7 @@ ath5k_tasklet_rx(unsigned long data)
/* let crypto-error packets fall through in MNTR */
if ((rs.rs_status &
~(AR5K_RXERR_DECRYPT|AR5K_RXERR_MIC)) ||
- sc->opmode != IEEE80211_IF_TYPE_MNTR)
+ sc->opmode != NL80211_IFTYPE_MONITOR)
goto next;
}
accept:
@@ -1777,7 +1777,7 @@ accept:
ath5k_debug_dump_skb(sc, skb, "RX ", 0);
/* check beacons in IBSS mode */
- if (sc->opmode == IEEE80211_IF_TYPE_IBSS)
+ if (sc->opmode == NL80211_IFTYPE_ADHOC)
ath5k_check_ibss_tsf(sc, skb, &rxs);
__ieee80211_rx(sc->hw, skb, &rxs);
@@ -1892,7 +1892,7 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
ds = bf->desc;
flags = AR5K_TXDESC_NOACK;
- if (sc->opmode == IEEE80211_IF_TYPE_IBSS && ath5k_hw_hasveol(ah)) {
+ if (sc->opmode == NL80211_IFTYPE_ADHOC && ath5k_hw_hasveol(ah)) {
ds->ds_link = bf->daddr; /* self-linked */
flags |= AR5K_TXDESC_VEOL;
/*
@@ -1941,8 +1941,8 @@ ath5k_beacon_send(struct ath5k_softc *sc)
ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, "in beacon_send\n");
- if (unlikely(bf->skb == NULL || sc->opmode == IEEE80211_IF_TYPE_STA ||
- sc->opmode == IEEE80211_IF_TYPE_MNTR)) {
+ if (unlikely(bf->skb == NULL || sc->opmode == NL80211_IFTYPE_STATION ||
+ sc->opmode == NL80211_IFTYPE_MONITOR)) {
ATH5K_WARN(sc, "bf=%p bf_skb=%p\n", bf, bf ? bf->skb : NULL);
return;
}
@@ -2116,9 +2116,9 @@ ath5k_beacon_config(struct ath5k_softc *sc)
sc->bmisscount = 0;
sc->imask &= ~(AR5K_INT_BMISS | AR5K_INT_SWBA);
- if (sc->opmode == IEEE80211_IF_TYPE_STA) {
+ if (sc->opmode == NL80211_IFTYPE_STATION) {
sc->imask |= AR5K_INT_BMISS;
- } else if (sc->opmode == IEEE80211_IF_TYPE_IBSS) {
+ } else if (sc->opmode == NL80211_IFTYPE_ADHOC) {
/*
* In IBSS mode we use a self-linked tx descriptor and let the
* hardware send the beacons automatically. We have to load it
@@ -2323,7 +2323,7 @@ ath5k_intr(int irq, void *dev_id)
* transmission time) in order to detect wether
* automatic TSF updates happened.
*/
- if (sc->opmode == IEEE80211_IF_TYPE_IBSS) {
+ if (sc->opmode == NL80211_IFTYPE_ADHOC) {
/* XXX: only if VEOL suppported */
u64 tsf = ath5k_hw_get_tsf64(ah);
sc->nexttbtt += sc->bintval;
@@ -2553,7 +2553,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
ath5k_debug_dump_skb(sc, skb, "TX ", 1);
- if (sc->opmode == IEEE80211_IF_TYPE_MNTR)
+ if (sc->opmode == NL80211_IFTYPE_MONITOR)
ATH5K_DBG(sc, ATH5K_DEBUG_XMIT, "tx in monitor (scan?)\n");
/*
@@ -2688,9 +2688,9 @@ static int ath5k_add_interface(struct ieee80211_hw *hw,
sc->vif = conf->vif;
switch (conf->type) {
- case IEEE80211_IF_TYPE_STA:
- case IEEE80211_IF_TYPE_IBSS:
- case IEEE80211_IF_TYPE_MNTR:
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_MONITOR:
sc->opmode = conf->type;
break;
default:
@@ -2761,7 +2761,7 @@ ath5k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
}
if (conf->changed & IEEE80211_IFCC_BEACON &&
- vif->type == IEEE80211_IF_TYPE_IBSS) {
+ vif->type == NL80211_IFTYPE_ADHOC) {
struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
if (!beacon) {
ret = -ENOMEM;
@@ -2880,17 +2880,17 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw,
/* XXX move these to mac80211, and add a beacon IFF flag to mac80211 */
- if (sc->opmode == IEEE80211_IF_TYPE_MNTR)
+ if (sc->opmode == NL80211_IFTYPE_MONITOR)
rfilt |= AR5K_RX_FILTER_CONTROL | AR5K_RX_FILTER_BEACON |
AR5K_RX_FILTER_PROBEREQ | AR5K_RX_FILTER_PROM;
- if (sc->opmode != IEEE80211_IF_TYPE_STA)
+ if (sc->opmode != NL80211_IFTYPE_STATION)
rfilt |= AR5K_RX_FILTER_PROBEREQ;
- if (sc->opmode != IEEE80211_IF_TYPE_AP &&
- sc->opmode != IEEE80211_IF_TYPE_MESH_POINT &&
+ if (sc->opmode != NL80211_IFTYPE_AP &&
+ sc->opmode != NL80211_IFTYPE_MESH_POINT &&
test_bit(ATH_STAT_PROMISC, sc->status))
rfilt |= AR5K_RX_FILTER_PROM;
- if (sc->opmode == IEEE80211_IF_TYPE_STA ||
- sc->opmode == IEEE80211_IF_TYPE_IBSS) {
+ if (sc->opmode == NL80211_IFTYPE_STATION ||
+ sc->opmode == NL80211_IFTYPE_ADHOC) {
rfilt |= AR5K_RX_FILTER_BEACON;
}
@@ -2995,7 +2995,7 @@ ath5k_reset_tsf(struct ieee80211_hw *hw)
* in IBSS mode we need to update the beacon timers too.
* this will also reset the TSF if we call it with 0
*/
- if (sc->opmode == IEEE80211_IF_TYPE_IBSS)
+ if (sc->opmode == NL80211_IFTYPE_ADHOC)
ath5k_beacon_update_timers(sc, 0);
else
ath5k_hw_reset_tsf(sc->ah);
@@ -3010,7 +3010,7 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
ath5k_debug_dump_skb(sc, skb, "BC ", 1);
- if (sc->opmode != IEEE80211_IF_TYPE_IBSS) {
+ if (sc->opmode != NL80211_IFTYPE_ADHOC) {
ret = -EIO;
goto end;
}
diff --git a/drivers/net/wireless/ath5k/base.h b/drivers/net/wireless/ath5k/base.h
index 1549b63d6138..9d0b728928e3 100644
--- a/drivers/net/wireless/ath5k/base.h
+++ b/drivers/net/wireless/ath5k/base.h
@@ -113,7 +113,7 @@ struct ath5k_softc {
struct ieee80211_channel channels[ATH_CHAN_MAX];
struct ieee80211_rate rates[IEEE80211_NUM_BANDS][AR5K_MAX_RATES];
u8 rate_idx[IEEE80211_NUM_BANDS][AR5K_MAX_RATES];
- enum ieee80211_if_types opmode;
+ enum nl80211_iftype opmode;
struct ath5k_hw *ah; /* Atheros HW */
struct ieee80211_supported_band *curband;
diff --git a/drivers/net/wireless/ath5k/pcu.c b/drivers/net/wireless/ath5k/pcu.c
index 5a896d1e2a2b..c77cee2a5582 100644
--- a/drivers/net/wireless/ath5k/pcu.c
+++ b/drivers/net/wireless/ath5k/pcu.c
@@ -52,26 +52,26 @@ int ath5k_hw_set_opmode(struct ath5k_hw *ah)
ATH5K_TRACE(ah->ah_sc);
switch (ah->ah_op_mode) {
- case IEEE80211_IF_TYPE_IBSS:
+ case NL80211_IFTYPE_ADHOC:
pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_DESC_ANTENNA |
(ah->ah_version == AR5K_AR5210 ?
AR5K_STA_ID1_NO_PSPOLL : 0);
beacon_reg |= AR5K_BCR_ADHOC;
break;
- case IEEE80211_IF_TYPE_AP:
- case IEEE80211_IF_TYPE_MESH_POINT:
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_MESH_POINT:
pcu_reg |= AR5K_STA_ID1_AP | AR5K_STA_ID1_RTS_DEF_ANTENNA |
(ah->ah_version == AR5K_AR5210 ?
AR5K_STA_ID1_NO_PSPOLL : 0);
beacon_reg |= AR5K_BCR_AP;
break;
- case IEEE80211_IF_TYPE_STA:
+ case NL80211_IFTYPE_STATION:
pcu_reg |= AR5K_STA_ID1_DEFAULT_ANTENNA |
(ah->ah_version == AR5K_AR5210 ?
AR5K_STA_ID1_PWR_SV : 0);
- case IEEE80211_IF_TYPE_MNTR:
+ case NL80211_IFTYPE_MONITOR:
pcu_reg |= AR5K_STA_ID1_DEFAULT_ANTENNA |
(ah->ah_version == AR5K_AR5210 ?
AR5K_STA_ID1_NO_PSPOLL : 0);
@@ -649,7 +649,7 @@ void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval)
* Set the additional timers by mode
*/
switch (ah->ah_op_mode) {
- case IEEE80211_IF_TYPE_STA:
+ case NL80211_IFTYPE_STATION:
if (ah->ah_version == AR5K_AR5210) {
timer1 = 0xffffffff;
timer2 = 0xffffffff;
diff --git a/drivers/net/wireless/ath5k/reset.c b/drivers/net/wireless/ath5k/reset.c
index d260fba0180f..f5c3de890cdb 100644
--- a/drivers/net/wireless/ath5k/reset.c
+++ b/drivers/net/wireless/ath5k/reset.c
@@ -399,7 +399,7 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
/*
* Main reset function
*/
-int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode,
+int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
struct ieee80211_channel *channel, bool change_channel)
{
struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h
index 28b8d84f49b4..0e897c276858 100644
--- a/drivers/net/wireless/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath9k/ath9k.h
@@ -798,10 +798,11 @@ struct ath_hal {
struct ath9k_channel *ah_curchan;
u32 ah_nchan;
- u16 ah_rfsilent;
- bool ah_rfkillEnabled;
bool ah_isPciExpress;
u16 ah_txTrigLevel;
+ u16 ah_rfsilent;
+ u32 ah_rfkill_gpio;
+ u32 ah_rfkill_polarity;
#ifndef ATH_NF_PER_CHAN
struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS];
@@ -1003,4 +1004,6 @@ bool ath9k_get_channel_edges(struct ath_hal *ah,
void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio,
u32 ah_signal_type);
void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 value);
+u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio);
+void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio);
#endif
diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h
index 1faa1effa02c..b66de29cf662 100644
--- a/drivers/net/wireless/ath9k/core.h
+++ b/drivers/net/wireless/ath9k/core.h
@@ -40,6 +40,7 @@
#include
#include
#include
+#include
#include "ath9k.h"
#include "rc.h"
@@ -823,6 +824,15 @@ struct ath_led {
bool registered;
};
+/* Rfkill */
+#define ATH_RFKILL_POLL_INTERVAL 2000 /* msecs */
+
+struct ath_rfkill {
+ struct rfkill *rfkill;
+ struct delayed_work rfkill_poll;
+ char rfkill_name[32];
+};
+
/********************/
/* Main driver core */
/********************/
@@ -906,6 +916,9 @@ struct ath_ht_info {
#define SC_OP_PROTECT_ENABLE BIT(8)
#define SC_OP_RXFLUSH BIT(9)
#define SC_OP_LED_ASSOCIATED BIT(10)
+#define SC_OP_RFKILL_REGISTERED BIT(11)
+#define SC_OP_RFKILL_SW_BLOCKED BIT(12)
+#define SC_OP_RFKILL_HW_BLOCKED BIT(13)
struct ath_softc {
struct ieee80211_hw *hw;
@@ -1015,6 +1028,9 @@ struct ath_softc {
struct ath_led assoc_led;
struct ath_led tx_led;
struct ath_led rx_led;
+
+ /* Rfkill */
+ struct ath_rfkill rf_kill;
};
int ath_init(u16 devid, struct ath_softc *sc);
diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c
index 4ccbbc07cf1e..0251e59f2f84 100644
--- a/drivers/net/wireless/ath9k/hw.c
+++ b/drivers/net/wireless/ath9k/hw.c
@@ -2821,7 +2821,38 @@ void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 val)
AR_GPIO_BIT(gpio));
}
-static u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio)
+/*
+ * Configure GPIO Input lines
+ */
+void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio)
+{
+ u32 gpio_shift;
+
+ ASSERT(gpio < ah->ah_caps.num_gpio_pins);
+
+ gpio_shift = gpio << 1;
+
+ REG_RMW(ah,
+ AR_GPIO_OE_OUT,
+ (AR_GPIO_OE_OUT_DRV_NO << gpio_shift),
+ (AR_GPIO_OE_OUT_DRV << gpio_shift));
+}
+
+#ifdef CONFIG_RFKILL
+static void ath9k_enable_rfkill(struct ath_hal *ah)
+{
+ REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
+ AR_GPIO_INPUT_EN_VAL_RFSILENT_BB);
+
+ REG_CLR_BIT(ah, AR_GPIO_INPUT_MUX2,
+ AR_GPIO_INPUT_MUX2_RFSILENT);
+
+ ath9k_hw_cfg_gpio_input(ah, ah->ah_rfkill_gpio);
+ REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB);
+}
+#endif
+
+u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio)
{
if (gpio >= ah->ah_caps.num_gpio_pins)
return 0xffffffff;
@@ -3034,17 +3065,17 @@ static bool ath9k_hw_fill_cap_info(struct ath_hal *ah)
pCap->hw_caps |= ATH9K_HW_CAP_ENHANCEDPM;
+#ifdef CONFIG_RFKILL
ah->ah_rfsilent = ath9k_hw_get_eeprom(ahp, EEP_RF_SILENT);
if (ah->ah_rfsilent & EEP_RFSILENT_ENABLED) {
- ahp->ah_gpioSelect =
+ ah->ah_rfkill_gpio =
MS(ah->ah_rfsilent, EEP_RFSILENT_GPIO_SEL);
- ahp->ah_polarity =
+ ah->ah_rfkill_polarity =
MS(ah->ah_rfsilent, EEP_RFSILENT_POLARITY);
- ath9k_hw_setcapability(ah, ATH9K_CAP_RFSILENT, 1, true,
- NULL);
pCap->hw_caps |= ATH9K_HW_CAP_RFSILENT;
}
+#endif
if ((ah->ah_macVersion == AR_SREV_VERSION_5416_PCI) ||
(ah->ah_macVersion == AR_SREV_VERSION_5416_PCIE) ||
@@ -5961,6 +5992,10 @@ bool ath9k_hw_reset(struct ath_hal *ah,
ath9k_hw_init_interrupt_masks(ah, ah->ah_opmode);
ath9k_hw_init_qos(ah);
+#ifdef CONFIG_RFKILL
+ if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+ ath9k_enable_rfkill(ah);
+#endif
ath9k_hw_init_user_settings(ah);
REG_WRITE(ah, AR_STA_ID1,
@@ -6490,31 +6525,6 @@ ath9k_hw_setbssidmask(struct ath_hal *ah, const u8 *mask)
return true;
}
-#ifdef CONFIG_ATH9K_RFKILL
-static void ath9k_enable_rfkill(struct ath_hal *ah)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
-
- REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
- AR_GPIO_INPUT_EN_VAL_RFSILENT_BB);
-
- REG_CLR_BIT(ah, AR_GPIO_INPUT_MUX2,
- AR_GPIO_INPUT_MUX2_RFSILENT);
-
- ath9k_hw_cfg_gpio_input(ah, ahp->ah_gpioSelect);
- REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB);
-
- if (ahp->ah_gpioBit == ath9k_hw_gpio_get(ah, ahp->ah_gpioSelect)) {
-
- ath9k_hw_set_gpio_intr(ah, ahp->ah_gpioSelect,
- !ahp->ah_gpioBit);
- } else {
- ath9k_hw_set_gpio_intr(ah, ahp->ah_gpioSelect,
- ahp->ah_gpioBit);
- }
-}
-#endif
-
void
ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid,
u16 assocId)
diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c
index 57d7cc87cb0f..1ba18006f475 100644
--- a/drivers/net/wireless/ath9k/main.c
+++ b/drivers/net/wireless/ath9k/main.c
@@ -140,7 +140,7 @@ static int ath_key_config(struct ath_softc *sc,
struct ath9k_keyval hk;
const u8 *mac = NULL;
int ret = 0;
- enum ieee80211_if_types opmode;
+ enum nl80211_iftype opmode;
memset(&hk, 0, sizeof(hk));
@@ -179,14 +179,14 @@ static int ath_key_config(struct ath_softc *sc,
*/
if (is_broadcast_ether_addr(addr)) {
switch (opmode) {
- case IEEE80211_IF_TYPE_STA:
+ case NL80211_IFTYPE_STATION:
/* default key: could be group WPA key
* or could be static WEP key */
mac = NULL;
break;
- case IEEE80211_IF_TYPE_IBSS:
+ case NL80211_IFTYPE_ADHOC:
break;
- case IEEE80211_IF_TYPE_AP:
+ case NL80211_IFTYPE_AP:
break;
default:
ASSERT(0);
@@ -325,479 +325,6 @@ static u8 parse_mpdudensity(u8 mpdudensity)
}
}
-static int ath9k_start(struct ieee80211_hw *hw)
-{
- struct ath_softc *sc = hw->priv;
- struct ieee80211_channel *curchan = hw->conf.channel;
- int error = 0, pos;
-
- DPRINTF(sc, ATH_DBG_CONFIG, "%s: Starting driver with "
- "initial channel: %d MHz\n", __func__, curchan->center_freq);
-
- /* setup initial channel */
-
- pos = ath_get_channel(sc, curchan);
- if (pos == -1) {
- DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__);
- return -EINVAL;
- }
-
- sc->sc_ah->ah_channels[pos].chanmode =
- (curchan->band == IEEE80211_BAND_2GHZ) ? CHANNEL_G : CHANNEL_A;
-
- /* open ath_dev */
- error = ath_open(sc, &sc->sc_ah->ah_channels[pos]);
- if (error) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: Unable to complete ath_open\n", __func__);
- return error;
- }
-
- ieee80211_wake_queues(hw);
- return 0;
-}
-
-static int ath9k_tx(struct ieee80211_hw *hw,
- struct sk_buff *skb)
-{
- struct ath_softc *sc = hw->priv;
- int hdrlen, padsize;
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-
- /*
- * As a temporary workaround, assign seq# here; this will likely need
- * to be cleaned up to work better with Beacon transmission and virtual
- * BSSes.
- */
- if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
- if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
- sc->seq_no += 0x10;
- hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
- hdr->seq_ctrl |= cpu_to_le16(sc->seq_no);
- }
-
- /* Add the padding after the header if this is not already done */
- hdrlen = ieee80211_get_hdrlen_from_skb(skb);
- if (hdrlen & 3) {
- padsize = hdrlen % 4;
- if (skb_headroom(skb) < padsize)
- return -1;
- skb_push(skb, padsize);
- memmove(skb->data, skb->data + padsize, hdrlen);
- }
-
- DPRINTF(sc, ATH_DBG_XMIT, "%s: transmitting packet, skb: %p\n",
- __func__,
- skb);
-
- if (ath_tx_start(sc, skb) != 0) {
- DPRINTF(sc, ATH_DBG_XMIT, "%s: TX failed\n", __func__);
- dev_kfree_skb_any(skb);
- /* FIXME: Check for proper return value from ATH_DEV */
- return 0;
- }
-
- return 0;
-}
-
-static void ath9k_stop(struct ieee80211_hw *hw)
-{
- struct ath_softc *sc = hw->priv;
- int error;
-
- DPRINTF(sc, ATH_DBG_CONFIG, "%s: Driver halt\n", __func__);
-
- error = ath_suspend(sc);
- if (error)
- DPRINTF(sc, ATH_DBG_CONFIG,
- "%s: Device is no longer present\n", __func__);
-
- ieee80211_stop_queues(hw);
-}
-
-static int ath9k_add_interface(struct ieee80211_hw *hw,
- struct ieee80211_if_init_conf *conf)
-{
- struct ath_softc *sc = hw->priv;
- int error, ic_opmode = 0;
-
- /* Support only vap for now */
-
- if (sc->sc_nvaps)
- return -ENOBUFS;
-
- switch (conf->type) {
- case IEEE80211_IF_TYPE_STA:
- ic_opmode = ATH9K_M_STA;
- break;
- case IEEE80211_IF_TYPE_IBSS:
- ic_opmode = ATH9K_M_IBSS;
- break;
- case IEEE80211_IF_TYPE_AP:
- ic_opmode = ATH9K_M_HOSTAP;
- break;
- default:
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: Interface type %d not yet supported\n",
- __func__, conf->type);
- return -EOPNOTSUPP;
- }
-
- DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach a VAP of type: %d\n",
- __func__,
- ic_opmode);
-
- error = ath_vap_attach(sc, 0, conf->vif, ic_opmode);
- if (error) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: Unable to attach vap, error: %d\n",
- __func__, error);
- return error;
- }
-
- return 0;
-}
-
-static void ath9k_remove_interface(struct ieee80211_hw *hw,
- struct ieee80211_if_init_conf *conf)
-{
- struct ath_softc *sc = hw->priv;
- struct ath_vap *avp;
- int error;
-
- DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach VAP\n", __func__);
-
- avp = sc->sc_vaps[0];
- if (avp == NULL) {
- DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n",
- __func__);
- return;
- }
-
-#ifdef CONFIG_SLOW_ANT_DIV
- ath_slow_ant_div_stop(&sc->sc_antdiv);
-#endif
-
- /* Update ratectrl */
- ath_rate_newstate(sc, avp);
-
- /* Reclaim beacon resources */
- if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP ||
- sc->sc_ah->ah_opmode == ATH9K_M_IBSS) {
- ath9k_hw_stoptxdma(sc->sc_ah, sc->sc_bhalq);
- ath_beacon_return(sc, avp);
- }
-
- /* Set interrupt mask */
- sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
- ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask & ~ATH9K_INT_GLOBAL);
- sc->sc_flags &= ~SC_OP_BEACONS;
-
- error = ath_vap_detach(sc, 0);
- if (error)
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: Unable to detach vap, error: %d\n",
- __func__, error);
-}
-
-static int ath9k_config(struct ieee80211_hw *hw,
- struct ieee80211_conf *conf)
-{
- struct ath_softc *sc = hw->priv;
- struct ieee80211_channel *curchan = hw->conf.channel;
- int pos;
-
- DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set channel: %d MHz\n",
- __func__,
- curchan->center_freq);
-
- pos = ath_get_channel(sc, curchan);
- if (pos == -1) {
- DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__);
- return -EINVAL;
- }
-
- sc->sc_ah->ah_channels[pos].chanmode =
- (curchan->band == IEEE80211_BAND_2GHZ) ?
- CHANNEL_G : CHANNEL_A;
-
- if (sc->sc_curaid && hw->conf.ht_conf.ht_supported)
- sc->sc_ah->ah_channels[pos].chanmode =
- ath_get_extchanmode(sc, curchan);
-
- sc->sc_config.txpowlimit = 2 * conf->power_level;
-
- /* set h/w channel */
- if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0)
- DPRINTF(sc, ATH_DBG_FATAL, "%s: Unable to set channel\n",
- __func__);
-
- return 0;
-}
-
-static int ath9k_config_interface(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_if_conf *conf)
-{
- struct ath_softc *sc = hw->priv;
- struct ath_hal *ah = sc->sc_ah;
- struct ath_vap *avp;
- u32 rfilt = 0;
- int error, i;
- DECLARE_MAC_BUF(mac);
-
- avp = sc->sc_vaps[0];
- if (avp == NULL) {
- DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n",
- __func__);
- return -EINVAL;
- }
-
- /* TODO: Need to decide which hw opmode to use for multi-interface
- * cases */
- if (vif->type == IEEE80211_IF_TYPE_AP &&
- ah->ah_opmode != ATH9K_M_HOSTAP) {
- ah->ah_opmode = ATH9K_M_HOSTAP;
- ath9k_hw_setopmode(ah);
- ath9k_hw_write_associd(ah, sc->sc_myaddr, 0);
- /* Request full reset to get hw opmode changed properly */
- sc->sc_flags |= SC_OP_FULL_RESET;
- }
-
- if ((conf->changed & IEEE80211_IFCC_BSSID) &&
- !is_zero_ether_addr(conf->bssid)) {
- switch (vif->type) {
- case IEEE80211_IF_TYPE_STA:
- case IEEE80211_IF_TYPE_IBSS:
- /* Update ratectrl about the new state */
- ath_rate_newstate(sc, avp);
-
- /* Set BSSID */
- memcpy(sc->sc_curbssid, conf->bssid, ETH_ALEN);
- sc->sc_curaid = 0;
- ath9k_hw_write_associd(sc->sc_ah, sc->sc_curbssid,
- sc->sc_curaid);
-
- /* Set aggregation protection mode parameters */
- sc->sc_config.ath_aggr_prot = 0;
-
- /*
- * Reset our TSF so that its value is lower than the
- * beacon that we are trying to catch.
- * Only then hw will update its TSF register with the
- * new beacon. Reset the TSF before setting the BSSID
- * to avoid allowing in any frames that would update
- * our TSF only to have us clear it
- * immediately thereafter.
- */
- ath9k_hw_reset_tsf(sc->sc_ah);
-
- /* Disable BMISS interrupt when we're not associated */
- ath9k_hw_set_interrupts(sc->sc_ah,
- sc->sc_imask &
- ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS));
- sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
-
- DPRINTF(sc, ATH_DBG_CONFIG,
- "%s: RX filter 0x%x bssid %s aid 0x%x\n",
- __func__, rfilt,
- print_mac(mac, sc->sc_curbssid), sc->sc_curaid);
-
- /* need to reconfigure the beacon */
- sc->sc_flags &= ~SC_OP_BEACONS ;
-
- break;
- default:
- break;
- }
- }
-
- if ((conf->changed & IEEE80211_IFCC_BEACON) &&
- ((vif->type == IEEE80211_IF_TYPE_IBSS) ||
- (vif->type == IEEE80211_IF_TYPE_AP))) {
- /*
- * Allocate and setup the beacon frame.
- *
- * Stop any previous beacon DMA. This may be
- * necessary, for example, when an ibss merge
- * causes reconfiguration; we may be called
- * with beacon transmission active.
- */
- ath9k_hw_stoptxdma(sc->sc_ah, sc->sc_bhalq);
-
- error = ath_beacon_alloc(sc, 0);
- if (error != 0)
- return error;
-
- ath_beacon_sync(sc, 0);
- }
-
- /* Check for WLAN_CAPABILITY_PRIVACY ? */
- if ((avp->av_opmode != IEEE80211_IF_TYPE_STA)) {
- for (i = 0; i < IEEE80211_WEP_NKID; i++)
- if (ath9k_hw_keyisvalid(sc->sc_ah, (u16)i))
- ath9k_hw_keysetmac(sc->sc_ah,
- (u16)i,
- sc->sc_curbssid);
- }
-
- /* Only legacy IBSS for now */
- if (vif->type == IEEE80211_IF_TYPE_IBSS)
- ath_update_chainmask(sc, 0);
-
- return 0;
-}
-
-#define SUPPORTED_FILTERS \
- (FIF_PROMISC_IN_BSS | \
- FIF_ALLMULTI | \
- FIF_CONTROL | \
- FIF_OTHER_BSS | \
- FIF_BCN_PRBRESP_PROMISC | \
- FIF_FCSFAIL)
-
-/* FIXME: sc->sc_full_reset ? */
-static void ath9k_configure_filter(struct ieee80211_hw *hw,
- unsigned int changed_flags,
- unsigned int *total_flags,
- int mc_count,
- struct dev_mc_list *mclist)
-{
- struct ath_softc *sc = hw->priv;
- u32 rfilt;
-
- changed_flags &= SUPPORTED_FILTERS;
- *total_flags &= SUPPORTED_FILTERS;
-
- sc->rx_filter = *total_flags;
- rfilt = ath_calcrxfilter(sc);
- ath9k_hw_setrxfilter(sc->sc_ah, rfilt);
-
- if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
- if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
- ath9k_hw_write_associd(sc->sc_ah, ath_bcast_mac, 0);
- }
-
- DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set HW RX filter: 0x%x\n",
- __func__, sc->rx_filter);
-}
-
-static void ath9k_sta_notify(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- enum sta_notify_cmd cmd,
- const u8 *addr)
-{
- struct ath_softc *sc = hw->priv;
- struct ath_node *an;
- unsigned long flags;
- DECLARE_MAC_BUF(mac);
-
- spin_lock_irqsave(&sc->node_lock, flags);
- an = ath_node_find(sc, (u8 *) addr);
- spin_unlock_irqrestore(&sc->node_lock, flags);
-
- switch (cmd) {
- case STA_NOTIFY_ADD:
- spin_lock_irqsave(&sc->node_lock, flags);
- if (!an) {
- ath_node_attach(sc, (u8 *)addr, 0);
- DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach a node: %s\n",
- __func__,
- print_mac(mac, addr));
- } else {
- ath_node_get(sc, (u8 *)addr);
- }
- spin_unlock_irqrestore(&sc->node_lock, flags);
- break;
- case STA_NOTIFY_REMOVE:
- if (!an)
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: Removal of a non-existent node\n",
- __func__);
- else {
- ath_node_put(sc, an, ATH9K_BH_STATUS_INTACT);
- DPRINTF(sc, ATH_DBG_CONFIG, "%s: Put a node: %s\n",
- __func__,
- print_mac(mac, addr));
- }
- break;
- default:
- break;
- }
-}
-
-static int ath9k_conf_tx(struct ieee80211_hw *hw,
- u16 queue,
- const struct ieee80211_tx_queue_params *params)
-{
- struct ath_softc *sc = hw->priv;
- struct ath9k_tx_queue_info qi;
- int ret = 0, qnum;
-
- if (queue >= WME_NUM_AC)
- return 0;
-
- qi.tqi_aifs = params->aifs;
- qi.tqi_cwmin = params->cw_min;
- qi.tqi_cwmax = params->cw_max;
- qi.tqi_burstTime = params->txop;
- qnum = ath_get_hal_qnum(queue, sc);
-
- DPRINTF(sc, ATH_DBG_CONFIG,
- "%s: Configure tx [queue/halq] [%d/%d], "
- "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
- __func__,
- queue,
- qnum,
- params->aifs,
- params->cw_min,
- params->cw_max,
- params->txop);
-
- ret = ath_txq_update(sc, qnum, &qi);
- if (ret)
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: TXQ Update failed\n", __func__);
-
- return ret;
-}
-
-static int ath9k_set_key(struct ieee80211_hw *hw,
- enum set_key_cmd cmd,
- const u8 *local_addr,
- const u8 *addr,
- struct ieee80211_key_conf *key)
-{
- struct ath_softc *sc = hw->priv;
- int ret = 0;
-
- DPRINTF(sc, ATH_DBG_KEYCACHE, " %s: Set HW Key\n", __func__);
-
- switch (cmd) {
- case SET_KEY:
- ret = ath_key_config(sc, addr, key);
- if (!ret) {
- set_bit(key->keyidx, sc->sc_keymap);
- key->hw_key_idx = key->keyidx;
- /* push IV and Michael MIC generation to stack */
- key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
- if (key->alg == ALG_TKIP)
- key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
- }
- break;
- case DISABLE_KEY:
- ath_key_delete(sc, key);
- clear_bit(key->keyidx, sc->sc_keymap);
- sc->sc_keytype = ATH9K_CIPHER_CLR;
- break;
- default:
- ret = -EINVAL;
- }
-
- return ret;
-}
-
static void ath9k_ht_conf(struct ath_softc *sc,
struct ieee80211_bss_conf *bss_conf)
{
@@ -909,145 +436,6 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
}
}
-static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_bss_conf *bss_conf,
- u32 changed)
-{
- struct ath_softc *sc = hw->priv;
-
- if (changed & BSS_CHANGED_ERP_PREAMBLE) {
- DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed PREAMBLE %d\n",
- __func__,
- bss_conf->use_short_preamble);
- if (bss_conf->use_short_preamble)
- sc->sc_flags |= SC_OP_PREAMBLE_SHORT;
- else
- sc->sc_flags &= ~SC_OP_PREAMBLE_SHORT;
- }
-
- if (changed & BSS_CHANGED_ERP_CTS_PROT) {
- DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed CTS PROT %d\n",
- __func__,
- bss_conf->use_cts_prot);
- if (bss_conf->use_cts_prot &&
- hw->conf.channel->band != IEEE80211_BAND_5GHZ)
- sc->sc_flags |= SC_OP_PROTECT_ENABLE;
- else
- sc->sc_flags &= ~SC_OP_PROTECT_ENABLE;
- }
-
- if (changed & BSS_CHANGED_HT) {
- DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed HT %d\n",
- __func__,
- bss_conf->assoc_ht);
- ath9k_ht_conf(sc, bss_conf);
- }
-
- if (changed & BSS_CHANGED_ASSOC) {
- DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed ASSOC %d\n",
- __func__,
- bss_conf->assoc);
- ath9k_bss_assoc_info(sc, bss_conf);
- }
-}
-
-static u64 ath9k_get_tsf(struct ieee80211_hw *hw)
-{
- u64 tsf;
- struct ath_softc *sc = hw->priv;
- struct ath_hal *ah = sc->sc_ah;
-
- tsf = ath9k_hw_gettsf64(ah);
-
- return tsf;
-}
-
-static void ath9k_reset_tsf(struct ieee80211_hw *hw)
-{
- struct ath_softc *sc = hw->priv;
- struct ath_hal *ah = sc->sc_ah;
-
- ath9k_hw_reset_tsf(ah);
-}
-
-static int ath9k_ampdu_action(struct ieee80211_hw *hw,
- enum ieee80211_ampdu_mlme_action action,
- const u8 *addr,
- u16 tid,
- u16 *ssn)
-{
- struct ath_softc *sc = hw->priv;
- int ret = 0;
-
- switch (action) {
- case IEEE80211_AMPDU_RX_START:
- ret = ath_rx_aggr_start(sc, addr, tid, ssn);
- if (ret < 0)
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: Unable to start RX aggregation\n",
- __func__);
- break;
- case IEEE80211_AMPDU_RX_STOP:
- ret = ath_rx_aggr_stop(sc, addr, tid);
- if (ret < 0)
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: Unable to stop RX aggregation\n",
- __func__);
- break;
- case IEEE80211_AMPDU_TX_START:
- ret = ath_tx_aggr_start(sc, addr, tid, ssn);
- if (ret < 0)
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: Unable to start TX aggregation\n",
- __func__);
- else
- ieee80211_start_tx_ba_cb_irqsafe(hw, (u8 *)addr, tid);
- break;
- case IEEE80211_AMPDU_TX_STOP:
- ret = ath_tx_aggr_stop(sc, addr, tid);
- if (ret < 0)
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: Unable to stop TX aggregation\n",
- __func__);
-
- ieee80211_stop_tx_ba_cb_irqsafe(hw, (u8 *)addr, tid);
- break;
- default:
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: Unknown AMPDU action\n", __func__);
- }
-
- return ret;
-}
-
-static struct ieee80211_ops ath9k_ops = {
- .tx = ath9k_tx,
- .start = ath9k_start,
- .stop = ath9k_stop,
- .add_interface = ath9k_add_interface,
- .remove_interface = ath9k_remove_interface,
- .config = ath9k_config,
- .config_interface = ath9k_config_interface,
- .configure_filter = ath9k_configure_filter,
- .get_stats = NULL,
- .sta_notify = ath9k_sta_notify,
- .conf_tx = ath9k_conf_tx,
- .get_tx_stats = NULL,
- .bss_info_changed = ath9k_bss_info_changed,
- .set_tim = NULL,
- .set_key = ath9k_set_key,
- .hw_scan = NULL,
- .get_tkip_seq = NULL,
- .set_rts_threshold = NULL,
- .set_frag_threshold = NULL,
- .set_retry_limit = NULL,
- .get_tsf = ath9k_get_tsf,
- .reset_tsf = ath9k_reset_tsf,
- .tx_last_beacon = NULL,
- .ampdu_action = ath9k_ampdu_action
-};
-
void ath_get_beaconconfig(struct ath_softc *sc,
int if_id,
struct ath_beacon_config *conf)
@@ -1284,6 +672,209 @@ fail:
ath_deinit_leds(sc);
}
+#ifdef CONFIG_RFKILL
+/*******************/
+/* Rfkill */
+/*******************/
+
+static void ath_radio_enable(struct ath_softc *sc)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ int status;
+
+ spin_lock_bh(&sc->sc_resetlock);
+ if (!ath9k_hw_reset(ah, ah->ah_curchan,
+ sc->sc_ht_info.tx_chan_width,
+ sc->sc_tx_chainmask,
+ sc->sc_rx_chainmask,
+ sc->sc_ht_extprotspacing,
+ false, &status)) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: unable to reset channel %u (%uMhz) "
+ "flags 0x%x hal status %u\n", __func__,
+ ath9k_hw_mhz2ieee(ah,
+ ah->ah_curchan->channel,
+ ah->ah_curchan->channelFlags),
+ ah->ah_curchan->channel,
+ ah->ah_curchan->channelFlags, status);
+ }
+ spin_unlock_bh(&sc->sc_resetlock);
+
+ ath_update_txpow(sc);
+ if (ath_startrecv(sc) != 0) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: unable to restart recv logic\n", __func__);
+ return;
+ }
+
+ if (sc->sc_flags & SC_OP_BEACONS)
+ ath_beacon_config(sc, ATH_IF_ID_ANY); /* restart beacons */
+
+ /* Re-Enable interrupts */
+ ath9k_hw_set_interrupts(ah, sc->sc_imask);
+
+ /* Enable LED */
+ ath9k_hw_cfg_output(ah, ATH_LED_PIN,
+ AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
+ ath9k_hw_set_gpio(ah, ATH_LED_PIN, 0);
+
+ ieee80211_wake_queues(sc->hw);
+}
+
+static void ath_radio_disable(struct ath_softc *sc)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ int status;
+
+
+ ieee80211_stop_queues(sc->hw);
+
+ /* Disable LED */
+ ath9k_hw_set_gpio(ah, ATH_LED_PIN, 1);
+ ath9k_hw_cfg_gpio_input(ah, ATH_LED_PIN);
+
+ /* Disable interrupts */
+ ath9k_hw_set_interrupts(ah, 0);
+
+ ath_draintxq(sc, false); /* clear pending tx frames */
+ ath_stoprecv(sc); /* turn off frame recv */
+ ath_flushrecv(sc); /* flush recv queue */
+
+ spin_lock_bh(&sc->sc_resetlock);
+ if (!ath9k_hw_reset(ah, ah->ah_curchan,
+ sc->sc_ht_info.tx_chan_width,
+ sc->sc_tx_chainmask,
+ sc->sc_rx_chainmask,
+ sc->sc_ht_extprotspacing,
+ false, &status)) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: unable to reset channel %u (%uMhz) "
+ "flags 0x%x hal status %u\n", __func__,
+ ath9k_hw_mhz2ieee(ah,
+ ah->ah_curchan->channel,
+ ah->ah_curchan->channelFlags),
+ ah->ah_curchan->channel,
+ ah->ah_curchan->channelFlags, status);
+ }
+ spin_unlock_bh(&sc->sc_resetlock);
+
+ ath9k_hw_phy_disable(ah);
+ ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP);
+}
+
+static bool ath_is_rfkill_set(struct ath_softc *sc)
+{
+ struct ath_hal *ah = sc->sc_ah;
+
+ return ath9k_hw_gpio_get(ah, ah->ah_rfkill_gpio) ==
+ ah->ah_rfkill_polarity;
+}
+
+/* h/w rfkill poll function */
+static void ath_rfkill_poll(struct work_struct *work)
+{
+ struct ath_softc *sc = container_of(work, struct ath_softc,
+ rf_kill.rfkill_poll.work);
+ bool radio_on;
+
+ if (sc->sc_flags & SC_OP_INVALID)
+ return;
+
+ radio_on = !ath_is_rfkill_set(sc);
+
+ /*
+ * enable/disable radio only when there is a
+ * state change in RF switch
+ */
+ if (radio_on == !!(sc->sc_flags & SC_OP_RFKILL_HW_BLOCKED)) {
+ enum rfkill_state state;
+
+ if (sc->sc_flags & SC_OP_RFKILL_SW_BLOCKED) {
+ state = radio_on ? RFKILL_STATE_SOFT_BLOCKED
+ : RFKILL_STATE_HARD_BLOCKED;
+ } else if (radio_on) {
+ ath_radio_enable(sc);
+ state = RFKILL_STATE_UNBLOCKED;
+ } else {
+ ath_radio_disable(sc);
+ state = RFKILL_STATE_HARD_BLOCKED;
+ }
+
+ if (state == RFKILL_STATE_HARD_BLOCKED)
+ sc->sc_flags |= SC_OP_RFKILL_HW_BLOCKED;
+ else
+ sc->sc_flags &= ~SC_OP_RFKILL_HW_BLOCKED;
+
+ rfkill_force_state(sc->rf_kill.rfkill, state);
+ }
+
+ queue_delayed_work(sc->hw->workqueue, &sc->rf_kill.rfkill_poll,
+ msecs_to_jiffies(ATH_RFKILL_POLL_INTERVAL));
+}
+
+/* s/w rfkill handler */
+static int ath_sw_toggle_radio(void *data, enum rfkill_state state)
+{
+ struct ath_softc *sc = data;
+
+ switch (state) {
+ case RFKILL_STATE_SOFT_BLOCKED:
+ if (!(sc->sc_flags & (SC_OP_RFKILL_HW_BLOCKED |
+ SC_OP_RFKILL_SW_BLOCKED)))
+ ath_radio_disable(sc);
+ sc->sc_flags |= SC_OP_RFKILL_SW_BLOCKED;
+ return 0;
+ case RFKILL_STATE_UNBLOCKED:
+ if ((sc->sc_flags & SC_OP_RFKILL_SW_BLOCKED)) {
+ sc->sc_flags &= ~SC_OP_RFKILL_SW_BLOCKED;
+ if (sc->sc_flags & SC_OP_RFKILL_HW_BLOCKED) {
+ DPRINTF(sc, ATH_DBG_FATAL, "Can't turn on the"
+ "radio as it is disabled by h/w \n");
+ return -EPERM;
+ }
+ ath_radio_enable(sc);
+ }
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+/* Init s/w rfkill */
+static int ath_init_sw_rfkill(struct ath_softc *sc)
+{
+ sc->rf_kill.rfkill = rfkill_allocate(wiphy_dev(sc->hw->wiphy),
+ RFKILL_TYPE_WLAN);
+ if (!sc->rf_kill.rfkill) {
+ DPRINTF(sc, ATH_DBG_FATAL, "Failed to allocate rfkill\n");
+ return -ENOMEM;
+ }
+
+ snprintf(sc->rf_kill.rfkill_name, sizeof(sc->rf_kill.rfkill_name),
+ "ath9k-%s:rfkill", wiphy_name(sc->hw->wiphy));
+ sc->rf_kill.rfkill->name = sc->rf_kill.rfkill_name;
+ sc->rf_kill.rfkill->data = sc;
+ sc->rf_kill.rfkill->toggle_radio = ath_sw_toggle_radio;
+ sc->rf_kill.rfkill->state = RFKILL_STATE_UNBLOCKED;
+ sc->rf_kill.rfkill->user_claim_unsupported = 1;
+
+ return 0;
+}
+
+/* Deinitialize rfkill */
+static void ath_deinit_rfkill(struct ath_softc *sc)
+{
+ if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+ cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll);
+
+ if (sc->sc_flags & SC_OP_RFKILL_REGISTERED) {
+ rfkill_unregister(sc->rf_kill.rfkill);
+ sc->sc_flags &= ~SC_OP_RFKILL_REGISTERED;
+ sc->rf_kill.rfkill = NULL;
+ }
+}
+#endif /* CONFIG_RFKILL */
+
static int ath_detach(struct ath_softc *sc)
{
struct ieee80211_hw *hw = sc->hw;
@@ -1293,6 +884,11 @@ static int ath_detach(struct ath_softc *sc)
/* Deinit LED control */
ath_deinit_leds(sc);
+#ifdef CONFIG_RFKILL
+ /* deinit rfkill */
+ ath_deinit_rfkill(sc);
+#endif
+
/* Unregister hw */
ieee80211_unregister_hw(hw);
@@ -1389,6 +985,16 @@ static int ath_attach(u16 devid,
/* Initialize LED control */
ath_init_leds(sc);
+#ifdef CONFIG_RFKILL
+ /* Initialze h/w Rfkill */
+ if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+ INIT_DELAYED_WORK(&sc->rf_kill.rfkill_poll, ath_rfkill_poll);
+
+ /* Initialize s/w rfkill */
+ if (ath_init_sw_rfkill(sc))
+ goto detach;
+#endif
+
/* initialize tx/rx engine */
error = ath_tx_init(sc, ATH_TXBUF);
@@ -1406,6 +1012,648 @@ bad:
return error;
}
+static int ath9k_start(struct ieee80211_hw *hw)
+{
+ struct ath_softc *sc = hw->priv;
+ struct ieee80211_channel *curchan = hw->conf.channel;
+ int error = 0, pos;
+
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s: Starting driver with "
+ "initial channel: %d MHz\n", __func__, curchan->center_freq);
+
+ /* setup initial channel */
+
+ pos = ath_get_channel(sc, curchan);
+ if (pos == -1) {
+ DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__);
+ return -EINVAL;
+ }
+
+ sc->sc_ah->ah_channels[pos].chanmode =
+ (curchan->band == IEEE80211_BAND_2GHZ) ? CHANNEL_G : CHANNEL_A;
+
+ /* open ath_dev */
+ error = ath_open(sc, &sc->sc_ah->ah_channels[pos]);
+ if (error) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: Unable to complete ath_open\n", __func__);
+ return error;
+ }
+
+#ifdef CONFIG_RFKILL
+ /* Start rfkill polling */
+ if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+ queue_delayed_work(sc->hw->workqueue,
+ &sc->rf_kill.rfkill_poll, 0);
+
+ if (!(sc->sc_flags & SC_OP_RFKILL_REGISTERED)) {
+ if (rfkill_register(sc->rf_kill.rfkill)) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "Unable to register rfkill\n");
+ rfkill_free(sc->rf_kill.rfkill);
+
+ /* Deinitialize the device */
+ if (sc->pdev->irq)
+ free_irq(sc->pdev->irq, sc);
+ ath_detach(sc);
+ pci_iounmap(sc->pdev, sc->mem);
+ pci_release_region(sc->pdev, 0);
+ pci_disable_device(sc->pdev);
+ ieee80211_free_hw(hw);
+ return -EIO;
+ } else {
+ sc->sc_flags |= SC_OP_RFKILL_REGISTERED;
+ }
+ }
+#endif
+
+ ieee80211_wake_queues(hw);
+ return 0;
+}
+
+static int ath9k_tx(struct ieee80211_hw *hw,
+ struct sk_buff *skb)
+{
+ struct ath_softc *sc = hw->priv;
+ int hdrlen, padsize;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+ /*
+ * As a temporary workaround, assign seq# here; this will likely need
+ * to be cleaned up to work better with Beacon transmission and virtual
+ * BSSes.
+ */
+ if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
+ sc->seq_no += 0x10;
+ hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
+ hdr->seq_ctrl |= cpu_to_le16(sc->seq_no);
+ }
+
+ /* Add the padding after the header if this is not already done */
+ hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+ if (hdrlen & 3) {
+ padsize = hdrlen % 4;
+ if (skb_headroom(skb) < padsize)
+ return -1;
+ skb_push(skb, padsize);
+ memmove(skb->data, skb->data + padsize, hdrlen);
+ }
+
+ DPRINTF(sc, ATH_DBG_XMIT, "%s: transmitting packet, skb: %p\n",
+ __func__,
+ skb);
+
+ if (ath_tx_start(sc, skb) != 0) {
+ DPRINTF(sc, ATH_DBG_XMIT, "%s: TX failed\n", __func__);
+ dev_kfree_skb_any(skb);
+ /* FIXME: Check for proper return value from ATH_DEV */
+ return 0;
+ }
+
+ return 0;
+}
+
+static void ath9k_stop(struct ieee80211_hw *hw)
+{
+ struct ath_softc *sc = hw->priv;
+ int error;
+
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s: Driver halt\n", __func__);
+
+ error = ath_suspend(sc);
+ if (error)
+ DPRINTF(sc, ATH_DBG_CONFIG,
+ "%s: Device is no longer present\n", __func__);
+
+ ieee80211_stop_queues(hw);
+
+#ifdef CONFIG_RFKILL
+ if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+ cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll);
+#endif
+}
+
+static int ath9k_add_interface(struct ieee80211_hw *hw,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct ath_softc *sc = hw->priv;
+ int error, ic_opmode = 0;
+
+ /* Support only vap for now */
+
+ if (sc->sc_nvaps)
+ return -ENOBUFS;
+
+ switch (conf->type) {
+ case NL80211_IFTYPE_STATION:
+ ic_opmode = ATH9K_M_STA;
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ ic_opmode = ATH9K_M_IBSS;
+ break;
+ case NL80211_IFTYPE_AP:
+ ic_opmode = ATH9K_M_HOSTAP;
+ break;
+ default:
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: Interface type %d not yet supported\n",
+ __func__, conf->type);
+ return -EOPNOTSUPP;
+ }
+
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach a VAP of type: %d\n",
+ __func__,
+ ic_opmode);
+
+ error = ath_vap_attach(sc, 0, conf->vif, ic_opmode);
+ if (error) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: Unable to attach vap, error: %d\n",
+ __func__, error);
+ return error;
+ }
+
+ return 0;
+}
+
+static void ath9k_remove_interface(struct ieee80211_hw *hw,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct ath_softc *sc = hw->priv;
+ struct ath_vap *avp;
+ int error;
+
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach VAP\n", __func__);
+
+ avp = sc->sc_vaps[0];
+ if (avp == NULL) {
+ DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n",
+ __func__);
+ return;
+ }
+
+#ifdef CONFIG_SLOW_ANT_DIV
+ ath_slow_ant_div_stop(&sc->sc_antdiv);
+#endif
+
+ /* Update ratectrl */
+ ath_rate_newstate(sc, avp);
+
+ /* Reclaim beacon resources */
+ if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP ||
+ sc->sc_ah->ah_opmode == ATH9K_M_IBSS) {
+ ath9k_hw_stoptxdma(sc->sc_ah, sc->sc_bhalq);
+ ath_beacon_return(sc, avp);
+ }
+
+ /* Set interrupt mask */
+ sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
+ ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask & ~ATH9K_INT_GLOBAL);
+ sc->sc_flags &= ~SC_OP_BEACONS;
+
+ error = ath_vap_detach(sc, 0);
+ if (error)
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: Unable to detach vap, error: %d\n",
+ __func__, error);
+}
+
+static int ath9k_config(struct ieee80211_hw *hw,
+ struct ieee80211_conf *conf)
+{
+ struct ath_softc *sc = hw->priv;
+ struct ieee80211_channel *curchan = hw->conf.channel;
+ int pos;
+
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set channel: %d MHz\n",
+ __func__,
+ curchan->center_freq);
+
+ pos = ath_get_channel(sc, curchan);
+ if (pos == -1) {
+ DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__);
+ return -EINVAL;
+ }
+
+ sc->sc_ah->ah_channels[pos].chanmode =
+ (curchan->band == IEEE80211_BAND_2GHZ) ?
+ CHANNEL_G : CHANNEL_A;
+
+ if (sc->sc_curaid && hw->conf.ht_conf.ht_supported)
+ sc->sc_ah->ah_channels[pos].chanmode =
+ ath_get_extchanmode(sc, curchan);
+
+ sc->sc_config.txpowlimit = 2 * conf->power_level;
+
+ /* set h/w channel */
+ if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0)
+ DPRINTF(sc, ATH_DBG_FATAL, "%s: Unable to set channel\n",
+ __func__);
+
+ return 0;
+}
+
+static int ath9k_config_interface(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_if_conf *conf)
+{
+ struct ath_softc *sc = hw->priv;
+ struct ath_hal *ah = sc->sc_ah;
+ struct ath_vap *avp;
+ u32 rfilt = 0;
+ int error, i;
+ DECLARE_MAC_BUF(mac);
+
+ avp = sc->sc_vaps[0];
+ if (avp == NULL) {
+ DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ /* TODO: Need to decide which hw opmode to use for multi-interface
+ * cases */
+ if (vif->type == NL80211_IFTYPE_AP &&
+ ah->ah_opmode != ATH9K_M_HOSTAP) {
+ ah->ah_opmode = ATH9K_M_HOSTAP;
+ ath9k_hw_setopmode(ah);
+ ath9k_hw_write_associd(ah, sc->sc_myaddr, 0);
+ /* Request full reset to get hw opmode changed properly */
+ sc->sc_flags |= SC_OP_FULL_RESET;
+ }
+
+ if ((conf->changed & IEEE80211_IFCC_BSSID) &&
+ !is_zero_ether_addr(conf->bssid)) {
+ switch (vif->type) {
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_ADHOC:
+ /* Update ratectrl about the new state */
+ ath_rate_newstate(sc, avp);
+
+ /* Set BSSID */
+ memcpy(sc->sc_curbssid, conf->bssid, ETH_ALEN);
+ sc->sc_curaid = 0;
+ ath9k_hw_write_associd(sc->sc_ah, sc->sc_curbssid,
+ sc->sc_curaid);
+
+ /* Set aggregation protection mode parameters */
+ sc->sc_config.ath_aggr_prot = 0;
+
+ /*
+ * Reset our TSF so that its value is lower than the
+ * beacon that we are trying to catch.
+ * Only then hw will update its TSF register with the
+ * new beacon. Reset the TSF before setting the BSSID
+ * to avoid allowing in any frames that would update
+ * our TSF only to have us clear it
+ * immediately thereafter.
+ */
+ ath9k_hw_reset_tsf(sc->sc_ah);
+
+ /* Disable BMISS interrupt when we're not associated */
+ ath9k_hw_set_interrupts(sc->sc_ah,
+ sc->sc_imask &
+ ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS));
+ sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
+
+ DPRINTF(sc, ATH_DBG_CONFIG,
+ "%s: RX filter 0x%x bssid %s aid 0x%x\n",
+ __func__, rfilt,
+ print_mac(mac, sc->sc_curbssid), sc->sc_curaid);
+
+ /* need to reconfigure the beacon */
+ sc->sc_flags &= ~SC_OP_BEACONS ;
+
+ break;
+ default:
+ break;
+ }
+ }
+
+ if ((conf->changed & IEEE80211_IFCC_BEACON) &&
+ ((vif->type == NL80211_IFTYPE_ADHOC) ||
+ (vif->type == NL80211_IFTYPE_AP))) {
+ /*
+ * Allocate and setup the beacon frame.
+ *
+ * Stop any previous beacon DMA. This may be
+ * necessary, for example, when an ibss merge
+ * causes reconfiguration; we may be called
+ * with beacon transmission active.
+ */
+ ath9k_hw_stoptxdma(sc->sc_ah, sc->sc_bhalq);
+
+ error = ath_beacon_alloc(sc, 0);
+ if (error != 0)
+ return error;
+
+ ath_beacon_sync(sc, 0);
+ }
+
+ /* Check for WLAN_CAPABILITY_PRIVACY ? */
+ if ((avp->av_opmode != NL80211_IFTYPE_STATION)) {
+ for (i = 0; i < IEEE80211_WEP_NKID; i++)
+ if (ath9k_hw_keyisvalid(sc->sc_ah, (u16)i))
+ ath9k_hw_keysetmac(sc->sc_ah,
+ (u16)i,
+ sc->sc_curbssid);
+ }
+
+ /* Only legacy IBSS for now */
+ if (vif->type == NL80211_IFTYPE_ADHOC)
+ ath_update_chainmask(sc, 0);
+
+ return 0;
+}
+
+#define SUPPORTED_FILTERS \
+ (FIF_PROMISC_IN_BSS | \
+ FIF_ALLMULTI | \
+ FIF_CONTROL | \
+ FIF_OTHER_BSS | \
+ FIF_BCN_PRBRESP_PROMISC | \
+ FIF_FCSFAIL)
+
+/* FIXME: sc->sc_full_reset ? */
+static void ath9k_configure_filter(struct ieee80211_hw *hw,
+ unsigned int changed_flags,
+ unsigned int *total_flags,
+ int mc_count,
+ struct dev_mc_list *mclist)
+{
+ struct ath_softc *sc = hw->priv;
+ u32 rfilt;
+
+ changed_flags &= SUPPORTED_FILTERS;
+ *total_flags &= SUPPORTED_FILTERS;
+
+ sc->rx_filter = *total_flags;
+ rfilt = ath_calcrxfilter(sc);
+ ath9k_hw_setrxfilter(sc->sc_ah, rfilt);
+
+ if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
+ if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
+ ath9k_hw_write_associd(sc->sc_ah, ath_bcast_mac, 0);
+ }
+
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set HW RX filter: 0x%x\n",
+ __func__, sc->rx_filter);
+}
+
+static void ath9k_sta_notify(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ enum sta_notify_cmd cmd,
+ struct ieee80211_sta *sta)
+{
+ struct ath_softc *sc = hw->priv;
+ struct ath_node *an;
+ unsigned long flags;
+ DECLARE_MAC_BUF(mac);
+
+ spin_lock_irqsave(&sc->node_lock, flags);
+ an = ath_node_find(sc, sta->addr);
+ spin_unlock_irqrestore(&sc->node_lock, flags);
+
+ switch (cmd) {
+ case STA_NOTIFY_ADD:
+ spin_lock_irqsave(&sc->node_lock, flags);
+ if (!an) {
+ ath_node_attach(sc, sta->addr, 0);
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach a node: %s\n",
+ __func__, print_mac(mac, sta->addr));
+ } else {
+ ath_node_get(sc, sta->addr);
+ }
+ spin_unlock_irqrestore(&sc->node_lock, flags);
+ break;
+ case STA_NOTIFY_REMOVE:
+ if (!an)
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: Removal of a non-existent node\n",
+ __func__);
+ else {
+ ath_node_put(sc, an, ATH9K_BH_STATUS_INTACT);
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s: Put a node: %s\n",
+ __func__,
+ print_mac(mac, sta->addr));
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static int ath9k_conf_tx(struct ieee80211_hw *hw,
+ u16 queue,
+ const struct ieee80211_tx_queue_params *params)
+{
+ struct ath_softc *sc = hw->priv;
+ struct ath9k_tx_queue_info qi;
+ int ret = 0, qnum;
+
+ if (queue >= WME_NUM_AC)
+ return 0;
+
+ qi.tqi_aifs = params->aifs;
+ qi.tqi_cwmin = params->cw_min;
+ qi.tqi_cwmax = params->cw_max;
+ qi.tqi_burstTime = params->txop;
+ qnum = ath_get_hal_qnum(queue, sc);
+
+ DPRINTF(sc, ATH_DBG_CONFIG,
+ "%s: Configure tx [queue/halq] [%d/%d], "
+ "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
+ __func__,
+ queue,
+ qnum,
+ params->aifs,
+ params->cw_min,
+ params->cw_max,
+ params->txop);
+
+ ret = ath_txq_update(sc, qnum, &qi);
+ if (ret)
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: TXQ Update failed\n", __func__);
+
+ return ret;
+}
+
+static int ath9k_set_key(struct ieee80211_hw *hw,
+ enum set_key_cmd cmd,
+ const u8 *local_addr,
+ const u8 *addr,
+ struct ieee80211_key_conf *key)
+{
+ struct ath_softc *sc = hw->priv;
+ int ret = 0;
+
+ DPRINTF(sc, ATH_DBG_KEYCACHE, " %s: Set HW Key\n", __func__);
+
+ switch (cmd) {
+ case SET_KEY:
+ ret = ath_key_config(sc, addr, key);
+ if (!ret) {
+ set_bit(key->keyidx, sc->sc_keymap);
+ key->hw_key_idx = key->keyidx;
+ /* push IV and Michael MIC generation to stack */
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+ if (key->alg == ALG_TKIP)
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
+ }
+ break;
+ case DISABLE_KEY:
+ ath_key_delete(sc, key);
+ clear_bit(key->keyidx, sc->sc_keymap);
+ sc->sc_keytype = ATH9K_CIPHER_CLR;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *bss_conf,
+ u32 changed)
+{
+ struct ath_softc *sc = hw->priv;
+
+ if (changed & BSS_CHANGED_ERP_PREAMBLE) {
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed PREAMBLE %d\n",
+ __func__,
+ bss_conf->use_short_preamble);
+ if (bss_conf->use_short_preamble)
+ sc->sc_flags |= SC_OP_PREAMBLE_SHORT;
+ else
+ sc->sc_flags &= ~SC_OP_PREAMBLE_SHORT;
+ }
+
+ if (changed & BSS_CHANGED_ERP_CTS_PROT) {
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed CTS PROT %d\n",
+ __func__,
+ bss_conf->use_cts_prot);
+ if (bss_conf->use_cts_prot &&
+ hw->conf.channel->band != IEEE80211_BAND_5GHZ)
+ sc->sc_flags |= SC_OP_PROTECT_ENABLE;
+ else
+ sc->sc_flags &= ~SC_OP_PROTECT_ENABLE;
+ }
+
+ if (changed & BSS_CHANGED_HT) {
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed HT %d\n",
+ __func__,
+ bss_conf->assoc_ht);
+ ath9k_ht_conf(sc, bss_conf);
+ }
+
+ if (changed & BSS_CHANGED_ASSOC) {
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed ASSOC %d\n",
+ __func__,
+ bss_conf->assoc);
+ ath9k_bss_assoc_info(sc, bss_conf);
+ }
+}
+
+static u64 ath9k_get_tsf(struct ieee80211_hw *hw)
+{
+ u64 tsf;
+ struct ath_softc *sc = hw->priv;
+ struct ath_hal *ah = sc->sc_ah;
+
+ tsf = ath9k_hw_gettsf64(ah);
+
+ return tsf;
+}
+
+static void ath9k_reset_tsf(struct ieee80211_hw *hw)
+{
+ struct ath_softc *sc = hw->priv;
+ struct ath_hal *ah = sc->sc_ah;
+
+ ath9k_hw_reset_tsf(ah);
+}
+
+static int ath9k_ampdu_action(struct ieee80211_hw *hw,
+ enum ieee80211_ampdu_mlme_action action,
+ struct ieee80211_sta *sta,
+ u16 tid, u16 *ssn)
+{
+ struct ath_softc *sc = hw->priv;
+ int ret = 0;
+
+ switch (action) {
+ case IEEE80211_AMPDU_RX_START:
+ ret = ath_rx_aggr_start(sc, sta->addr, tid, ssn);
+ if (ret < 0)
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: Unable to start RX aggregation\n",
+ __func__);
+ break;
+ case IEEE80211_AMPDU_RX_STOP:
+ ret = ath_rx_aggr_stop(sc, sta->addr, tid);
+ if (ret < 0)
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: Unable to stop RX aggregation\n",
+ __func__);
+ break;
+ case IEEE80211_AMPDU_TX_START:
+ ret = ath_tx_aggr_start(sc, sta->addr, tid, ssn);
+ if (ret < 0)
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: Unable to start TX aggregation\n",
+ __func__);
+ else
+ ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid);
+ break;
+ case IEEE80211_AMPDU_TX_STOP:
+ ret = ath_tx_aggr_stop(sc, sta->addr, tid);
+ if (ret < 0)
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: Unable to stop TX aggregation\n",
+ __func__);
+
+ ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid);
+ break;
+ default:
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: Unknown AMPDU action\n", __func__);
+ }
+
+ return ret;
+}
+
+static struct ieee80211_ops ath9k_ops = {
+ .tx = ath9k_tx,
+ .start = ath9k_start,
+ .stop = ath9k_stop,
+ .add_interface = ath9k_add_interface,
+ .remove_interface = ath9k_remove_interface,
+ .config = ath9k_config,
+ .config_interface = ath9k_config_interface,
+ .configure_filter = ath9k_configure_filter,
+ .get_stats = NULL,
+ .sta_notify = ath9k_sta_notify,
+ .conf_tx = ath9k_conf_tx,
+ .get_tx_stats = NULL,
+ .bss_info_changed = ath9k_bss_info_changed,
+ .set_tim = NULL,
+ .set_key = ath9k_set_key,
+ .hw_scan = NULL,
+ .get_tkip_seq = NULL,
+ .set_rts_threshold = NULL,
+ .set_frag_threshold = NULL,
+ .set_retry_limit = NULL,
+ .get_tsf = ath9k_get_tsf,
+ .reset_tsf = ath9k_reset_tsf,
+ .tx_last_beacon = NULL,
+ .ampdu_action = ath9k_ampdu_action
+};
+
static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
void __iomem *mem;
@@ -1554,6 +1802,12 @@ static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state)
struct ath_softc *sc = hw->priv;
ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
+
+#ifdef CONFIG_RFKILL
+ if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+ cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll);
+#endif
+
pci_save_state(pdev);
pci_disable_device(pdev);
pci_set_power_state(pdev, 3);
@@ -1586,6 +1840,16 @@ static int ath_pci_resume(struct pci_dev *pdev)
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
+#ifdef CONFIG_RFKILL
+ /*
+ * check the h/w rfkill state on resume
+ * and start the rfkill poll timer
+ */
+ if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+ queue_delayed_work(sc->hw->workqueue,
+ &sc->rf_kill.rfkill_poll, 0);
+#endif
+
return 0;
}
diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c
index 390019ed398e..1cc9daf44550 100644
--- a/drivers/net/wireless/ath9k/rc.c
+++ b/drivers/net/wireless/ath9k/rc.c
@@ -1825,7 +1825,7 @@ static void ath_setup_rates(struct ieee80211_local *local, struct sta_info *sta)
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
for (i = 0; i < sband->n_bitrates; i++) {
- if (sta->supp_rates[local->hw.conf.channel->band] & BIT(i)) {
+ if (sta->sta.supp_rates[local->hw.conf.channel->band] & BIT(i)) {
rc_priv->neg_rates.rs_rates[j]
= (sband->bitrates[i].bitrate * 2) / 10;
j++;
@@ -2039,7 +2039,6 @@ static void ath_rate_init(void *priv, void *priv_sta,
DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
- sta->txrate_idx = rate_lowest_index(local, sband, sta);
ath_setup_rates(local, sta);
if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) {
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index 07d2825458ab..427b8203e3f9 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -569,7 +569,7 @@ struct b43_key {
#define B43_QOS_VOICE B43_QOS_PARAMS(3)
/* QOS parameter hardware data structure offsets. */
-#define B43_NR_QOSPARAMS 22
+#define B43_NR_QOSPARAMS 16
enum {
B43_QOSPARAM_TXOP = 0,
B43_QOSPARAM_CWMIN,
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index d4a356b11636..0f628a29d833 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -1244,13 +1244,13 @@ generate_new:
static void handle_irq_tbtt_indication(struct b43_wldev *dev)
{
- if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) {
+ if (b43_is_mode(dev->wl, NL80211_IFTYPE_AP)) {
///TODO: PS TBTT
} else {
if (1 /*FIXME: the last PSpoll frame was sent successfully */ )
b43_power_saving_ctl_bits(dev, 0);
}
- if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS))
+ if (b43_is_mode(dev->wl, NL80211_IFTYPE_ADHOC))
dev->dfq_valid = 1;
}
@@ -1599,8 +1599,8 @@ static void handle_irq_beacon(struct b43_wldev *dev)
struct b43_wl *wl = dev->wl;
u32 cmd, beacon0_valid, beacon1_valid;
- if (!b43_is_mode(wl, IEEE80211_IF_TYPE_AP) &&
- !b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT))
+ if (!b43_is_mode(wl, NL80211_IFTYPE_AP) &&
+ !b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT))
return;
/* This is the bottom half of the asynchronous beacon update. */
@@ -2568,10 +2568,10 @@ static void b43_adjust_opmode(struct b43_wldev *dev)
ctl &= ~B43_MACCTL_BEACPROMISC;
ctl |= B43_MACCTL_INFRA;
- if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) ||
- b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT))
+ if (b43_is_mode(wl, NL80211_IFTYPE_AP) ||
+ b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT))
ctl |= B43_MACCTL_AP;
- else if (b43_is_mode(wl, IEEE80211_IF_TYPE_IBSS))
+ else if (b43_is_mode(wl, NL80211_IFTYPE_ADHOC))
ctl &= ~B43_MACCTL_INFRA;
if (wl->filter_flags & FIF_CONTROL)
@@ -3406,8 +3406,8 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
phy->ops->set_rx_antenna(dev, antenna);
/* Update templates for AP/mesh mode. */
- if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) ||
- b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT))
+ if (b43_is_mode(wl, NL80211_IFTYPE_AP) ||
+ b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT))
b43_set_beacon_int(dev, conf->beacon_int);
if (!!conf->radio_enabled != phy->radio_on) {
@@ -3595,14 +3595,14 @@ static int b43_op_config_interface(struct ieee80211_hw *hw,
else
memset(wl->bssid, 0, ETH_ALEN);
if (b43_status(dev) >= B43_STAT_INITIALIZED) {
- if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) ||
- b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT)) {
+ if (b43_is_mode(wl, NL80211_IFTYPE_AP) ||
+ b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT)) {
B43_WARN_ON(vif->type != wl->if_type);
if (conf->changed & IEEE80211_IFCC_SSID)
b43_set_ssid(dev, conf->ssid, conf->ssid_len);
if (conf->changed & IEEE80211_IFCC_BEACON)
b43_update_templates(wl);
- } else if (b43_is_mode(wl, IEEE80211_IF_TYPE_IBSS)) {
+ } else if (b43_is_mode(wl, NL80211_IFTYPE_ADHOC)) {
if (conf->changed & IEEE80211_IFCC_BEACON)
b43_update_templates(wl);
}
@@ -3903,7 +3903,7 @@ static void b43_set_synth_pu_delay(struct b43_wldev *dev, bool idle)
pu_delay = 3700;
else
pu_delay = 1050;
- if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS) || idle)
+ if (b43_is_mode(dev->wl, NL80211_IFTYPE_ADHOC) || idle)
pu_delay = 500;
if ((dev->phy.radio_ver == 0x2050) && (dev->phy.radio_rev == 8))
pu_delay = max(pu_delay, (u16)2400);
@@ -3917,7 +3917,7 @@ static void b43_set_pretbtt(struct b43_wldev *dev)
u16 pretbtt;
/* The time value is in microseconds. */
- if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS)) {
+ if (b43_is_mode(dev->wl, NL80211_IFTYPE_ADHOC)) {
pretbtt = 2;
} else {
if (dev->phy.type == B43_PHYTYPE_A)
@@ -4084,11 +4084,11 @@ static int b43_op_add_interface(struct ieee80211_hw *hw,
/* TODO: allow WDS/AP devices to coexist */
- if (conf->type != IEEE80211_IF_TYPE_AP &&
- conf->type != IEEE80211_IF_TYPE_MESH_POINT &&
- conf->type != IEEE80211_IF_TYPE_STA &&
- conf->type != IEEE80211_IF_TYPE_WDS &&
- conf->type != IEEE80211_IF_TYPE_IBSS)
+ if (conf->type != NL80211_IFTYPE_AP &&
+ conf->type != NL80211_IFTYPE_MESH_POINT &&
+ conf->type != NL80211_IFTYPE_STATION &&
+ conf->type != NL80211_IFTYPE_WDS &&
+ conf->type != NL80211_IFTYPE_ADHOC)
return -EOPNOTSUPP;
mutex_lock(&wl->mutex);
@@ -4234,7 +4234,8 @@ out_unlock:
return err;
}
-static int b43_op_beacon_set_tim(struct ieee80211_hw *hw, int aid, int set)
+static int b43_op_beacon_set_tim(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta, bool set)
{
struct b43_wl *wl = hw_to_b43_wl(hw);
unsigned long flags;
@@ -4249,7 +4250,7 @@ static int b43_op_beacon_set_tim(struct ieee80211_hw *hw, int aid, int set)
static void b43_op_sta_notify(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
enum sta_notify_cmd notify_cmd,
- const u8 *addr)
+ struct ieee80211_sta *sta)
{
struct b43_wl *wl = hw_to_b43_wl(hw);
diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c
index 4d4345d76abf..af37abccccb3 100644
--- a/drivers/net/wireless/b43/phy_common.c
+++ b/drivers/net/wireless/b43/phy_common.c
@@ -162,7 +162,7 @@ void b43_phy_lock(struct b43_wldev *dev)
#endif
B43_WARN_ON(dev->dev->id.revision < 3);
- if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
+ if (!b43_is_mode(dev->wl, NL80211_IFTYPE_AP))
b43_power_saving_ctl_bits(dev, B43_PS_AWAKE);
}
@@ -174,7 +174,7 @@ void b43_phy_unlock(struct b43_wldev *dev)
#endif
B43_WARN_ON(dev->dev->id.revision < 3);
- if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
+ if (!b43_is_mode(dev->wl, NL80211_IFTYPE_AP))
b43_power_saving_ctl_bits(dev, 0);
}
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index 68f63f5093af..9fb1421cbec2 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -888,13 +888,13 @@ generate_new:
static void handle_irq_tbtt_indication(struct b43legacy_wldev *dev)
{
- if (b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) {
+ if (b43legacy_is_mode(dev->wl, NL80211_IFTYPE_AP)) {
/* TODO: PS TBTT */
} else {
if (1/*FIXME: the last PSpoll frame was sent successfully */)
b43legacy_power_saving_ctl_bits(dev, -1, -1);
}
- if (b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS))
+ if (b43legacy_is_mode(dev->wl, NL80211_IFTYPE_ADHOC))
dev->dfq_valid = 1;
}
@@ -1201,7 +1201,7 @@ static void handle_irq_beacon(struct b43legacy_wldev *dev)
struct b43legacy_wl *wl = dev->wl;
u32 cmd;
- if (!b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP))
+ if (!b43legacy_is_mode(wl, NL80211_IFTYPE_AP))
return;
/* This is the bottom half of the asynchronous beacon update. */
@@ -1936,9 +1936,9 @@ static void b43legacy_adjust_opmode(struct b43legacy_wldev *dev)
ctl &= ~B43legacy_MACCTL_BEACPROMISC;
ctl |= B43legacy_MACCTL_INFRA;
- if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP))
+ if (b43legacy_is_mode(wl, NL80211_IFTYPE_AP))
ctl |= B43legacy_MACCTL_AP;
- else if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_IBSS))
+ else if (b43legacy_is_mode(wl, NL80211_IFTYPE_ADHOC))
ctl &= ~B43legacy_MACCTL_INFRA;
if (wl->filter_flags & FIF_CONTROL)
@@ -2646,7 +2646,7 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw,
b43legacy_mgmtframe_txantenna(dev, antenna_tx);
/* Update templates for AP mode. */
- if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP))
+ if (b43legacy_is_mode(wl, NL80211_IFTYPE_AP))
b43legacy_set_beacon_int(dev, conf->beacon_int);
@@ -2733,12 +2733,12 @@ static int b43legacy_op_config_interface(struct ieee80211_hw *hw,
else
memset(wl->bssid, 0, ETH_ALEN);
if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) {
- if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP)) {
- B43legacy_WARN_ON(vif->type != IEEE80211_IF_TYPE_AP);
+ if (b43legacy_is_mode(wl, NL80211_IFTYPE_AP)) {
+ B43legacy_WARN_ON(vif->type != NL80211_IFTYPE_AP);
b43legacy_set_ssid(dev, conf->ssid, conf->ssid_len);
if (conf->changed & IEEE80211_IFCC_BEACON)
b43legacy_update_templates(wl);
- } else if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_IBSS)) {
+ } else if (b43legacy_is_mode(wl, NL80211_IFTYPE_ADHOC)) {
if (conf->changed & IEEE80211_IFCC_BEACON)
b43legacy_update_templates(wl);
}
@@ -3020,7 +3020,7 @@ static void b43legacy_set_synth_pu_delay(struct b43legacy_wldev *dev,
bool idle) {
u16 pu_delay = 1050;
- if (b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS) || idle)
+ if (b43legacy_is_mode(dev->wl, NL80211_IFTYPE_ADHOC) || idle)
pu_delay = 500;
if ((dev->phy.radio_ver == 0x2050) && (dev->phy.radio_rev == 8))
pu_delay = max(pu_delay, (u16)2400);
@@ -3035,7 +3035,7 @@ static void b43legacy_set_pretbtt(struct b43legacy_wldev *dev)
u16 pretbtt;
/* The time value is in microseconds. */
- if (b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS))
+ if (b43legacy_is_mode(dev->wl, NL80211_IFTYPE_ADHOC))
pretbtt = 2;
else
pretbtt = 250;
@@ -3259,10 +3259,10 @@ static int b43legacy_op_add_interface(struct ieee80211_hw *hw,
/* TODO: allow WDS/AP devices to coexist */
- if (conf->type != IEEE80211_IF_TYPE_AP &&
- conf->type != IEEE80211_IF_TYPE_STA &&
- conf->type != IEEE80211_IF_TYPE_WDS &&
- conf->type != IEEE80211_IF_TYPE_IBSS)
+ if (conf->type != NL80211_IFTYPE_AP &&
+ conf->type != NL80211_IFTYPE_STATION &&
+ conf->type != NL80211_IFTYPE_WDS &&
+ conf->type != NL80211_IFTYPE_ADHOC)
return -EOPNOTSUPP;
mutex_lock(&wl->mutex);
@@ -3403,7 +3403,7 @@ out_unlock:
}
static int b43legacy_op_beacon_set_tim(struct ieee80211_hw *hw,
- int aid, int set)
+ struct ieee80211_sta *sta, bool set)
{
struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
unsigned long flags;
diff --git a/drivers/net/wireless/b43legacy/phy.c b/drivers/net/wireless/b43legacy/phy.c
index bed67a54250c..4c9442b16f3f 100644
--- a/drivers/net/wireless/b43legacy/phy.c
+++ b/drivers/net/wireless/b43legacy/phy.c
@@ -103,7 +103,7 @@ void b43legacy_phy_lock(struct b43legacy_wldev *dev)
if (dev->dev->id.revision < 3) {
b43legacy_mac_suspend(dev);
} else {
- if (!b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
+ if (!b43legacy_is_mode(dev->wl, NL80211_IFTYPE_AP))
b43legacy_power_saving_ctl_bits(dev, -1, 1);
}
}
@@ -118,7 +118,7 @@ void b43legacy_phy_unlock(struct b43legacy_wldev *dev)
if (dev->dev->id.revision < 3) {
b43legacy_mac_enable(dev);
} else {
- if (!b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
+ if (!b43legacy_is_mode(dev->wl, NL80211_IFTYPE_AP))
b43legacy_power_saving_ctl_bits(dev, -1, -1);
}
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
index 10c64bdb314c..a279bf1dc9b0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
@@ -65,6 +65,9 @@ struct iwl3945_rs_sta {
u8 ibss_sta_added;
struct timer_list rate_scale_flush;
struct iwl3945_rate_scale_data win[IWL_RATE_COUNT];
+
+ /* used to be in sta_info */
+ int last_txrate_idx;
};
static s32 iwl3945_expected_tpt_g[IWL_RATE_COUNT] = {
@@ -319,6 +322,7 @@ static void iwl3945_collect_tx_data(struct iwl3945_rs_sta *rs_sta,
static void rs_rate_init(void *priv_rate, void *priv_sta,
struct ieee80211_local *local, struct sta_info *sta)
{
+ struct iwl3945_rs_sta *rs_sta = (void *)sta->rate_ctrl_priv;
int i;
IWL_DEBUG_RATE("enter\n");
@@ -329,17 +333,15 @@ static void rs_rate_init(void *priv_rate, void *priv_sta,
* after assoc.. */
for (i = IWL_RATE_COUNT - 1; i >= 0; i--) {
- if (sta->supp_rates[local->hw.conf.channel->band] & (1 << i)) {
- sta->txrate_idx = i;
+ if (sta->sta.supp_rates[local->hw.conf.channel->band] & (1 << i)) {
+ rs_sta->last_txrate_idx = i;
break;
}
}
- sta->last_txrate_idx = sta->txrate_idx;
-
/* For 5 GHz band it start at IWL_FIRST_OFDM_RATE */
if (local->hw.conf.channel->band == IEEE80211_BAND_5GHZ)
- sta->last_txrate_idx += IWL_FIRST_OFDM_RATE;
+ rs_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE;
IWL_DEBUG_RATE("leave\n");
}
@@ -674,15 +676,15 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev,
return;
}
- rate_mask = sta->supp_rates[sband->band];
- index = min(sta->last_txrate_idx & 0xffff, IWL_RATE_COUNT - 1);
+ rs_sta = (void *)sta->rate_ctrl_priv;
+
+ rate_mask = sta->sta.supp_rates[sband->band];
+ index = min(rs_sta->last_txrate_idx & 0xffff, IWL_RATE_COUNT - 1);
if (sband->band == IEEE80211_BAND_5GHZ)
rate_mask = rate_mask << IWL_FIRST_OFDM_RATE;
- rs_sta = (void *)sta->rate_ctrl_priv;
-
- if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
+ if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
!rs_sta->ibss_sta_added) {
u8 sta_id = iwl3945_hw_find_station(priv, hdr->addr1);
@@ -803,17 +805,15 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev,
out:
- sta->last_txrate_idx = index;
+ rs_sta->last_txrate_idx = index;
if (sband->band == IEEE80211_BAND_5GHZ)
- sta->txrate_idx = sta->last_txrate_idx - IWL_FIRST_OFDM_RATE;
+ sel->rate_idx = rs_sta->last_txrate_idx - IWL_FIRST_OFDM_RATE;
else
- sta->txrate_idx = sta->last_txrate_idx;
+ sel->rate_idx = rs_sta->last_txrate_idx;
rcu_read_unlock();
IWL_DEBUG_RATE("leave: %d\n", index);
-
- sel->rate_idx = sta->txrate_idx;
}
static struct rate_control_ops rs_ops = {
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index 3d100e898249..7ca5627cc078 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -520,10 +520,10 @@ static int iwl3945_is_network_packet(struct iwl3945_priv *priv,
/* Filter incoming packets to determine if they are targeted toward
* this network, discarding packets coming from ourselves */
switch (priv->iw_mode) {
- case IEEE80211_IF_TYPE_IBSS: /* Header: Dest. | Source | BSSID */
+ case NL80211_IFTYPE_ADHOC: /* Header: Dest. | Source | BSSID */
/* packets to our IBSS update information */
return !compare_ether_addr(header->addr3, priv->bssid);
- case IEEE80211_IF_TYPE_STA: /* Header: Dest. | AP{BSSID} | Source */
+ case NL80211_IFTYPE_STATION: /* Header: Dest. | AP{BSSID} | Source */
/* packets to our IBSS update information */
return !compare_ether_addr(header->addr2, priv->bssid);
default:
@@ -807,7 +807,7 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl3945_priv *priv,
priv->stations[sta_id].current_rate.rate_n_flags = rate;
- if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
+ if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
(sta_id != priv->hw_setting.bcast_sta_id) &&
(sta_id != IWL_MULTICAST_ID))
priv->stations[IWL_STA_ID].current_rate.rate_n_flags = rate;
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h
index 9bbbc9d7c0e8..2a4933b5fb64 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.h
@@ -851,7 +851,7 @@ struct iwl3945_priv {
/* eeprom */
struct iwl3945_eeprom eeprom;
- enum ieee80211_if_types iw_mode;
+ enum nl80211_iftype iw_mode;
struct sk_buff *ibss_beacon;
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index cccd84c2f8ea..f6003e7996af 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -1569,6 +1569,8 @@ struct iwl_cfg iwl5350_agn_cfg = {
.mod_params = &iwl50_mod_params,
};
+MODULE_FIRMWARE("iwlwifi-5000" IWL5000_UCODE_API ".ucode");
+
module_param_named(disable50, iwl50_mod_params.disable, int, 0444);
MODULE_PARM_DESC(disable50,
"manually disable the 50XX radio (default 0 [radio on])");
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
index c293e5b6cbb5..8b57b390c8ba 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
@@ -163,6 +163,9 @@ struct iwl_lq_sta {
u32 dbg_fixed_rate;
#endif
struct iwl_priv *drv;
+
+ /* used to be in sta_info */
+ int last_txrate_idx;
};
static void rs_rate_scale_perform(struct iwl_priv *priv,
@@ -356,18 +359,12 @@ static void rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv,
struct iwl_lq_sta *lq_data, u8 tid,
struct sta_info *sta)
{
- unsigned long state;
DECLARE_MAC_BUF(mac);
- spin_lock_bh(&sta->lock);
- state = sta->ampdu_mlme.tid_state_tx[tid];
- spin_unlock_bh(&sta->lock);
-
- if (state == HT_AGG_STATE_IDLE &&
- rs_tl_get_load(lq_data, tid) > IWL_AGG_LOAD_THRESHOLD) {
+ if (rs_tl_get_load(lq_data, tid) > IWL_AGG_LOAD_THRESHOLD) {
IWL_DEBUG_HT("Starting Tx agg: STA: %s tid: %d\n",
- print_mac(mac, sta->addr), tid);
- ieee80211_start_tx_ba_session(priv->hw, sta->addr, tid);
+ print_mac(mac, sta->sta.addr), tid);
+ ieee80211_start_tx_ba_session(priv->hw, sta->sta.addr, tid);
}
}
@@ -821,7 +818,7 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev,
lq_sta = (struct iwl_lq_sta *)sta->rate_ctrl_priv;
- if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
+ if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
!lq_sta->ibss_sta_added)
goto out;
@@ -1151,10 +1148,10 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv,
s8 is_green = lq_sta->is_green;
if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) ||
- !sta->ht_info.ht_supported)
+ !sta->sta.ht_info.ht_supported)
return -1;
- if (((sta->ht_info.cap & IEEE80211_HT_CAP_SM_PS) >> 2)
+ if (((sta->sta.ht_info.cap & IEEE80211_HT_CAP_SM_PS) >> 2)
== WLAN_HT_CAP_SM_PS_STATIC)
return -1;
@@ -1219,7 +1216,7 @@ static int rs_switch_to_siso(struct iwl_priv *priv,
s32 rate;
if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) ||
- !sta->ht_info.ht_supported)
+ !sta->sta.ht_info.ht_supported)
return -1;
IWL_DEBUG_RATE("LQ: try to switch to SISO\n");
@@ -1728,7 +1725,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
return;
lq_sta = (struct iwl_lq_sta *)sta->rate_ctrl_priv;
- lq_sta->supp_rates = sta->supp_rates[lq_sta->band];
+ lq_sta->supp_rates = sta->sta.supp_rates[lq_sta->band];
tid = rs_tl_add_packet(lq_sta, hdr);
@@ -1746,7 +1743,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
is_green = lq_sta->is_green;
/* current tx rate */
- index = sta->last_txrate_idx;
+ index = lq_sta->last_txrate_idx;
IWL_DEBUG_RATE("Rate scale index %d for type %d\n", index,
tbl->lq_type);
@@ -2059,15 +2056,7 @@ lq_update:
out:
tbl->current_rate = rate_n_flags_from_tbl(tbl, index, is_green);
i = index;
- sta->last_txrate_idx = i;
-
- /* sta->txrate_idx is an index to A mode rates which start
- * at IWL_FIRST_OFDM_RATE
- */
- if (lq_sta->band == IEEE80211_BAND_5GHZ)
- sta->txrate_idx = i - IWL_FIRST_OFDM_RATE;
- else
- sta->txrate_idx = i;
+ lq_sta->last_txrate_idx = i;
return;
}
@@ -2090,10 +2079,10 @@ static void rs_initialize_lq(struct iwl_priv *priv,
goto out;
lq_sta = (struct iwl_lq_sta *)sta->rate_ctrl_priv;
- i = sta->last_txrate_idx;
+ i = lq_sta->last_txrate_idx;
if ((lq_sta->lq.sta_id == 0xff) &&
- (priv->iw_mode == IEEE80211_IF_TYPE_IBSS))
+ (priv->iw_mode == NL80211_IFTYPE_ADHOC))
goto out;
valid_tx_ant = priv->hw_params.valid_tx_ant;
@@ -2161,9 +2150,9 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev,
}
lq_sta = (struct iwl_lq_sta *)sta->rate_ctrl_priv;
- i = sta->last_txrate_idx;
+ i = lq_sta->last_txrate_idx;
- if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
+ if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
!lq_sta->ibss_sta_added) {
u8 sta_id = iwl_find_station(priv, hdr->addr1);
DECLARE_MAC_BUF(mac);
@@ -2230,8 +2219,7 @@ static void rs_rate_init(void *priv_rate, void *priv_sta,
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
lq_sta->flush_timer = 0;
- lq_sta->supp_rates = sta->supp_rates[sband->band];
- sta->txrate_idx = 3;
+ lq_sta->supp_rates = sta->sta.supp_rates[sband->band];
for (j = 0; j < LQ_SIZE; j++)
for (i = 0; i < IWL_RATE_COUNT; i++)
rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]);
@@ -2243,18 +2231,18 @@ static void rs_rate_init(void *priv_rate, void *priv_sta,
* after assoc.. */
lq_sta->ibss_sta_added = 0;
- if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
- u8 sta_id = iwl_find_station(priv, sta->addr);
+ if (priv->iw_mode == NL80211_IFTYPE_AP) {
+ u8 sta_id = iwl_find_station(priv, sta->sta.addr);
DECLARE_MAC_BUF(mac);
/* for IBSS the call are from tasklet */
IWL_DEBUG_RATE("LQ: ADD station %s\n",
- print_mac(mac, sta->addr));
+ print_mac(mac, sta->sta.addr));
if (sta_id == IWL_INVALID_STATION) {
IWL_DEBUG_RATE("LQ: ADD station %s\n",
- print_mac(mac, sta->addr));
- sta_id = iwl_add_station_flags(priv, sta->addr,
+ print_mac(mac, sta->sta.addr));
+ sta_id = iwl_add_station_flags(priv, sta->sta.addr,
0, CMD_ASYNC, NULL);
}
if ((sta_id != IWL_INVALID_STATION)) {
@@ -2266,14 +2254,14 @@ static void rs_rate_init(void *priv_rate, void *priv_sta,
}
/* Find highest tx rate supported by hardware and destination station */
+ lq_sta->last_txrate_idx = 3;
for (i = 0; i < sband->n_bitrates; i++)
- if (sta->supp_rates[sband->band] & BIT(i))
- sta->txrate_idx = i;
+ if (sta->sta.supp_rates[sband->band] & BIT(i))
+ lq_sta->last_txrate_idx = i;
- sta->last_txrate_idx = sta->txrate_idx;
/* For MODE_IEEE80211A, skip over cck rates in global rate table */
if (local->hw.conf.channel->band == IEEE80211_BAND_5GHZ)
- sta->last_txrate_idx += IWL_FIRST_OFDM_RATE;
+ lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE;
lq_sta->is_dup = 0;
lq_sta->is_green = rs_use_green(priv, conf);
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 31ea28858896..273762769767 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -337,7 +337,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
/* If we have set the ASSOC_MSK and we are in BSS mode then
* add the IWL_AP_ID to the station rate table */
if (new_assoc) {
- if (priv->iw_mode == IEEE80211_IF_TYPE_STA) {
+ if (priv->iw_mode == NL80211_IFTYPE_STATION) {
ret = iwl_rxon_add_station(priv,
priv->active_rxon.bssid_addr, 1);
if (ret == IWL_INVALID_STATION) {
@@ -448,8 +448,8 @@ static unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv,
const u8 *dest, int left)
{
if (!iwl_is_associated(priv) || !priv->ibss_beacon ||
- ((priv->iw_mode != IEEE80211_IF_TYPE_IBSS) &&
- (priv->iw_mode != IEEE80211_IF_TYPE_AP)))
+ ((priv->iw_mode != NL80211_IFTYPE_ADHOC) &&
+ (priv->iw_mode != NL80211_IFTYPE_AP)))
return 0;
if (priv->ibss_beacon->len > left)
@@ -672,7 +672,7 @@ static void iwl4965_setup_rxon_timing(struct iwl_priv *priv)
beacon_int = priv->beacon_int;
spin_unlock_irqrestore(&priv->lock, flags);
- if (priv->iw_mode == IEEE80211_IF_TYPE_STA) {
+ if (priv->iw_mode == NL80211_IFTYPE_STATION) {
if (beacon_int == 0) {
priv->rxon_timing.beacon_interval = cpu_to_le16(100);
priv->rxon_timing.beacon_init_val = cpu_to_le32(102400);
@@ -721,7 +721,7 @@ static void iwl_set_flags_for_band(struct iwl_priv *priv,
else
priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
- if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+ if (priv->iw_mode == NL80211_IFTYPE_ADHOC)
priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK;
@@ -740,23 +740,23 @@ static void iwl4965_connection_init_rx_config(struct iwl_priv *priv)
memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon));
switch (priv->iw_mode) {
- case IEEE80211_IF_TYPE_AP:
+ case NL80211_IFTYPE_AP:
priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP;
break;
- case IEEE80211_IF_TYPE_STA:
+ case NL80211_IFTYPE_STATION:
priv->staging_rxon.dev_type = RXON_DEV_TYPE_ESS;
priv->staging_rxon.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK;
break;
- case IEEE80211_IF_TYPE_IBSS:
+ case NL80211_IFTYPE_ADHOC:
priv->staging_rxon.dev_type = RXON_DEV_TYPE_IBSS;
priv->staging_rxon.flags = RXON_FLG_SHORT_PREAMBLE_MSK;
priv->staging_rxon.filter_flags = RXON_FILTER_BCON_AWARE_MSK |
RXON_FILTER_ACCEPT_GRP_MSK;
break;
- case IEEE80211_IF_TYPE_MNTR:
+ case NL80211_IFTYPE_MONITOR:
priv->staging_rxon.dev_type = RXON_DEV_TYPE_SNIFFER;
priv->staging_rxon.filter_flags = RXON_FILTER_PROMISC_MSK |
RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK;
@@ -785,7 +785,7 @@ static void iwl4965_connection_init_rx_config(struct iwl_priv *priv)
* in some case A channels are all non IBSS
* in this case force B/G channel
*/
- if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
+ if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
!(is_channel_ibss(ch_info)))
ch_info = &priv->channel_info[0];
@@ -1182,7 +1182,7 @@ static void iwl4965_rx_beacon_notif(struct iwl_priv *priv,
le32_to_cpu(beacon->low_tsf), rate);
#endif
- if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) &&
+ if ((priv->iw_mode == NL80211_IFTYPE_AP) &&
(!test_bit(STATUS_EXIT_PENDING, &priv->status)))
queue_work(priv->workqueue, &priv->beacon_update);
}
@@ -2388,7 +2388,7 @@ static void iwl4965_bg_set_monitor(struct work_struct *work)
mutex_lock(&priv->mutex);
- ret = iwl4965_set_mode(priv, IEEE80211_IF_TYPE_MNTR);
+ ret = iwl4965_set_mode(priv, NL80211_IFTYPE_MONITOR);
if (ret) {
if (ret == -EAGAIN)
@@ -2469,7 +2469,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv)
DECLARE_MAC_BUF(mac);
unsigned long flags;
- if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+ if (priv->iw_mode == NL80211_IFTYPE_AP) {
IWL_ERROR("%s Should not be called in AP mode\n", __func__);
return;
}
@@ -2524,7 +2524,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv)
else
priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
- if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+ if (priv->iw_mode == NL80211_IFTYPE_ADHOC)
priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
}
@@ -2532,10 +2532,10 @@ static void iwl4965_post_associate(struct iwl_priv *priv)
iwl4965_commit_rxon(priv);
switch (priv->iw_mode) {
- case IEEE80211_IF_TYPE_STA:
+ case NL80211_IFTYPE_STATION:
break;
- case IEEE80211_IF_TYPE_IBSS:
+ case NL80211_IFTYPE_ADHOC:
/* assume default assoc id */
priv->assoc_id = 1;
@@ -2551,7 +2551,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv)
break;
}
- if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+ if (priv->iw_mode == NL80211_IFTYPE_ADHOC)
priv->assoc_station_added = 1;
spin_lock_irqsave(&priv->lock, flags);
@@ -2828,7 +2828,7 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co
goto out;
}
- if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS &&
+ if (priv->iw_mode == NL80211_IFTYPE_ADHOC &&
!is_channel_ibss(ch_info)) {
IWL_ERROR("channel %d in band %d not IBSS channel\n",
conf->channel->hw_value, conf->channel->band);
@@ -2943,7 +2943,7 @@ static void iwl4965_config_ap(struct iwl_priv *priv)
priv->staging_rxon.flags &=
~RXON_FLG_SHORT_SLOT_MSK;
- if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+ if (priv->iw_mode == NL80211_IFTYPE_ADHOC)
priv->staging_rxon.flags &=
~RXON_FLG_SHORT_SLOT_MSK;
}
@@ -2982,7 +2982,7 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw,
return 0;
}
- if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS &&
+ if (priv->iw_mode == NL80211_IFTYPE_ADHOC &&
conf->changed & IEEE80211_IFCC_BEACON) {
struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
if (!beacon)
@@ -2992,7 +2992,7 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw,
return rc;
}
- if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) &&
+ if ((priv->iw_mode == NL80211_IFTYPE_AP) &&
(!conf->ssid_len)) {
IWL_DEBUG_MAC80211
("Leaving in AP mode because HostAPD is not ready.\n");
@@ -3015,7 +3015,7 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw,
!(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) {
*/
- if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+ if (priv->iw_mode == NL80211_IFTYPE_AP) {
if (!conf->bssid) {
conf->bssid = priv->mac_addr;
memcpy(priv->bssid, priv->mac_addr, ETH_ALEN);
@@ -3050,11 +3050,11 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw,
* to verify) - jpk */
memcpy(priv->bssid, conf->bssid, ETH_ALEN);
- if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
+ if (priv->iw_mode == NL80211_IFTYPE_AP)
iwl4965_config_ap(priv);
else {
rc = iwl4965_commit_rxon(priv);
- if ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && rc)
+ if ((priv->iw_mode == NL80211_IFTYPE_STATION) && rc)
iwl_rxon_add_station(
priv, priv->active_rxon.bssid_addr, 1);
}
@@ -3090,7 +3090,7 @@ static void iwl4965_configure_filter(struct ieee80211_hw *hw,
if (changed_flags & (*total_flags) & FIF_OTHER_BSS) {
IWL_DEBUG_MAC80211("Enter: type %d (0x%x, 0x%x)\n",
- IEEE80211_IF_TYPE_MNTR,
+ NL80211_IFTYPE_MONITOR,
changed_flags, *total_flags);
/* queue work 'cuz mac80211 is holding a lock which
* prevents us from issuing (synchronous) f/w cmds */
@@ -3204,7 +3204,7 @@ static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t ssid_len)
goto out_unlock;
}
- if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { /* APs don't scan */
+ if (priv->iw_mode == NL80211_IFTYPE_AP) { /* APs don't scan */
ret = -EIO;
IWL_ERROR("ERROR: APs don't scan\n");
goto out_unlock;
@@ -3329,7 +3329,7 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
* in 1X mode.
* In legacy wep mode, we use another host command to the uCode */
if (key->alg == ALG_WEP && sta_id == priv->hw_params.bcast_sta_id &&
- priv->iw_mode != IEEE80211_IF_TYPE_AP) {
+ priv->iw_mode != NL80211_IFTYPE_AP) {
if (cmd == SET_KEY)
is_default_wep_key = !priv->key_mapping_key;
else
@@ -3400,7 +3400,7 @@ static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
priv->qos_data.def_qos_parm.ac[q].reserved1 = 0;
priv->qos_data.qos_active = 1;
- if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
+ if (priv->iw_mode == NL80211_IFTYPE_AP)
iwl_activate_qos(priv, 1);
else if (priv->assoc_id && iwl_is_associated(priv))
iwl_activate_qos(priv, 0);
@@ -3413,13 +3413,13 @@ static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
static int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw,
enum ieee80211_ampdu_mlme_action action,
- const u8 *addr, u16 tid, u16 *ssn)
+ struct ieee80211_sta *sta, u16 tid, u16 *ssn)
{
struct iwl_priv *priv = hw->priv;
DECLARE_MAC_BUF(mac);
IWL_DEBUG_HT("A-MPDU action on addr %s tid %d\n",
- print_mac(mac, addr), tid);
+ print_mac(mac, sta->addr), tid);
if (!(priv->cfg->sku & IWL_SKU_N))
return -EACCES;
@@ -3427,16 +3427,16 @@ static int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw,
switch (action) {
case IEEE80211_AMPDU_RX_START:
IWL_DEBUG_HT("start Rx\n");
- return iwl_rx_agg_start(priv, addr, tid, *ssn);
+ return iwl_rx_agg_start(priv, sta->addr, tid, *ssn);
case IEEE80211_AMPDU_RX_STOP:
IWL_DEBUG_HT("stop Rx\n");
- return iwl_rx_agg_stop(priv, addr, tid);
+ return iwl_rx_agg_stop(priv, sta->addr, tid);
case IEEE80211_AMPDU_TX_START:
IWL_DEBUG_HT("start Tx\n");
- return iwl_tx_agg_start(priv, addr, tid, ssn);
+ return iwl_tx_agg_start(priv, sta->addr, tid, ssn);
case IEEE80211_AMPDU_TX_STOP:
IWL_DEBUG_HT("stop Tx\n");
- return iwl_tx_agg_stop(priv, addr, tid);
+ return iwl_tx_agg_stop(priv, sta->addr, tid);
default:
IWL_DEBUG_HT("unknown\n");
return -EINVAL;
@@ -3518,7 +3518,7 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw)
priv->beacon_int = priv->hw->conf.beacon_int;
priv->timestamp = 0;
- if ((priv->iw_mode == IEEE80211_IF_TYPE_STA))
+ if ((priv->iw_mode == NL80211_IFTYPE_STATION))
priv->beacon_int = 0;
spin_unlock_irqrestore(&priv->lock, flags);
@@ -3532,7 +3532,7 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw)
/* we are restarting association process
* clear RXON_FILTER_ASSOC_MSK bit
*/
- if (priv->iw_mode != IEEE80211_IF_TYPE_AP) {
+ if (priv->iw_mode != NL80211_IFTYPE_AP) {
iwl_scan_cancel_timeout(priv, 100);
priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
iwl4965_commit_rxon(priv);
@@ -3541,7 +3541,7 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw)
iwl_power_update_mode(priv, 0);
/* Per mac80211.h: This is only used in IBSS mode... */
- if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) {
+ if (priv->iw_mode != NL80211_IFTYPE_ADHOC) {
/* switch to CAM during association period.
* the ucode will block any association/authentication
@@ -3580,7 +3580,7 @@ static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk
return -EIO;
}
- if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) {
+ if (priv->iw_mode != NL80211_IFTYPE_ADHOC) {
IWL_DEBUG_MAC80211("leave - not IBSS\n");
mutex_unlock(&priv->mutex);
return -EIO;
@@ -4506,7 +4506,10 @@ static struct pci_device_id iwl_hw_card_ids[] = {
{IWL_PCI_DEVICE(0x4235, PCI_ANY_ID, iwl5300_agn_cfg)},
{IWL_PCI_DEVICE(0x4236, PCI_ANY_ID, iwl5300_agn_cfg)},
{IWL_PCI_DEVICE(0x4237, PCI_ANY_ID, iwl5100_agn_cfg)},
- {IWL_PCI_DEVICE(0x423A, PCI_ANY_ID, iwl5350_agn_cfg)},
+/* 5350 WiFi/WiMax */
+ {IWL_PCI_DEVICE(0x423A, 0x1001, iwl5350_agn_cfg)},
+ {IWL_PCI_DEVICE(0x423A, 0x1021, iwl5350_agn_cfg)},
+ {IWL_PCI_DEVICE(0x423B, 0x1011, iwl5350_agn_cfg)},
#endif /* CONFIG_IWL5000 */
{0}
};
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 36d08b0eec43..d80184ee911c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -306,14 +306,14 @@ void iwl_reset_qos(struct iwl_priv *priv)
spin_lock_irqsave(&priv->lock, flags);
priv->qos_data.qos_active = 0;
- if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) {
+ if (priv->iw_mode == NL80211_IFTYPE_ADHOC) {
if (priv->qos_data.qos_enable)
priv->qos_data.qos_active = 1;
if (!(priv->active_rate & 0xfff0)) {
cw_min = 31;
is_legacy = 1;
}
- } else if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+ } else if (priv->iw_mode == NL80211_IFTYPE_AP) {
if (priv->qos_data.qos_enable)
priv->qos_data.qos_active = 1;
} else if (!(priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK)) {
@@ -932,7 +932,7 @@ int iwl_init_drv(struct iwl_priv *priv)
priv->ieee_rates = NULL;
priv->band = IEEE80211_BAND_2GHZ;
- priv->iw_mode = IEEE80211_IF_TYPE_STA;
+ priv->iw_mode = NL80211_IFTYPE_STATION;
priv->use_ant_b_for_management_frame = 1; /* start with ant B */
priv->current_ht_config.sm_ps = WLAN_HT_CAP_SM_PS_DISABLED;
@@ -1396,7 +1396,7 @@ void iwl_radio_kill_sw_disable_radio(struct iwl_priv *priv)
iwl_scan_cancel(priv);
/* FIXME: This is a workaround for AP */
- if (priv->iw_mode != IEEE80211_IF_TYPE_AP) {
+ if (priv->iw_mode != NL80211_IFTYPE_AP) {
spin_lock_irqsave(&priv->lock, flags);
iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
CSR_UCODE_SW_BIT_RFKILL);
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 1823687e5820..c018121085e9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -954,7 +954,7 @@ struct iwl_priv {
u8 *eeprom;
struct iwl_eeprom_calib_info *calib_info;
- enum ieee80211_if_types iw_mode;
+ enum nl80211_iftype iw_mode;
struct sk_buff *ibss_beacon;
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c
index 55ec31ec9e15..60a03d2d2d0e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.c
+++ b/drivers/net/wireless/iwlwifi/iwl-power.c
@@ -290,7 +290,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force)
final_mode = setting->critical_power_setting;
/* driver only support CAM for non STA network */
- if (priv->iw_mode != IEEE80211_IF_TYPE_STA)
+ if (priv->iw_mode != NL80211_IFTYPE_STATION)
final_mode = IWL_POWER_MODE_CAM;
if (!iwl_is_rfkill(priv) && !setting->power_disabled &&
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
index faad4d3f56e1..38b2946b1d81 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -1026,10 +1026,10 @@ static int iwl_is_network_packet(struct iwl_priv *priv,
/* Filter incoming packets to determine if they are targeted toward
* this network, discarding packets coming from ourselves */
switch (priv->iw_mode) {
- case IEEE80211_IF_TYPE_IBSS: /* Header: Dest. | Source | BSSID */
+ case NL80211_IFTYPE_ADHOC: /* Header: Dest. | Source | BSSID */
/* packets to our IBSS update information */
return !compare_ether_addr(header->addr3, priv->bssid);
- case IEEE80211_IF_TYPE_STA: /* Header: Dest. | AP{BSSID} | Source */
+ case NL80211_IFTYPE_STATION: /* Header: Dest. | AP{BSSID} | Source */
/* packets to our IBSS update information */
return !compare_ether_addr(header->addr2, priv->bssid);
default:
@@ -1169,7 +1169,7 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
rx_status.flag |= RX_FLAG_SHORTPRE;
/* Take shortcut when only in monitor mode */
- if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
+ if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
iwl_pass_packet_to_mac80211(priv, include_phy,
rxb, &rx_status);
return;
@@ -1186,7 +1186,7 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
switch (fc & IEEE80211_FCTL_FTYPE) {
case IEEE80211_FTYPE_MGMT:
case IEEE80211_FTYPE_DATA:
- if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
+ if (priv->iw_mode == NL80211_IFTYPE_AP)
iwl_update_ps_mode(priv, fc & IEEE80211_FCTL_PM,
header->addr2);
/* fall through */
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index d026aaf62335..09c264be0496 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -463,7 +463,7 @@ void iwl_init_scan_params(struct iwl_priv *priv)
int iwl_scan_initiate(struct iwl_priv *priv)
{
- if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+ if (priv->iw_mode == NL80211_IFTYPE_AP) {
IWL_ERROR("APs don't scan.\n");
return 0;
}
@@ -868,7 +868,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
scan->tx_cmd.len = cpu_to_le16(cmd_len);
- if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR)
+ if (priv->iw_mode == NL80211_IFTYPE_MONITOR)
scan->filter_flags = RXON_FILTER_PROMISC_MSK;
scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK |
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c
index a72569f1acb5..61797f3f8d5c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.c
@@ -47,8 +47,8 @@ u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr)
unsigned long flags;
DECLARE_MAC_BUF(mac);
- if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) ||
- (priv->iw_mode == IEEE80211_IF_TYPE_AP))
+ if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) ||
+ (priv->iw_mode == NL80211_IFTYPE_AP))
start = IWL_STA_ID;
if (is_broadcast_ether_addr(addr))
@@ -74,7 +74,7 @@ EXPORT_SYMBOL(iwl_find_station);
int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
{
- if (priv->iw_mode == IEEE80211_IF_TYPE_STA) {
+ if (priv->iw_mode == NL80211_IFTYPE_STATION) {
return IWL_AP_ID;
} else {
u8 *da = ieee80211_get_DA(hdr);
@@ -286,7 +286,7 @@ u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap,
/* BCAST station and IBSS stations do not work in HT mode */
if (sta_id != priv->hw_params.bcast_sta_id &&
- priv->iw_mode != IEEE80211_IF_TYPE_IBSS)
+ priv->iw_mode != NL80211_IFTYPE_ADHOC)
iwl_set_ht_add_station(priv, sta_id, ht_info);
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
@@ -817,7 +817,7 @@ int iwl_send_lq_cmd(struct iwl_priv *priv,
};
if ((lq->sta_id == 0xFF) &&
- (priv->iw_mode == IEEE80211_IF_TYPE_IBSS))
+ (priv->iw_mode == NL80211_IFTYPE_ADHOC))
return -EINVAL;
if (lq->sta_id == 0xFF)
@@ -904,7 +904,7 @@ int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
if ((is_ap) &&
(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) &&
- (priv->iw_mode == IEEE80211_IF_TYPE_STA))
+ (priv->iw_mode == NL80211_IFTYPE_STATION))
sta_id = iwl_add_station_flags(priv, addr, is_ap,
0, cur_ht_config);
else
@@ -938,11 +938,11 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
/* If we are a client station in a BSS network, use the special
* AP station entry (that's the only station we communicate with) */
- case IEEE80211_IF_TYPE_STA:
+ case NL80211_IFTYPE_STATION:
return IWL_AP_ID;
/* If we are an AP, then find the station, or use BCAST */
- case IEEE80211_IF_TYPE_AP:
+ case NL80211_IFTYPE_AP:
sta_id = iwl_find_station(priv, hdr->addr1);
if (sta_id != IWL_INVALID_STATION)
return sta_id;
@@ -950,7 +950,7 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
/* If this frame is going out to an IBSS network, find the station,
* or create a new station table entry */
- case IEEE80211_IF_TYPE_IBSS:
+ case NL80211_IFTYPE_ADHOC:
sta_id = iwl_find_station(priv, hdr->addr1);
if (sta_id != IWL_INVALID_STATION)
return sta_id;
@@ -970,7 +970,7 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
/* If we are in monitor mode, use BCAST. This is required for
* packet injection. */
- case IEEE80211_IF_TYPE_MNTR:
+ case NL80211_IFTYPE_MONITOR:
return priv->hw_params.bcast_sta_id;
default:
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 9d5bcf46cbe9..e9feca4033f9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -814,10 +814,10 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
/* drop all data frame if we are not associated */
if (ieee80211_is_data(fc) &&
- (priv->iw_mode != IEEE80211_IF_TYPE_MNTR ||
+ (priv->iw_mode != NL80211_IFTYPE_MONITOR ||
!(info->flags & IEEE80211_TX_CTL_INJECTED)) && /* packet injection */
(!iwl_is_associated(priv) ||
- ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && !priv->assoc_id) ||
+ ((priv->iw_mode == NL80211_IFTYPE_STATION) && !priv->assoc_id) ||
!priv->assoc_station_added)) {
IWL_DEBUG_DROP("Dropping - !iwl_is_associated\n");
goto drop_unlock;
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index cbbe73a12887..62b26befddc5 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -1160,7 +1160,7 @@ static int iwl3945_commit_rxon(struct iwl3945_priv *priv)
/* If we have set the ASSOC_MSK and we are in BSS mode then
* add the IWL_AP_ID to the station rate table */
if (iwl3945_is_associated(priv) &&
- (priv->iw_mode == IEEE80211_IF_TYPE_STA))
+ (priv->iw_mode == NL80211_IFTYPE_STATION))
if (iwl3945_add_station(priv, priv->active_rxon.bssid_addr, 1, 0)
== IWL_INVALID_STATION) {
IWL_ERROR("Error adding AP address for transmit.\n");
@@ -1447,8 +1447,8 @@ unsigned int iwl3945_fill_beacon_frame(struct iwl3945_priv *priv,
{
if (!iwl3945_is_associated(priv) || !priv->ibss_beacon ||
- ((priv->iw_mode != IEEE80211_IF_TYPE_IBSS) &&
- (priv->iw_mode != IEEE80211_IF_TYPE_AP)))
+ ((priv->iw_mode != NL80211_IFTYPE_ADHOC) &&
+ (priv->iw_mode != NL80211_IFTYPE_AP)))
return 0;
if (priv->ibss_beacon->len > left)
@@ -1746,14 +1746,14 @@ static void iwl3945_reset_qos(struct iwl3945_priv *priv)
spin_lock_irqsave(&priv->lock, flags);
priv->qos_data.qos_active = 0;
- if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) {
+ if (priv->iw_mode == NL80211_IFTYPE_ADHOC) {
if (priv->qos_data.qos_enable)
priv->qos_data.qos_active = 1;
if (!(priv->active_rate & 0xfff0)) {
cw_min = 31;
is_legacy = 1;
}
- } else if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+ } else if (priv->iw_mode == NL80211_IFTYPE_AP) {
if (priv->qos_data.qos_enable)
priv->qos_data.qos_active = 1;
} else if (!(priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK)) {
@@ -2120,7 +2120,7 @@ static void iwl3945_setup_rxon_timing(struct iwl3945_priv *priv)
beacon_int = priv->beacon_int;
spin_unlock_irqrestore(&priv->lock, flags);
- if (priv->iw_mode == IEEE80211_IF_TYPE_STA) {
+ if (priv->iw_mode == NL80211_IFTYPE_STATION) {
if (beacon_int == 0) {
priv->rxon_timing.beacon_interval = cpu_to_le16(100);
priv->rxon_timing.beacon_init_val = cpu_to_le32(102400);
@@ -2156,7 +2156,7 @@ static void iwl3945_setup_rxon_timing(struct iwl3945_priv *priv)
static int iwl3945_scan_initiate(struct iwl3945_priv *priv)
{
- if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+ if (priv->iw_mode == NL80211_IFTYPE_AP) {
IWL_ERROR("APs don't scan.\n");
return 0;
}
@@ -2218,7 +2218,7 @@ static void iwl3945_set_flags_for_phymode(struct iwl3945_priv *priv,
else
priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
- if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+ if (priv->iw_mode == NL80211_IFTYPE_ADHOC)
priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK;
@@ -2237,23 +2237,23 @@ static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv)
memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon));
switch (priv->iw_mode) {
- case IEEE80211_IF_TYPE_AP:
+ case NL80211_IFTYPE_AP:
priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP;
break;
- case IEEE80211_IF_TYPE_STA:
+ case NL80211_IFTYPE_STATION:
priv->staging_rxon.dev_type = RXON_DEV_TYPE_ESS;
priv->staging_rxon.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK;
break;
- case IEEE80211_IF_TYPE_IBSS:
+ case NL80211_IFTYPE_ADHOC:
priv->staging_rxon.dev_type = RXON_DEV_TYPE_IBSS;
priv->staging_rxon.flags = RXON_FLG_SHORT_PREAMBLE_MSK;
priv->staging_rxon.filter_flags = RXON_FILTER_BCON_AWARE_MSK |
RXON_FILTER_ACCEPT_GRP_MSK;
break;
- case IEEE80211_IF_TYPE_MNTR:
+ case NL80211_IFTYPE_MONITOR:
priv->staging_rxon.dev_type = RXON_DEV_TYPE_SNIFFER;
priv->staging_rxon.filter_flags = RXON_FILTER_PROMISC_MSK |
RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK;
@@ -2282,7 +2282,7 @@ static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv)
* in some case A channels are all non IBSS
* in this case force B/G channel
*/
- if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
+ if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
!(is_channel_ibss(ch_info)))
ch_info = &priv->channel_info[0];
@@ -2302,7 +2302,7 @@ static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv)
static int iwl3945_set_mode(struct iwl3945_priv *priv, int mode)
{
- if (mode == IEEE80211_IF_TYPE_IBSS) {
+ if (mode == NL80211_IFTYPE_ADHOC) {
const struct iwl3945_channel_info *ch_info;
ch_info = iwl3945_get_channel_info(priv,
@@ -2469,11 +2469,11 @@ static int iwl3945_get_sta_id(struct iwl3945_priv *priv, struct ieee80211_hdr *h
/* If we are a client station in a BSS network, use the special
* AP station entry (that's the only station we communicate with) */
- case IEEE80211_IF_TYPE_STA:
+ case NL80211_IFTYPE_STATION:
return IWL_AP_ID;
/* If we are an AP, then find the station, or use BCAST */
- case IEEE80211_IF_TYPE_AP:
+ case NL80211_IFTYPE_AP:
sta_id = iwl3945_hw_find_station(priv, hdr->addr1);
if (sta_id != IWL_INVALID_STATION)
return sta_id;
@@ -2481,7 +2481,7 @@ static int iwl3945_get_sta_id(struct iwl3945_priv *priv, struct ieee80211_hdr *h
/* If this frame is going out to an IBSS network, find the station,
* or create a new station table entry */
- case IEEE80211_IF_TYPE_IBSS: {
+ case NL80211_IFTYPE_ADHOC: {
DECLARE_MAC_BUF(mac);
/* Create new station table entry */
@@ -2502,7 +2502,7 @@ static int iwl3945_get_sta_id(struct iwl3945_priv *priv, struct ieee80211_hdr *h
}
/* If we are in monitor mode, use BCAST. This is required for
* packet injection. */
- case IEEE80211_IF_TYPE_MNTR:
+ case NL80211_IFTYPE_MONITOR:
return priv->hw_setting.bcast_sta_id;
default:
@@ -2565,9 +2565,9 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, struct sk_buff *skb)
/* drop all data frame if we are not associated */
if (ieee80211_is_data(fc) &&
- (priv->iw_mode != IEEE80211_IF_TYPE_MNTR) && /* packet injection */
+ (priv->iw_mode != NL80211_IFTYPE_MONITOR) && /* packet injection */
(!iwl3945_is_associated(priv) ||
- ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && !priv->assoc_id))) {
+ ((priv->iw_mode == NL80211_IFTYPE_STATION) && !priv->assoc_id))) {
IWL_DEBUG_DROP("Dropping - !iwl3945_is_associated\n");
goto drop_unlock;
}
@@ -2806,7 +2806,7 @@ static void iwl3945_radio_kill_sw(struct iwl3945_priv *priv, int disable_radio)
if (disable_radio) {
iwl3945_scan_cancel(priv);
/* FIXME: This is a workaround for AP */
- if (priv->iw_mode != IEEE80211_IF_TYPE_AP) {
+ if (priv->iw_mode != NL80211_IFTYPE_AP) {
spin_lock_irqsave(&priv->lock, flags);
iwl3945_write32(priv, CSR_UCODE_DRV_GP1_SET,
CSR_UCODE_SW_BIT_RFKILL);
@@ -3161,7 +3161,7 @@ static void iwl3945_rx_beacon_notif(struct iwl3945_priv *priv,
le32_to_cpu(beacon->low_tsf), rate);
#endif
- if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) &&
+ if ((priv->iw_mode == NL80211_IFTYPE_AP) &&
(!test_bit(STATUS_EXIT_PENDING, &priv->status)))
queue_work(priv->workqueue, &priv->beacon_update);
}
@@ -6059,7 +6059,7 @@ static void iwl3945_bg_set_monitor(struct work_struct *work)
if (!iwl3945_is_ready(priv))
IWL_DEBUG(IWL_DL_STATE, "leave - not ready\n");
else
- if (iwl3945_set_mode(priv, IEEE80211_IF_TYPE_MNTR) != 0)
+ if (iwl3945_set_mode(priv, NL80211_IFTYPE_MONITOR) != 0)
IWL_ERROR("iwl3945_set_mode() failed\n");
mutex_unlock(&priv->mutex);
@@ -6248,7 +6248,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
/* select Rx antennas */
scan->flags |= iwl3945_get_antenna_flags(priv);
- if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR)
+ if (priv->iw_mode == NL80211_IFTYPE_MONITOR)
scan->filter_flags = RXON_FILTER_PROMISC_MSK;
scan->channel_count =
@@ -6323,7 +6323,7 @@ static void iwl3945_post_associate(struct iwl3945_priv *priv)
struct ieee80211_conf *conf = NULL;
DECLARE_MAC_BUF(mac);
- if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+ if (priv->iw_mode == NL80211_IFTYPE_AP) {
IWL_ERROR("%s Should not be called in AP mode\n", __func__);
return;
}
@@ -6372,7 +6372,7 @@ static void iwl3945_post_associate(struct iwl3945_priv *priv)
else
priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
- if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+ if (priv->iw_mode == NL80211_IFTYPE_ADHOC)
priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
}
@@ -6380,11 +6380,11 @@ static void iwl3945_post_associate(struct iwl3945_priv *priv)
iwl3945_commit_rxon(priv);
switch (priv->iw_mode) {
- case IEEE80211_IF_TYPE_STA:
+ case NL80211_IFTYPE_STATION:
iwl3945_rate_scale_init(priv->hw, IWL_AP_ID);
break;
- case IEEE80211_IF_TYPE_IBSS:
+ case NL80211_IFTYPE_ADHOC:
/* clear out the station table */
iwl3945_clear_stations_table(priv);
@@ -6754,7 +6754,7 @@ static void iwl3945_config_ap(struct iwl3945_priv *priv)
priv->staging_rxon.flags &=
~RXON_FLG_SHORT_SLOT_MSK;
- if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+ if (priv->iw_mode == NL80211_IFTYPE_ADHOC)
priv->staging_rxon.flags &=
~RXON_FLG_SHORT_SLOT_MSK;
}
@@ -6791,7 +6791,7 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw,
}
/* handle this temporarily here */
- if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS &&
+ if (priv->iw_mode == NL80211_IFTYPE_ADHOC &&
conf->changed & IEEE80211_IFCC_BEACON) {
struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
if (!beacon)
@@ -6803,7 +6803,7 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw,
/* XXX: this MUST use conf->mac_addr */
- if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) &&
+ if ((priv->iw_mode == NL80211_IFTYPE_AP) &&
(!conf->ssid_len)) {
IWL_DEBUG_MAC80211
("Leaving in AP mode because HostAPD is not ready.\n");
@@ -6826,7 +6826,7 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw,
!(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) {
*/
- if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+ if (priv->iw_mode == NL80211_IFTYPE_AP) {
if (!conf->bssid) {
conf->bssid = priv->mac_addr;
memcpy(priv->bssid, priv->mac_addr, ETH_ALEN);
@@ -6861,11 +6861,11 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw,
* to verify) - jpk */
memcpy(priv->bssid, conf->bssid, ETH_ALEN);
- if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
+ if (priv->iw_mode == NL80211_IFTYPE_AP)
iwl3945_config_ap(priv);
else {
rc = iwl3945_commit_rxon(priv);
- if ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && rc)
+ if ((priv->iw_mode == NL80211_IFTYPE_STATION) && rc)
iwl3945_add_station(priv,
priv->active_rxon.bssid_addr, 1, 0);
}
@@ -6901,7 +6901,7 @@ static void iwl3945_configure_filter(struct ieee80211_hw *hw,
if (changed_flags & (*total_flags) & FIF_OTHER_BSS) {
IWL_DEBUG_MAC80211("Enter: type %d (0x%x, 0x%x)\n",
- IEEE80211_IF_TYPE_MNTR,
+ NL80211_IFTYPE_MONITOR,
changed_flags, *total_flags);
/* queue work 'cuz mac80211 is holding a lock which
* prevents us from issuing (synchronous) f/w cmds */
@@ -7010,7 +7010,7 @@ static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
goto out_unlock;
}
- if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { /* APs don't scan */
+ if (priv->iw_mode == NL80211_IFTYPE_AP) { /* APs don't scan */
rc = -EIO;
IWL_ERROR("ERROR: APs don't scan\n");
goto out_unlock;
@@ -7152,7 +7152,7 @@ static int iwl3945_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
spin_unlock_irqrestore(&priv->lock, flags);
mutex_lock(&priv->mutex);
- if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
+ if (priv->iw_mode == NL80211_IFTYPE_AP)
iwl3945_activate_qos(priv, 1);
else if (priv->assoc_id && iwl3945_is_associated(priv))
iwl3945_activate_qos(priv, 0);
@@ -7239,7 +7239,7 @@ static void iwl3945_mac_reset_tsf(struct ieee80211_hw *hw)
priv->beacon_int = priv->hw->conf.beacon_int;
priv->timestamp1 = 0;
priv->timestamp0 = 0;
- if ((priv->iw_mode == IEEE80211_IF_TYPE_STA))
+ if ((priv->iw_mode == NL80211_IFTYPE_STATION))
priv->beacon_int = 0;
spin_unlock_irqrestore(&priv->lock, flags);
@@ -7253,14 +7253,14 @@ static void iwl3945_mac_reset_tsf(struct ieee80211_hw *hw)
/* we are restarting association process
* clear RXON_FILTER_ASSOC_MSK bit
*/
- if (priv->iw_mode != IEEE80211_IF_TYPE_AP) {
+ if (priv->iw_mode != NL80211_IFTYPE_AP) {
iwl3945_scan_cancel_timeout(priv, 100);
priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
iwl3945_commit_rxon(priv);
}
/* Per mac80211.h: This is only used in IBSS mode... */
- if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) {
+ if (priv->iw_mode != NL80211_IFTYPE_ADHOC) {
IWL_DEBUG_MAC80211("leave - not in IBSS\n");
mutex_unlock(&priv->mutex);
@@ -7289,7 +7289,7 @@ static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk
return -EIO;
}
- if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) {
+ if (priv->iw_mode != NL80211_IFTYPE_ADHOC) {
IWL_DEBUG_MAC80211("leave - not IBSS\n");
mutex_unlock(&priv->mutex);
return -EIO;
@@ -7996,7 +7996,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
IWL_DEBUG_INFO("Radio disabled.\n");
}
- priv->iw_mode = IEEE80211_IF_TYPE_STA;
+ priv->iw_mode = NL80211_IFTYPE_STATION;
printk(KERN_INFO DRV_NAME
": Detected Intel Wireless WiFi Link %s\n", priv->cfg->name);
@@ -8376,6 +8376,8 @@ static void __exit iwl3945_exit(void)
iwl3945_rate_control_unregister();
}
+MODULE_FIRMWARE("iwlwifi-3945" IWL3945_UCODE_API ".ucode");
+
module_param_named(antenna, iwl3945_param_antenna, int, 0444);
MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
module_param_named(disable, iwl3945_param_disable, int, 0444);
diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c
index 4ddf44b2758b..92be60415d04 100644
--- a/drivers/net/wireless/libertas/assoc.c
+++ b/drivers/net/wireless/libertas/assoc.c
@@ -823,11 +823,7 @@ static int assoc_helper_mode(struct lbs_private *priv,
}
priv->mode = assoc_req->mode;
- ret = lbs_prepare_and_send_command(priv,
- CMD_802_11_SNMP_MIB,
- 0, CMD_OPTION_WAITFORRSP,
- OID_802_11_INFRASTRUCTURE_MODE,
- /* Shoot me now */ (void *) (size_t) assoc_req->mode);
+ ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, assoc_req->mode);
done:
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index 5fef05f3cd00..aee19fa844e4 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -480,138 +480,103 @@ int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action,
return ret;
}
-static int lbs_cmd_802_11_reset(struct cmd_ds_command *cmd, int cmd_action)
+/**
+ * @brief Set an SNMP MIB value
+ *
+ * @param priv A pointer to struct lbs_private structure
+ * @param oid The OID to set in the firmware
+ * @param val Value to set the OID to
+ *
+ * @return 0 on success, error on failure
+ */
+int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val)
{
- struct cmd_ds_802_11_reset *reset = &cmd->params.reset;
+ struct cmd_ds_802_11_snmp_mib cmd;
+ int ret;
lbs_deb_enter(LBS_DEB_CMD);
- cmd->command = cpu_to_le16(CMD_802_11_RESET);
- cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset) + S_DS_GEN);
- reset->action = cpu_to_le16(cmd_action);
-
- lbs_deb_leave(LBS_DEB_CMD);
- return 0;
-}
-
-static int lbs_cmd_802_11_snmp_mib(struct lbs_private *priv,
- struct cmd_ds_command *cmd,
- int cmd_action,
- int cmd_oid, void *pdata_buf)
-{
- struct cmd_ds_802_11_snmp_mib *pSNMPMIB = &cmd->params.smib;
- u8 ucTemp;
-
- lbs_deb_enter(LBS_DEB_CMD);
-
- lbs_deb_cmd("SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid);
-
- cmd->command = cpu_to_le16(CMD_802_11_SNMP_MIB);
- cmd->size = cpu_to_le16(sizeof(*pSNMPMIB) + S_DS_GEN);
-
- switch (cmd_oid) {
- case OID_802_11_INFRASTRUCTURE_MODE:
- {
- u8 mode = (u8) (size_t) pdata_buf;
- pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
- pSNMPMIB->oid = cpu_to_le16((u16) DESIRED_BSSTYPE_I);
- pSNMPMIB->bufsize = cpu_to_le16(sizeof(u8));
- if (mode == IW_MODE_ADHOC) {
- ucTemp = SNMP_MIB_VALUE_ADHOC;
- } else {
- /* Infra and Auto modes */
- ucTemp = SNMP_MIB_VALUE_INFRA;
- }
-
- memmove(pSNMPMIB->value, &ucTemp, sizeof(u8));
+ memset(&cmd, 0, sizeof (cmd));
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+ cmd.action = cpu_to_le16(CMD_ACT_SET);
+ cmd.oid = cpu_to_le16((u16) oid);
+ switch (oid) {
+ case SNMP_MIB_OID_BSS_TYPE:
+ cmd.bufsize = cpu_to_le16(sizeof(u8));
+ cmd.value[0] = (val == IW_MODE_ADHOC) ? 2 : 1;
break;
- }
-
- case OID_802_11D_ENABLE:
- {
- u32 ulTemp;
-
- pSNMPMIB->oid = cpu_to_le16((u16) DOT11D_I);
-
- if (cmd_action == CMD_ACT_SET) {
- pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
- pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
- ulTemp = *(u32 *)pdata_buf;
- *((__le16 *)(pSNMPMIB->value)) =
- cpu_to_le16((u16) ulTemp);
- }
- break;
- }
-
- case OID_802_11_FRAGMENTATION_THRESHOLD:
- {
- u32 ulTemp;
-
- pSNMPMIB->oid = cpu_to_le16((u16) FRAGTHRESH_I);
-
- if (cmd_action == CMD_ACT_GET) {
- pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET);
- } else if (cmd_action == CMD_ACT_SET) {
- pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
- pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
- ulTemp = *((u32 *) pdata_buf);
- *((__le16 *)(pSNMPMIB->value)) =
- cpu_to_le16((u16) ulTemp);
-
- }
-
- break;
- }
-
- case OID_802_11_RTS_THRESHOLD:
- {
-
- u32 ulTemp;
- pSNMPMIB->oid = cpu_to_le16(RTSTHRESH_I);
-
- if (cmd_action == CMD_ACT_GET) {
- pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET);
- } else if (cmd_action == CMD_ACT_SET) {
- pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
- pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
- ulTemp = *((u32 *)pdata_buf);
- *(__le16 *)(pSNMPMIB->value) =
- cpu_to_le16((u16) ulTemp);
-
- }
- break;
- }
- case OID_802_11_TX_RETRYCOUNT:
- pSNMPMIB->oid = cpu_to_le16((u16) SHORT_RETRYLIM_I);
-
- if (cmd_action == CMD_ACT_GET) {
- pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET);
- } else if (cmd_action == CMD_ACT_SET) {
- pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
- pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
- *((__le16 *)(pSNMPMIB->value)) =
- cpu_to_le16((u16) priv->txretrycount);
- }
-
+ case SNMP_MIB_OID_11D_ENABLE:
+ case SNMP_MIB_OID_FRAG_THRESHOLD:
+ case SNMP_MIB_OID_RTS_THRESHOLD:
+ case SNMP_MIB_OID_SHORT_RETRY_LIMIT:
+ case SNMP_MIB_OID_LONG_RETRY_LIMIT:
+ cmd.bufsize = cpu_to_le16(sizeof(u16));
+ *((__le16 *)(&cmd.value)) = cpu_to_le16(val);
break;
default:
+ lbs_deb_cmd("SNMP_CMD: (set) unhandled OID 0x%x\n", oid);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ lbs_deb_cmd("SNMP_CMD: (set) oid 0x%x, oid size 0x%x, value 0x%x\n",
+ le16_to_cpu(cmd.oid), le16_to_cpu(cmd.bufsize), val);
+
+ ret = lbs_cmd_with_response(priv, CMD_802_11_SNMP_MIB, &cmd);
+
+out:
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ return ret;
+}
+
+/**
+ * @brief Get an SNMP MIB value
+ *
+ * @param priv A pointer to struct lbs_private structure
+ * @param oid The OID to retrieve from the firmware
+ * @param out_val Location for the returned value
+ *
+ * @return 0 on success, error on failure
+ */
+int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val)
+{
+ struct cmd_ds_802_11_snmp_mib cmd;
+ int ret;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ memset(&cmd, 0, sizeof (cmd));
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+ cmd.action = cpu_to_le16(CMD_ACT_GET);
+ cmd.oid = cpu_to_le16(oid);
+
+ ret = lbs_cmd_with_response(priv, CMD_802_11_SNMP_MIB, &cmd);
+ if (ret)
+ goto out;
+
+ switch (le16_to_cpu(cmd.bufsize)) {
+ case sizeof(u8):
+ if (oid == SNMP_MIB_OID_BSS_TYPE) {
+ if (cmd.value[0] == 2)
+ *out_val = IW_MODE_ADHOC;
+ else
+ *out_val = IW_MODE_INFRA;
+ } else
+ *out_val = cmd.value[0];
+ break;
+ case sizeof(u16):
+ *out_val = le16_to_cpu(*((__le16 *)(&cmd.value)));
+ break;
+ default:
+ lbs_deb_cmd("SNMP_CMD: (get) unhandled OID 0x%x size %d\n",
+ oid, le16_to_cpu(cmd.bufsize));
break;
}
- lbs_deb_cmd(
- "SNMP_CMD: command=0x%x, size=0x%x, seqnum=0x%x, result=0x%x\n",
- le16_to_cpu(cmd->command), le16_to_cpu(cmd->size),
- le16_to_cpu(cmd->seqnum), le16_to_cpu(cmd->result));
-
- lbs_deb_cmd(
- "SNMP_CMD: action 0x%x, oid 0x%x, oidsize 0x%x, value 0x%x\n",
- le16_to_cpu(pSNMPMIB->querytype), le16_to_cpu(pSNMPMIB->oid),
- le16_to_cpu(pSNMPMIB->bufsize),
- le16_to_cpu(*(__le16 *) pSNMPMIB->value));
-
- lbs_deb_leave(LBS_DEB_CMD);
- return 0;
+out:
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ return ret;
}
/**
@@ -1419,19 +1384,10 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
ret = lbs_cmd_80211_associate(priv, cmdptr, pdata_buf);
break;
- case CMD_802_11_RESET:
- ret = lbs_cmd_802_11_reset(cmdptr, cmd_action);
- break;
-
case CMD_802_11_AUTHENTICATE:
ret = lbs_cmd_80211_authenticate(priv, cmdptr, pdata_buf);
break;
- case CMD_802_11_SNMP_MIB:
- ret = lbs_cmd_802_11_snmp_mib(priv, cmdptr,
- cmd_action, cmd_oid, pdata_buf);
- break;
-
case CMD_MAC_REG_ACCESS:
case CMD_BBP_REG_ACCESS:
case CMD_RF_REG_ACCESS:
diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h
index 336a181d857a..d002160f597d 100644
--- a/drivers/net/wireless/libertas/cmd.h
+++ b/drivers/net/wireless/libertas/cmd.h
@@ -73,4 +73,8 @@ int lbs_set_tx_power(struct lbs_private *priv, s16 dbm);
int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on);
+int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val);
+
+int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val);
+
#endif /* _LBS_CMD_H */
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
index 0371c83f5661..bcf2a9756fb6 100644
--- a/drivers/net/wireless/libertas/cmdresp.c
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -146,48 +146,6 @@ static int lbs_ret_reg_access(struct lbs_private *priv,
return ret;
}
-static int lbs_ret_802_11_snmp_mib(struct lbs_private *priv,
- struct cmd_ds_command *resp)
-{
- struct cmd_ds_802_11_snmp_mib *smib = &resp->params.smib;
- u16 oid = le16_to_cpu(smib->oid);
- u16 querytype = le16_to_cpu(smib->querytype);
-
- lbs_deb_enter(LBS_DEB_CMD);
-
- lbs_deb_cmd("SNMP_RESP: oid 0x%x, querytype 0x%x\n", oid,
- querytype);
- lbs_deb_cmd("SNMP_RESP: Buf size %d\n", le16_to_cpu(smib->bufsize));
-
- if (querytype == CMD_ACT_GET) {
- switch (oid) {
- case FRAGTHRESH_I:
- priv->fragthsd =
- le16_to_cpu(*((__le16 *)(smib->value)));
- lbs_deb_cmd("SNMP_RESP: frag threshold %u\n",
- priv->fragthsd);
- break;
- case RTSTHRESH_I:
- priv->rtsthsd =
- le16_to_cpu(*((__le16 *)(smib->value)));
- lbs_deb_cmd("SNMP_RESP: rts threshold %u\n",
- priv->rtsthsd);
- break;
- case SHORT_RETRYLIM_I:
- priv->txretrycount =
- le16_to_cpu(*((__le16 *)(smib->value)));
- lbs_deb_cmd("SNMP_RESP: tx retry count %u\n",
- priv->rtsthsd);
- break;
- default:
- break;
- }
- }
-
- lbs_deb_enter(LBS_DEB_CMD);
- return 0;
-}
-
static int lbs_ret_802_11_rssi(struct lbs_private *priv,
struct cmd_ds_command *resp)
{
@@ -258,10 +216,6 @@ static inline int handle_cmd_response(struct lbs_private *priv,
ret = lbs_ret_80211_associate(priv, resp);
break;
- case CMD_RET(CMD_802_11_SNMP_MIB):
- ret = lbs_ret_802_11_snmp_mib(priv, resp);
- break;
-
case CMD_RET(CMD_802_11_SET_AFC):
case CMD_RET(CMD_802_11_GET_AFC):
spin_lock_irqsave(&priv->driver_lock, flags);
@@ -271,7 +225,6 @@ static inline int handle_cmd_response(struct lbs_private *priv,
break;
- case CMD_RET(CMD_802_11_RESET):
case CMD_RET(CMD_802_11_AUTHENTICATE):
case CMD_RET(CMD_802_11_BEACON_STOP):
break;
diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h
index c89d7a1041a8..58d11a35e61b 100644
--- a/drivers/net/wireless/libertas/defs.h
+++ b/drivers/net/wireless/libertas/defs.h
@@ -352,27 +352,6 @@ enum mv_ms_type {
MVMS_EVENT
};
-/** SNMP_MIB_INDEX_e */
-enum SNMP_MIB_INDEX_e {
- DESIRED_BSSTYPE_I = 0,
- OP_RATESET_I,
- BCNPERIOD_I,
- DTIMPERIOD_I,
- ASSOCRSP_TIMEOUT_I,
- RTSTHRESH_I,
- SHORT_RETRYLIM_I,
- LONG_RETRYLIM_I,
- FRAGTHRESH_I,
- DOT11D_I,
- DOT11H_I,
- MANUFID_I,
- PRODID_I,
- MANUF_OUI_I,
- MANUF_NAME_I,
- MANUF_PRODNAME_I,
- MANUF_PRODVER_I,
-};
-
/** KEY_TYPE_ID */
enum KEY_TYPE_ID {
KEY_TYPE_ID_WEP = 0,
@@ -387,12 +366,6 @@ enum KEY_INFO_WPA {
KEY_INFO_WPA_ENABLED = 0x04
};
-/** SNMP_MIB_VALUE_e */
-enum SNMP_MIB_VALUE_e {
- SNMP_MIB_VALUE_INFRA = 1,
- SNMP_MIB_VALUE_ADHOC
-};
-
/* Default values for fwt commands. */
#define FWT_DEFAULT_METRIC 0
#define FWT_DEFAULT_DIR 1
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index fd59e1816460..acb889e25900 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -240,9 +240,6 @@ struct lbs_private {
uint16_t enablehwauto;
uint16_t ratebitmap;
- u32 fragthsd;
- u32 rtsthsd;
-
u8 txretrycount;
/** Tx-related variables (for single packet tx) */
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h
index a916bb9bd5da..5004d7679c02 100644
--- a/drivers/net/wireless/libertas/host.h
+++ b/drivers/net/wireless/libertas/host.h
@@ -9,17 +9,6 @@
#define DEFAULT_AD_HOC_CHANNEL 6
#define DEFAULT_AD_HOC_CHANNEL_A 36
-/** IEEE 802.11 oids */
-#define OID_802_11_SSID 0x00008002
-#define OID_802_11_INFRASTRUCTURE_MODE 0x00008008
-#define OID_802_11_FRAGMENTATION_THRESHOLD 0x00008009
-#define OID_802_11_RTS_THRESHOLD 0x0000800A
-#define OID_802_11_TX_ANTENNA_SELECTED 0x0000800D
-#define OID_802_11_SUPPORTED_RATES 0x0000800E
-#define OID_802_11_STATISTICS 0x00008012
-#define OID_802_11_TX_RETRYCOUNT 0x0000801D
-#define OID_802_11D_ENABLE 0x00008020
-
#define CMD_OPTION_WAITFORRSP 0x0002
/** Host command IDs */
@@ -191,6 +180,19 @@
#define CMD_WAKE_METHOD_COMMAND_INT 0x0001
#define CMD_WAKE_METHOD_GPIO 0x0002
+/* Object IDs for CMD_802_11_SNMP_MIB */
+#define SNMP_MIB_OID_BSS_TYPE 0x0000
+#define SNMP_MIB_OID_OP_RATE_SET 0x0001
+#define SNMP_MIB_OID_BEACON_PERIOD 0x0002 /* Reserved on v9+ */
+#define SNMP_MIB_OID_DTIM_PERIOD 0x0003 /* Reserved on v9+ */
+#define SNMP_MIB_OID_ASSOC_TIMEOUT 0x0004 /* Reserved on v9+ */
+#define SNMP_MIB_OID_RTS_THRESHOLD 0x0005
+#define SNMP_MIB_OID_SHORT_RETRY_LIMIT 0x0006
+#define SNMP_MIB_OID_LONG_RETRY_LIMIT 0x0007
+#define SNMP_MIB_OID_FRAG_THRESHOLD 0x0008
+#define SNMP_MIB_OID_11D_ENABLE 0x0009
+#define SNMP_MIB_OID_11H_ENABLE 0x000A
+
/* Define action or option for CMD_BT_ACCESS */
enum cmd_bt_access_opts {
/* The bt commands start at 5 instead of 1 because the old dft commands
diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h
index 630b79967560..d9f9a12a739e 100644
--- a/drivers/net/wireless/libertas/hostcmd.h
+++ b/drivers/net/wireless/libertas/hostcmd.h
@@ -151,10 +151,6 @@ struct cmd_ds_get_hw_spec {
__le32 fwcapinfo;
} __attribute__ ((packed));
-struct cmd_ds_802_11_reset {
- __le16 action;
-};
-
struct cmd_ds_802_11_subscribe_event {
struct cmd_header hdr;
@@ -301,7 +297,9 @@ struct cmd_ds_802_11_get_stat {
};
struct cmd_ds_802_11_snmp_mib {
- __le16 querytype;
+ struct cmd_header hdr;
+
+ __le16 action;
__le16 oid;
__le16 bufsize;
u8 value[128];
@@ -717,11 +715,9 @@ struct cmd_ds_command {
union {
struct cmd_ds_802_11_ps_mode psmode;
struct cmd_ds_802_11_associate associate;
- struct cmd_ds_802_11_reset reset;
struct cmd_ds_802_11_authenticate auth;
struct cmd_ds_802_11_get_stat gstat;
struct cmd_ds_802_3_get_stat gstat_8023;
- struct cmd_ds_802_11_snmp_mib smib;
struct cmd_ds_802_11_rf_antenna rant;
struct cmd_ds_802_11_monitor_mode monitor;
struct cmd_ds_802_11_rssi rssi;
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index 7b02d612b076..cafbccb74143 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -439,11 +439,10 @@ static int if_usb_reset_device(struct if_usb_card *cardp)
*(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_REQUEST);
cmd->command = cpu_to_le16(CMD_802_11_RESET);
- cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset) + S_DS_GEN);
+ cmd->size = cpu_to_le16(sizeof(struct cmd_header));
cmd->result = cpu_to_le16(0);
cmd->seqnum = cpu_to_le16(0x5a5a);
- cmd->params.reset.action = cpu_to_le16(CMD_ACT_HALT);
- usb_tx_block(cardp, cardp->ep_out_buf, 4 + S_DS_GEN + sizeof(struct cmd_ds_802_11_reset));
+ usb_tx_block(cardp, cardp->ep_out_buf, 4 + sizeof(struct cmd_header));
msleep(100);
ret = usb_reset_device(cardp->udev);
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
index e8cadad2c863..11297dcf9fc3 100644
--- a/drivers/net/wireless/libertas/wext.c
+++ b/drivers/net/wireless/libertas/wext.c
@@ -30,6 +30,14 @@ static inline void lbs_postpone_association_work(struct lbs_private *priv)
queue_delayed_work(priv->work_thread, &priv->assoc_work, HZ / 2);
}
+static inline void lbs_do_association_work(struct lbs_private *priv)
+{
+ if (priv->surpriseremoved)
+ return;
+ cancel_delayed_work(&priv->assoc_work);
+ queue_delayed_work(priv->work_thread, &priv->assoc_work, 0);
+}
+
static inline void lbs_cancel_association_work(struct lbs_private *priv)
{
cancel_delayed_work(&priv->assoc_work);
@@ -266,21 +274,17 @@ static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info,
{
int ret = 0;
struct lbs_private *priv = dev->priv;
- u32 rthr = vwrq->value;
+ u32 val = vwrq->value;
lbs_deb_enter(LBS_DEB_WEXT);
- if (vwrq->disabled) {
- priv->rtsthsd = rthr = MRVDRV_RTS_MAX_VALUE;
- } else {
- if (rthr < MRVDRV_RTS_MIN_VALUE || rthr > MRVDRV_RTS_MAX_VALUE)
- return -EINVAL;
- priv->rtsthsd = rthr;
- }
+ if (vwrq->disabled)
+ val = MRVDRV_RTS_MAX_VALUE;
- ret = lbs_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB,
- CMD_ACT_SET, CMD_OPTION_WAITFORRSP,
- OID_802_11_RTS_THRESHOLD, &rthr);
+ if (val > MRVDRV_RTS_MAX_VALUE) /* min rts value is 0 */
+ return -EINVAL;
+
+ ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_RTS_THRESHOLD, (u16) val);
lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
return ret;
@@ -289,21 +293,18 @@ static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info,
static int lbs_get_rts(struct net_device *dev, struct iw_request_info *info,
struct iw_param *vwrq, char *extra)
{
- int ret = 0;
struct lbs_private *priv = dev->priv;
+ int ret = 0;
+ u16 val = 0;
lbs_deb_enter(LBS_DEB_WEXT);
- priv->rtsthsd = 0;
- ret = lbs_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB,
- CMD_ACT_GET, CMD_OPTION_WAITFORRSP,
- OID_802_11_RTS_THRESHOLD, NULL);
+ ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_RTS_THRESHOLD, &val);
if (ret)
goto out;
- vwrq->value = priv->rtsthsd;
- vwrq->disabled = ((vwrq->value < MRVDRV_RTS_MIN_VALUE)
- || (vwrq->value > MRVDRV_RTS_MAX_VALUE));
+ vwrq->value = val;
+ vwrq->disabled = val > MRVDRV_RTS_MAX_VALUE; /* min rts value is 0 */
vwrq->fixed = 1;
out:
@@ -314,24 +315,19 @@ out:
static int lbs_set_frag(struct net_device *dev, struct iw_request_info *info,
struct iw_param *vwrq, char *extra)
{
- int ret = 0;
- u32 fthr = vwrq->value;
struct lbs_private *priv = dev->priv;
+ int ret = 0;
+ u32 val = vwrq->value;
lbs_deb_enter(LBS_DEB_WEXT);
- if (vwrq->disabled) {
- priv->fragthsd = fthr = MRVDRV_FRAG_MAX_VALUE;
- } else {
- if (fthr < MRVDRV_FRAG_MIN_VALUE
- || fthr > MRVDRV_FRAG_MAX_VALUE)
- return -EINVAL;
- priv->fragthsd = fthr;
- }
+ if (vwrq->disabled)
+ val = MRVDRV_FRAG_MAX_VALUE;
- ret = lbs_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB,
- CMD_ACT_SET, CMD_OPTION_WAITFORRSP,
- OID_802_11_FRAGMENTATION_THRESHOLD, &fthr);
+ if (val < MRVDRV_FRAG_MIN_VALUE || val > MRVDRV_FRAG_MAX_VALUE)
+ return -EINVAL;
+
+ ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_FRAG_THRESHOLD, (u16) val);
lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
return ret;
@@ -340,22 +336,19 @@ static int lbs_set_frag(struct net_device *dev, struct iw_request_info *info,
static int lbs_get_frag(struct net_device *dev, struct iw_request_info *info,
struct iw_param *vwrq, char *extra)
{
- int ret = 0;
struct lbs_private *priv = dev->priv;
+ int ret = 0;
+ u16 val = 0;
lbs_deb_enter(LBS_DEB_WEXT);
- priv->fragthsd = 0;
- ret = lbs_prepare_and_send_command(priv,
- CMD_802_11_SNMP_MIB,
- CMD_ACT_GET, CMD_OPTION_WAITFORRSP,
- OID_802_11_FRAGMENTATION_THRESHOLD, NULL);
+ ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_FRAG_THRESHOLD, &val);
if (ret)
goto out;
- vwrq->value = priv->fragthsd;
- vwrq->disabled = ((vwrq->value < MRVDRV_FRAG_MIN_VALUE)
- || (vwrq->value > MRVDRV_FRAG_MAX_VALUE));
+ vwrq->value = val;
+ vwrq->disabled = ((val < MRVDRV_FRAG_MIN_VALUE)
+ || (val > MRVDRV_FRAG_MAX_VALUE));
vwrq->fixed = 1;
out:
@@ -382,7 +375,7 @@ static int mesh_wlan_get_mode(struct net_device *dev,
{
lbs_deb_enter(LBS_DEB_WEXT);
- *uwrq = IW_MODE_REPEAT ;
+ *uwrq = IW_MODE_REPEAT;
lbs_deb_leave(LBS_DEB_WEXT);
return 0;
@@ -425,31 +418,44 @@ out:
static int lbs_set_retry(struct net_device *dev, struct iw_request_info *info,
struct iw_param *vwrq, char *extra)
{
- int ret = 0;
struct lbs_private *priv = dev->priv;
+ int ret = 0;
+ u16 slimit = 0, llimit = 0;
lbs_deb_enter(LBS_DEB_WEXT);
- if (vwrq->flags == IW_RETRY_LIMIT) {
- /* The MAC has a 4-bit Total_Tx_Count register
- Total_Tx_Count = 1 + Tx_Retry_Count */
+ if ((vwrq->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT)
+ return -EOPNOTSUPP;
+
+ /* The MAC has a 4-bit Total_Tx_Count register
+ Total_Tx_Count = 1 + Tx_Retry_Count */
#define TX_RETRY_MIN 0
#define TX_RETRY_MAX 14
- if (vwrq->value < TX_RETRY_MIN || vwrq->value > TX_RETRY_MAX)
- return -EINVAL;
+ if (vwrq->value < TX_RETRY_MIN || vwrq->value > TX_RETRY_MAX)
+ return -EINVAL;
- /* Adding 1 to convert retry count to try count */
- priv->txretrycount = vwrq->value + 1;
-
- ret = lbs_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB,
- CMD_ACT_SET,
- CMD_OPTION_WAITFORRSP,
- OID_802_11_TX_RETRYCOUNT, NULL);
+ /* Add 1 to convert retry count to try count */
+ if (vwrq->flags & IW_RETRY_SHORT)
+ slimit = (u16) (vwrq->value + 1);
+ else if (vwrq->flags & IW_RETRY_LONG)
+ llimit = (u16) (vwrq->value + 1);
+ else
+ slimit = llimit = (u16) (vwrq->value + 1); /* set both */
+ if (llimit) {
+ ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_LONG_RETRY_LIMIT,
+ llimit);
+ if (ret)
+ goto out;
+ }
+
+ if (slimit) {
+ /* txretrycount follows the short retry limit */
+ priv->txretrycount = slimit;
+ ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_SHORT_RETRY_LIMIT,
+ slimit);
if (ret)
goto out;
- } else {
- return -EOPNOTSUPP;
}
out:
@@ -462,22 +468,30 @@ static int lbs_get_retry(struct net_device *dev, struct iw_request_info *info,
{
struct lbs_private *priv = dev->priv;
int ret = 0;
+ u16 val = 0;
lbs_deb_enter(LBS_DEB_WEXT);
- priv->txretrycount = 0;
- ret = lbs_prepare_and_send_command(priv,
- CMD_802_11_SNMP_MIB,
- CMD_ACT_GET, CMD_OPTION_WAITFORRSP,
- OID_802_11_TX_RETRYCOUNT, NULL);
- if (ret)
- goto out;
-
vwrq->disabled = 0;
- if (!vwrq->flags) {
- vwrq->flags = IW_RETRY_LIMIT;
+
+ if (vwrq->flags & IW_RETRY_LONG) {
+ ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_LONG_RETRY_LIMIT, &val);
+ if (ret)
+ goto out;
+
/* Subtract 1 to convert try count to retry count */
- vwrq->value = priv->txretrycount - 1;
+ vwrq->value = val - 1;
+ vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
+ } else {
+ ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_SHORT_RETRY_LIMIT, &val);
+ if (ret)
+ goto out;
+
+ /* txretry count follows the short retry limit */
+ priv->txretrycount = val;
+ /* Subtract 1 to convert try count to retry count */
+ vwrq->value = val - 1;
+ vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_SHORT;
}
out:
@@ -1578,12 +1592,14 @@ static int lbs_set_encodeext(struct net_device *dev,
set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
}
- disable_wep (assoc_req);
+ /* Only disable wep if necessary: can't waste time here. */
+ if (priv->mac_control & CMD_ACT_MAC_WEP_ENABLE)
+ disable_wep(assoc_req);
}
out:
- if (ret == 0) {
- lbs_postpone_association_work(priv);
+ if (ret == 0) { /* key installation is time critical: postpone not! */
+ lbs_do_association_work(priv);
} else {
lbs_cancel_association_work(priv);
}
diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c
index c948021bff6a..feff945ad856 100644
--- a/drivers/net/wireless/libertas_tf/main.c
+++ b/drivers/net/wireless/libertas_tf/main.c
@@ -219,7 +219,7 @@ static void lbtf_tx_work(struct work_struct *work)
struct sk_buff *skb = NULL;
int err;
- if ((priv->vif->type == IEEE80211_IF_TYPE_AP) &&
+ if ((priv->vif->type == NL80211_IFTYPE_AP) &&
(!skb_queue_empty(&priv->bc_ps_buf)))
skb = skb_dequeue(&priv->bc_ps_buf);
else if (priv->skb_to_tx) {
@@ -326,11 +326,11 @@ static int lbtf_op_add_interface(struct ieee80211_hw *hw,
priv->vif = conf->vif;
switch (conf->type) {
- case IEEE80211_IF_TYPE_MESH_POINT:
- case IEEE80211_IF_TYPE_AP:
+ case NL80211_IFTYPE_MESH_POINT:
+ case NL80211_IFTYPE_AP:
lbtf_set_mode(priv, LBTF_AP_MODE);
break;
- case IEEE80211_IF_TYPE_STA:
+ case NL80211_IFTYPE_STATION:
lbtf_set_mode(priv, LBTF_STA_MODE);
break;
default:
@@ -346,8 +346,8 @@ static void lbtf_op_remove_interface(struct ieee80211_hw *hw,
{
struct lbtf_private *priv = hw->priv;
- if (priv->vif->type == IEEE80211_IF_TYPE_AP ||
- priv->vif->type == IEEE80211_IF_TYPE_MESH_POINT)
+ if (priv->vif->type == NL80211_IFTYPE_AP ||
+ priv->vif->type == NL80211_IFTYPE_MESH_POINT)
lbtf_beacon_ctrl(priv, 0, 0);
lbtf_set_mode(priv, LBTF_PASSIVE_MODE);
lbtf_set_bssid(priv, 0, NULL);
@@ -372,8 +372,8 @@ static int lbtf_op_config_interface(struct ieee80211_hw *hw,
struct sk_buff *beacon;
switch (priv->vif->type) {
- case IEEE80211_IF_TYPE_AP:
- case IEEE80211_IF_TYPE_MESH_POINT:
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_MESH_POINT:
beacon = ieee80211_beacon_get(hw, vif);
if (beacon) {
lbtf_beacon_set(priv, beacon);
@@ -614,7 +614,7 @@ void lbtf_bcn_sent(struct lbtf_private *priv)
{
struct sk_buff *skb = NULL;
- if (priv->vif->type != IEEE80211_IF_TYPE_AP)
+ if (priv->vif->type != NL80211_IFTYPE_AP)
return;
if (skb_queue_empty(&priv->bc_ps_buf)) {
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 6ba50f087f7b..c9e4a435b2fc 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -14,6 +14,8 @@
* - RX filtering based on filter configuration (data->rx_filter)
*/
+#include
+#include
#include
#include
#include
@@ -28,11 +30,56 @@ static int radios = 2;
module_param(radios, int, 0444);
MODULE_PARM_DESC(radios, "Number of simulated radios");
+struct hwsim_vif_priv {
+ u32 magic;
+};
+
+#define HWSIM_VIF_MAGIC 0x69537748
+
+static inline void hwsim_check_magic(struct ieee80211_vif *vif)
+{
+ struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
+ WARN_ON(vp->magic != HWSIM_VIF_MAGIC);
+}
+
+static inline void hwsim_set_magic(struct ieee80211_vif *vif)
+{
+ struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
+ vp->magic = HWSIM_VIF_MAGIC;
+}
+
+static inline void hwsim_clear_magic(struct ieee80211_vif *vif)
+{
+ struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
+ vp->magic = 0;
+}
+
+struct hwsim_sta_priv {
+ u32 magic;
+};
+
+#define HWSIM_STA_MAGIC 0x6d537748
+
+static inline void hwsim_check_sta_magic(struct ieee80211_sta *sta)
+{
+ struct hwsim_sta_priv *sp = (void *)sta->drv_priv;
+ WARN_ON(sp->magic != HWSIM_VIF_MAGIC);
+}
+
+static inline void hwsim_set_sta_magic(struct ieee80211_sta *sta)
+{
+ struct hwsim_sta_priv *sp = (void *)sta->drv_priv;
+ sp->magic = HWSIM_VIF_MAGIC;
+}
+
+static inline void hwsim_clear_sta_magic(struct ieee80211_sta *sta)
+{
+ struct hwsim_sta_priv *sp = (void *)sta->drv_priv;
+ sp->magic = 0;
+}
static struct class *hwsim_class;
-static struct ieee80211_hw **hwsim_radios;
-static int hwsim_radio_count;
static struct net_device *hwsim_mon; /* global monitor netdev */
@@ -68,7 +115,12 @@ static const struct ieee80211_rate hwsim_rates[] = {
{ .bitrate = 540 }
};
+static spinlock_t hwsim_radio_lock;
+static struct list_head hwsim_radios;
+
struct mac80211_hwsim_data {
+ struct list_head list;
+ struct ieee80211_hw *hw;
struct device *dev;
struct ieee80211_supported_band band;
struct ieee80211_channel channels[ARRAY_SIZE(hwsim_channels)];
@@ -144,11 +196,11 @@ static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw,
}
-static int mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
- struct sk_buff *skb)
+static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
+ struct sk_buff *skb)
{
- struct mac80211_hwsim_data *data = hw->priv;
- int i, ack = 0;
+ struct mac80211_hwsim_data *data = hw->priv, *data2;
+ bool ack = false;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_rx_status rx_status;
@@ -161,13 +213,13 @@ static int mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
/* TODO: simulate signal strength (and optional packet drop) */
/* Copy skb to all enabled radios that are on the current frequency */
- for (i = 0; i < hwsim_radio_count; i++) {
- struct mac80211_hwsim_data *data2;
+ spin_lock(&hwsim_radio_lock);
+ list_for_each_entry(data2, &hwsim_radios, list) {
struct sk_buff *nskb;
- if (hwsim_radios[i] == NULL || hwsim_radios[i] == hw)
+ if (data == data2)
continue;
- data2 = hwsim_radios[i]->priv;
+
if (!data2->started || !data2->radio_enabled ||
data->channel->center_freq != data2->channel->center_freq)
continue;
@@ -176,11 +228,12 @@ static int mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
if (nskb == NULL)
continue;
- if (memcmp(hdr->addr1, hwsim_radios[i]->wiphy->perm_addr,
+ if (memcmp(hdr->addr1, data2->hw->wiphy->perm_addr,
ETH_ALEN) == 0)
- ack = 1;
- ieee80211_rx_irqsafe(hwsim_radios[i], nskb, &rx_status);
+ ack = true;
+ ieee80211_rx_irqsafe(data2->hw, nskb, &rx_status);
}
+ spin_unlock(&hwsim_radio_lock);
return ack;
}
@@ -189,7 +242,7 @@ static int mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
static int mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct mac80211_hwsim_data *data = hw->priv;
- int ack;
+ bool ack;
struct ieee80211_tx_info *txi;
mac80211_hwsim_monitor_rx(hw, skb);
@@ -210,6 +263,12 @@ static int mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
ack = mac80211_hwsim_tx_frame(hw, skb);
txi = IEEE80211_SKB_CB(skb);
+
+ if (txi->control.vif)
+ hwsim_check_magic(txi->control.vif);
+ if (txi->control.sta)
+ hwsim_check_sta_magic(txi->control.sta);
+
memset(&txi->status, 0, sizeof(txi->status));
if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK)) {
if (ack)
@@ -246,6 +305,7 @@ static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw,
printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%s)\n",
wiphy_name(hw->wiphy), __func__, conf->type,
print_mac(mac, conf->mac_addr));
+ hwsim_set_magic(conf->vif);
return 0;
}
@@ -257,6 +317,8 @@ static void mac80211_hwsim_remove_interface(
printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%s)\n",
wiphy_name(hw->wiphy), __func__, conf->type,
print_mac(mac, conf->mac_addr));
+ hwsim_check_magic(conf->vif);
+ hwsim_clear_magic(conf->vif);
}
@@ -267,7 +329,9 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
struct sk_buff *skb;
struct ieee80211_tx_info *info;
- if (vif->type != IEEE80211_IF_TYPE_AP)
+ hwsim_check_magic(vif);
+
+ if (vif->type != NL80211_IFTYPE_AP)
return;
skb = ieee80211_beacon_get(hw, vif);
@@ -341,7 +405,45 @@ static void mac80211_hwsim_configure_filter(struct ieee80211_hw *hw,
*total_flags = data->rx_filter;
}
+static int mac80211_hwsim_config_interface(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_if_conf *conf)
+{
+ hwsim_check_magic(vif);
+ return 0;
+}
+static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *info,
+ u32 changed)
+{
+ hwsim_check_magic(vif);
+}
+
+static void mac80211_hwsim_sta_notify(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ enum sta_notify_cmd cmd,
+ struct ieee80211_sta *sta)
+{
+ hwsim_check_magic(vif);
+ switch (cmd) {
+ case STA_NOTIFY_ADD:
+ hwsim_set_sta_magic(sta);
+ break;
+ case STA_NOTIFY_REMOVE:
+ hwsim_clear_sta_magic(sta);
+ break;
+ }
+}
+
+static int mac80211_hwsim_set_tim(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta,
+ bool set)
+{
+ hwsim_check_sta_magic(sta);
+ return 0;
+}
static const struct ieee80211_ops mac80211_hwsim_ops =
{
@@ -352,23 +454,30 @@ static const struct ieee80211_ops mac80211_hwsim_ops =
.remove_interface = mac80211_hwsim_remove_interface,
.config = mac80211_hwsim_config,
.configure_filter = mac80211_hwsim_configure_filter,
+ .config_interface = mac80211_hwsim_config_interface,
+ .bss_info_changed = mac80211_hwsim_bss_info_changed,
+ .sta_notify = mac80211_hwsim_sta_notify,
+ .set_tim = mac80211_hwsim_set_tim,
};
static void mac80211_hwsim_free(void)
{
- int i;
+ struct list_head tmplist, *i, *tmp;
+ struct mac80211_hwsim_data *data;
- for (i = 0; i < hwsim_radio_count; i++) {
- if (hwsim_radios[i]) {
- struct mac80211_hwsim_data *data;
- data = hwsim_radios[i]->priv;
- ieee80211_unregister_hw(hwsim_radios[i]);
- device_unregister(data->dev);
- ieee80211_free_hw(hwsim_radios[i]);
- }
+ INIT_LIST_HEAD(&tmplist);
+
+ spin_lock_bh(&hwsim_radio_lock);
+ list_for_each_safe(i, tmp, &hwsim_radios)
+ list_move(i, &tmplist);
+ spin_unlock_bh(&hwsim_radio_lock);
+
+ list_for_each_entry(data, &tmplist, list) {
+ ieee80211_unregister_hw(data->hw);
+ device_unregister(data->dev);
+ ieee80211_free_hw(data->hw);
}
- kfree(hwsim_radios);
class_destroy(hwsim_class);
}
@@ -398,37 +507,32 @@ static int __init init_mac80211_hwsim(void)
struct ieee80211_hw *hw;
DECLARE_MAC_BUF(mac);
- if (radios < 1 || radios > 65535)
+ if (radios < 1 || radios > 100)
return -EINVAL;
- hwsim_radio_count = radios;
- hwsim_radios = kcalloc(hwsim_radio_count,
- sizeof(struct ieee80211_hw *), GFP_KERNEL);
- if (hwsim_radios == NULL)
- return -ENOMEM;
+ spin_lock_init(&hwsim_radio_lock);
+ INIT_LIST_HEAD(&hwsim_radios);
hwsim_class = class_create(THIS_MODULE, "mac80211_hwsim");
- if (IS_ERR(hwsim_class)) {
- kfree(hwsim_radios);
+ if (IS_ERR(hwsim_class))
return PTR_ERR(hwsim_class);
- }
memset(addr, 0, ETH_ALEN);
addr[0] = 0x02;
- for (i = 0; i < hwsim_radio_count; i++) {
+ for (i = 0; i < radios; i++) {
printk(KERN_DEBUG "mac80211_hwsim: Initializing radio %d\n",
i);
hw = ieee80211_alloc_hw(sizeof(*data), &mac80211_hwsim_ops);
- if (hw == NULL) {
+ if (!hw) {
printk(KERN_DEBUG "mac80211_hwsim: ieee80211_alloc_hw "
"failed\n");
err = -ENOMEM;
goto failed;
}
- hwsim_radios[i] = hw;
-
data = hw->priv;
+ data->hw = hw;
+
data->dev = device_create_drvdata(hwsim_class, NULL, 0, hw,
"hwsim%d", i);
if (IS_ERR(data->dev)) {
@@ -452,6 +556,10 @@ static int __init init_mac80211_hwsim(void)
BIT(NL80211_IFTYPE_AP);
hw->ampdu_queues = 1;
+ /* ask mac80211 to reserve space for magic */
+ hw->vif_data_size = sizeof(struct hwsim_vif_priv);
+ hw->sta_data_size = sizeof(struct hwsim_sta_priv);
+
memcpy(data->channels, hwsim_channels, sizeof(hwsim_channels));
memcpy(data->rates, hwsim_rates, sizeof(hwsim_rates));
data->band.channels = data->channels;
@@ -486,6 +594,8 @@ static int __init init_mac80211_hwsim(void)
setup_timer(&data->beacon_timer, mac80211_hwsim_beacon,
(unsigned long) hw);
+
+ list_add_tail(&data->list, &hwsim_radios);
}
hwsim_mon = alloc_netdev(0, "hwsim%d", hwsim_mon_setup);
@@ -517,7 +627,6 @@ failed_hw:
device_unregister(data->dev);
failed_drvdata:
ieee80211_free_hw(hw);
- hwsim_radios[i] = NULL;
failed:
mac80211_hwsim_free();
return err;
@@ -526,8 +635,7 @@ failed:
static void __exit exit_mac80211_hwsim(void)
{
- printk(KERN_DEBUG "mac80211_hwsim: unregister %d radios\n",
- hwsim_radio_count);
+ printk(KERN_DEBUG "mac80211_hwsim: unregister radios\n");
unregister_netdev(hwsim_mon);
mac80211_hwsim_free();
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
index ec0451cbb8e1..9a2fcc0163d6 100644
--- a/drivers/net/wireless/orinoco.c
+++ b/drivers/net/wireless/orinoco.c
@@ -4777,14 +4777,14 @@ static int orinoco_ioctl_get_encodeext(struct net_device *dev,
encoding->flags |= IW_ENCODE_DISABLED;
break;
case IW_ENCODE_ALG_WEP:
- ext->key_len = min(le16_to_cpu(priv->keys[idx].len),
- (u16) max_key_len);
+ ext->key_len = min_t(u16, le16_to_cpu(priv->keys[idx].len),
+ max_key_len);
memcpy(ext->key, priv->keys[idx].data, ext->key_len);
encoding->flags |= IW_ENCODE_ENABLED;
break;
case IW_ENCODE_ALG_TKIP:
- ext->key_len = min((u16) sizeof(struct orinoco_tkip_key),
- (u16) max_key_len);
+ ext->key_len = min_t(u16, sizeof(struct orinoco_tkip_key),
+ max_key_len);
memcpy(ext->key, &priv->tkip_key[idx], ext->key_len);
encoding->flags |= IW_ENCODE_ENABLED;
break;
@@ -5686,9 +5686,9 @@ static inline char *orinoco_translate_ext_scan(struct net_device *dev,
/* Timestamp */
iwe.cmd = IWEVCUSTOM;
- iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
- "tsf=%016llx",
- le64_to_cpu(bss->timestamp));
+ iwe.u.data.length =
+ snprintf(custom, MAX_CUSTOM_LEN, "tsf=%016llx",
+ (unsigned long long) le64_to_cpu(bss->timestamp));
if (iwe.u.data.length)
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
&iwe, custom);
diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c
index da51786254dc..bac58ed03e5c 100644
--- a/drivers/net/wireless/p54/p54common.c
+++ b/drivers/net/wireless/p54/p54common.c
@@ -1139,7 +1139,7 @@ static int p54_start(struct ieee80211_hw *dev)
err = priv->open(dev);
if (!err)
- priv->mode = IEEE80211_IF_TYPE_MNTR;
+ priv->mode = NL80211_IFTYPE_MONITOR;
p54_init_vdcf(dev);
@@ -1157,7 +1157,7 @@ static void p54_stop(struct ieee80211_hw *dev)
kfree_skb(skb);
priv->stop(dev);
priv->tsf_high32 = priv->tsf_low32 = 0;
- priv->mode = IEEE80211_IF_TYPE_INVALID;
+ priv->mode = NL80211_IFTYPE_UNSPECIFIED;
}
static int p54_add_interface(struct ieee80211_hw *dev,
@@ -1165,11 +1165,11 @@ static int p54_add_interface(struct ieee80211_hw *dev,
{
struct p54_common *priv = dev->priv;
- if (priv->mode != IEEE80211_IF_TYPE_MNTR)
+ if (priv->mode != NL80211_IFTYPE_MONITOR)
return -EOPNOTSUPP;
switch (conf->type) {
- case IEEE80211_IF_TYPE_STA:
+ case NL80211_IFTYPE_STATION:
priv->mode = conf->type;
break;
default:
@@ -1181,7 +1181,7 @@ static int p54_add_interface(struct ieee80211_hw *dev,
p54_set_filter(dev, 0, NULL);
switch (conf->type) {
- case IEEE80211_IF_TYPE_STA:
+ case NL80211_IFTYPE_STATION:
p54_set_filter(dev, 1, NULL);
break;
default:
@@ -1198,7 +1198,7 @@ static void p54_remove_interface(struct ieee80211_hw *dev,
struct ieee80211_if_init_conf *conf)
{
struct p54_common *priv = dev->priv;
- priv->mode = IEEE80211_IF_TYPE_MNTR;
+ priv->mode = NL80211_IFTYPE_MONITOR;
memset(priv->mac_addr, 0, ETH_ALEN);
p54_set_filter(dev, 0, NULL);
}
@@ -1380,7 +1380,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
return NULL;
priv = dev->priv;
- priv->mode = IEEE80211_IF_TYPE_INVALID;
+ priv->mode = NL80211_IFTYPE_UNSPECIFIED;
skb_queue_head_init(&priv->tx_queue);
dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | /* not sure */
IEEE80211_HW_RX_INCLUDES_FCS |
diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c
index 1594786205f8..1c2a02a741af 100644
--- a/drivers/net/wireless/p54/p54pci.c
+++ b/drivers/net/wireless/p54/p54pci.c
@@ -616,7 +616,7 @@ static int p54p_suspend(struct pci_dev *pdev, pm_message_t state)
struct ieee80211_hw *dev = pci_get_drvdata(pdev);
struct p54p_priv *priv = dev->priv;
- if (priv->common.mode != IEEE80211_IF_TYPE_INVALID) {
+ if (priv->common.mode != NL80211_IFTYPE_UNSPECIFIED) {
ieee80211_stop_queues(dev);
p54p_stop(dev);
}
@@ -634,7 +634,7 @@ static int p54p_resume(struct pci_dev *pdev)
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
- if (priv->common.mode != IEEE80211_IF_TYPE_INVALID) {
+ if (priv->common.mode != NL80211_IFTYPE_UNSPECIFIED) {
p54p_open(dev);
ieee80211_wake_queues(dev);
}
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index cb5f2d01a9c3..d3bf7bba611a 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -384,7 +384,7 @@ static void rt2500usb_config_intf(struct rt2x00_dev *rt2x00dev,
rt2500usb_register_read(rt2x00dev, TXRX_CSR20, ®);
rt2x00_set_field16(®, TXRX_CSR20_OFFSET, bcn_preload >> 6);
rt2x00_set_field16(®, TXRX_CSR20_BCN_EXPECT_WINDOW,
- 2 * (conf->type != IEEE80211_IF_TYPE_STA));
+ 2 * (conf->type != NL80211_IFTYPE_STATION));
rt2500usb_register_write(rt2x00dev, TXRX_CSR20, reg);
/*
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 6f296cef76ad..1359a3768404 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -483,7 +483,7 @@ struct rt2x00intf_conf {
/*
* Interface type
*/
- enum ieee80211_if_types type;
+ enum nl80211_iftype type;
/*
* TSF sync value, this is dependant on the operation type.
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c
index ca051f50ef10..4d5e87b015a0 100644
--- a/drivers/net/wireless/rt2x00/rt2x00config.c
+++ b/drivers/net/wireless/rt2x00/rt2x00config.c
@@ -31,7 +31,7 @@
void rt2x00lib_config_intf(struct rt2x00_dev *rt2x00dev,
struct rt2x00_intf *intf,
- enum ieee80211_if_types type,
+ enum nl80211_iftype type,
u8 *mac, u8 *bssid)
{
struct rt2x00intf_conf conf;
@@ -40,11 +40,11 @@ void rt2x00lib_config_intf(struct rt2x00_dev *rt2x00dev,
conf.type = type;
switch (type) {
- case IEEE80211_IF_TYPE_IBSS:
- case IEEE80211_IF_TYPE_AP:
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_AP:
conf.sync = TSF_SYNC_BEACON;
break;
- case IEEE80211_IF_TYPE_STA:
+ case NL80211_IFTYPE_STATION:
conf.sync = TSF_SYNC_INFRA;
break;
default:
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 2f3bfc606880..86840e3585e8 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -467,8 +467,8 @@ static void rt2x00lib_beacondone_iter(void *data, u8 *mac,
struct rt2x00_dev *rt2x00dev = data;
struct rt2x00_intf *intf = vif_to_intf(vif);
- if (vif->type != IEEE80211_IF_TYPE_AP &&
- vif->type != IEEE80211_IF_TYPE_IBSS)
+ if (vif->type != NL80211_IFTYPE_AP &&
+ vif->type != NL80211_IFTYPE_ADHOC)
return;
/*
@@ -1212,8 +1212,8 @@ static void rt2x00lib_resume_intf(void *data, u8 *mac,
/*
* Master or Ad-hoc mode require a new beacon update.
*/
- if (vif->type == IEEE80211_IF_TYPE_AP ||
- vif->type == IEEE80211_IF_TYPE_IBSS)
+ if (vif->type == NL80211_IFTYPE_AP ||
+ vif->type == NL80211_IFTYPE_ADHOC)
intf->delayed_flags |= DELAYED_UPDATE_BEACON;
spin_unlock(&intf->lock);
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h
index 7bbc16b1b6c6..797eb619aa0a 100644
--- a/drivers/net/wireless/rt2x00/rt2x00lib.h
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -88,7 +88,7 @@ void rt2x00lib_stop(struct rt2x00_dev *rt2x00dev);
*/
void rt2x00lib_config_intf(struct rt2x00_dev *rt2x00dev,
struct rt2x00_intf *intf,
- enum ieee80211_if_types type,
+ enum nl80211_iftype type,
u8 *mac, u8 *bssid);
void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev,
struct rt2x00_intf *intf,
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index 56829fad3471..485c40de5cc0 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -211,7 +211,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
return -ENODEV;
switch (conf->type) {
- case IEEE80211_IF_TYPE_AP:
+ case NL80211_IFTYPE_AP:
/*
* We don't support mixed combinations of
* sta and ap interfaces.
@@ -227,8 +227,8 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
return -ENOBUFS;
break;
- case IEEE80211_IF_TYPE_STA:
- case IEEE80211_IF_TYPE_IBSS:
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_ADHOC:
/*
* We don't support mixed combinations of
* sta and ap interfaces.
@@ -268,7 +268,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
* increase interface count and start initialization.
*/
- if (conf->type == IEEE80211_IF_TYPE_AP)
+ if (conf->type == NL80211_IFTYPE_AP)
rt2x00dev->intf_ap_count++;
else
rt2x00dev->intf_sta_count++;
@@ -277,7 +277,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
spin_lock_init(&intf->seqlock);
intf->beacon = entry;
- if (conf->type == IEEE80211_IF_TYPE_AP)
+ if (conf->type == NL80211_IFTYPE_AP)
memcpy(&intf->bssid, conf->mac_addr, ETH_ALEN);
memcpy(&intf->mac, conf->mac_addr, ETH_ALEN);
@@ -311,11 +311,11 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw,
* no interface is present.
*/
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) ||
- (conf->type == IEEE80211_IF_TYPE_AP && !rt2x00dev->intf_ap_count) ||
- (conf->type != IEEE80211_IF_TYPE_AP && !rt2x00dev->intf_sta_count))
+ (conf->type == NL80211_IFTYPE_AP && !rt2x00dev->intf_ap_count) ||
+ (conf->type != NL80211_IFTYPE_AP && !rt2x00dev->intf_sta_count))
return;
- if (conf->type == IEEE80211_IF_TYPE_AP)
+ if (conf->type == NL80211_IFTYPE_AP)
rt2x00dev->intf_ap_count--;
else
rt2x00dev->intf_sta_count--;
@@ -331,7 +331,7 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw,
* are cleared to prevent false ACKing of frames.
*/
rt2x00lib_config_intf(rt2x00dev, intf,
- IEEE80211_IF_TYPE_INVALID, NULL, NULL);
+ NL80211_IFTYPE_UNSPECIFIED, NULL, NULL);
}
EXPORT_SYMBOL_GPL(rt2x00mac_remove_interface);
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index a5e965068c83..b7f4fe8fba6e 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -155,7 +155,6 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
- struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data;
struct ieee80211_rate *rate =
ieee80211_get_tx_rate(rt2x00dev->hw, tx_info);
@@ -278,16 +277,22 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
* sequence counter given by mac80211.
*/
if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
- spin_lock_irqsave(&intf->seqlock, irqflags);
+ if (likely(tx_info->control.vif)) {
+ struct rt2x00_intf *intf;
- if (test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags))
- intf->seqno += 0x10;
- hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
- hdr->seq_ctrl |= cpu_to_le16(intf->seqno);
+ intf = vif_to_intf(tx_info->control.vif);
- spin_unlock_irqrestore(&intf->seqlock, irqflags);
+ spin_lock_irqsave(&intf->seqlock, irqflags);
- __set_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags);
+ if (test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags))
+ intf->seqno += 0x10;
+ hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
+ hdr->seq_ctrl |= cpu_to_le16(intf->seqno);
+
+ spin_unlock_irqrestore(&intf->seqlock, irqflags);
+
+ __set_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags);
+ }
}
/*
diff --git a/drivers/net/wireless/rtl8180_dev.c b/drivers/net/wireless/rtl8180_dev.c
index 861c76a65d6a..abcd641c54be 100644
--- a/drivers/net/wireless/rtl8180_dev.c
+++ b/drivers/net/wireless/rtl8180_dev.c
@@ -615,7 +615,7 @@ static int rtl8180_start(struct ieee80211_hw *dev)
reg |= RTL818X_CMD_TX_ENABLE;
rtl818x_iowrite8(priv, &priv->map->CMD, reg);
- priv->mode = IEEE80211_IF_TYPE_MNTR;
+ priv->mode = NL80211_IFTYPE_MONITOR;
return 0;
err_free_rings:
@@ -633,7 +633,7 @@ static void rtl8180_stop(struct ieee80211_hw *dev)
u8 reg;
int i;
- priv->mode = IEEE80211_IF_TYPE_INVALID;
+ priv->mode = NL80211_IFTYPE_UNSPECIFIED;
rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0);
@@ -661,11 +661,11 @@ static int rtl8180_add_interface(struct ieee80211_hw *dev,
{
struct rtl8180_priv *priv = dev->priv;
- if (priv->mode != IEEE80211_IF_TYPE_MNTR)
+ if (priv->mode != NL80211_IFTYPE_MONITOR)
return -EOPNOTSUPP;
switch (conf->type) {
- case IEEE80211_IF_TYPE_STA:
+ case NL80211_IFTYPE_STATION:
priv->mode = conf->type;
break;
default:
@@ -688,7 +688,7 @@ static void rtl8180_remove_interface(struct ieee80211_hw *dev,
struct ieee80211_if_init_conf *conf)
{
struct rtl8180_priv *priv = dev->priv;
- priv->mode = IEEE80211_IF_TYPE_MNTR;
+ priv->mode = NL80211_IFTYPE_MONITOR;
priv->vif = NULL;
}
diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c
index 8a42bfa6d4f0..e9902613e2ee 100644
--- a/drivers/net/wireless/rtl8187_dev.c
+++ b/drivers/net/wireless/rtl8187_dev.c
@@ -836,11 +836,11 @@ static int rtl8187_add_interface(struct ieee80211_hw *dev,
struct rtl8187_priv *priv = dev->priv;
int i;
- if (priv->mode != IEEE80211_IF_TYPE_MNTR)
+ if (priv->mode != NL80211_IFTYPE_MONITOR)
return -EOPNOTSUPP;
switch (conf->type) {
- case IEEE80211_IF_TYPE_STA:
+ case NL80211_IFTYPE_STATION:
priv->mode = conf->type;
break;
default:
@@ -865,7 +865,7 @@ static void rtl8187_remove_interface(struct ieee80211_hw *dev,
{
struct rtl8187_priv *priv = dev->priv;
mutex_lock(&priv->conf_mutex);
- priv->mode = IEEE80211_IF_TYPE_MNTR;
+ priv->mode = NL80211_IFTYPE_MONITOR;
priv->vif = NULL;
mutex_unlock(&priv->conf_mutex);
}
@@ -1057,7 +1057,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
- priv->mode = IEEE80211_IF_TYPE_MNTR;
+ priv->mode = NL80211_IFTYPE_MONITOR;
dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
IEEE80211_HW_RX_INCLUDES_FCS;
diff --git a/drivers/net/wireless/zd1211rw/Makefile b/drivers/net/wireless/zd1211rw/Makefile
index cc36126cee88..1907eafb9b16 100644
--- a/drivers/net/wireless/zd1211rw/Makefile
+++ b/drivers/net/wireless/zd1211rw/Makefile
@@ -1,6 +1,6 @@
obj-$(CONFIG_ZD1211RW) += zd1211rw.o
-zd1211rw-objs := zd_chip.o zd_ieee80211.o zd_mac.o \
+zd1211rw-objs := zd_chip.o zd_mac.o \
zd_rf_al2230.o zd_rf_rf2959.o \
zd_rf_al7230b.o zd_rf_uw2453.o \
zd_rf.o zd_usb.o
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c
index 0acb5c345734..e0ac58b8ff1f 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.c
+++ b/drivers/net/wireless/zd1211rw/zd_chip.c
@@ -28,7 +28,6 @@
#include "zd_def.h"
#include "zd_chip.h"
-#include "zd_ieee80211.h"
#include "zd_mac.h"
#include "zd_rf.h"
diff --git a/drivers/net/wireless/zd1211rw/zd_ieee80211.c b/drivers/net/wireless/zd1211rw/zd_ieee80211.c
deleted file mode 100644
index d8dc41ec0e5d..000000000000
--- a/drivers/net/wireless/zd1211rw/zd_ieee80211.c
+++ /dev/null
@@ -1,100 +0,0 @@
-/* ZD1211 USB-WLAN driver for Linux
- *
- * Copyright (C) 2005-2007 Ulrich Kunitz
- * Copyright (C) 2006-2007 Daniel Drake
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-/*
- * In the long term, we'll probably find a better way of handling regulatory
- * requirements outside of the driver.
- */
-
-#include
-#include
-
-#include "zd_ieee80211.h"
-#include "zd_mac.h"
-
-struct channel_range {
- u8 regdomain;
- u8 start;
- u8 end; /* exclusive (channel must be less than end) */
-};
-
-static const struct channel_range channel_ranges[] = {
- { ZD_REGDOMAIN_FCC, 1, 12 },
- { ZD_REGDOMAIN_IC, 1, 12 },
- { ZD_REGDOMAIN_ETSI, 1, 14 },
- { ZD_REGDOMAIN_JAPAN, 1, 14 },
- { ZD_REGDOMAIN_SPAIN, 1, 14 },
- { ZD_REGDOMAIN_FRANCE, 1, 14 },
-
- /* Japan originally only had channel 14 available (see CHNL_ID 0x40 in
- * 802.11). However, in 2001 the range was extended to include channels
- * 1-13. The ZyDAS devices still use the old region code but are
- * designed to allow the extra channel access in Japan. */
- { ZD_REGDOMAIN_JAPAN_ADD, 1, 15 },
-};
-
-static const struct channel_range *zd_channel_range(u8 regdomain)
-{
- int i;
- for (i = 0; i < ARRAY_SIZE(channel_ranges); i++) {
- const struct channel_range *range = &channel_ranges[i];
- if (range->regdomain == regdomain)
- return range;
- }
- return NULL;
-}
-
-#define CHAN_TO_IDX(chan) ((chan) - 1)
-
-static void unmask_bg_channels(struct ieee80211_hw *hw,
- const struct channel_range *range,
- struct ieee80211_supported_band *sband)
-{
- u8 channel;
-
- for (channel = range->start; channel < range->end; channel++) {
- struct ieee80211_channel *chan =
- &sband->channels[CHAN_TO_IDX(channel)];
- chan->flags = 0;
- }
-}
-
-void zd_geo_init(struct ieee80211_hw *hw, u8 regdomain)
-{
- struct zd_mac *mac = zd_hw_mac(hw);
- const struct channel_range *range;
-
- dev_dbg(zd_mac_dev(mac), "regdomain %#02x\n", regdomain);
-
- range = zd_channel_range(regdomain);
- if (!range) {
- /* The vendor driver overrides the regulatory domain and
- * allowed channel registers and unconditionally restricts
- * available channels to 1-11 everywhere. Match their
- * questionable behaviour only for regdomains which we don't
- * recognise. */
- dev_warn(zd_mac_dev(mac), "Unrecognised regulatory domain: "
- "%#02x. Defaulting to FCC.\n", regdomain);
- range = zd_channel_range(ZD_REGDOMAIN_FCC);
- }
-
- unmask_bg_channels(hw, range, &mac->band);
-}
-
diff --git a/drivers/net/wireless/zd1211rw/zd_ieee80211.h b/drivers/net/wireless/zd1211rw/zd_ieee80211.h
deleted file mode 100644
index 26b79f197587..000000000000
--- a/drivers/net/wireless/zd1211rw/zd_ieee80211.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/* ZD1211 USB-WLAN driver for Linux
- *
- * Copyright (C) 2005-2007 Ulrich Kunitz
- * Copyright (C) 2006-2007 Daniel Drake
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _ZD_IEEE80211_H
-#define _ZD_IEEE80211_H
-
-#include
-
-/* Additional definitions from the standards.
- */
-
-#define ZD_REGDOMAIN_FCC 0x10
-#define ZD_REGDOMAIN_IC 0x20
-#define ZD_REGDOMAIN_ETSI 0x30
-#define ZD_REGDOMAIN_SPAIN 0x31
-#define ZD_REGDOMAIN_FRANCE 0x32
-#define ZD_REGDOMAIN_JAPAN_ADD 0x40
-#define ZD_REGDOMAIN_JAPAN 0x41
-
-enum {
- MIN_CHANNEL24 = 1,
- MAX_CHANNEL24 = 14,
-};
-
-void zd_geo_init(struct ieee80211_hw *hw, u8 regdomain);
-
-#define ZD_PLCP_SERVICE_LENGTH_EXTENSION 0x80
-
-struct ofdm_plcp_header {
- u8 prefix[3];
- __le16 service;
-} __attribute__((packed));
-
-static inline u8 zd_ofdm_plcp_header_rate(const struct ofdm_plcp_header *header)
-{
- return header->prefix[0] & 0xf;
-}
-
-/* The following defines give the encoding of the 4-bit rate field in the
- * OFDM (802.11a/802.11g) PLCP header. Notify that these values are used to
- * define the zd-rate values for OFDM.
- *
- * See the struct zd_ctrlset definition in zd_mac.h.
- */
-#define ZD_OFDM_PLCP_RATE_6M 0xb
-#define ZD_OFDM_PLCP_RATE_9M 0xf
-#define ZD_OFDM_PLCP_RATE_12M 0xa
-#define ZD_OFDM_PLCP_RATE_18M 0xe
-#define ZD_OFDM_PLCP_RATE_24M 0x9
-#define ZD_OFDM_PLCP_RATE_36M 0xd
-#define ZD_OFDM_PLCP_RATE_48M 0x8
-#define ZD_OFDM_PLCP_RATE_54M 0xc
-
-struct cck_plcp_header {
- u8 signal;
- u8 service;
- __le16 length;
- __le16 crc16;
-} __attribute__((packed));
-
-static inline u8 zd_cck_plcp_header_signal(const struct cck_plcp_header *header)
-{
- return header->signal;
-}
-
-/* These defines give the encodings of the signal field in the 802.11b PLCP
- * header. The signal field gives the bit rate of the following packet. Even
- * if technically wrong we use CCK here also for the 1 MBit/s and 2 MBit/s
- * rate to stay consistent with Zydas and our use of the term.
- *
- * Notify that these values are *not* used in the zd-rates.
- */
-#define ZD_CCK_PLCP_SIGNAL_1M 0x0a
-#define ZD_CCK_PLCP_SIGNAL_2M 0x14
-#define ZD_CCK_PLCP_SIGNAL_5M5 0x37
-#define ZD_CCK_PLCP_SIGNAL_11M 0x6e
-
-#endif /* _ZD_IEEE80211_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index e019102b2285..a3da014f928d 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -3,7 +3,7 @@
* Copyright (C) 2005-2007 Ulrich Kunitz
* Copyright (C) 2006-2007 Daniel Drake
* Copyright (C) 2006-2007 Michael Wu
- * Copyright (c) 2007 Luis R. Rodriguez
+ * Copyright (C) 2007-2008 Luis R. Rodriguez
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -29,9 +29,23 @@
#include "zd_def.h"
#include "zd_chip.h"
#include "zd_mac.h"
-#include "zd_ieee80211.h"
#include "zd_rf.h"
+struct zd_reg_alpha2_map {
+ u32 reg;
+ char alpha2[2];
+};
+
+static struct zd_reg_alpha2_map reg_alpha2_map[] = {
+ { ZD_REGDOMAIN_FCC, "US" },
+ { ZD_REGDOMAIN_IC, "CA" },
+ { ZD_REGDOMAIN_ETSI, "DE" }, /* Generic ETSI, use most restrictive */
+ { ZD_REGDOMAIN_JAPAN, "JP" },
+ { ZD_REGDOMAIN_JAPAN_ADD, "JP" },
+ { ZD_REGDOMAIN_SPAIN, "ES" },
+ { ZD_REGDOMAIN_FRANCE, "FR" },
+};
+
/* This table contains the hardware specific values for the modulation rates. */
static const struct ieee80211_rate zd_rates[] = {
{ .bitrate = 10,
@@ -95,6 +109,21 @@ static void housekeeping_init(struct zd_mac *mac);
static void housekeeping_enable(struct zd_mac *mac);
static void housekeeping_disable(struct zd_mac *mac);
+static int zd_reg2alpha2(u8 regdomain, char *alpha2)
+{
+ unsigned int i;
+ struct zd_reg_alpha2_map *reg_map;
+ for (i = 0; i < ARRAY_SIZE(reg_alpha2_map); i++) {
+ reg_map = ®_alpha2_map[i];
+ if (regdomain == reg_map->reg) {
+ alpha2[0] = reg_map->alpha2[0];
+ alpha2[1] = reg_map->alpha2[1];
+ return 0;
+ }
+ }
+ return 1;
+}
+
int zd_mac_preinit_hw(struct ieee80211_hw *hw)
{
int r;
@@ -115,6 +144,7 @@ int zd_mac_init_hw(struct ieee80211_hw *hw)
int r;
struct zd_mac *mac = zd_hw_mac(hw);
struct zd_chip *chip = &mac->chip;
+ char alpha2[2];
u8 default_regdomain;
r = zd_chip_enable_int(chip);
@@ -139,7 +169,9 @@ int zd_mac_init_hw(struct ieee80211_hw *hw)
if (r)
goto disable_int;
- zd_geo_init(hw, mac->regdomain);
+ r = zd_reg2alpha2(mac->regdomain, alpha2);
+ if (!r)
+ regulatory_hint(hw->wiphy, alpha2, NULL);
r = 0;
disable_int:
@@ -684,15 +716,15 @@ static int zd_op_add_interface(struct ieee80211_hw *hw,
{
struct zd_mac *mac = zd_hw_mac(hw);
- /* using IEEE80211_IF_TYPE_INVALID to indicate no mode selected */
- if (mac->type != IEEE80211_IF_TYPE_INVALID)
+ /* using NL80211_IFTYPE_UNSPECIFIED to indicate no mode selected */
+ if (mac->type != NL80211_IFTYPE_UNSPECIFIED)
return -EOPNOTSUPP;
switch (conf->type) {
- case IEEE80211_IF_TYPE_MNTR:
- case IEEE80211_IF_TYPE_MESH_POINT:
- case IEEE80211_IF_TYPE_STA:
- case IEEE80211_IF_TYPE_IBSS:
+ case NL80211_IFTYPE_MONITOR:
+ case NL80211_IFTYPE_MESH_POINT:
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_ADHOC:
mac->type = conf->type;
break;
default:
@@ -706,7 +738,7 @@ static void zd_op_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
{
struct zd_mac *mac = zd_hw_mac(hw);
- mac->type = IEEE80211_IF_TYPE_INVALID;
+ mac->type = NL80211_IFTYPE_UNSPECIFIED;
zd_set_beacon_interval(&mac->chip, 0);
zd_write_mac_addr(&mac->chip, NULL);
}
@@ -725,8 +757,8 @@ static int zd_op_config_interface(struct ieee80211_hw *hw,
int associated;
int r;
- if (mac->type == IEEE80211_IF_TYPE_MESH_POINT ||
- mac->type == IEEE80211_IF_TYPE_IBSS) {
+ if (mac->type == NL80211_IFTYPE_MESH_POINT ||
+ mac->type == NL80211_IFTYPE_ADHOC) {
associated = true;
if (conf->changed & IEEE80211_IFCC_BEACON) {
struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
@@ -753,7 +785,7 @@ static int zd_op_config_interface(struct ieee80211_hw *hw,
return 0;
}
-void zd_process_intr(struct work_struct *work)
+static void zd_process_intr(struct work_struct *work)
{
u16 int_status;
struct zd_mac *mac = container_of(work, struct zd_mac, process_intr);
@@ -923,7 +955,7 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf)
spin_lock_init(&mac->lock);
mac->hw = hw;
- mac->type = IEEE80211_IF_TYPE_INVALID;
+ mac->type = NL80211_IFTYPE_UNSPECIFIED;
memcpy(mac->channels, zd_channels, sizeof(zd_channels));
memcpy(mac->rates, zd_rates, sizeof(zd_rates));
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h
index 18c1d56d3dd7..4c05d3ee4c37 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.h
+++ b/drivers/net/wireless/zd1211rw/zd_mac.h
@@ -25,7 +25,6 @@
#include
#include "zd_chip.h"
-#include "zd_ieee80211.h"
struct zd_ctrlset {
u8 modulation;
@@ -187,6 +186,70 @@ struct zd_mac {
unsigned int pass_ctrl:1;
};
+#define ZD_REGDOMAIN_FCC 0x10
+#define ZD_REGDOMAIN_IC 0x20
+#define ZD_REGDOMAIN_ETSI 0x30
+#define ZD_REGDOMAIN_SPAIN 0x31
+#define ZD_REGDOMAIN_FRANCE 0x32
+#define ZD_REGDOMAIN_JAPAN_ADD 0x40
+#define ZD_REGDOMAIN_JAPAN 0x41
+
+enum {
+ MIN_CHANNEL24 = 1,
+ MAX_CHANNEL24 = 14,
+};
+
+#define ZD_PLCP_SERVICE_LENGTH_EXTENSION 0x80
+
+struct ofdm_plcp_header {
+ u8 prefix[3];
+ __le16 service;
+} __attribute__((packed));
+
+static inline u8 zd_ofdm_plcp_header_rate(const struct ofdm_plcp_header *header)
+{
+ return header->prefix[0] & 0xf;
+}
+
+/* The following defines give the encoding of the 4-bit rate field in the
+ * OFDM (802.11a/802.11g) PLCP header. Notify that these values are used to
+ * define the zd-rate values for OFDM.
+ *
+ * See the struct zd_ctrlset definition in zd_mac.h.
+ */
+#define ZD_OFDM_PLCP_RATE_6M 0xb
+#define ZD_OFDM_PLCP_RATE_9M 0xf
+#define ZD_OFDM_PLCP_RATE_12M 0xa
+#define ZD_OFDM_PLCP_RATE_18M 0xe
+#define ZD_OFDM_PLCP_RATE_24M 0x9
+#define ZD_OFDM_PLCP_RATE_36M 0xd
+#define ZD_OFDM_PLCP_RATE_48M 0x8
+#define ZD_OFDM_PLCP_RATE_54M 0xc
+
+struct cck_plcp_header {
+ u8 signal;
+ u8 service;
+ __le16 length;
+ __le16 crc16;
+} __attribute__((packed));
+
+static inline u8 zd_cck_plcp_header_signal(const struct cck_plcp_header *header)
+{
+ return header->signal;
+}
+
+/* These defines give the encodings of the signal field in the 802.11b PLCP
+ * header. The signal field gives the bit rate of the following packet. Even
+ * if technically wrong we use CCK here also for the 1 MBit/s and 2 MBit/s
+ * rate to stay consistent with Zydas and our use of the term.
+ *
+ * Notify that these values are *not* used in the zd-rates.
+ */
+#define ZD_CCK_PLCP_SIGNAL_1M 0x0a
+#define ZD_CCK_PLCP_SIGNAL_2M 0x14
+#define ZD_CCK_PLCP_SIGNAL_5M5 0x37
+#define ZD_CCK_PLCP_SIGNAL_11M 0x6e
+
static inline struct zd_mac *zd_hw_mac(struct ieee80211_hw *hw)
{
return hw->priv;
diff --git a/drivers/net/wireless/zd1211rw/zd_rf.c b/drivers/net/wireless/zd1211rw/zd_rf.c
index ec4129312813..7207bfd2e6cd 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf.c
@@ -23,7 +23,7 @@
#include "zd_def.h"
#include "zd_rf.h"
-#include "zd_ieee80211.h"
+#include "zd_mac.h"
#include "zd_chip.h"
static const char * const rfs[] = {
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 5e51f4e7600b..9bad65400fba 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -92,6 +92,20 @@
* @NL80211_CMD_SET_BSS: Set BSS attributes for BSS identified by
* %NL80211_ATTR_IFINDEX.
*
+ * @NL80211_CMD_SET_REG: Set current regulatory domain. CRDA sends this command
+ * after being queried by the kernel. CRDA replies by sending a regulatory
+ * domain structure which consists of %NL80211_ATTR_REG_ALPHA set to our
+ * current alpha2 if it found a match. It also provides
+ * NL80211_ATTR_REG_RULE_FLAGS, and a set of regulatory rules. Each
+ * regulatory rule is a nested set of attributes given by
+ * %NL80211_ATTR_REG_RULE_FREQ_[START|END] and
+ * %NL80211_ATTR_FREQ_RANGE_MAX_BW with an attached power rule given by
+ * %NL80211_ATTR_REG_RULE_POWER_MAX_ANT_GAIN and
+ * %NL80211_ATTR_REG_RULE_POWER_MAX_EIRP.
+ * @NL80211_CMD_REQ_SET_REG: ask the wireless core to set the regulatory domain
+ * to the the specified ISO/IEC 3166-1 alpha2 country code. The core will
+ * store this as a valid request and then query userspace for it.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -131,7 +145,10 @@ enum nl80211_commands {
NL80211_CMD_SET_BSS,
- /* add commands here */
+ NL80211_CMD_SET_REG,
+ NL80211_CMD_REQ_SET_REG,
+
+ /* add new commands above here */
/* used to define NL80211_CMD_MAX below */
__NL80211_CMD_AFTER_LAST,
@@ -197,10 +214,21 @@ enum nl80211_commands {
* info given for %NL80211_CMD_GET_MPATH, nested attribute described at
* &enum nl80211_mpath_info.
*
- *
* @NL80211_ATTR_MNTR_FLAGS: flags, nested element with NLA_FLAG attributes of
* &enum nl80211_mntr_flags.
*
+ * @NL80211_ATTR_REG_ALPHA2: an ISO-3166-alpha2 country code for which the
+ * current regulatory domain should be set to or is already set to.
+ * For example, 'CR', for Costa Rica. This attribute is used by the kernel
+ * to query the CRDA to retrieve one regulatory domain. This attribute can
+ * also be used by userspace to query the kernel for the currently set
+ * regulatory domain. We chose an alpha2 as that is also used by the
+ * IEEE-802.11d country information element to identify a country.
+ * Users can also simply ask the wireless core to set regulatory domain
+ * to a specific alpha2.
+ * @NL80211_ATTR_REG_RULES: a nested array of regulatory domain regulatory
+ * rules.
+ *
* @NL80211_ATTR_BSS_CTS_PROT: whether CTS protection is enabled (u8, 0 or 1)
* @NL80211_ATTR_BSS_SHORT_PREAMBLE: whether short preamble is enabled
* (u8, 0 or 1)
@@ -265,6 +293,9 @@ enum nl80211_attrs {
NL80211_ATTR_SUPPORTED_IFTYPES,
+ NL80211_ATTR_REG_ALPHA2,
+ NL80211_ATTR_REG_RULES,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -278,6 +309,7 @@ enum nl80211_attrs {
#define NL80211_ATTR_HT_CAPABILITY NL80211_ATTR_HT_CAPABILITY
#define NL80211_MAX_SUPP_RATES 32
+#define NL80211_MAX_SUPP_REG_RULES 32
#define NL80211_TKIP_DATA_OFFSET_ENCR_KEY 0
#define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY 16
#define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY 24
@@ -472,6 +504,66 @@ enum nl80211_bitrate_attr {
NL80211_BITRATE_ATTR_MAX = __NL80211_BITRATE_ATTR_AFTER_LAST - 1
};
+/**
+ * enum nl80211_reg_rule_attr - regulatory rule attributes
+ * @NL80211_ATTR_REG_RULE_FLAGS: a set of flags which specify additional
+ * considerations for a given frequency range. These are the
+ * &enum nl80211_reg_rule_flags.
+ * @NL80211_ATTR_FREQ_RANGE_START: starting frequencry for the regulatory
+ * rule in KHz. This is not a center of frequency but an actual regulatory
+ * band edge.
+ * @NL80211_ATTR_FREQ_RANGE_END: ending frequency for the regulatory rule
+ * in KHz. This is not a center a frequency but an actual regulatory
+ * band edge.
+ * @NL80211_ATTR_FREQ_RANGE_MAX_BW: maximum allowed bandwidth for this
+ * frequency range, in KHz.
+ * @NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN: the maximum allowed antenna gain
+ * for a given frequency range. The value is in mBi (100 * dBi).
+ * If you don't have one then don't send this.
+ * @NL80211_ATTR_POWER_RULE_MAX_EIRP: the maximum allowed EIRP for
+ * a given frequency range. The value is in mBm (100 * dBm).
+ */
+enum nl80211_reg_rule_attr {
+ __NL80211_REG_RULE_ATTR_INVALID,
+ NL80211_ATTR_REG_RULE_FLAGS,
+
+ NL80211_ATTR_FREQ_RANGE_START,
+ NL80211_ATTR_FREQ_RANGE_END,
+ NL80211_ATTR_FREQ_RANGE_MAX_BW,
+
+ NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN,
+ NL80211_ATTR_POWER_RULE_MAX_EIRP,
+
+ /* keep last */
+ __NL80211_REG_RULE_ATTR_AFTER_LAST,
+ NL80211_REG_RULE_ATTR_MAX = __NL80211_REG_RULE_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_reg_rule_flags - regulatory rule flags
+ *
+ * @NL80211_RRF_NO_OFDM: OFDM modulation not allowed
+ * @NL80211_RRF_NO_CCK: CCK modulation not allowed
+ * @NL80211_RRF_NO_INDOOR: indoor operation not allowed
+ * @NL80211_RRF_NO_OUTDOOR: outdoor operation not allowed
+ * @NL80211_RRF_DFS: DFS support is required to be used
+ * @NL80211_RRF_PTP_ONLY: this is only for Point To Point links
+ * @NL80211_RRF_PTMP_ONLY: this is only for Point To Multi Point links
+ * @NL80211_RRF_PASSIVE_SCAN: passive scan is required
+ * @NL80211_RRF_NO_IBSS: no IBSS is allowed
+ */
+enum nl80211_reg_rule_flags {
+ NL80211_RRF_NO_OFDM = 1<<0,
+ NL80211_RRF_NO_CCK = 1<<1,
+ NL80211_RRF_NO_INDOOR = 1<<2,
+ NL80211_RRF_NO_OUTDOOR = 1<<3,
+ NL80211_RRF_DFS = 1<<4,
+ NL80211_RRF_PTP_ONLY = 1<<5,
+ NL80211_RRF_PTMP_ONLY = 1<<6,
+ NL80211_RRF_PASSIVE_SCAN = 1<<7,
+ NL80211_RRF_NO_IBSS = 1<<8,
+};
+
/**
* enum nl80211_mntr_flags - monitor configuration flags
*
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 0a72d1e3d3ab..9f40c4d417d7 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -287,6 +287,66 @@ struct bss_parameters {
int use_short_slot_time;
};
+/**
+ * enum reg_set_by - Indicates who is trying to set the regulatory domain
+ * @REGDOM_SET_BY_INIT: regulatory domain was set by initialization. We will be
+ * using a static world regulatory domain by default.
+ * @REGDOM_SET_BY_CORE: Core queried CRDA for a dynamic world regulatory domain.
+ * @REGDOM_SET_BY_USER: User asked the wireless core to set the
+ * regulatory domain.
+ * @REGDOM_SET_BY_DRIVER: a wireless drivers has hinted to the wireless core
+ * it thinks its knows the regulatory domain we should be in.
+ * @REGDOM_SET_BY_COUNTRY_IE: the wireless core has received an 802.11 country
+ * information element with regulatory information it thinks we
+ * should consider.
+ */
+enum reg_set_by {
+ REGDOM_SET_BY_INIT,
+ REGDOM_SET_BY_CORE,
+ REGDOM_SET_BY_USER,
+ REGDOM_SET_BY_DRIVER,
+ REGDOM_SET_BY_COUNTRY_IE,
+};
+
+struct ieee80211_freq_range {
+ u32 start_freq_khz;
+ u32 end_freq_khz;
+ u32 max_bandwidth_khz;
+};
+
+struct ieee80211_power_rule {
+ u32 max_antenna_gain;
+ u32 max_eirp;
+};
+
+struct ieee80211_reg_rule {
+ struct ieee80211_freq_range freq_range;
+ struct ieee80211_power_rule power_rule;
+ u32 flags;
+};
+
+struct ieee80211_regdomain {
+ u32 n_reg_rules;
+ char alpha2[2];
+ struct ieee80211_reg_rule reg_rules[];
+};
+
+#define MHZ_TO_KHZ(freq) (freq * 1000)
+#define KHZ_TO_MHZ(freq) (freq / 1000)
+#define DBI_TO_MBI(gain) (gain * 100)
+#define MBI_TO_DBI(gain) (gain / 100)
+#define DBM_TO_MBM(gain) (gain * 100)
+#define MBM_TO_DBM(gain) (gain / 100)
+
+#define REG_RULE(start, end, bw, gain, eirp, reg_flags) { \
+ .freq_range.start_freq_khz = (start) * 1000, \
+ .freq_range.end_freq_khz = (end) * 1000, \
+ .freq_range.max_bandwidth_khz = (bw) * 1000, \
+ .power_rule.max_antenna_gain = (gain) * 100, \
+ .power_rule.max_eirp = (eirp) * 100, \
+ .flags = reg_flags, \
+ }
+
/* from net/wireless.h */
struct wiphy;
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index fb9e62211c34..003e4a03874e 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -160,6 +160,7 @@ struct ieee80211_low_level_stats {
* @BSS_CHANGED_ERP_PREAMBLE: preamble changed
* @BSS_CHANGED_ERP_SLOT: slot timing changed
* @BSS_CHANGED_HT: 802.11n parameters changed
+ * @BSS_CHANGED_BASIC_RATES: Basic rateset changed
*/
enum ieee80211_bss_change {
BSS_CHANGED_ASSOC = 1<<0,
@@ -167,6 +168,7 @@ enum ieee80211_bss_change {
BSS_CHANGED_ERP_PREAMBLE = 1<<2,
BSS_CHANGED_ERP_SLOT = 1<<3,
BSS_CHANGED_HT = 1<<4,
+ BSS_CHANGED_BASIC_RATES = 1<<5,
};
/**
@@ -187,6 +189,9 @@ enum ieee80211_bss_change {
* @assoc_ht: association in HT mode
* @ht_conf: ht capabilities
* @ht_bss_conf: ht extended capabilities
+ * @basic_rates: bitmap of basic rates, each bit stands for an
+ * index into the rate table configured by the driver in
+ * the current band.
*/
struct ieee80211_bss_conf {
/* association related data */
@@ -200,6 +205,7 @@ struct ieee80211_bss_conf {
u16 beacon_int;
u16 assoc_capability;
u64 timestamp;
+ u64 basic_rates;
/* ht related data */
bool assoc_ht;
struct ieee80211_ht_info *ht_conf;
@@ -294,6 +300,9 @@ enum mac80211_tx_control_flags {
* (2) driver internal use (if applicable)
* (3) TX status information - driver tells mac80211 what happened
*
+ * The TX control's sta pointer is only valid during the ->tx call,
+ * it may be NULL.
+ *
* @flags: transmit info flags, defined above
* @band: TBD
* @tx_rate_idx: TBD
@@ -321,10 +330,11 @@ struct ieee80211_tx_info {
union {
struct {
+ /* NB: vif can be NULL for injected frames */
struct ieee80211_vif *vif;
struct ieee80211_key_conf *hw_key;
+ struct ieee80211_sta *sta;
unsigned long jiffies;
- u16 aid;
s8 rts_cts_rate_idx, alt_retry_rate_idx;
u8 retry_limit;
u8 icv_len;
@@ -471,33 +481,6 @@ struct ieee80211_conf {
struct ieee80211_ht_bss_info ht_bss_conf;
};
-/**
- * enum ieee80211_if_types - types of 802.11 network interfaces
- *
- * @IEEE80211_IF_TYPE_INVALID: invalid interface type, not used
- * by mac80211 itself
- * @IEEE80211_IF_TYPE_AP: interface in AP mode.
- * @IEEE80211_IF_TYPE_MGMT: special interface for communication with hostap
- * daemon. Drivers should never see this type.
- * @IEEE80211_IF_TYPE_STA: interface in STA (client) mode.
- * @IEEE80211_IF_TYPE_IBSS: interface in IBSS (ad-hoc) mode.
- * @IEEE80211_IF_TYPE_MNTR: interface in monitor (rfmon) mode.
- * @IEEE80211_IF_TYPE_WDS: interface in WDS mode.
- * @IEEE80211_IF_TYPE_VLAN: VLAN interface bound to an AP, drivers
- * will never see this type.
- * @IEEE80211_IF_TYPE_MESH_POINT: 802.11s mesh point
- */
-enum ieee80211_if_types {
- IEEE80211_IF_TYPE_INVALID,
- IEEE80211_IF_TYPE_AP,
- IEEE80211_IF_TYPE_STA,
- IEEE80211_IF_TYPE_IBSS,
- IEEE80211_IF_TYPE_MESH_POINT,
- IEEE80211_IF_TYPE_MNTR,
- IEEE80211_IF_TYPE_WDS,
- IEEE80211_IF_TYPE_VLAN,
-};
-
/**
* struct ieee80211_vif - per-interface data
*
@@ -509,7 +492,7 @@ enum ieee80211_if_types {
* sizeof(void *).
*/
struct ieee80211_vif {
- enum ieee80211_if_types type;
+ enum nl80211_iftype type;
/* must be last */
u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *))));
};
@@ -517,7 +500,7 @@ struct ieee80211_vif {
static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif)
{
#ifdef CONFIG_MAC80211_MESH
- return vif->type == IEEE80211_IF_TYPE_MESH_POINT;
+ return vif->type == NL80211_IFTYPE_MESH_POINT;
#endif
return false;
}
@@ -528,7 +511,7 @@ static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif)
* @vif: pointer to a driver-use per-interface structure. The pointer
* itself is also used for various functions including
* ieee80211_beacon_get() and ieee80211_get_buffered_bc().
- * @type: one of &enum ieee80211_if_types constants. Determines the type of
+ * @type: one of &enum nl80211_iftype constants. Determines the type of
* added/removed interface.
* @mac_addr: pointer to MAC address of the interface. This pointer is valid
* until the interface is removed (i.e. it cannot be used after
@@ -544,7 +527,7 @@ static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif)
* in pure monitor mode.
*/
struct ieee80211_if_init_conf {
- enum ieee80211_if_types type;
+ enum nl80211_iftype type;
struct ieee80211_vif *vif;
void *mac_addr;
};
@@ -672,6 +655,33 @@ enum set_key_cmd {
SET_KEY, DISABLE_KEY,
};
+/**
+ * struct ieee80211_sta - station table entry
+ *
+ * A station table entry represents a station we are possibly
+ * communicating with. Since stations are RCU-managed in
+ * mac80211, any ieee80211_sta pointer you get access to must
+ * either be protected by rcu_read_lock() explicitly or implicitly,
+ * or you must take good care to not use such a pointer after a
+ * call to your sta_notify callback that removed it.
+ *
+ * @addr: MAC address
+ * @aid: AID we assigned to the station if we're an AP
+ * @supp_rates: Bitmap of supported rates (per band)
+ * @ht_info: HT capabilities of this STA
+ * @drv_priv: data area for driver use, will always be aligned to
+ * sizeof(void *), size is determined in hw information.
+ */
+struct ieee80211_sta {
+ u64 supp_rates[IEEE80211_NUM_BANDS];
+ u8 addr[ETH_ALEN];
+ u16 aid;
+ struct ieee80211_ht_info ht_info;
+
+ /* must be last */
+ u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *))));
+};
+
/**
* enum sta_notify_cmd - sta notify command
*
@@ -816,6 +826,8 @@ enum ieee80211_hw_flags {
*
* @vif_data_size: size (in bytes) of the drv_priv data area
* within &struct ieee80211_vif.
+ * @sta_data_size: size (in bytes) of the drv_priv data area
+ * within &struct ieee80211_sta.
*/
struct ieee80211_hw {
struct ieee80211_conf conf;
@@ -827,12 +839,15 @@ struct ieee80211_hw {
unsigned int extra_tx_headroom;
int channel_change_time;
int vif_data_size;
+ int sta_data_size;
u16 queues;
u16 ampdu_queues;
u16 max_listen_interval;
s8 max_signal;
};
+struct ieee80211_hw *wiphy_to_hw(struct wiphy *wiphy);
+
/**
* SET_IEEE80211_DEV - set device for 802.11 hardware
*
@@ -1108,7 +1123,7 @@ enum ieee80211_ampdu_mlme_action {
* This callback must be implemented and atomic.
*
* @set_tim: Set TIM bit. mac80211 calls this function when a TIM bit
- * must be set or cleared for a given AID. Must be atomic.
+ * must be set or cleared for a given STA. Must be atomic.
*
* @set_key: See the section "Hardware crypto acceleration"
* This callback can sleep, and is only called between add_interface
@@ -1122,7 +1137,9 @@ enum ieee80211_ampdu_mlme_action {
* @hw_scan: Ask the hardware to service the scan request, no need to start
* the scan state machine in stack. The scan must honour the channel
* configuration done by the regulatory agent in the wiphy's registered
- * bands.
+ * bands. When the scan finishes, ieee80211_scan_completed() must be
+ * called; note that it also must be called when the scan cannot finish
+ * because the hardware is turned off! Anything else is a bug!
*
* @get_stats: return low-level statistics
*
@@ -1192,7 +1209,8 @@ struct ieee80211_ops {
unsigned int changed_flags,
unsigned int *total_flags,
int mc_count, struct dev_addr_list *mc_list);
- int (*set_tim)(struct ieee80211_hw *hw, int aid, int set);
+ int (*set_tim)(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
+ bool set);
int (*set_key)(struct ieee80211_hw *hw, enum set_key_cmd cmd,
const u8 *local_address, const u8 *address,
struct ieee80211_key_conf *key);
@@ -1209,7 +1227,7 @@ struct ieee80211_ops {
int (*set_retry_limit)(struct ieee80211_hw *hw,
u32 short_retry, u32 long_retr);
void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- enum sta_notify_cmd, const u8 *addr);
+ enum sta_notify_cmd, struct ieee80211_sta *sta);
int (*conf_tx)(struct ieee80211_hw *hw, u16 queue,
const struct ieee80211_tx_queue_params *params);
int (*get_tx_stats)(struct ieee80211_hw *hw,
@@ -1219,7 +1237,7 @@ struct ieee80211_ops {
int (*tx_last_beacon)(struct ieee80211_hw *hw);
int (*ampdu_action)(struct ieee80211_hw *hw,
enum ieee80211_ampdu_mlme_action action,
- const u8 *addr, u16 tid, u16 *ssn);
+ struct ieee80211_sta *sta, u16 tid, u16 *ssn);
};
/**
@@ -1769,4 +1787,17 @@ void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra,
*/
void ieee80211_notify_mac(struct ieee80211_hw *hw,
enum ieee80211_notification_types notif_type);
+
+/**
+ * ieee80211_find_sta - find a station
+ *
+ * @hw: pointer as obtained from ieee80211_alloc_hw()
+ * @addr: station's address
+ *
+ * This function must be called under RCU lock and the
+ * resulting pointer is only valid under RCU lock as well.
+ */
+struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_hw *hw,
+ const u8 *addr);
+
#endif /* MAC80211_H */
diff --git a/include/net/wireless.h b/include/net/wireless.h
index 1dc8ec3daa2f..e4378cc6bf8e 100644
--- a/include/net/wireless.h
+++ b/include/net/wireless.h
@@ -60,6 +60,7 @@ enum ieee80211_channel_flags {
* with cfg80211.
*
* @center_freq: center frequency in MHz
+ * @max_bandwidth: maximum allowed bandwidth for this channel, in MHz
* @hw_value: hardware-specific value for the channel
* @flags: channel flags from &enum ieee80211_channel_flags.
* @orig_flags: channel flags at registration time, used by regulatory
@@ -73,6 +74,7 @@ enum ieee80211_channel_flags {
struct ieee80211_channel {
enum ieee80211_band band;
u16 center_freq;
+ u8 max_bandwidth;
u16 hw_value;
u32 flags;
int max_antenna_gain;
@@ -178,6 +180,7 @@ struct ieee80211_supported_band {
* struct wiphy - wireless hardware description
* @idx: the wiphy index assigned to this item
* @class_dev: the class device representing /sys/class/ieee80211/
+ * @reg_notifier: the driver's regulatory notification callback
*/
struct wiphy {
/* assign these fields before you register the wiphy */
@@ -197,6 +200,9 @@ struct wiphy {
struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS];
+ /* Lets us get back the wiphy on the callback */
+ int (*reg_notifier)(struct wiphy *wiphy, enum reg_set_by setby);
+
/* fields below are read-only, assigned by cfg80211 */
/* the item in /sys/class/ieee80211/ points to this,
@@ -322,6 +328,58 @@ extern int ieee80211_frequency_to_channel(int freq);
*/
extern struct ieee80211_channel *__ieee80211_get_channel(struct wiphy *wiphy,
int freq);
+/**
+ * __regulatory_hint - hint to the wireless core a regulatory domain
+ * @wiphy: if a driver is providing the hint this is the driver's very
+ * own &struct wiphy
+ * @alpha2: the ISO/IEC 3166 alpha2 being claimed the regulatory domain
+ * should be in. If @rd is set this should be NULL
+ * @rd: a complete regulatory domain, if passed the caller need not worry
+ * about freeing it
+ *
+ * The Wireless subsystem can use this function to hint to the wireless core
+ * what it believes should be the current regulatory domain by
+ * giving it an ISO/IEC 3166 alpha2 country code it knows its regulatory
+ * domain should be in or by providing a completely build regulatory domain.
+ *
+ * Returns -EALREADY if *a regulatory domain* has already been set. Note that
+ * this could be by another driver. It is safe for drivers to continue if
+ * -EALREADY is returned, if drivers are not capable of world roaming they
+ * should not register more channels than they support. Right now we only
+ * support listening to the first driver hint. If the driver is capable
+ * of world roaming but wants to respect its own EEPROM mappings for
+ * specific regulatory domains it should register the @reg_notifier callback
+ * on the &struct wiphy. Returns 0 if the hint went through fine or through an
+ * intersection operation. Otherwise a standard error code is returned.
+ *
+ */
+extern int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
+ const char *alpha2, struct ieee80211_regdomain *rd);
+/**
+ * regulatory_hint - driver hint to the wireless core a regulatory domain
+ * @wiphy: the driver's very own &struct wiphy
+ * @alpha2: the ISO/IEC 3166 alpha2 the driver claims its regulatory domain
+ * should be in. If @rd is set this should be NULL. Note that if you
+ * set this to NULL you should still set rd->alpha2 to some accepted
+ * alpha2.
+ * @rd: a complete regulatory domain provided by the driver. If passed
+ * the driver does not need to worry about freeing it.
+ *
+ * Wireless drivers can use this function to hint to the wireless core
+ * what it believes should be the current regulatory domain by
+ * giving it an ISO/IEC 3166 alpha2 country code it knows its regulatory
+ * domain should be in or by providing a completely build regulatory domain.
+ * If the driver provides an ISO/IEC 3166 alpha2 userspace will be queried
+ * for a regulatory domain structure for the respective country. If
+ * a regulatory domain is build and passed you should set the alpha2
+ * if possible, otherwise set it to the special value of "99" which tells
+ * the wireless core it is unknown. If you pass a built regulatory domain
+ * and we return non zero you are in charge of kfree()'ing the structure.
+ *
+ * See __regulatory_hint() documentation for possible return values.
+ */
+extern int regulatory_hint(struct wiphy *wiphy,
+ const char *alpha2, struct ieee80211_regdomain *rd);
/**
* ieee80211_get_channel - get channel struct from wiphy for specified frequency
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
index 80d693392b0f..8427518e4f20 100644
--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -179,19 +179,6 @@ config MAC80211_VERBOSE_MPL_DEBUG
Do not select this option.
-config MAC80211_LOWTX_FRAME_DUMP
- bool "Debug frame dumping"
- depends on MAC80211_DEBUG_MENU
- ---help---
- Selecting this option will cause the stack to
- print a message for each frame that is handed
- to the lowlevel driver for transmission. This
- message includes all MAC addresses and the
- frame control field.
-
- If unsure, say N and insert the debugging code
- you require into the driver you are debugging.
-
config MAC80211_DEBUG_COUNTERS
bool "Extra statistics for TX/RX debugging"
depends on MAC80211_DEBUG_MENU
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 928813ce08e2..e2574885db4a 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -17,26 +17,26 @@
#include "rate.h"
#include "mesh.h"
-static enum ieee80211_if_types
-nl80211_type_to_mac80211_type(enum nl80211_iftype type)
+struct ieee80211_hw *wiphy_to_hw(struct wiphy *wiphy)
+{
+ struct ieee80211_local *local = wiphy_priv(wiphy);
+ return &local->hw;
+}
+EXPORT_SYMBOL(wiphy_to_hw);
+
+static bool nl80211_type_check(enum nl80211_iftype type)
{
switch (type) {
- case NL80211_IFTYPE_UNSPECIFIED:
- return IEEE80211_IF_TYPE_STA;
case NL80211_IFTYPE_ADHOC:
- return IEEE80211_IF_TYPE_IBSS;
case NL80211_IFTYPE_STATION:
- return IEEE80211_IF_TYPE_STA;
case NL80211_IFTYPE_MONITOR:
- return IEEE80211_IF_TYPE_MNTR;
#ifdef CONFIG_MAC80211_MESH
case NL80211_IFTYPE_MESH_POINT:
- return IEEE80211_IF_TYPE_MESH_POINT;
#endif
case NL80211_IFTYPE_WDS:
- return IEEE80211_IF_TYPE_WDS;
+ return true;
default:
- return IEEE80211_IF_TYPE_INVALID;
+ return false;
}
}
@@ -45,17 +45,15 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
struct vif_params *params)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
- enum ieee80211_if_types itype;
struct net_device *dev;
struct ieee80211_sub_if_data *sdata;
int err;
- itype = nl80211_type_to_mac80211_type(type);
- if (itype == IEEE80211_IF_TYPE_INVALID)
+ if (!nl80211_type_check(type))
return -EINVAL;
- err = ieee80211_if_add(local, name, &dev, itype, params);
- if (err || itype != IEEE80211_IF_TYPE_MNTR || !flags)
+ err = ieee80211_if_add(local, name, &dev, type, params);
+ if (err || type != NL80211_IFTYPE_MONITOR || !flags)
return err;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@@ -86,7 +84,6 @@ static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex,
{
struct ieee80211_local *local = wiphy_priv(wiphy);
struct net_device *dev;
- enum ieee80211_if_types itype;
struct ieee80211_sub_if_data *sdata;
int ret;
@@ -95,8 +92,7 @@ static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex,
if (!dev)
return -ENODEV;
- itype = nl80211_type_to_mac80211_type(type);
- if (itype == IEEE80211_IF_TYPE_INVALID)
+ if (!nl80211_type_check(type))
return -EINVAL;
if (dev == local->mdev)
@@ -104,16 +100,16 @@ static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex,
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- ret = ieee80211_if_change_type(sdata, itype);
+ ret = ieee80211_if_change_type(sdata, type);
if (ret)
return ret;
if (ieee80211_vif_is_mesh(&sdata->vif) && params->mesh_id_len)
- ieee80211_if_sta_set_mesh_id(&sdata->u.sta,
- params->mesh_id_len,
- params->mesh_id);
+ ieee80211_sdata_set_mesh_id(sdata,
+ params->mesh_id_len,
+ params->mesh_id);
- if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR || !flags)
+ if (sdata->vif.type != NL80211_IFTYPE_MONITOR || !flags)
return 0;
sdata->u.mntr_flags = *flags;
@@ -368,7 +364,7 @@ static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev,
sta = sta_info_get_by_idx(local, idx, dev);
if (sta) {
ret = 0;
- memcpy(mac, sta->addr, ETH_ALEN);
+ memcpy(mac, sta->sta.addr, ETH_ALEN);
sta_set_sinfo(sta, sinfo);
}
@@ -509,7 +505,7 @@ static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- if (sdata->vif.type != IEEE80211_IF_TYPE_AP)
+ if (sdata->vif.type != NL80211_IFTYPE_AP)
return -EINVAL;
old = sdata->u.ap.beacon;
@@ -532,7 +528,7 @@ static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- if (sdata->vif.type != IEEE80211_IF_TYPE_AP)
+ if (sdata->vif.type != NL80211_IFTYPE_AP)
return -EINVAL;
old = sdata->u.ap.beacon;
@@ -554,7 +550,7 @@ static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- if (sdata->vif.type != IEEE80211_IF_TYPE_AP)
+ if (sdata->vif.type != NL80211_IFTYPE_AP)
return -EINVAL;
old = sdata->u.ap.beacon;
@@ -597,7 +593,7 @@ static void ieee80211_send_layer2_update(struct sta_info *sta)
* Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */
memset(msg->da, 0xff, ETH_ALEN);
- memcpy(msg->sa, sta->addr, ETH_ALEN);
+ memcpy(msg->sa, sta->sta.addr, ETH_ALEN);
msg->len = htons(6);
msg->dsap = 0;
msg->ssap = 0x01; /* NULL LSAP, CR Bit: Response */
@@ -652,9 +648,9 @@ static void sta_apply_parameters(struct ieee80211_local *local,
*/
if (params->aid) {
- sta->aid = params->aid;
- if (sta->aid > IEEE80211_MAX_AID)
- sta->aid = 0; /* XXX: should this be an error? */
+ sta->sta.aid = params->aid;
+ if (sta->sta.aid > IEEE80211_MAX_AID)
+ sta->sta.aid = 0; /* XXX: should this be an error? */
}
if (params->listen_interval >= 0)
@@ -671,12 +667,12 @@ static void sta_apply_parameters(struct ieee80211_local *local,
rates |= BIT(j);
}
}
- sta->supp_rates[local->oper_channel->band] = rates;
+ sta->sta.supp_rates[local->oper_channel->band] = rates;
}
if (params->ht_capa) {
ieee80211_ht_cap_ie_to_ht_info(params->ht_capa,
- &sta->ht_info);
+ &sta->sta.ht_info);
}
if (ieee80211_vif_is_mesh(&sdata->vif) && params->plink_action) {
@@ -709,8 +705,8 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
if (params->vlan) {
sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
- if (sdata->vif.type != IEEE80211_IF_TYPE_VLAN &&
- sdata->vif.type != IEEE80211_IF_TYPE_AP)
+ if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
+ sdata->vif.type != NL80211_IFTYPE_AP)
return -EINVAL;
} else
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@@ -740,8 +736,8 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
return err;
}
- if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN ||
- sdata->vif.type == IEEE80211_IF_TYPE_AP)
+ if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
+ sdata->vif.type == NL80211_IFTYPE_AP)
ieee80211_send_layer2_update(sta);
rcu_read_unlock();
@@ -805,8 +801,8 @@ static int ieee80211_change_station(struct wiphy *wiphy,
if (params->vlan && params->vlan != sta->sdata->dev) {
vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
- if (vlansdata->vif.type != IEEE80211_IF_TYPE_VLAN &&
- vlansdata->vif.type != IEEE80211_IF_TYPE_AP) {
+ if (vlansdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
+ vlansdata->vif.type != NL80211_IFTYPE_AP) {
rcu_read_unlock();
return -EINVAL;
}
@@ -840,7 +836,7 @@ static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev,
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)
+ if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
return -ENOTSUPP;
rcu_read_lock();
@@ -896,7 +892,7 @@ static int ieee80211_change_mpath(struct wiphy *wiphy,
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)
+ if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
return -ENOTSUPP;
rcu_read_lock();
@@ -923,7 +919,7 @@ static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop,
struct mpath_info *pinfo)
{
if (mpath->next_hop)
- memcpy(next_hop, mpath->next_hop->addr, ETH_ALEN);
+ memcpy(next_hop, mpath->next_hop->sta.addr, ETH_ALEN);
else
memset(next_hop, 0, ETH_ALEN);
@@ -971,7 +967,7 @@ static int ieee80211_get_mpath(struct wiphy *wiphy, struct net_device *dev,
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)
+ if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
return -ENOTSUPP;
rcu_read_lock();
@@ -999,7 +995,7 @@ static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev,
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)
+ if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
return -ENOTSUPP;
rcu_read_lock();
@@ -1028,7 +1024,7 @@ static int ieee80211_change_bss(struct wiphy *wiphy,
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- if (sdata->vif.type != IEEE80211_IF_TYPE_AP)
+ if (sdata->vif.type != NL80211_IFTYPE_AP)
return -EINVAL;
if (params->use_cts_prot >= 0) {
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index ee509f1109e2..24ce54463310 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -51,8 +51,6 @@ DEBUGFS_READONLY_FILE(antenna_sel_tx, 20, "%d",
local->hw.conf.antenna_sel_tx);
DEBUGFS_READONLY_FILE(antenna_sel_rx, 20, "%d",
local->hw.conf.antenna_sel_rx);
-DEBUGFS_READONLY_FILE(bridge_packets, 20, "%d",
- local->bridge_packets);
DEBUGFS_READONLY_FILE(rts_threshold, 20, "%d",
local->rts_threshold);
DEBUGFS_READONLY_FILE(fragmentation_threshold, 20, "%d",
@@ -206,7 +204,6 @@ void debugfs_hw_add(struct ieee80211_local *local)
DEBUGFS_ADD(frequency);
DEBUGFS_ADD(antenna_sel_tx);
DEBUGFS_ADD(antenna_sel_rx);
- DEBUGFS_ADD(bridge_packets);
DEBUGFS_ADD(rts_threshold);
DEBUGFS_ADD(fragmentation_threshold);
DEBUGFS_ADD(short_retry_limit);
@@ -263,7 +260,6 @@ void debugfs_hw_del(struct ieee80211_local *local)
DEBUGFS_DEL(frequency);
DEBUGFS_DEL(antenna_sel_tx);
DEBUGFS_DEL(antenna_sel_rx);
- DEBUGFS_DEL(bridge_packets);
DEBUGFS_DEL(rts_threshold);
DEBUGFS_DEL(fragmentation_threshold);
DEBUGFS_DEL(short_retry_limit);
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c
index cf82acec913a..a3294d109322 100644
--- a/net/mac80211/debugfs_key.c
+++ b/net/mac80211/debugfs_key.c
@@ -206,7 +206,8 @@ void ieee80211_debugfs_key_add(struct ieee80211_key *key)
rcu_read_lock();
sta = rcu_dereference(key->sta);
if (sta)
- sprintf(buf, "../../stations/%s", print_mac(mac, sta->addr));
+ sprintf(buf, "../../stations/%s",
+ print_mac(mac, sta->sta.addr));
rcu_read_unlock();
/* using sta as a boolean is fine outside RCU lock */
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index 8165df578c92..2a4515623776 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -173,7 +173,6 @@ IEEE80211_IF_FILE(assoc_tries, u.sta.assoc_tries, DEC);
IEEE80211_IF_FILE(auth_algs, u.sta.auth_algs, HEX);
IEEE80211_IF_FILE(auth_alg, u.sta.auth_alg, DEC);
IEEE80211_IF_FILE(auth_transaction, u.sta.auth_transaction, DEC);
-IEEE80211_IF_FILE(num_beacons_sta, u.sta.num_beacons, DEC);
static ssize_t ieee80211_if_fmt_flags(
const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
@@ -192,7 +191,6 @@ __IEEE80211_IF_FILE(flags);
/* AP attributes */
IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC);
IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC);
-IEEE80211_IF_FILE(num_beacons, u.ap.num_beacons, DEC);
static ssize_t ieee80211_if_fmt_num_buffered_multicast(
const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
@@ -207,37 +205,37 @@ IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC);
#ifdef CONFIG_MAC80211_MESH
/* Mesh stats attributes */
-IEEE80211_IF_FILE(fwded_frames, u.sta.mshstats.fwded_frames, DEC);
-IEEE80211_IF_FILE(dropped_frames_ttl, u.sta.mshstats.dropped_frames_ttl, DEC);
+IEEE80211_IF_FILE(fwded_frames, u.mesh.mshstats.fwded_frames, DEC);
+IEEE80211_IF_FILE(dropped_frames_ttl, u.mesh.mshstats.dropped_frames_ttl, DEC);
IEEE80211_IF_FILE(dropped_frames_no_route,
- u.sta.mshstats.dropped_frames_no_route, DEC);
-IEEE80211_IF_FILE(estab_plinks, u.sta.mshstats.estab_plinks, ATOMIC);
+ u.mesh.mshstats.dropped_frames_no_route, DEC);
+IEEE80211_IF_FILE(estab_plinks, u.mesh.mshstats.estab_plinks, ATOMIC);
/* Mesh parameters */
IEEE80211_IF_WFILE(dot11MeshMaxRetries,
- u.sta.mshcfg.dot11MeshMaxRetries, DEC, u8);
+ u.mesh.mshcfg.dot11MeshMaxRetries, DEC, u8);
IEEE80211_IF_WFILE(dot11MeshRetryTimeout,
- u.sta.mshcfg.dot11MeshRetryTimeout, DEC, u16);
+ u.mesh.mshcfg.dot11MeshRetryTimeout, DEC, u16);
IEEE80211_IF_WFILE(dot11MeshConfirmTimeout,
- u.sta.mshcfg.dot11MeshConfirmTimeout, DEC, u16);
+ u.mesh.mshcfg.dot11MeshConfirmTimeout, DEC, u16);
IEEE80211_IF_WFILE(dot11MeshHoldingTimeout,
- u.sta.mshcfg.dot11MeshHoldingTimeout, DEC, u16);
-IEEE80211_IF_WFILE(dot11MeshTTL, u.sta.mshcfg.dot11MeshTTL, DEC, u8);
-IEEE80211_IF_WFILE(auto_open_plinks, u.sta.mshcfg.auto_open_plinks, DEC, u8);
+ u.mesh.mshcfg.dot11MeshHoldingTimeout, DEC, u16);
+IEEE80211_IF_WFILE(dot11MeshTTL, u.mesh.mshcfg.dot11MeshTTL, DEC, u8);
+IEEE80211_IF_WFILE(auto_open_plinks, u.mesh.mshcfg.auto_open_plinks, DEC, u8);
IEEE80211_IF_WFILE(dot11MeshMaxPeerLinks,
- u.sta.mshcfg.dot11MeshMaxPeerLinks, DEC, u16);
+ u.mesh.mshcfg.dot11MeshMaxPeerLinks, DEC, u16);
IEEE80211_IF_WFILE(dot11MeshHWMPactivePathTimeout,
- u.sta.mshcfg.dot11MeshHWMPactivePathTimeout, DEC, u32);
+ u.mesh.mshcfg.dot11MeshHWMPactivePathTimeout, DEC, u32);
IEEE80211_IF_WFILE(dot11MeshHWMPpreqMinInterval,
- u.sta.mshcfg.dot11MeshHWMPpreqMinInterval, DEC, u16);
+ u.mesh.mshcfg.dot11MeshHWMPpreqMinInterval, DEC, u16);
IEEE80211_IF_WFILE(dot11MeshHWMPnetDiameterTraversalTime,
- u.sta.mshcfg.dot11MeshHWMPnetDiameterTraversalTime, DEC, u16);
+ u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime, DEC, u16);
IEEE80211_IF_WFILE(dot11MeshHWMPmaxPREQretries,
- u.sta.mshcfg.dot11MeshHWMPmaxPREQretries, DEC, u8);
+ u.mesh.mshcfg.dot11MeshHWMPmaxPREQretries, DEC, u8);
IEEE80211_IF_WFILE(path_refresh_time,
- u.sta.mshcfg.path_refresh_time, DEC, u32);
+ u.mesh.mshcfg.path_refresh_time, DEC, u32);
IEEE80211_IF_WFILE(min_discovery_timeout,
- u.sta.mshcfg.min_discovery_timeout, DEC, u16);
+ u.mesh.mshcfg.min_discovery_timeout, DEC, u16);
#endif
@@ -265,7 +263,6 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
DEBUGFS_ADD(auth_alg, sta);
DEBUGFS_ADD(auth_transaction, sta);
DEBUGFS_ADD(flags, sta);
- DEBUGFS_ADD(num_beacons_sta, sta);
}
static void add_ap_files(struct ieee80211_sub_if_data *sdata)
@@ -276,7 +273,6 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata)
DEBUGFS_ADD(num_sta_ps, ap);
DEBUGFS_ADD(dtim_count, ap);
- DEBUGFS_ADD(num_beacons, ap);
DEBUGFS_ADD(num_buffered_multicast, ap);
}
@@ -345,26 +341,26 @@ static void add_files(struct ieee80211_sub_if_data *sdata)
return;
switch (sdata->vif.type) {
- case IEEE80211_IF_TYPE_MESH_POINT:
+ case NL80211_IFTYPE_MESH_POINT:
#ifdef CONFIG_MAC80211_MESH
add_mesh_stats(sdata);
add_mesh_config(sdata);
#endif
- /* fall through */
- case IEEE80211_IF_TYPE_STA:
- case IEEE80211_IF_TYPE_IBSS:
+ break;
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_ADHOC:
add_sta_files(sdata);
break;
- case IEEE80211_IF_TYPE_AP:
+ case NL80211_IFTYPE_AP:
add_ap_files(sdata);
break;
- case IEEE80211_IF_TYPE_WDS:
+ case NL80211_IFTYPE_WDS:
add_wds_files(sdata);
break;
- case IEEE80211_IF_TYPE_MNTR:
+ case NL80211_IFTYPE_MONITOR:
add_monitor_files(sdata);
break;
- case IEEE80211_IF_TYPE_VLAN:
+ case NL80211_IFTYPE_AP_VLAN:
add_vlan_files(sdata);
break;
default:
@@ -398,7 +394,6 @@ static void del_sta_files(struct ieee80211_sub_if_data *sdata)
DEBUGFS_DEL(auth_alg, sta);
DEBUGFS_DEL(auth_transaction, sta);
DEBUGFS_DEL(flags, sta);
- DEBUGFS_DEL(num_beacons_sta, sta);
}
static void del_ap_files(struct ieee80211_sub_if_data *sdata)
@@ -409,7 +404,6 @@ static void del_ap_files(struct ieee80211_sub_if_data *sdata)
DEBUGFS_DEL(num_sta_ps, ap);
DEBUGFS_DEL(dtim_count, ap);
- DEBUGFS_DEL(num_beacons, ap);
DEBUGFS_DEL(num_buffered_multicast, ap);
}
@@ -482,26 +476,26 @@ static void del_files(struct ieee80211_sub_if_data *sdata)
return;
switch (sdata->vif.type) {
- case IEEE80211_IF_TYPE_MESH_POINT:
+ case NL80211_IFTYPE_MESH_POINT:
#ifdef CONFIG_MAC80211_MESH
del_mesh_stats(sdata);
del_mesh_config(sdata);
#endif
- /* fall through */
- case IEEE80211_IF_TYPE_STA:
- case IEEE80211_IF_TYPE_IBSS:
+ break;
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_ADHOC:
del_sta_files(sdata);
break;
- case IEEE80211_IF_TYPE_AP:
+ case NL80211_IFTYPE_AP:
del_ap_files(sdata);
break;
- case IEEE80211_IF_TYPE_WDS:
+ case NL80211_IFTYPE_WDS:
del_wds_files(sdata);
break;
- case IEEE80211_IF_TYPE_MNTR:
+ case NL80211_IFTYPE_MONITOR:
del_monitor_files(sdata);
break;
- case IEEE80211_IF_TYPE_VLAN:
+ case NL80211_IFTYPE_AP_VLAN:
del_vlan_files(sdata);
break;
default:
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index 6abe5427752b..81f350eaf8a3 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -50,7 +50,7 @@ static const struct file_operations sta_ ##name## _ops = { \
STA_READ_##format(name, field) \
STA_OPS(name)
-STA_FILE(aid, aid, D);
+STA_FILE(aid, sta.aid, D);
STA_FILE(dev, sdata->dev->name, S);
STA_FILE(rx_packets, rx_packets, LU);
STA_FILE(tx_packets, tx_packets, LU);
@@ -176,7 +176,7 @@ static ssize_t sta_agg_status_write(struct file *file,
struct net_device *dev = sta->sdata->dev;
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_hw *hw = &local->hw;
- u8 *da = sta->addr;
+ u8 *da = sta->sta.addr;
static int tid_static_tx[16] = {0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0};
static int tid_static_rx[16] = {1, 1, 1, 1, 1, 1, 1, 1,
@@ -253,7 +253,7 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
if (!stations_dir)
return;
- mac = print_mac(mbuf, sta->addr);
+ mac = print_mac(mbuf, sta->sta.addr);
sta->debugfs.dir = debugfs_create_dir(mac, stations_dir);
if (!sta->debugfs.dir)
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
index 4dc35c9dabc7..dc7d9a3d70d5 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -89,7 +89,7 @@ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
memset(mgmt, 0, 24);
memcpy(mgmt->da, da, ETH_ALEN);
memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
- if (sdata->vif.type == IEEE80211_IF_TYPE_AP)
+ if (sdata->vif.type == NL80211_IFTYPE_AP)
memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
else
memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
@@ -139,7 +139,7 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d
memset(mgmt, 0, 24);
memcpy(mgmt->da, da, ETH_ALEN);
memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
- if (sdata->vif.type == IEEE80211_IF_TYPE_AP)
+ if (sdata->vif.type == NL80211_IFTYPE_AP)
memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
else
memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
@@ -185,7 +185,7 @@ static void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
memset(mgmt, 0, 24);
memcpy(mgmt->da, da, ETH_ALEN);
memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
- if (sdata->vif.type == IEEE80211_IF_TYPE_AP)
+ if (sdata->vif.type == NL80211_IFTYPE_AP)
memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
else
memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
@@ -274,7 +274,7 @@ void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *r
#endif /* CONFIG_MAC80211_HT_DEBUG */
ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_STOP,
- ra, tid, NULL);
+ &sta->sta, tid, NULL);
if (ret)
printk(KERN_DEBUG "HW problem - can not stop rx "
"aggregation for tid %d\n", tid);
@@ -328,7 +328,7 @@ static void sta_addba_resp_timer_expired(unsigned long data)
rcu_read_lock();
- sta = sta_info_get(local, temp_sta->addr);
+ sta = sta_info_get(local, temp_sta->sta.addr);
if (!sta) {
rcu_read_unlock();
return;
@@ -354,7 +354,7 @@ static void sta_addba_resp_timer_expired(unsigned long data)
/* go through the state check in stop_BA_session */
*state = HT_AGG_STATE_OPERATIONAL;
spin_unlock_bh(&sta->lock);
- ieee80211_stop_tx_ba_session(hw, temp_sta->addr, tid,
+ ieee80211_stop_tx_ba_session(hw, temp_sta->sta.addr, tid,
WLAN_BACK_INITIATOR);
timer_expired_exit:
@@ -465,7 +465,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
if (local->ops->ampdu_action)
ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_START,
- ra, tid, &start_seq_num);
+ &sta->sta, tid, &start_seq_num);
if (ret) {
/* No need to requeue the packets in the agg queue, since we
@@ -557,7 +557,7 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
if (local->ops->ampdu_action)
ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_STOP,
- ra, tid, NULL);
+ &sta->sta, tid, NULL);
/* case HW denied going back to legacy */
if (ret) {
@@ -767,7 +767,7 @@ static void sta_rx_agg_session_timer_expired(unsigned long data)
#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid);
#endif
- ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->addr,
+ ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->sta.addr,
(u16)*ptid, WLAN_BACK_TIMER,
WLAN_REASON_QSTA_TIMEOUT);
}
@@ -874,7 +874,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
if (local->ops->ampdu_action)
ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_START,
- sta->addr, tid, &start_seq_num);
+ &sta->sta, tid, &start_seq_num);
#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret);
#endif /* CONFIG_MAC80211_HT_DEBUG */
@@ -899,7 +899,7 @@ end:
spin_unlock_bh(&sta->lock);
end_no_lock:
- ieee80211_send_addba_resp(sta->sdata, sta->addr, tid,
+ ieee80211_send_addba_resp(sta->sdata, sta->sta.addr, tid,
dialog_token, status, 1, buf_size, timeout);
}
@@ -952,7 +952,7 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
/* this will allow the state check in stop_BA_session */
*state = HT_AGG_STATE_OPERATIONAL;
spin_unlock_bh(&sta->lock);
- ieee80211_stop_tx_ba_session(hw, sta->addr, tid,
+ ieee80211_stop_tx_ba_session(hw, sta->sta.addr, tid,
WLAN_BACK_INITIATOR);
}
}
@@ -979,14 +979,14 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
#endif /* CONFIG_MAC80211_HT_DEBUG */
if (initiator == WLAN_BACK_INITIATOR)
- ieee80211_sta_stop_rx_ba_session(sdata, sta->addr, tid,
+ ieee80211_sta_stop_rx_ba_session(sdata, sta->sta.addr, tid,
WLAN_BACK_INITIATOR, 0);
else { /* WLAN_BACK_RECIPIENT */
spin_lock_bh(&sta->lock);
sta->ampdu_mlme.tid_state_tx[tid] =
HT_AGG_STATE_OPERATIONAL;
spin_unlock_bh(&sta->lock);
- ieee80211_stop_tx_ba_session(&local->hw, sta->addr, tid,
+ ieee80211_stop_tx_ba_session(&local->hw, sta->sta.addr, tid,
WLAN_BACK_RECIPIENT);
}
}
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 6f334e4c3d66..3912fba6d3d0 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -29,9 +29,6 @@
#include "key.h"
#include "sta_info.h"
-/* ieee80211.o internal definitions, etc. These are not included into
- * low-level drivers. */
-
struct ieee80211_local;
/* Maximum number of broadcast/multicast frames to buffer when some of the
@@ -71,9 +68,9 @@ struct ieee80211_fragment_entry {
};
-struct ieee80211_sta_bss {
+struct ieee80211_bss {
struct list_head list;
- struct ieee80211_sta_bss *hnext;
+ struct ieee80211_bss *hnext;
size_t ssid_len;
atomic_t users;
@@ -112,7 +109,7 @@ struct ieee80211_sta_bss {
u8 erp_value;
};
-static inline u8 *bss_mesh_cfg(struct ieee80211_sta_bss *bss)
+static inline u8 *bss_mesh_cfg(struct ieee80211_bss *bss)
{
#ifdef CONFIG_MAC80211_MESH
return bss->mesh_cfg;
@@ -120,7 +117,7 @@ static inline u8 *bss_mesh_cfg(struct ieee80211_sta_bss *bss)
return NULL;
}
-static inline u8 *bss_mesh_id(struct ieee80211_sta_bss *bss)
+static inline u8 *bss_mesh_id(struct ieee80211_bss *bss)
{
#ifdef CONFIG_MAC80211_MESH
return bss->mesh_id;
@@ -128,7 +125,7 @@ static inline u8 *bss_mesh_id(struct ieee80211_sta_bss *bss)
return NULL;
}
-static inline u8 bss_mesh_id_len(struct ieee80211_sta_bss *bss)
+static inline u8 bss_mesh_id_len(struct ieee80211_bss *bss)
{
#ifdef CONFIG_MAC80211_MESH
return bss->mesh_id_len;
@@ -232,7 +229,6 @@ struct ieee80211_if_ap {
struct sk_buff_head ps_bc_buf;
atomic_t num_sta_ps; /* number of stations in PS mode */
int dtim_count;
- int num_beacons; /* number of TXed beacon frames for this BSS */
};
struct ieee80211_if_wds {
@@ -293,13 +289,13 @@ struct mesh_config {
#define IEEE80211_STA_AUTO_BSSID_SEL BIT(11)
#define IEEE80211_STA_AUTO_CHANNEL_SEL BIT(12)
#define IEEE80211_STA_PRIVACY_INVOKED BIT(13)
-/* flags for MLME request*/
+/* flags for MLME request */
#define IEEE80211_STA_REQ_SCAN 0
#define IEEE80211_STA_REQ_DIRECT_PROBE 1
#define IEEE80211_STA_REQ_AUTH 2
#define IEEE80211_STA_REQ_RUN 3
-/* flags used for setting mlme state */
+/* STA/IBSS MLME states */
enum ieee80211_sta_mlme_state {
IEEE80211_STA_MLME_DISABLED,
IEEE80211_STA_MLME_DIRECT_PROBE,
@@ -308,7 +304,6 @@ enum ieee80211_sta_mlme_state {
IEEE80211_STA_MLME_ASSOCIATED,
IEEE80211_STA_MLME_IBSS_SEARCH,
IEEE80211_STA_MLME_IBSS_JOINED,
- IEEE80211_STA_MLME_MESH_UP
};
/* bitfield of allowed auth algs */
@@ -325,34 +320,6 @@ struct ieee80211_if_sta {
size_t ssid_len;
u8 scan_ssid[IEEE80211_MAX_SSID_LEN];
size_t scan_ssid_len;
-#ifdef CONFIG_MAC80211_MESH
- struct timer_list mesh_path_timer;
- u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN];
- size_t mesh_id_len;
- /* Active Path Selection Protocol Identifier */
- u8 mesh_pp_id[4];
- /* Active Path Selection Metric Identifier */
- u8 mesh_pm_id[4];
- /* Congestion Control Mode Identifier */
- u8 mesh_cc_id[4];
- /* Local mesh Destination Sequence Number */
- u32 dsn;
- /* Last used PREQ ID */
- u32 preq_id;
- atomic_t mpaths;
- /* Timestamp of last DSN update */
- unsigned long last_dsn_update;
- /* Timestamp of last DSN sent */
- unsigned long last_preq;
- struct mesh_rmc *rmc;
- spinlock_t mesh_preq_queue_lock;
- struct mesh_preq_queue preq_queue;
- int preq_queue_len;
- struct mesh_stats mshstats;
- struct mesh_config mshcfg;
- u32 mesh_seqnum;
- bool accepting_plinks;
-#endif
u16 aid;
u16 ap_capab, capab;
u8 *extra_ie; /* to be added to the end of AssocReq */
@@ -384,31 +351,70 @@ struct ieee80211_if_sta {
u32 supp_rates_bits[IEEE80211_NUM_BANDS];
int wmm_last_param_set;
- int num_beacons; /* number of TXed beacon frames by this STA */
};
-static inline void ieee80211_if_sta_set_mesh_id(struct ieee80211_if_sta *ifsta,
- u8 mesh_id_len, u8 *mesh_id)
-{
-#ifdef CONFIG_MAC80211_MESH
- ifsta->mesh_id_len = mesh_id_len;
- memcpy(ifsta->mesh_id, mesh_id, mesh_id_len);
-#endif
-}
+struct ieee80211_if_mesh {
+ struct work_struct work;
+ struct timer_list housekeeping_timer;
+ struct timer_list mesh_path_timer;
+ struct sk_buff_head skb_queue;
+
+ bool housekeeping;
+
+ u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN];
+ size_t mesh_id_len;
+ /* Active Path Selection Protocol Identifier */
+ u8 mesh_pp_id[4];
+ /* Active Path Selection Metric Identifier */
+ u8 mesh_pm_id[4];
+ /* Congestion Control Mode Identifier */
+ u8 mesh_cc_id[4];
+ /* Local mesh Destination Sequence Number */
+ u32 dsn;
+ /* Last used PREQ ID */
+ u32 preq_id;
+ atomic_t mpaths;
+ /* Timestamp of last DSN update */
+ unsigned long last_dsn_update;
+ /* Timestamp of last DSN sent */
+ unsigned long last_preq;
+ struct mesh_rmc *rmc;
+ spinlock_t mesh_preq_queue_lock;
+ struct mesh_preq_queue preq_queue;
+ int preq_queue_len;
+ struct mesh_stats mshstats;
+ struct mesh_config mshcfg;
+ u32 mesh_seqnum;
+ bool accepting_plinks;
+};
#ifdef CONFIG_MAC80211_MESH
-#define IEEE80211_IFSTA_MESH_CTR_INC(sta, name) \
- do { (sta)->mshstats.name++; } while (0)
+#define IEEE80211_IFSTA_MESH_CTR_INC(msh, name) \
+ do { (msh)->mshstats.name++; } while (0)
#else
-#define IEEE80211_IFSTA_MESH_CTR_INC(sta, name) \
+#define IEEE80211_IFSTA_MESH_CTR_INC(msh, name) \
do { } while (0)
#endif
-/* flags used in struct ieee80211_sub_if_data.flags */
-#define IEEE80211_SDATA_ALLMULTI BIT(0)
-#define IEEE80211_SDATA_PROMISC BIT(1)
-#define IEEE80211_SDATA_USERSPACE_MLME BIT(2)
-#define IEEE80211_SDATA_OPERATING_GMODE BIT(3)
+/**
+ * enum ieee80211_sub_if_data_flags - virtual interface flags
+ *
+ * @IEEE80211_SDATA_ALLMULTI: interface wants all multicast packets
+ * @IEEE80211_SDATA_PROMISC: interface is promisc
+ * @IEEE80211_SDATA_USERSPACE_MLME: userspace MLME is active
+ * @IEEE80211_SDATA_OPERATING_GMODE: operating in G-only mode
+ * @IEEE80211_SDATA_DONT_BRIDGE_PACKETS: bridge packets between
+ * associated stations and deliver multicast frames both
+ * back to wireless media and to the local net stack.
+ */
+enum ieee80211_sub_if_data_flags {
+ IEEE80211_SDATA_ALLMULTI = BIT(0),
+ IEEE80211_SDATA_PROMISC = BIT(1),
+ IEEE80211_SDATA_USERSPACE_MLME = BIT(2),
+ IEEE80211_SDATA_OPERATING_GMODE = BIT(3),
+ IEEE80211_SDATA_DONT_BRIDGE_PACKETS = BIT(4),
+};
+
struct ieee80211_sub_if_data {
struct list_head list;
@@ -424,11 +430,6 @@ struct ieee80211_sub_if_data {
int drop_unencrypted;
- /*
- * basic rates of this AP or the AP we're associated to
- */
- u64 basic_rates;
-
/* Fragment table for host-based reassembly */
struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX];
unsigned int fragment_next;
@@ -455,6 +456,9 @@ struct ieee80211_sub_if_data {
struct ieee80211_if_wds wds;
struct ieee80211_if_vlan vlan;
struct ieee80211_if_sta sta;
+#ifdef CONFIG_MAC80211_MESH
+ struct ieee80211_if_mesh mesh;
+#endif
u32 mntr_flags;
} u;
@@ -477,7 +481,6 @@ struct ieee80211_sub_if_data {
struct dentry *auth_alg;
struct dentry *auth_transaction;
struct dentry *flags;
- struct dentry *num_beacons_sta;
struct dentry *force_unicast_rateidx;
struct dentry *max_ratectrl_rateidx;
} sta;
@@ -485,7 +488,6 @@ struct ieee80211_sub_if_data {
struct dentry *drop_unencrypted;
struct dentry *num_sta_ps;
struct dentry *dtim_count;
- struct dentry *num_beacons;
struct dentry *force_unicast_rateidx;
struct dentry *max_ratectrl_rateidx;
struct dentry *num_buffered_multicast;
@@ -548,6 +550,19 @@ struct ieee80211_sub_if_data *vif_to_sdata(struct ieee80211_vif *p)
return container_of(p, struct ieee80211_sub_if_data, vif);
}
+static inline void
+ieee80211_sdata_set_mesh_id(struct ieee80211_sub_if_data *sdata,
+ u8 mesh_id_len, u8 *mesh_id)
+{
+#ifdef CONFIG_MAC80211_MESH
+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+ ifmsh->mesh_id_len = mesh_id_len;
+ memcpy(ifmsh->mesh_id, mesh_id, mesh_id_len);
+#else
+ WARN_ON(1);
+#endif
+}
+
enum {
IEEE80211_RX_MSG = 1,
IEEE80211_TX_STATUS_MSG = 2,
@@ -621,10 +636,6 @@ struct ieee80211_local {
struct crypto_blkcipher *wep_rx_tfm;
u32 wep_iv;
- int bridge_packets; /* bridge packets between associated stations and
- * deliver multicast frames both back to wireless
- * media and to the local net stack */
-
struct list_head interfaces;
/*
@@ -634,8 +645,8 @@ struct ieee80211_local {
spinlock_t key_lock;
- bool sta_sw_scanning;
- bool sta_hw_scanning;
+ /* Scanning and BSS list */
+ bool sw_scanning, hw_scanning;
int scan_channel_idx;
enum ieee80211_band scan_band;
@@ -646,9 +657,9 @@ struct ieee80211_local {
struct ieee80211_channel *oper_channel, *scan_channel;
u8 scan_ssid[IEEE80211_MAX_SSID_LEN];
size_t scan_ssid_len;
- struct list_head sta_bss_list;
- struct ieee80211_sta_bss *sta_bss_hash[STA_HASH_SIZE];
- spinlock_t sta_bss_lock;
+ struct list_head bss_list;
+ struct ieee80211_bss *bss_hash[STA_HASH_SIZE];
+ spinlock_t bss_lock;
/* SNMP counters */
/* dot11CountersTable */
@@ -712,7 +723,6 @@ struct ieee80211_local {
struct dentry *frequency;
struct dentry *antenna_sel_tx;
struct dentry *antenna_sel_rx;
- struct dentry *bridge_packets;
struct dentry *rts_threshold;
struct dentry *fragmentation_threshold;
struct dentry *short_retry_limit;
@@ -868,87 +878,81 @@ static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr)
}
-/* ieee80211.c */
int ieee80211_hw_config(struct ieee80211_local *local);
int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed);
void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx);
u32 ieee80211_handle_ht(struct ieee80211_local *local, int enable_ht,
struct ieee80211_ht_info *req_ht_cap,
struct ieee80211_ht_bss_info *req_bss_cap);
+void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
+ u32 changed);
+void ieee80211_configure_filter(struct ieee80211_local *local);
-/* ieee80211_ioctl.c */
+/* wireless extensions */
extern const struct iw_handler_def ieee80211_iw_handler_def;
-int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freq);
-/* ieee80211_sta.c */
-void ieee80211_sta_timer(unsigned long data);
-void ieee80211_sta_work(struct work_struct *work);
-void ieee80211_sta_scan_work(struct work_struct *work);
+/* STA/IBSS code */
+void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata);
+void ieee80211_scan_work(struct work_struct *work);
void ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
struct ieee80211_rx_status *rx_status);
int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len);
int ieee80211_sta_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len);
int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid);
-int ieee80211_sta_req_scan(struct ieee80211_sub_if_data *sdata, u8 *ssid, size_t ssid_len);
void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_sta *ifsta);
-int ieee80211_sta_scan_results(struct ieee80211_local *local,
- struct iw_request_info *info,
- char *buf, size_t len);
-ieee80211_rx_result ieee80211_sta_rx_scan(
- struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
- struct ieee80211_rx_status *rx_status);
-void ieee80211_rx_bss_list_init(struct ieee80211_local *local);
-void ieee80211_rx_bss_list_deinit(struct ieee80211_local *local);
-int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, char *ie, size_t len);
struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb, u8 *bssid,
u8 *addr, u64 supp_rates);
int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason);
int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason);
-void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
- u32 changed);
u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata);
u64 ieee80211_sta_get_rates(struct ieee80211_local *local,
struct ieee802_11_elems *elems,
enum ieee80211_band band);
void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
u8 *ssid, size_t ssid_len);
-void ieee802_11_parse_elems(u8 *start, size_t len,
- struct ieee802_11_elems *elems);
+
+/* scan/BSS handling */
+int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
+ u8 *ssid, size_t ssid_len);
+int ieee80211_scan_results(struct ieee80211_local *local,
+ struct iw_request_info *info,
+ char *buf, size_t len);
+ieee80211_rx_result
+ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata,
+ struct sk_buff *skb,
+ struct ieee80211_rx_status *rx_status);
+void ieee80211_rx_bss_list_init(struct ieee80211_local *local);
+void ieee80211_rx_bss_list_deinit(struct ieee80211_local *local);
+int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata,
+ char *ie, size_t len);
+
void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local);
-int ieee80211_sta_start_scan(struct ieee80211_sub_if_data *scan_sdata,
- u8 *ssid, size_t ssid_len);
-struct ieee80211_sta_bss *
+int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata,
+ u8 *ssid, size_t ssid_len);
+struct ieee80211_bss *
ieee80211_bss_info_update(struct ieee80211_local *local,
struct ieee80211_rx_status *rx_status,
struct ieee80211_mgmt *mgmt,
size_t len,
struct ieee802_11_elems *elems,
int freq, bool beacon);
-struct ieee80211_sta_bss *
+struct ieee80211_bss *
ieee80211_rx_bss_add(struct ieee80211_local *local, u8 *bssid, int freq,
u8 *ssid, u8 ssid_len);
-struct ieee80211_sta_bss *
+struct ieee80211_bss *
ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq,
u8 *ssid, u8 ssid_len);
void ieee80211_rx_bss_put(struct ieee80211_local *local,
- struct ieee80211_sta_bss *bss);
-
-#ifdef CONFIG_MAC80211_MESH
-void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata);
-#else
-static inline void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
-{}
-#endif
+ struct ieee80211_bss *bss);
/* interface handling */
-void ieee80211_if_setup(struct net_device *dev);
int ieee80211_if_add(struct ieee80211_local *local, const char *name,
- struct net_device **new_dev, enum ieee80211_if_types type,
+ struct net_device **new_dev, enum nl80211_iftype type,
struct vif_params *params);
int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
- enum ieee80211_if_types type);
+ enum nl80211_iftype type);
void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata);
void ieee80211_remove_interfaces(struct ieee80211_local *local);
@@ -992,7 +996,7 @@ extern void *mac80211_wiphy_privid; /* for wiphy privid */
extern const unsigned char rfc1042_header[6];
extern const unsigned char bridge_tunnel_header[6];
u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
- enum ieee80211_if_types type);
+ enum nl80211_iftype type);
int ieee80211_frame_duration(struct ieee80211_local *local, size_t len,
int rate, int erp, int short_preamble);
void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int keyidx,
@@ -1000,6 +1004,11 @@ void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int ke
void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata);
void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
int encrypt);
+void ieee802_11_parse_elems(u8 *start, size_t len,
+ struct ieee802_11_elems *elems);
+int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freq);
+u64 ieee80211_mandatory_rates(struct ieee80211_local *local,
+ enum ieee80211_band band);
#ifdef CONFIG_MAC80211_NOINLINE
#define debug_noinline noinline
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 672cec60a2fb..a72fbebb8ea2 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -1,4 +1,6 @@
/*
+ * Interface handling (except master interface)
+ *
* Copyright 2002-2005, Instant802 Networks, Inc.
* Copyright 2005-2006, Devicescape Software, Inc.
* Copyright (c) 2006 Jiri Benc
@@ -17,7 +19,540 @@
#include "sta_info.h"
#include "debugfs_netdev.h"
#include "mesh.h"
+#include "led.h"
+static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
+{
+ int meshhdrlen;
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ meshhdrlen = (sdata->vif.type == NL80211_IFTYPE_MESH_POINT) ? 5 : 0;
+
+ /* FIX: what would be proper limits for MTU?
+ * This interface uses 802.3 frames. */
+ if (new_mtu < 256 ||
+ new_mtu > IEEE80211_MAX_DATA_LEN - 24 - 6 - meshhdrlen) {
+ return -EINVAL;
+ }
+
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+ printk(KERN_DEBUG "%s: setting MTU %d\n", dev->name, new_mtu);
+#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+ dev->mtu = new_mtu;
+ return 0;
+}
+
+static inline int identical_mac_addr_allowed(int type1, int type2)
+{
+ return type1 == NL80211_IFTYPE_MONITOR ||
+ type2 == NL80211_IFTYPE_MONITOR ||
+ (type1 == NL80211_IFTYPE_AP && type2 == NL80211_IFTYPE_WDS) ||
+ (type1 == NL80211_IFTYPE_WDS &&
+ (type2 == NL80211_IFTYPE_WDS ||
+ type2 == NL80211_IFTYPE_AP)) ||
+ (type1 == NL80211_IFTYPE_AP && type2 == NL80211_IFTYPE_AP_VLAN) ||
+ (type1 == NL80211_IFTYPE_AP_VLAN &&
+ (type2 == NL80211_IFTYPE_AP ||
+ type2 == NL80211_IFTYPE_AP_VLAN));
+}
+
+static int ieee80211_open(struct net_device *dev)
+{
+ struct ieee80211_sub_if_data *sdata, *nsdata;
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct sta_info *sta;
+ struct ieee80211_if_init_conf conf;
+ u32 changed = 0;
+ int res;
+ bool need_hw_reconfig = 0;
+ u8 null_addr[ETH_ALEN] = {0};
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ /* fail early if user set an invalid address */
+ if (compare_ether_addr(dev->dev_addr, null_addr) &&
+ !is_valid_ether_addr(dev->dev_addr))
+ return -EADDRNOTAVAIL;
+
+ /* we hold the RTNL here so can safely walk the list */
+ list_for_each_entry(nsdata, &local->interfaces, list) {
+ struct net_device *ndev = nsdata->dev;
+
+ if (ndev != dev && netif_running(ndev)) {
+ /*
+ * Allow only a single IBSS interface to be up at any
+ * time. This is restricted because beacon distribution
+ * cannot work properly if both are in the same IBSS.
+ *
+ * To remove this restriction we'd have to disallow them
+ * from setting the same SSID on different IBSS interfaces
+ * belonging to the same hardware. Then, however, we're
+ * faced with having to adopt two different TSF timers...
+ */
+ if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
+ nsdata->vif.type == NL80211_IFTYPE_ADHOC)
+ return -EBUSY;
+
+ /*
+ * The remaining checks are only performed for interfaces
+ * with the same MAC address.
+ */
+ if (compare_ether_addr(dev->dev_addr, ndev->dev_addr))
+ continue;
+
+ /*
+ * check whether it may have the same address
+ */
+ if (!identical_mac_addr_allowed(sdata->vif.type,
+ nsdata->vif.type))
+ return -ENOTUNIQ;
+
+ /*
+ * can only add VLANs to enabled APs
+ */
+ if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
+ nsdata->vif.type == NL80211_IFTYPE_AP)
+ sdata->bss = &nsdata->u.ap;
+ }
+ }
+
+ switch (sdata->vif.type) {
+ case NL80211_IFTYPE_WDS:
+ if (!is_valid_ether_addr(sdata->u.wds.remote_addr))
+ return -ENOLINK;
+ break;
+ case NL80211_IFTYPE_AP_VLAN:
+ if (!sdata->bss)
+ return -ENOLINK;
+ list_add(&sdata->u.vlan.list, &sdata->bss->vlans);
+ break;
+ case NL80211_IFTYPE_AP:
+ sdata->bss = &sdata->u.ap;
+ break;
+ case NL80211_IFTYPE_MESH_POINT:
+ if (!ieee80211_vif_is_mesh(&sdata->vif))
+ break;
+ /* mesh ifaces must set allmulti to forward mcast traffic */
+ atomic_inc(&local->iff_allmultis);
+ break;
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_MONITOR:
+ case NL80211_IFTYPE_ADHOC:
+ /* no special treatment */
+ break;
+ case NL80211_IFTYPE_UNSPECIFIED:
+ case __NL80211_IFTYPE_AFTER_LAST:
+ /* cannot happen */
+ WARN_ON(1);
+ break;
+ }
+
+ if (local->open_count == 0) {
+ res = 0;
+ if (local->ops->start)
+ res = local->ops->start(local_to_hw(local));
+ if (res)
+ goto err_del_bss;
+ need_hw_reconfig = 1;
+ ieee80211_led_radio(local, local->hw.conf.radio_enabled);
+ }
+
+ /*
+ * Check all interfaces and copy the hopefully now-present
+ * MAC address to those that have the special null one.
+ */
+ list_for_each_entry(nsdata, &local->interfaces, list) {
+ struct net_device *ndev = nsdata->dev;
+
+ /*
+ * No need to check netif_running since we do not allow
+ * it to start up with this invalid address.
+ */
+ if (compare_ether_addr(null_addr, ndev->dev_addr) == 0)
+ memcpy(ndev->dev_addr,
+ local->hw.wiphy->perm_addr,
+ ETH_ALEN);
+ }
+
+ if (compare_ether_addr(null_addr, local->mdev->dev_addr) == 0)
+ memcpy(local->mdev->dev_addr, local->hw.wiphy->perm_addr,
+ ETH_ALEN);
+
+ /*
+ * Validate the MAC address for this device.
+ */
+ if (!is_valid_ether_addr(dev->dev_addr)) {
+ if (!local->open_count && local->ops->stop)
+ local->ops->stop(local_to_hw(local));
+ return -EADDRNOTAVAIL;
+ }
+
+ switch (sdata->vif.type) {
+ case NL80211_IFTYPE_AP_VLAN:
+ /* no need to tell driver */
+ break;
+ case NL80211_IFTYPE_MONITOR:
+ if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) {
+ local->cooked_mntrs++;
+ break;
+ }
+
+ /* must be before the call to ieee80211_configure_filter */
+ local->monitors++;
+ if (local->monitors == 1)
+ local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
+
+ if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL)
+ local->fif_fcsfail++;
+ if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL)
+ local->fif_plcpfail++;
+ if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL)
+ local->fif_control++;
+ if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
+ local->fif_other_bss++;
+
+ netif_addr_lock_bh(local->mdev);
+ ieee80211_configure_filter(local);
+ netif_addr_unlock_bh(local->mdev);
+ break;
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_ADHOC:
+ sdata->u.sta.flags &= ~IEEE80211_STA_PREV_BSSID_SET;
+ /* fall through */
+ default:
+ conf.vif = &sdata->vif;
+ conf.type = sdata->vif.type;
+ conf.mac_addr = dev->dev_addr;
+ res = local->ops->add_interface(local_to_hw(local), &conf);
+ if (res)
+ goto err_stop;
+
+ if (ieee80211_vif_is_mesh(&sdata->vif))
+ ieee80211_start_mesh(sdata);
+ changed |= ieee80211_reset_erp_info(sdata);
+ ieee80211_bss_info_change_notify(sdata, changed);
+ ieee80211_enable_keys(sdata);
+
+ if (sdata->vif.type == NL80211_IFTYPE_STATION &&
+ !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME))
+ netif_carrier_off(dev);
+ else
+ netif_carrier_on(dev);
+ }
+
+ if (sdata->vif.type == NL80211_IFTYPE_WDS) {
+ /* Create STA entry for the WDS peer */
+ sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr,
+ GFP_KERNEL);
+ if (!sta) {
+ res = -ENOMEM;
+ goto err_del_interface;
+ }
+
+ /* no locking required since STA is not live yet */
+ sta->flags |= WLAN_STA_AUTHORIZED;
+
+ res = sta_info_insert(sta);
+ if (res) {
+ /* STA has been freed */
+ goto err_del_interface;
+ }
+ }
+
+ if (local->open_count == 0) {
+ res = dev_open(local->mdev);
+ WARN_ON(res);
+ if (res)
+ goto err_del_interface;
+ tasklet_enable(&local->tx_pending_tasklet);
+ tasklet_enable(&local->tasklet);
+ }
+
+ /*
+ * set_multicast_list will be invoked by the networking core
+ * which will check whether any increments here were done in
+ * error and sync them down to the hardware as filter flags.
+ */
+ if (sdata->flags & IEEE80211_SDATA_ALLMULTI)
+ atomic_inc(&local->iff_allmultis);
+
+ if (sdata->flags & IEEE80211_SDATA_PROMISC)
+ atomic_inc(&local->iff_promiscs);
+
+ local->open_count++;
+ if (need_hw_reconfig) {
+ ieee80211_hw_config(local);
+ /*
+ * set default queue parameters so drivers don't
+ * need to initialise the hardware if the hardware
+ * doesn't start up with sane defaults
+ */
+ ieee80211_set_wmm_default(sdata);
+ }
+
+ /*
+ * ieee80211_sta_work is disabled while network interface
+ * is down. Therefore, some configuration changes may not
+ * yet be effective. Trigger execution of ieee80211_sta_work
+ * to fix this.
+ */
+ if (sdata->vif.type == NL80211_IFTYPE_STATION ||
+ sdata->vif.type == NL80211_IFTYPE_ADHOC) {
+ struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+ queue_work(local->hw.workqueue, &ifsta->work);
+ }
+
+ netif_tx_start_all_queues(dev);
+
+ return 0;
+ err_del_interface:
+ local->ops->remove_interface(local_to_hw(local), &conf);
+ err_stop:
+ if (!local->open_count && local->ops->stop)
+ local->ops->stop(local_to_hw(local));
+ err_del_bss:
+ sdata->bss = NULL;
+ if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+ list_del(&sdata->u.vlan.list);
+ return res;
+}
+
+static int ieee80211_stop(struct net_device *dev)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_if_init_conf conf;
+ struct sta_info *sta;
+
+ /*
+ * Stop TX on this interface first.
+ */
+ netif_tx_stop_all_queues(dev);
+
+ /*
+ * Now delete all active aggregation sessions.
+ */
+ rcu_read_lock();
+
+ list_for_each_entry_rcu(sta, &local->sta_list, list) {
+ if (sta->sdata == sdata)
+ ieee80211_sta_tear_down_BA_sessions(sdata,
+ sta->sta.addr);
+ }
+
+ rcu_read_unlock();
+
+ /*
+ * Remove all stations associated with this interface.
+ *
+ * This must be done before calling ops->remove_interface()
+ * because otherwise we can later invoke ops->sta_notify()
+ * whenever the STAs are removed, and that invalidates driver
+ * assumptions about always getting a vif pointer that is valid
+ * (because if we remove a STA after ops->remove_interface()
+ * the driver will have removed the vif info already!)
+ *
+ * We could relax this and only unlink the stations from the
+ * hash table and list but keep them on a per-sdata list that
+ * will be inserted back again when the interface is brought
+ * up again, but I don't currently see a use case for that,
+ * except with WDS which gets a STA entry created when it is
+ * brought up.
+ */
+ sta_info_flush(local, sdata);
+
+ /*
+ * Don't count this interface for promisc/allmulti while it
+ * is down. dev_mc_unsync() will invoke set_multicast_list
+ * on the master interface which will sync these down to the
+ * hardware as filter flags.
+ */
+ if (sdata->flags & IEEE80211_SDATA_ALLMULTI)
+ atomic_dec(&local->iff_allmultis);
+
+ if (sdata->flags & IEEE80211_SDATA_PROMISC)
+ atomic_dec(&local->iff_promiscs);
+
+ dev_mc_unsync(local->mdev, dev);
+
+ /* APs need special treatment */
+ if (sdata->vif.type == NL80211_IFTYPE_AP) {
+ struct ieee80211_sub_if_data *vlan, *tmp;
+ struct beacon_data *old_beacon = sdata->u.ap.beacon;
+
+ /* remove beacon */
+ rcu_assign_pointer(sdata->u.ap.beacon, NULL);
+ synchronize_rcu();
+ kfree(old_beacon);
+
+ /* down all dependent devices, that is VLANs */
+ list_for_each_entry_safe(vlan, tmp, &sdata->u.ap.vlans,
+ u.vlan.list)
+ dev_close(vlan->dev);
+ WARN_ON(!list_empty(&sdata->u.ap.vlans));
+ }
+
+ local->open_count--;
+
+ switch (sdata->vif.type) {
+ case NL80211_IFTYPE_AP_VLAN:
+ list_del(&sdata->u.vlan.list);
+ /* no need to tell driver */
+ break;
+ case NL80211_IFTYPE_MONITOR:
+ if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) {
+ local->cooked_mntrs--;
+ break;
+ }
+
+ local->monitors--;
+ if (local->monitors == 0)
+ local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP;
+
+ if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL)
+ local->fif_fcsfail--;
+ if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL)
+ local->fif_plcpfail--;
+ if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL)
+ local->fif_control--;
+ if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
+ local->fif_other_bss--;
+
+ netif_addr_lock_bh(local->mdev);
+ ieee80211_configure_filter(local);
+ netif_addr_unlock_bh(local->mdev);
+ break;
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_ADHOC:
+ sdata->u.sta.state = IEEE80211_STA_MLME_DISABLED;
+ memset(sdata->u.sta.bssid, 0, ETH_ALEN);
+ del_timer_sync(&sdata->u.sta.timer);
+ /*
+ * If the timer fired while we waited for it, it will have
+ * requeued the work. Now the work will be running again
+ * but will not rearm the timer again because it checks
+ * whether the interface is running, which, at this point,
+ * it no longer is.
+ */
+ cancel_work_sync(&sdata->u.sta.work);
+ /*
+ * When we get here, the interface is marked down.
+ * Call synchronize_rcu() to wait for the RX path
+ * should it be using the interface and enqueuing
+ * frames at this very time on another CPU.
+ */
+ synchronize_rcu();
+ skb_queue_purge(&sdata->u.sta.skb_queue);
+
+ sdata->u.sta.flags &= ~IEEE80211_STA_PRIVACY_INVOKED;
+ kfree(sdata->u.sta.extra_ie);
+ sdata->u.sta.extra_ie = NULL;
+ sdata->u.sta.extra_ie_len = 0;
+ /* fall through */
+ case NL80211_IFTYPE_MESH_POINT:
+ if (ieee80211_vif_is_mesh(&sdata->vif)) {
+ /* allmulti is always set on mesh ifaces */
+ atomic_dec(&local->iff_allmultis);
+ ieee80211_stop_mesh(sdata);
+ }
+ /* fall through */
+ default:
+ if (local->scan_sdata == sdata) {
+ if (!local->ops->hw_scan)
+ cancel_delayed_work_sync(&local->scan_work);
+ /*
+ * The software scan can no longer run now, so we can
+ * clear out the scan_sdata reference. However, the
+ * hardware scan may still be running. The complete
+ * function must be prepared to handle a NULL value.
+ */
+ local->scan_sdata = NULL;
+ /*
+ * The memory barrier guarantees that another CPU
+ * that is hardware-scanning will now see the fact
+ * that this interface is gone.
+ */
+ smp_mb();
+ /*
+ * If software scanning, complete the scan but since
+ * the scan_sdata is NULL already don't send out a
+ * scan event to userspace -- the scan is incomplete.
+ */
+ if (local->sw_scanning)
+ ieee80211_scan_completed(&local->hw);
+ }
+
+ conf.vif = &sdata->vif;
+ conf.type = sdata->vif.type;
+ conf.mac_addr = dev->dev_addr;
+ /* disable all keys for as long as this netdev is down */
+ ieee80211_disable_keys(sdata);
+ local->ops->remove_interface(local_to_hw(local), &conf);
+ }
+
+ sdata->bss = NULL;
+
+ if (local->open_count == 0) {
+ if (netif_running(local->mdev))
+ dev_close(local->mdev);
+
+ if (local->ops->stop)
+ local->ops->stop(local_to_hw(local));
+
+ ieee80211_led_radio(local, 0);
+
+ flush_workqueue(local->hw.workqueue);
+
+ tasklet_disable(&local->tx_pending_tasklet);
+ tasklet_disable(&local->tasklet);
+ }
+
+ return 0;
+}
+
+static void ieee80211_set_multicast_list(struct net_device *dev)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ int allmulti, promisc, sdata_allmulti, sdata_promisc;
+
+ allmulti = !!(dev->flags & IFF_ALLMULTI);
+ promisc = !!(dev->flags & IFF_PROMISC);
+ sdata_allmulti = !!(sdata->flags & IEEE80211_SDATA_ALLMULTI);
+ sdata_promisc = !!(sdata->flags & IEEE80211_SDATA_PROMISC);
+
+ if (allmulti != sdata_allmulti) {
+ if (dev->flags & IFF_ALLMULTI)
+ atomic_inc(&local->iff_allmultis);
+ else
+ atomic_dec(&local->iff_allmultis);
+ sdata->flags ^= IEEE80211_SDATA_ALLMULTI;
+ }
+
+ if (promisc != sdata_promisc) {
+ if (dev->flags & IFF_PROMISC)
+ atomic_inc(&local->iff_promiscs);
+ else
+ atomic_dec(&local->iff_promiscs);
+ sdata->flags ^= IEEE80211_SDATA_PROMISC;
+ }
+
+ dev_mc_sync(local->mdev, dev);
+}
+
+static void ieee80211_if_setup(struct net_device *dev)
+{
+ ether_setup(dev);
+ dev->hard_start_xmit = ieee80211_subif_start_xmit;
+ dev->wireless_handlers = &ieee80211_iw_handler_def;
+ dev->set_multicast_list = ieee80211_set_multicast_list;
+ dev->change_mtu = ieee80211_change_mtu;
+ dev->open = ieee80211_open;
+ dev->stop = ieee80211_stop;
+ dev->destructor = free_netdev;
+ /* we will validate the address ourselves in ->open */
+ dev->validate_addr = NULL;
+}
/*
* Called when the netdev is removed or, by the code below, before
* the interface type changes.
@@ -41,7 +576,7 @@ static void ieee80211_teardown_sdata(struct net_device *dev)
sdata->fragment_next = 0;
switch (sdata->vif.type) {
- case IEEE80211_IF_TYPE_AP:
+ case NL80211_IFTYPE_AP:
beacon = sdata->u.ap.beacon;
rcu_assign_pointer(sdata->u.ap.beacon, NULL);
synchronize_rcu();
@@ -53,23 +588,23 @@ static void ieee80211_teardown_sdata(struct net_device *dev)
}
break;
- case IEEE80211_IF_TYPE_MESH_POINT:
- /* Allow compiler to elide mesh_rmc_free call. */
+ case NL80211_IFTYPE_MESH_POINT:
if (ieee80211_vif_is_mesh(&sdata->vif))
mesh_rmc_free(sdata);
- /* fall through */
- case IEEE80211_IF_TYPE_STA:
- case IEEE80211_IF_TYPE_IBSS:
+ break;
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_ADHOC:
kfree(sdata->u.sta.extra_ie);
kfree(sdata->u.sta.assocreq_ies);
kfree(sdata->u.sta.assocresp_ies);
kfree_skb(sdata->u.sta.probe_resp);
break;
- case IEEE80211_IF_TYPE_WDS:
- case IEEE80211_IF_TYPE_VLAN:
- case IEEE80211_IF_TYPE_MNTR:
+ case NL80211_IFTYPE_WDS:
+ case NL80211_IFTYPE_AP_VLAN:
+ case NL80211_IFTYPE_MONITOR:
break;
- case IEEE80211_IF_TYPE_INVALID:
+ case NL80211_IFTYPE_UNSPECIFIED:
+ case __NL80211_IFTYPE_AFTER_LAST:
BUG();
break;
}
@@ -82,55 +617,42 @@ static void ieee80211_teardown_sdata(struct net_device *dev)
* Helper function to initialise an interface to a specific type.
*/
static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
- enum ieee80211_if_types type)
+ enum nl80211_iftype type)
{
- struct ieee80211_if_sta *ifsta;
-
/* clear type-dependent union */
memset(&sdata->u, 0, sizeof(sdata->u));
/* and set some type-dependent values */
sdata->vif.type = type;
+ sdata->dev->hard_start_xmit = ieee80211_subif_start_xmit;
/* only monitor differs */
sdata->dev->type = ARPHRD_ETHER;
switch (type) {
- case IEEE80211_IF_TYPE_AP:
+ case NL80211_IFTYPE_AP:
skb_queue_head_init(&sdata->u.ap.ps_bc_buf);
INIT_LIST_HEAD(&sdata->u.ap.vlans);
break;
- case IEEE80211_IF_TYPE_MESH_POINT:
- case IEEE80211_IF_TYPE_STA:
- case IEEE80211_IF_TYPE_IBSS:
- ifsta = &sdata->u.sta;
- INIT_WORK(&ifsta->work, ieee80211_sta_work);
- setup_timer(&ifsta->timer, ieee80211_sta_timer,
- (unsigned long) sdata);
- skb_queue_head_init(&ifsta->skb_queue);
-
- ifsta->capab = WLAN_CAPABILITY_ESS;
- ifsta->auth_algs = IEEE80211_AUTH_ALG_OPEN |
- IEEE80211_AUTH_ALG_SHARED_KEY;
- ifsta->flags |= IEEE80211_STA_CREATE_IBSS |
- IEEE80211_STA_AUTO_BSSID_SEL |
- IEEE80211_STA_AUTO_CHANNEL_SEL;
- if (ieee80211_num_regular_queues(&sdata->local->hw) >= 4)
- ifsta->flags |= IEEE80211_STA_WMM_ENABLED;
-
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_ADHOC:
+ ieee80211_sta_setup_sdata(sdata);
+ break;
+ case NL80211_IFTYPE_MESH_POINT:
if (ieee80211_vif_is_mesh(&sdata->vif))
ieee80211_mesh_init_sdata(sdata);
break;
- case IEEE80211_IF_TYPE_MNTR:
+ case NL80211_IFTYPE_MONITOR:
sdata->dev->type = ARPHRD_IEEE80211_RADIOTAP;
sdata->dev->hard_start_xmit = ieee80211_monitor_start_xmit;
sdata->u.mntr_flags = MONITOR_FLAG_CONTROL |
MONITOR_FLAG_OTHER_BSS;
break;
- case IEEE80211_IF_TYPE_WDS:
- case IEEE80211_IF_TYPE_VLAN:
+ case NL80211_IFTYPE_WDS:
+ case NL80211_IFTYPE_AP_VLAN:
break;
- case IEEE80211_IF_TYPE_INVALID:
+ case NL80211_IFTYPE_UNSPECIFIED:
+ case __NL80211_IFTYPE_AFTER_LAST:
BUG();
break;
}
@@ -139,7 +661,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
}
int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
- enum ieee80211_if_types type)
+ enum nl80211_iftype type)
{
ASSERT_RTNL();
@@ -160,14 +682,16 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
ieee80211_setup_sdata(sdata, type);
/* reset some values that shouldn't be kept across type changes */
- sdata->basic_rates = 0;
+ sdata->bss_conf.basic_rates =
+ ieee80211_mandatory_rates(sdata->local,
+ sdata->local->hw.conf.channel->band);
sdata->drop_unencrypted = 0;
return 0;
}
int ieee80211_if_add(struct ieee80211_local *local, const char *name,
- struct net_device **new_dev, enum ieee80211_if_types type,
+ struct net_device **new_dev, enum nl80211_iftype type,
struct vif_params *params)
{
struct net_device *ndev;
@@ -225,9 +749,9 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
if (ieee80211_vif_is_mesh(&sdata->vif) &&
params && params->mesh_id_len)
- ieee80211_if_sta_set_mesh_id(&sdata->u.sta,
- params->mesh_id_len,
- params->mesh_id);
+ ieee80211_sdata_set_mesh_id(sdata,
+ params->mesh_id_len,
+ params->mesh_id);
list_add_tail_rcu(&sdata->list, &local->interfaces);
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index 6597c779e35a..57afcd38cd9e 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -118,12 +118,12 @@ static const u8 *get_mac_for_key(struct ieee80211_key *key)
* address to indicate a transmit-only key.
*/
if (key->conf.alg != ALG_WEP &&
- (key->sdata->vif.type == IEEE80211_IF_TYPE_AP ||
- key->sdata->vif.type == IEEE80211_IF_TYPE_VLAN))
+ (key->sdata->vif.type == NL80211_IFTYPE_AP ||
+ key->sdata->vif.type == NL80211_IFTYPE_AP_VLAN))
addr = zero_addr;
if (key->sta)
- addr = key->sta->addr;
+ addr = key->sta->sta.addr;
return addr;
}
@@ -331,7 +331,7 @@ void ieee80211_key_link(struct ieee80211_key *key,
*/
key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE;
} else {
- if (sdata->vif.type == IEEE80211_IF_TYPE_STA) {
+ if (sdata->vif.type == NL80211_IFTYPE_STATION) {
struct sta_info *ap;
/*
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 6a7f4fae18c2..c307dba7ec03 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -45,16 +45,9 @@ struct ieee80211_tx_status_rtap_hdr {
u8 data_retries;
} __attribute__ ((packed));
-/* common interface routines */
-
-static int header_parse_80211(const struct sk_buff *skb, unsigned char *haddr)
-{
- memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */
- return ETH_ALEN;
-}
/* must be called under mdev tx lock */
-static void ieee80211_configure_filter(struct ieee80211_local *local)
+void ieee80211_configure_filter(struct ieee80211_local *local)
{
unsigned int changed_flags;
unsigned int new_flags = 0;
@@ -97,6 +90,20 @@ static void ieee80211_configure_filter(struct ieee80211_local *local)
/* master interface */
+static int header_parse_80211(const struct sk_buff *skb, unsigned char *haddr)
+{
+ memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */
+ return ETH_ALEN;
+}
+
+static const struct header_ops ieee80211_header_ops = {
+ .create = eth_header,
+ .parse = header_parse_80211,
+ .rebuild = eth_rebuild_header,
+ .cache = eth_header_cache,
+ .cache_update = eth_header_cache_update,
+};
+
static int ieee80211_master_open(struct net_device *dev)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
@@ -139,519 +146,6 @@ static void ieee80211_master_set_multicast_list(struct net_device *dev)
ieee80211_configure_filter(local);
}
-/* regular interfaces */
-
-static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
-{
- int meshhdrlen;
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
- meshhdrlen = (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) ? 5 : 0;
-
- /* FIX: what would be proper limits for MTU?
- * This interface uses 802.3 frames. */
- if (new_mtu < 256 ||
- new_mtu > IEEE80211_MAX_DATA_LEN - 24 - 6 - meshhdrlen) {
- return -EINVAL;
- }
-
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- printk(KERN_DEBUG "%s: setting MTU %d\n", dev->name, new_mtu);
-#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
- dev->mtu = new_mtu;
- return 0;
-}
-
-static inline int identical_mac_addr_allowed(int type1, int type2)
-{
- return (type1 == IEEE80211_IF_TYPE_MNTR ||
- type2 == IEEE80211_IF_TYPE_MNTR ||
- (type1 == IEEE80211_IF_TYPE_AP &&
- type2 == IEEE80211_IF_TYPE_WDS) ||
- (type1 == IEEE80211_IF_TYPE_WDS &&
- (type2 == IEEE80211_IF_TYPE_WDS ||
- type2 == IEEE80211_IF_TYPE_AP)) ||
- (type1 == IEEE80211_IF_TYPE_AP &&
- type2 == IEEE80211_IF_TYPE_VLAN) ||
- (type1 == IEEE80211_IF_TYPE_VLAN &&
- (type2 == IEEE80211_IF_TYPE_AP ||
- type2 == IEEE80211_IF_TYPE_VLAN)));
-}
-
-static int ieee80211_open(struct net_device *dev)
-{
- struct ieee80211_sub_if_data *sdata, *nsdata;
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct sta_info *sta;
- struct ieee80211_if_init_conf conf;
- u32 changed = 0;
- int res;
- bool need_hw_reconfig = 0;
- u8 null_addr[ETH_ALEN] = {0};
-
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
- /* fail early if user set an invalid address */
- if (compare_ether_addr(dev->dev_addr, null_addr) &&
- !is_valid_ether_addr(dev->dev_addr))
- return -EADDRNOTAVAIL;
-
- /* we hold the RTNL here so can safely walk the list */
- list_for_each_entry(nsdata, &local->interfaces, list) {
- struct net_device *ndev = nsdata->dev;
-
- if (ndev != dev && netif_running(ndev)) {
- /*
- * Allow only a single IBSS interface to be up at any
- * time. This is restricted because beacon distribution
- * cannot work properly if both are in the same IBSS.
- *
- * To remove this restriction we'd have to disallow them
- * from setting the same SSID on different IBSS interfaces
- * belonging to the same hardware. Then, however, we're
- * faced with having to adopt two different TSF timers...
- */
- if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS &&
- nsdata->vif.type == IEEE80211_IF_TYPE_IBSS)
- return -EBUSY;
-
- /*
- * The remaining checks are only performed for interfaces
- * with the same MAC address.
- */
- if (compare_ether_addr(dev->dev_addr, ndev->dev_addr))
- continue;
-
- /*
- * check whether it may have the same address
- */
- if (!identical_mac_addr_allowed(sdata->vif.type,
- nsdata->vif.type))
- return -ENOTUNIQ;
-
- /*
- * can only add VLANs to enabled APs
- */
- if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN &&
- nsdata->vif.type == IEEE80211_IF_TYPE_AP)
- sdata->bss = &nsdata->u.ap;
- }
- }
-
- switch (sdata->vif.type) {
- case IEEE80211_IF_TYPE_WDS:
- if (!is_valid_ether_addr(sdata->u.wds.remote_addr))
- return -ENOLINK;
- break;
- case IEEE80211_IF_TYPE_VLAN:
- if (!sdata->bss)
- return -ENOLINK;
- list_add(&sdata->u.vlan.list, &sdata->bss->vlans);
- break;
- case IEEE80211_IF_TYPE_AP:
- sdata->bss = &sdata->u.ap;
- break;
- case IEEE80211_IF_TYPE_MESH_POINT:
- /* mesh ifaces must set allmulti to forward mcast traffic */
- atomic_inc(&local->iff_allmultis);
- break;
- case IEEE80211_IF_TYPE_STA:
- case IEEE80211_IF_TYPE_MNTR:
- case IEEE80211_IF_TYPE_IBSS:
- /* no special treatment */
- break;
- case IEEE80211_IF_TYPE_INVALID:
- /* cannot happen */
- WARN_ON(1);
- break;
- }
-
- if (local->open_count == 0) {
- res = 0;
- if (local->ops->start)
- res = local->ops->start(local_to_hw(local));
- if (res)
- goto err_del_bss;
- need_hw_reconfig = 1;
- ieee80211_led_radio(local, local->hw.conf.radio_enabled);
- }
-
- /*
- * Check all interfaces and copy the hopefully now-present
- * MAC address to those that have the special null one.
- */
- list_for_each_entry(nsdata, &local->interfaces, list) {
- struct net_device *ndev = nsdata->dev;
-
- /*
- * No need to check netif_running since we do not allow
- * it to start up with this invalid address.
- */
- if (compare_ether_addr(null_addr, ndev->dev_addr) == 0)
- memcpy(ndev->dev_addr,
- local->hw.wiphy->perm_addr,
- ETH_ALEN);
- }
-
- if (compare_ether_addr(null_addr, local->mdev->dev_addr) == 0)
- memcpy(local->mdev->dev_addr, local->hw.wiphy->perm_addr,
- ETH_ALEN);
-
- /*
- * Validate the MAC address for this device.
- */
- if (!is_valid_ether_addr(dev->dev_addr)) {
- if (!local->open_count && local->ops->stop)
- local->ops->stop(local_to_hw(local));
- return -EADDRNOTAVAIL;
- }
-
- switch (sdata->vif.type) {
- case IEEE80211_IF_TYPE_VLAN:
- /* no need to tell driver */
- break;
- case IEEE80211_IF_TYPE_MNTR:
- if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) {
- local->cooked_mntrs++;
- break;
- }
-
- /* must be before the call to ieee80211_configure_filter */
- local->monitors++;
- if (local->monitors == 1)
- local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
-
- if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL)
- local->fif_fcsfail++;
- if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL)
- local->fif_plcpfail++;
- if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL)
- local->fif_control++;
- if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
- local->fif_other_bss++;
-
- netif_addr_lock_bh(local->mdev);
- ieee80211_configure_filter(local);
- netif_addr_unlock_bh(local->mdev);
- break;
- case IEEE80211_IF_TYPE_STA:
- case IEEE80211_IF_TYPE_IBSS:
- sdata->u.sta.flags &= ~IEEE80211_STA_PREV_BSSID_SET;
- /* fall through */
- default:
- conf.vif = &sdata->vif;
- conf.type = sdata->vif.type;
- conf.mac_addr = dev->dev_addr;
- res = local->ops->add_interface(local_to_hw(local), &conf);
- if (res)
- goto err_stop;
-
- if (ieee80211_vif_is_mesh(&sdata->vif))
- ieee80211_start_mesh(sdata);
- changed |= ieee80211_reset_erp_info(sdata);
- ieee80211_bss_info_change_notify(sdata, changed);
- ieee80211_enable_keys(sdata);
-
- if (sdata->vif.type == IEEE80211_IF_TYPE_STA &&
- !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME))
- netif_carrier_off(dev);
- else
- netif_carrier_on(dev);
- }
-
- if (sdata->vif.type == IEEE80211_IF_TYPE_WDS) {
- /* Create STA entry for the WDS peer */
- sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr,
- GFP_KERNEL);
- if (!sta) {
- res = -ENOMEM;
- goto err_del_interface;
- }
-
- /* no locking required since STA is not live yet */
- sta->flags |= WLAN_STA_AUTHORIZED;
-
- res = sta_info_insert(sta);
- if (res) {
- /* STA has been freed */
- goto err_del_interface;
- }
- }
-
- if (local->open_count == 0) {
- res = dev_open(local->mdev);
- WARN_ON(res);
- if (res)
- goto err_del_interface;
- tasklet_enable(&local->tx_pending_tasklet);
- tasklet_enable(&local->tasklet);
- }
-
- /*
- * set_multicast_list will be invoked by the networking core
- * which will check whether any increments here were done in
- * error and sync them down to the hardware as filter flags.
- */
- if (sdata->flags & IEEE80211_SDATA_ALLMULTI)
- atomic_inc(&local->iff_allmultis);
-
- if (sdata->flags & IEEE80211_SDATA_PROMISC)
- atomic_inc(&local->iff_promiscs);
-
- local->open_count++;
- if (need_hw_reconfig) {
- ieee80211_hw_config(local);
- /*
- * set default queue parameters so drivers don't
- * need to initialise the hardware if the hardware
- * doesn't start up with sane defaults
- */
- ieee80211_set_wmm_default(sdata);
- }
-
- /*
- * ieee80211_sta_work is disabled while network interface
- * is down. Therefore, some configuration changes may not
- * yet be effective. Trigger execution of ieee80211_sta_work
- * to fix this.
- */
- if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
- sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
- struct ieee80211_if_sta *ifsta = &sdata->u.sta;
- queue_work(local->hw.workqueue, &ifsta->work);
- }
-
- netif_tx_start_all_queues(dev);
-
- return 0;
- err_del_interface:
- local->ops->remove_interface(local_to_hw(local), &conf);
- err_stop:
- if (!local->open_count && local->ops->stop)
- local->ops->stop(local_to_hw(local));
- err_del_bss:
- sdata->bss = NULL;
- if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
- list_del(&sdata->u.vlan.list);
- return res;
-}
-
-static int ieee80211_stop(struct net_device *dev)
-{
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- struct ieee80211_local *local = sdata->local;
- struct ieee80211_if_init_conf conf;
- struct sta_info *sta;
-
- /*
- * Stop TX on this interface first.
- */
- netif_tx_stop_all_queues(dev);
-
- /*
- * Now delete all active aggregation sessions.
- */
- rcu_read_lock();
-
- list_for_each_entry_rcu(sta, &local->sta_list, list) {
- if (sta->sdata == sdata)
- ieee80211_sta_tear_down_BA_sessions(sdata, sta->addr);
- }
-
- rcu_read_unlock();
-
- /*
- * Remove all stations associated with this interface.
- *
- * This must be done before calling ops->remove_interface()
- * because otherwise we can later invoke ops->sta_notify()
- * whenever the STAs are removed, and that invalidates driver
- * assumptions about always getting a vif pointer that is valid
- * (because if we remove a STA after ops->remove_interface()
- * the driver will have removed the vif info already!)
- *
- * We could relax this and only unlink the stations from the
- * hash table and list but keep them on a per-sdata list that
- * will be inserted back again when the interface is brought
- * up again, but I don't currently see a use case for that,
- * except with WDS which gets a STA entry created when it is
- * brought up.
- */
- sta_info_flush(local, sdata);
-
- /*
- * Don't count this interface for promisc/allmulti while it
- * is down. dev_mc_unsync() will invoke set_multicast_list
- * on the master interface which will sync these down to the
- * hardware as filter flags.
- */
- if (sdata->flags & IEEE80211_SDATA_ALLMULTI)
- atomic_dec(&local->iff_allmultis);
-
- if (sdata->flags & IEEE80211_SDATA_PROMISC)
- atomic_dec(&local->iff_promiscs);
-
- dev_mc_unsync(local->mdev, dev);
-
- /* APs need special treatment */
- if (sdata->vif.type == IEEE80211_IF_TYPE_AP) {
- struct ieee80211_sub_if_data *vlan, *tmp;
- struct beacon_data *old_beacon = sdata->u.ap.beacon;
-
- /* remove beacon */
- rcu_assign_pointer(sdata->u.ap.beacon, NULL);
- synchronize_rcu();
- kfree(old_beacon);
-
- /* down all dependent devices, that is VLANs */
- list_for_each_entry_safe(vlan, tmp, &sdata->u.ap.vlans,
- u.vlan.list)
- dev_close(vlan->dev);
- WARN_ON(!list_empty(&sdata->u.ap.vlans));
- }
-
- local->open_count--;
-
- switch (sdata->vif.type) {
- case IEEE80211_IF_TYPE_VLAN:
- list_del(&sdata->u.vlan.list);
- /* no need to tell driver */
- break;
- case IEEE80211_IF_TYPE_MNTR:
- if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) {
- local->cooked_mntrs--;
- break;
- }
-
- local->monitors--;
- if (local->monitors == 0)
- local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP;
-
- if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL)
- local->fif_fcsfail--;
- if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL)
- local->fif_plcpfail--;
- if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL)
- local->fif_control--;
- if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
- local->fif_other_bss--;
-
- netif_addr_lock_bh(local->mdev);
- ieee80211_configure_filter(local);
- netif_addr_unlock_bh(local->mdev);
- break;
- case IEEE80211_IF_TYPE_MESH_POINT:
- /* allmulti is always set on mesh ifaces */
- atomic_dec(&local->iff_allmultis);
- /* fall through */
- case IEEE80211_IF_TYPE_STA:
- case IEEE80211_IF_TYPE_IBSS:
- sdata->u.sta.state = IEEE80211_STA_MLME_DISABLED;
- memset(sdata->u.sta.bssid, 0, ETH_ALEN);
- del_timer_sync(&sdata->u.sta.timer);
- /*
- * When we get here, the interface is marked down.
- * Call synchronize_rcu() to wait for the RX path
- * should it be using the interface and enqueuing
- * frames at this very time on another CPU.
- */
- synchronize_rcu();
- skb_queue_purge(&sdata->u.sta.skb_queue);
-
- if (local->scan_sdata == sdata) {
- if (!local->ops->hw_scan) {
- local->sta_sw_scanning = 0;
- cancel_delayed_work(&local->scan_work);
- } else
- local->sta_hw_scanning = 0;
- }
-
- sdata->u.sta.flags &= ~IEEE80211_STA_PRIVACY_INVOKED;
- kfree(sdata->u.sta.extra_ie);
- sdata->u.sta.extra_ie = NULL;
- sdata->u.sta.extra_ie_len = 0;
- /* fall through */
- default:
- conf.vif = &sdata->vif;
- conf.type = sdata->vif.type;
- conf.mac_addr = dev->dev_addr;
- /* disable all keys for as long as this netdev is down */
- ieee80211_disable_keys(sdata);
- local->ops->remove_interface(local_to_hw(local), &conf);
- }
-
- sdata->bss = NULL;
-
- if (local->open_count == 0) {
- if (netif_running(local->mdev))
- dev_close(local->mdev);
-
- if (local->ops->stop)
- local->ops->stop(local_to_hw(local));
-
- ieee80211_led_radio(local, 0);
-
- flush_workqueue(local->hw.workqueue);
-
- tasklet_disable(&local->tx_pending_tasklet);
- tasklet_disable(&local->tasklet);
- }
-
- return 0;
-}
-
-static void ieee80211_set_multicast_list(struct net_device *dev)
-{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- int allmulti, promisc, sdata_allmulti, sdata_promisc;
-
- allmulti = !!(dev->flags & IFF_ALLMULTI);
- promisc = !!(dev->flags & IFF_PROMISC);
- sdata_allmulti = !!(sdata->flags & IEEE80211_SDATA_ALLMULTI);
- sdata_promisc = !!(sdata->flags & IEEE80211_SDATA_PROMISC);
-
- if (allmulti != sdata_allmulti) {
- if (dev->flags & IFF_ALLMULTI)
- atomic_inc(&local->iff_allmultis);
- else
- atomic_dec(&local->iff_allmultis);
- sdata->flags ^= IEEE80211_SDATA_ALLMULTI;
- }
-
- if (promisc != sdata_promisc) {
- if (dev->flags & IFF_PROMISC)
- atomic_inc(&local->iff_promiscs);
- else
- atomic_dec(&local->iff_promiscs);
- sdata->flags ^= IEEE80211_SDATA_PROMISC;
- }
-
- dev_mc_sync(local->mdev, dev);
-}
-
-static const struct header_ops ieee80211_header_ops = {
- .create = eth_header,
- .parse = header_parse_80211,
- .rebuild = eth_rebuild_header,
- .cache = eth_header_cache,
- .cache_update = eth_header_cache_update,
-};
-
-void ieee80211_if_setup(struct net_device *dev)
-{
- ether_setup(dev);
- dev->hard_start_xmit = ieee80211_subif_start_xmit;
- dev->wireless_handlers = &ieee80211_iw_handler_def;
- dev->set_multicast_list = ieee80211_set_multicast_list;
- dev->change_mtu = ieee80211_change_mtu;
- dev->open = ieee80211_open;
- dev->stop = ieee80211_stop;
- dev->destructor = free_netdev;
- /* we will validate the address ourselves in ->open */
- dev->validate_addr = NULL;
-}
-
/* everything else */
int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed)
@@ -662,18 +156,21 @@ int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed)
if (WARN_ON(!netif_running(sdata->dev)))
return 0;
+ if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN))
+ return -EINVAL;
+
if (!local->ops->config_interface)
return 0;
memset(&conf, 0, sizeof(conf));
conf.changed = changed;
- if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
- sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
+ if (sdata->vif.type == NL80211_IFTYPE_STATION ||
+ sdata->vif.type == NL80211_IFTYPE_ADHOC) {
conf.bssid = sdata->u.sta.bssid;
conf.ssid = sdata->u.sta.ssid;
conf.ssid_len = sdata->u.sta.ssid_len;
- } else if (sdata->vif.type == IEEE80211_IF_TYPE_AP) {
+ } else if (sdata->vif.type == NL80211_IFTYPE_AP) {
conf.bssid = sdata->dev->dev_addr;
conf.ssid = sdata->u.ap.ssid;
conf.ssid_len = sdata->u.ap.ssid_len;
@@ -702,7 +199,7 @@ int ieee80211_hw_config(struct ieee80211_local *local)
struct ieee80211_channel *chan;
int ret = 0;
- if (local->sta_sw_scanning)
+ if (local->sw_scanning)
chan = local->scan_channel;
else
chan = local->oper_channel;
@@ -827,6 +324,9 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
{
struct ieee80211_local *local = sdata->local;
+ if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN))
+ return;
+
if (!changed)
return;
@@ -1046,29 +546,27 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
rcu_read_lock();
- if (info->status.excessive_retries) {
- sta = sta_info_get(local, hdr->addr1);
- if (sta) {
- if (test_sta_flags(sta, WLAN_STA_PS)) {
- /*
- * The STA is in power save mode, so assume
- * that this TX packet failed because of that.
- */
- ieee80211_handle_filtered_frame(local, sta, skb);
- rcu_read_unlock();
- return;
- }
+ sta = sta_info_get(local, hdr->addr1);
+
+ if (sta) {
+ if (info->status.excessive_retries &&
+ test_sta_flags(sta, WLAN_STA_PS)) {
+ /*
+ * The STA is in power save mode, so assume
+ * that this TX packet failed because of that.
+ */
+ ieee80211_handle_filtered_frame(local, sta, skb);
+ rcu_read_unlock();
+ return;
}
- }
- fc = hdr->frame_control;
+ fc = hdr->frame_control;
+
+ if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) &&
+ (ieee80211_is_data_qos(fc))) {
+ u16 tid, ssn;
+ u8 *qc;
- if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) &&
- (ieee80211_is_data_qos(fc))) {
- u16 tid, ssn;
- u8 *qc;
- sta = sta_info_get(local, hdr->addr1);
- if (sta) {
qc = ieee80211_get_qos_ctl(hdr);
tid = qc[0] & 0xf;
ssn = ((le16_to_cpu(hdr->seq_ctrl) + 0x10)
@@ -1076,17 +574,19 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
ieee80211_send_bar(sta->sdata, hdr->addr1,
tid, ssn);
}
- }
- if (info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
- sta = sta_info_get(local, hdr->addr1);
- if (sta) {
+ if (info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
ieee80211_handle_filtered_frame(local, sta, skb);
rcu_read_unlock();
return;
+ } else {
+ if (info->status.excessive_retries)
+ sta->tx_retry_failed++;
+ sta->tx_retry_count += info->status.retry_count;
}
- } else
+
rate_control_tx_status(local->mdev, skb);
+ }
rcu_read_unlock();
@@ -1174,7 +674,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
rcu_read_lock();
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
- if (sdata->vif.type == IEEE80211_IF_TYPE_MNTR) {
+ if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
if (!netif_running(sdata->dev))
continue;
@@ -1250,8 +750,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
local->hw.queues = 1; /* default */
- local->bridge_packets = 1;
-
local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD;
local->short_retry_limit = 7;
@@ -1262,7 +760,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
spin_lock_init(&local->key_lock);
- INIT_DELAYED_WORK(&local->scan_work, ieee80211_sta_scan_work);
+ INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work);
sta_info_init(local);
@@ -1422,7 +920,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
/* add one default STA interface */
result = ieee80211_if_add(local, "wlan%d", NULL,
- IEEE80211_IF_TYPE_STA, NULL);
+ NL80211_IFTYPE_STATION, NULL);
if (result)
printk(KERN_WARNING "%s: Failed to add default virtual iface\n",
wiphy_name(local->hw.wiphy));
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 3ccb3599c04f..30cf891fd3a8 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -12,6 +12,9 @@
#include "ieee80211_i.h"
#include "mesh.h"
+#define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ)
+#define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ)
+
#define PP_OFFSET 1 /* Path Selection Protocol */
#define PM_OFFSET 5 /* Path Selection Metric */
#define CC_OFFSET 9 /* Congestion Control Mode */
@@ -35,6 +38,16 @@ void ieee80211s_stop(void)
kmem_cache_destroy(rm_cache);
}
+static void ieee80211_mesh_housekeeping_timer(unsigned long data)
+{
+ struct ieee80211_sub_if_data *sdata = (void *) data;
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+
+ ifmsh->housekeeping = true;
+ queue_work(local->hw.workqueue, &ifmsh->work);
+}
+
/**
* mesh_matches_local - check if the config of a mesh point matches ours
*
@@ -46,7 +59,7 @@ void ieee80211s_stop(void)
*/
bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_data *sdata)
{
- struct ieee80211_if_sta *sta = &sdata->u.sta;
+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
/*
* As support for each feature is added, check for matching
@@ -58,11 +71,11 @@ bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_dat
* - MDA enabled
* - Power management control on fc
*/
- if (sta->mesh_id_len == ie->mesh_id_len &&
- memcmp(sta->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 &&
- memcmp(sta->mesh_pp_id, ie->mesh_config + PP_OFFSET, 4) == 0 &&
- memcmp(sta->mesh_pm_id, ie->mesh_config + PM_OFFSET, 4) == 0 &&
- memcmp(sta->mesh_cc_id, ie->mesh_config + CC_OFFSET, 4) == 0)
+ if (ifmsh->mesh_id_len == ie->mesh_id_len &&
+ memcmp(ifmsh->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 &&
+ memcmp(ifmsh->mesh_pp_id, ie->mesh_config + PP_OFFSET, 4) == 0 &&
+ memcmp(ifmsh->mesh_pm_id, ie->mesh_config + PM_OFFSET, 4) == 0 &&
+ memcmp(ifmsh->mesh_cc_id, ie->mesh_config + CC_OFFSET, 4) == 0)
return true;
return false;
@@ -95,11 +108,11 @@ void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata)
*/
free_plinks = mesh_plink_availables(sdata);
- if (free_plinks != sdata->u.sta.accepting_plinks)
- ieee80211_sta_timer((unsigned long) sdata);
+ if (free_plinks != sdata->u.mesh.accepting_plinks)
+ ieee80211_mesh_housekeeping_timer((unsigned long) sdata);
}
-void mesh_ids_set_default(struct ieee80211_if_sta *sta)
+void mesh_ids_set_default(struct ieee80211_if_mesh *sta)
{
u8 def_id[4] = {0x00, 0x0F, 0xAC, 0xff};
@@ -112,22 +125,22 @@ int mesh_rmc_init(struct ieee80211_sub_if_data *sdata)
{
int i;
- sdata->u.sta.rmc = kmalloc(sizeof(struct mesh_rmc), GFP_KERNEL);
- if (!sdata->u.sta.rmc)
+ sdata->u.mesh.rmc = kmalloc(sizeof(struct mesh_rmc), GFP_KERNEL);
+ if (!sdata->u.mesh.rmc)
return -ENOMEM;
- sdata->u.sta.rmc->idx_mask = RMC_BUCKETS - 1;
+ sdata->u.mesh.rmc->idx_mask = RMC_BUCKETS - 1;
for (i = 0; i < RMC_BUCKETS; i++)
- INIT_LIST_HEAD(&sdata->u.sta.rmc->bucket[i].list);
+ INIT_LIST_HEAD(&sdata->u.mesh.rmc->bucket[i].list);
return 0;
}
void mesh_rmc_free(struct ieee80211_sub_if_data *sdata)
{
- struct mesh_rmc *rmc = sdata->u.sta.rmc;
+ struct mesh_rmc *rmc = sdata->u.mesh.rmc;
struct rmc_entry *p, *n;
int i;
- if (!sdata->u.sta.rmc)
+ if (!sdata->u.mesh.rmc)
return;
for (i = 0; i < RMC_BUCKETS; i++)
@@ -137,7 +150,7 @@ void mesh_rmc_free(struct ieee80211_sub_if_data *sdata)
}
kfree(rmc);
- sdata->u.sta.rmc = NULL;
+ sdata->u.mesh.rmc = NULL;
}
/**
@@ -155,7 +168,7 @@ void mesh_rmc_free(struct ieee80211_sub_if_data *sdata)
int mesh_rmc_check(u8 *sa, struct ieee80211s_hdr *mesh_hdr,
struct ieee80211_sub_if_data *sdata)
{
- struct mesh_rmc *rmc = sdata->u.sta.rmc;
+ struct mesh_rmc *rmc = sdata->u.mesh.rmc;
u32 seqnum = 0;
int entries = 0;
u8 idx;
@@ -217,11 +230,11 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
}
}
- pos = skb_put(skb, 2 + sdata->u.sta.mesh_id_len);
+ pos = skb_put(skb, 2 + sdata->u.mesh.mesh_id_len);
*pos++ = WLAN_EID_MESH_ID;
- *pos++ = sdata->u.sta.mesh_id_len;
- if (sdata->u.sta.mesh_id_len)
- memcpy(pos, sdata->u.sta.mesh_id, sdata->u.sta.mesh_id_len);
+ *pos++ = sdata->u.mesh.mesh_id_len;
+ if (sdata->u.mesh.mesh_id_len)
+ memcpy(pos, sdata->u.mesh.mesh_id, sdata->u.mesh.mesh_id_len);
pos = skb_put(skb, 21);
*pos++ = WLAN_EID_MESH_CONFIG;
@@ -230,15 +243,15 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
*pos++ = 1;
/* Active path selection protocol ID */
- memcpy(pos, sdata->u.sta.mesh_pp_id, 4);
+ memcpy(pos, sdata->u.mesh.mesh_pp_id, 4);
pos += 4;
/* Active path selection metric ID */
- memcpy(pos, sdata->u.sta.mesh_pm_id, 4);
+ memcpy(pos, sdata->u.mesh.mesh_pm_id, 4);
pos += 4;
/* Congestion control mode identifier */
- memcpy(pos, sdata->u.sta.mesh_cc_id, 4);
+ memcpy(pos, sdata->u.mesh.mesh_cc_id, 4);
pos += 4;
/* Channel precedence:
@@ -248,8 +261,8 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
pos += 4;
/* Mesh capability */
- sdata->u.sta.accepting_plinks = mesh_plink_availables(sdata);
- *pos++ = sdata->u.sta.accepting_plinks ? ACCEPT_PLINKS : 0x00;
+ sdata->u.mesh.accepting_plinks = mesh_plink_availables(sdata);
+ *pos++ = sdata->u.mesh.accepting_plinks ? ACCEPT_PLINKS : 0x00;
*pos++ = 0x00;
return;
@@ -337,10 +350,10 @@ static void ieee80211_mesh_path_timer(unsigned long data)
{
struct ieee80211_sub_if_data *sdata =
(struct ieee80211_sub_if_data *) data;
- struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
struct ieee80211_local *local = wdev_priv(&sdata->wdev);
- queue_work(local->hw.workqueue, &ifsta->work);
+ queue_work(local->hw.workqueue, &ifmsh->work);
}
struct mesh_table *mesh_table_grow(struct mesh_table *tbl)
@@ -392,50 +405,264 @@ int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr,
struct ieee80211_sub_if_data *sdata)
{
meshhdr->flags = 0;
- meshhdr->ttl = sdata->u.sta.mshcfg.dot11MeshTTL;
- put_unaligned(cpu_to_le32(sdata->u.sta.mesh_seqnum), &meshhdr->seqnum);
- sdata->u.sta.mesh_seqnum++;
+ meshhdr->ttl = sdata->u.mesh.mshcfg.dot11MeshTTL;
+ put_unaligned(cpu_to_le32(sdata->u.mesh.mesh_seqnum), &meshhdr->seqnum);
+ sdata->u.mesh.mesh_seqnum++;
return 6;
}
+static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_if_mesh *ifmsh)
+{
+ bool free_plinks;
+
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+ printk(KERN_DEBUG "%s: running mesh housekeeping\n",
+ sdata->dev->name);
+#endif
+
+ ieee80211_sta_expire(sdata, IEEE80211_MESH_PEER_INACTIVITY_LIMIT);
+ mesh_path_expire(sdata);
+
+ free_plinks = mesh_plink_availables(sdata);
+ if (free_plinks != sdata->u.mesh.accepting_plinks)
+ ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON);
+
+ ifmsh->housekeeping = false;
+ mod_timer(&ifmsh->housekeeping_timer,
+ round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL));
+}
+
+
+void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+ struct ieee80211_local *local = sdata->local;
+
+ ifmsh->housekeeping = true;
+ queue_work(local->hw.workqueue, &ifmsh->work);
+ ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON);
+}
+
+void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
+{
+ del_timer_sync(&sdata->u.mesh.housekeeping_timer);
+ /*
+ * If the timer fired while we waited for it, it will have
+ * requeued the work. Now the work will be running again
+ * but will not rearm the timer again because it checks
+ * whether the interface is running, which, at this point,
+ * it no longer is.
+ */
+ cancel_work_sync(&sdata->u.mesh.work);
+
+ /*
+ * When we get here, the interface is marked down.
+ * Call synchronize_rcu() to wait for the RX path
+ * should it be using the interface and enqueuing
+ * frames at this very time on another CPU.
+ */
+ synchronize_rcu();
+ skb_queue_purge(&sdata->u.mesh.skb_queue);
+}
+
+static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
+ u16 stype,
+ struct ieee80211_mgmt *mgmt,
+ size_t len,
+ struct ieee80211_rx_status *rx_status)
+{
+ struct ieee80211_local *local= sdata->local;
+ struct ieee802_11_elems elems;
+ struct ieee80211_channel *channel;
+ u64 supp_rates = 0;
+ size_t baselen;
+ int freq;
+ enum ieee80211_band band = rx_status->band;
+
+ /* ignore ProbeResp to foreign address */
+ if (stype == IEEE80211_STYPE_PROBE_RESP &&
+ compare_ether_addr(mgmt->da, sdata->dev->dev_addr))
+ return;
+
+ baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
+ if (baselen > len)
+ return;
+
+ ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
+ &elems);
+
+ if (elems.ds_params && elems.ds_params_len == 1)
+ freq = ieee80211_channel_to_frequency(elems.ds_params[0]);
+ else
+ freq = rx_status->freq;
+
+ channel = ieee80211_get_channel(local->hw.wiphy, freq);
+
+ if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
+ return;
+
+ if (elems.mesh_id && elems.mesh_config &&
+ mesh_matches_local(&elems, sdata)) {
+ supp_rates = ieee80211_sta_get_rates(local, &elems, band);
+
+ mesh_neighbour_update(mgmt->sa, supp_rates, sdata,
+ mesh_peer_accepts_plinks(&elems));
+ }
+}
+
+static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_mgmt *mgmt,
+ size_t len,
+ struct ieee80211_rx_status *rx_status)
+{
+ switch (mgmt->u.action.category) {
+ case PLINK_CATEGORY:
+ mesh_rx_plink_frame(sdata, mgmt, len, rx_status);
+ break;
+ case MESH_PATH_SEL_CATEGORY:
+ mesh_rx_path_sel_frame(sdata, mgmt, len);
+ break;
+ }
+}
+
+static void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
+ struct sk_buff *skb)
+{
+ struct ieee80211_rx_status *rx_status;
+ struct ieee80211_if_mesh *ifmsh;
+ struct ieee80211_mgmt *mgmt;
+ u16 stype;
+
+ ifmsh = &sdata->u.mesh;
+
+ rx_status = (struct ieee80211_rx_status *) skb->cb;
+ mgmt = (struct ieee80211_mgmt *) skb->data;
+ stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE;
+
+ switch (stype) {
+ case IEEE80211_STYPE_PROBE_RESP:
+ case IEEE80211_STYPE_BEACON:
+ ieee80211_mesh_rx_bcn_presp(sdata, stype, mgmt, skb->len,
+ rx_status);
+ break;
+ case IEEE80211_STYPE_ACTION:
+ ieee80211_mesh_rx_mgmt_action(sdata, mgmt, skb->len, rx_status);
+ break;
+ }
+
+ kfree_skb(skb);
+}
+
+static void ieee80211_mesh_work(struct work_struct *work)
+{
+ struct ieee80211_sub_if_data *sdata =
+ container_of(work, struct ieee80211_sub_if_data, u.mesh.work);
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+ struct sk_buff *skb;
+
+ if (!netif_running(sdata->dev))
+ return;
+
+ if (local->sw_scanning || local->hw_scanning)
+ return;
+
+ while ((skb = skb_dequeue(&ifmsh->skb_queue)))
+ ieee80211_mesh_rx_queued_mgmt(sdata, skb);
+
+ if (ifmsh->preq_queue_len &&
+ time_after(jiffies,
+ ifmsh->last_preq + msecs_to_jiffies(ifmsh->mshcfg.dot11MeshHWMPpreqMinInterval)))
+ mesh_path_start_discovery(sdata);
+
+ if (ifmsh->housekeeping)
+ ieee80211_mesh_housekeeping(sdata, ifmsh);
+}
+
+void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local)
+{
+ struct ieee80211_sub_if_data *sdata;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(sdata, &local->interfaces, list)
+ if (ieee80211_vif_is_mesh(&sdata->vif))
+ queue_work(local->hw.workqueue, &sdata->u.mesh.work);
+ rcu_read_unlock();
+}
+
void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
{
- struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
- ifsta->mshcfg.dot11MeshRetryTimeout = MESH_RET_T;
- ifsta->mshcfg.dot11MeshConfirmTimeout = MESH_CONF_T;
- ifsta->mshcfg.dot11MeshHoldingTimeout = MESH_HOLD_T;
- ifsta->mshcfg.dot11MeshMaxRetries = MESH_MAX_RETR;
- ifsta->mshcfg.dot11MeshTTL = MESH_TTL;
- ifsta->mshcfg.auto_open_plinks = true;
- ifsta->mshcfg.dot11MeshMaxPeerLinks =
+ INIT_WORK(&ifmsh->work, ieee80211_mesh_work);
+ setup_timer(&ifmsh->housekeeping_timer,
+ ieee80211_mesh_housekeeping_timer,
+ (unsigned long) sdata);
+ skb_queue_head_init(&sdata->u.mesh.skb_queue);
+
+ ifmsh->mshcfg.dot11MeshRetryTimeout = MESH_RET_T;
+ ifmsh->mshcfg.dot11MeshConfirmTimeout = MESH_CONF_T;
+ ifmsh->mshcfg.dot11MeshHoldingTimeout = MESH_HOLD_T;
+ ifmsh->mshcfg.dot11MeshMaxRetries = MESH_MAX_RETR;
+ ifmsh->mshcfg.dot11MeshTTL = MESH_TTL;
+ ifmsh->mshcfg.auto_open_plinks = true;
+ ifmsh->mshcfg.dot11MeshMaxPeerLinks =
MESH_MAX_ESTAB_PLINKS;
- ifsta->mshcfg.dot11MeshHWMPactivePathTimeout =
+ ifmsh->mshcfg.dot11MeshHWMPactivePathTimeout =
MESH_PATH_TIMEOUT;
- ifsta->mshcfg.dot11MeshHWMPpreqMinInterval =
+ ifmsh->mshcfg.dot11MeshHWMPpreqMinInterval =
MESH_PREQ_MIN_INT;
- ifsta->mshcfg.dot11MeshHWMPnetDiameterTraversalTime =
+ ifmsh->mshcfg.dot11MeshHWMPnetDiameterTraversalTime =
MESH_DIAM_TRAVERSAL_TIME;
- ifsta->mshcfg.dot11MeshHWMPmaxPREQretries =
+ ifmsh->mshcfg.dot11MeshHWMPmaxPREQretries =
MESH_MAX_PREQ_RETRIES;
- ifsta->mshcfg.path_refresh_time =
+ ifmsh->mshcfg.path_refresh_time =
MESH_PATH_REFRESH_TIME;
- ifsta->mshcfg.min_discovery_timeout =
+ ifmsh->mshcfg.min_discovery_timeout =
MESH_MIN_DISCOVERY_TIMEOUT;
- ifsta->accepting_plinks = true;
- ifsta->preq_id = 0;
- ifsta->dsn = 0;
- atomic_set(&ifsta->mpaths, 0);
+ ifmsh->accepting_plinks = true;
+ ifmsh->preq_id = 0;
+ ifmsh->dsn = 0;
+ atomic_set(&ifmsh->mpaths, 0);
mesh_rmc_init(sdata);
- ifsta->last_preq = jiffies;
+ ifmsh->last_preq = jiffies;
/* Allocate all mesh structures when creating the first mesh interface. */
if (!mesh_allocated)
ieee80211s_init();
- mesh_ids_set_default(ifsta);
- setup_timer(&ifsta->mesh_path_timer,
+ mesh_ids_set_default(ifmsh);
+ setup_timer(&ifmsh->mesh_path_timer,
ieee80211_mesh_path_timer,
(unsigned long) sdata);
- INIT_LIST_HEAD(&ifsta->preq_queue.list);
- spin_lock_init(&ifsta->mesh_preq_queue_lock);
+ INIT_LIST_HEAD(&ifmsh->preq_queue.list);
+ spin_lock_init(&ifmsh->mesh_preq_queue_lock);
+}
+
+ieee80211_rx_result
+ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
+ struct ieee80211_rx_status *rx_status)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+ struct ieee80211_mgmt *mgmt;
+ u16 fc;
+
+ if (skb->len < 24)
+ return RX_DROP_MONITOR;
+
+ mgmt = (struct ieee80211_mgmt *) skb->data;
+ fc = le16_to_cpu(mgmt->frame_control);
+
+ switch (fc & IEEE80211_FCTL_STYPE) {
+ case IEEE80211_STYPE_PROBE_RESP:
+ case IEEE80211_STYPE_BEACON:
+ case IEEE80211_STYPE_ACTION:
+ memcpy(skb->cb, rx_status, sizeof(*rx_status));
+ skb_queue_tail(&ifmsh->skb_queue, skb);
+ queue_work(local->hw.workqueue, &ifmsh->work);
+ return RX_QUEUED;
+ }
+
+ return RX_CONTINUE;
}
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index 84ff5d828fdb..8ee414a0447c 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -206,7 +206,7 @@ int mesh_rmc_check(u8 *addr, struct ieee80211s_hdr *mesh_hdr,
struct ieee80211_sub_if_data *sdata);
bool mesh_matches_local(struct ieee802_11_elems *ie,
struct ieee80211_sub_if_data *sdata);
-void mesh_ids_set_default(struct ieee80211_if_sta *sta);
+void mesh_ids_set_default(struct ieee80211_if_mesh *mesh);
void mesh_mgmt_ies_add(struct sk_buff *skb,
struct ieee80211_sub_if_data *sdata);
void mesh_rmc_free(struct ieee80211_sub_if_data *sdata);
@@ -214,6 +214,11 @@ int mesh_rmc_init(struct ieee80211_sub_if_data *sdata);
void ieee80211s_init(void);
void ieee80211s_stop(void);
void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata);
+ieee80211_rx_result
+ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
+ struct ieee80211_rx_status *rx_status);
+void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata);
+void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata);
/* Mesh paths */
int mesh_nexthop_lookup(struct sk_buff *skb,
@@ -269,8 +274,8 @@ extern int mesh_allocated;
static inline int mesh_plink_free_count(struct ieee80211_sub_if_data *sdata)
{
- return sdata->u.sta.mshcfg.dot11MeshMaxPeerLinks -
- atomic_read(&sdata->u.sta.mshstats.estab_plinks);
+ return sdata->u.mesh.mshcfg.dot11MeshMaxPeerLinks -
+ atomic_read(&sdata->u.mesh.mshstats.estab_plinks);
}
static inline bool mesh_plink_availables(struct ieee80211_sub_if_data *sdata)
@@ -288,8 +293,12 @@ static inline void mesh_path_activate(struct mesh_path *mpath)
for (i = 0; i <= x->hash_mask; i++) \
hlist_for_each_entry_rcu(node, p, &x->hash_buckets[i], list)
+void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local);
+
#else
#define mesh_allocated 0
+static inline void
+ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) {}
#endif
#endif /* IEEE80211S_H */
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index 210d6b852406..501c7831adb4 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -64,14 +64,14 @@ static inline u32 u32_field_get(u8 *preq_elem, int offset, bool ae)
#define DSN_LT(x, y) ((long) (x) - (long) (y) < 0)
#define net_traversal_jiffies(s) \
- msecs_to_jiffies(s->u.sta.mshcfg.dot11MeshHWMPnetDiameterTraversalTime)
+ msecs_to_jiffies(s->u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime)
#define default_lifetime(s) \
- MSEC_TO_TU(s->u.sta.mshcfg.dot11MeshHWMPactivePathTimeout)
+ MSEC_TO_TU(s->u.mesh.mshcfg.dot11MeshHWMPactivePathTimeout)
#define min_preq_int_jiff(s) \
- (msecs_to_jiffies(s->u.sta.mshcfg.dot11MeshHWMPpreqMinInterval))
-#define max_preq_retries(s) (s->u.sta.mshcfg.dot11MeshHWMPmaxPREQretries)
+ (msecs_to_jiffies(s->u.mesh.mshcfg.dot11MeshHWMPpreqMinInterval))
+#define max_preq_retries(s) (s->u.mesh.mshcfg.dot11MeshHWMPmaxPREQretries)
#define disc_timeout_jiff(s) \
- msecs_to_jiffies(sdata->u.sta.mshcfg.min_discovery_timeout)
+ msecs_to_jiffies(sdata->u.mesh.mshcfg.min_discovery_timeout)
enum mpath_frame_type {
MPATH_PREQ = 0,
@@ -223,7 +223,7 @@ static u32 airtime_link_metric_get(struct ieee80211_local *local,
/* bitrate is in units of 100 Kbps, while we need rate in units of
* 1Mbps. This will be corrected on tx_time computation.
*/
- rate = sband->bitrates[sta->txrate_idx].bitrate;
+ rate = sband->bitrates[sta->last_txrate_idx].bitrate;
tx_time = (device_constant + 10 * test_frame_len / rate);
estimated_retx = ((1 << (2 * ARITH_SHIFT)) / (s_unit - err));
result = (tx_time * estimated_retx) >> (2 * ARITH_SHIFT) ;
@@ -395,7 +395,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata,
static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt,
u8 *preq_elem, u32 metric) {
- struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
struct mesh_path *mpath;
u8 *dst_addr, *orig_addr;
u8 dst_flags, ttl;
@@ -414,11 +414,11 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
forward = false;
reply = true;
metric = 0;
- if (time_after(jiffies, ifsta->last_dsn_update +
+ if (time_after(jiffies, ifmsh->last_dsn_update +
net_traversal_jiffies(sdata)) ||
- time_before(jiffies, ifsta->last_dsn_update)) {
- dst_dsn = ++ifsta->dsn;
- ifsta->last_dsn_update = jiffies;
+ time_before(jiffies, ifmsh->last_dsn_update)) {
+ dst_dsn = ++ifmsh->dsn;
+ ifmsh->last_dsn_update = jiffies;
}
} else {
rcu_read_lock();
@@ -444,7 +444,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
if (reply) {
lifetime = PREQ_IE_LIFETIME(preq_elem);
- ttl = ifsta->mshcfg.dot11MeshTTL;
+ ttl = ifmsh->mshcfg.dot11MeshTTL;
if (ttl != 0)
mesh_path_sel_frame_tx(MPATH_PREP, 0, dst_addr,
cpu_to_le32(dst_dsn), 0, orig_addr,
@@ -452,7 +452,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
cpu_to_le32(lifetime), cpu_to_le32(metric),
0, sdata);
else
- ifsta->mshstats.dropped_frames_ttl++;
+ ifmsh->mshstats.dropped_frames_ttl++;
}
if (forward) {
@@ -462,7 +462,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
ttl = PREQ_IE_TTL(preq_elem);
lifetime = PREQ_IE_LIFETIME(preq_elem);
if (ttl <= 1) {
- ifsta->mshstats.dropped_frames_ttl++;
+ ifmsh->mshstats.dropped_frames_ttl++;
return;
}
--ttl;
@@ -475,7 +475,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
hopcount, ttl, cpu_to_le32(lifetime),
cpu_to_le32(metric), cpu_to_le32(preq_id),
sdata);
- ifsta->mshstats.fwded_frames++;
+ ifmsh->mshstats.fwded_frames++;
}
}
@@ -503,7 +503,7 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata,
ttl = PREP_IE_TTL(prep_elem);
if (ttl <= 1) {
- sdata->u.sta.mshstats.dropped_frames_ttl++;
+ sdata->u.mesh.mshstats.dropped_frames_ttl++;
return;
}
@@ -517,7 +517,7 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata,
spin_unlock_bh(&mpath->state_lock);
goto fail;
}
- memcpy(next_hop, mpath->next_hop->addr, ETH_ALEN);
+ memcpy(next_hop, mpath->next_hop->sta.addr, ETH_ALEN);
spin_unlock_bh(&mpath->state_lock);
--ttl;
flags = PREP_IE_FLAGS(prep_elem);
@@ -529,16 +529,16 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata,
mesh_path_sel_frame_tx(MPATH_PREP, flags, orig_addr,
cpu_to_le32(orig_dsn), 0, dst_addr,
- cpu_to_le32(dst_dsn), mpath->next_hop->addr, hopcount, ttl,
+ cpu_to_le32(dst_dsn), mpath->next_hop->sta.addr, hopcount, ttl,
cpu_to_le32(lifetime), cpu_to_le32(metric),
0, sdata);
rcu_read_unlock();
- sdata->u.sta.mshstats.fwded_frames++;
+ sdata->u.mesh.mshstats.fwded_frames++;
return;
fail:
rcu_read_unlock();
- sdata->u.sta.mshstats.dropped_frames_no_route++;
+ sdata->u.mesh.mshstats.dropped_frames_no_route++;
return;
}
@@ -557,7 +557,7 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata,
if (mpath) {
spin_lock_bh(&mpath->state_lock);
if (mpath->flags & MESH_PATH_ACTIVE &&
- memcmp(ta, mpath->next_hop->addr, ETH_ALEN) == 0 &&
+ memcmp(ta, mpath->next_hop->sta.addr, ETH_ALEN) == 0 &&
(!(mpath->flags & MESH_PATH_DSN_VALID) ||
DSN_GT(dst_dsn, mpath->dsn))) {
mpath->flags &= ~MESH_PATH_ACTIVE;
@@ -631,7 +631,7 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,
static void mesh_queue_preq(struct mesh_path *mpath, u8 flags)
{
struct ieee80211_sub_if_data *sdata = mpath->sdata;
- struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
struct mesh_preq_queue *preq_node;
preq_node = kmalloc(sizeof(struct mesh_preq_queue), GFP_KERNEL);
@@ -640,9 +640,9 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags)
return;
}
- spin_lock(&ifsta->mesh_preq_queue_lock);
- if (ifsta->preq_queue_len == MAX_PREQ_QUEUE_LEN) {
- spin_unlock(&ifsta->mesh_preq_queue_lock);
+ spin_lock(&ifmsh->mesh_preq_queue_lock);
+ if (ifmsh->preq_queue_len == MAX_PREQ_QUEUE_LEN) {
+ spin_unlock(&ifmsh->mesh_preq_queue_lock);
kfree(preq_node);
if (printk_ratelimit())
printk(KERN_DEBUG "Mesh HWMP: PREQ node queue full\n");
@@ -652,21 +652,21 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags)
memcpy(preq_node->dst, mpath->dst, ETH_ALEN);
preq_node->flags = flags;
- list_add_tail(&preq_node->list, &ifsta->preq_queue.list);
- ++ifsta->preq_queue_len;
- spin_unlock(&ifsta->mesh_preq_queue_lock);
+ list_add_tail(&preq_node->list, &ifmsh->preq_queue.list);
+ ++ifmsh->preq_queue_len;
+ spin_unlock(&ifmsh->mesh_preq_queue_lock);
- if (time_after(jiffies, ifsta->last_preq + min_preq_int_jiff(sdata)))
- queue_work(sdata->local->hw.workqueue, &ifsta->work);
+ if (time_after(jiffies, ifmsh->last_preq + min_preq_int_jiff(sdata)))
+ queue_work(sdata->local->hw.workqueue, &ifmsh->work);
- else if (time_before(jiffies, ifsta->last_preq)) {
+ else if (time_before(jiffies, ifmsh->last_preq)) {
/* avoid long wait if did not send preqs for a long time
* and jiffies wrapped around
*/
- ifsta->last_preq = jiffies - min_preq_int_jiff(sdata) - 1;
- queue_work(sdata->local->hw.workqueue, &ifsta->work);
+ ifmsh->last_preq = jiffies - min_preq_int_jiff(sdata) - 1;
+ queue_work(sdata->local->hw.workqueue, &ifmsh->work);
} else
- mod_timer(&ifsta->mesh_path_timer, ifsta->last_preq +
+ mod_timer(&ifmsh->mesh_path_timer, ifmsh->last_preq +
min_preq_int_jiff(sdata));
}
@@ -677,25 +677,25 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags)
*/
void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata)
{
- struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
struct mesh_preq_queue *preq_node;
struct mesh_path *mpath;
u8 ttl, dst_flags;
u32 lifetime;
- spin_lock(&ifsta->mesh_preq_queue_lock);
- if (!ifsta->preq_queue_len ||
- time_before(jiffies, ifsta->last_preq +
+ spin_lock(&ifmsh->mesh_preq_queue_lock);
+ if (!ifmsh->preq_queue_len ||
+ time_before(jiffies, ifmsh->last_preq +
min_preq_int_jiff(sdata))) {
- spin_unlock(&ifsta->mesh_preq_queue_lock);
+ spin_unlock(&ifmsh->mesh_preq_queue_lock);
return;
}
- preq_node = list_first_entry(&ifsta->preq_queue.list,
+ preq_node = list_first_entry(&ifmsh->preq_queue.list,
struct mesh_preq_queue, list);
list_del(&preq_node->list);
- --ifsta->preq_queue_len;
- spin_unlock(&ifsta->mesh_preq_queue_lock);
+ --ifmsh->preq_queue_len;
+ spin_unlock(&ifmsh->mesh_preq_queue_lock);
rcu_read_lock();
mpath = mesh_path_lookup(preq_node->dst, sdata);
@@ -720,18 +720,18 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata)
goto enddiscovery;
}
- ifsta->last_preq = jiffies;
+ ifmsh->last_preq = jiffies;
- if (time_after(jiffies, ifsta->last_dsn_update +
+ if (time_after(jiffies, ifmsh->last_dsn_update +
net_traversal_jiffies(sdata)) ||
- time_before(jiffies, ifsta->last_dsn_update)) {
- ++ifsta->dsn;
- sdata->u.sta.last_dsn_update = jiffies;
+ time_before(jiffies, ifmsh->last_dsn_update)) {
+ ++ifmsh->dsn;
+ sdata->u.mesh.last_dsn_update = jiffies;
}
lifetime = default_lifetime(sdata);
- ttl = sdata->u.sta.mshcfg.dot11MeshTTL;
+ ttl = sdata->u.mesh.mshcfg.dot11MeshTTL;
if (ttl == 0) {
- sdata->u.sta.mshstats.dropped_frames_ttl++;
+ sdata->u.mesh.mshstats.dropped_frames_ttl++;
spin_unlock_bh(&mpath->state_lock);
goto enddiscovery;
}
@@ -743,10 +743,10 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata)
spin_unlock_bh(&mpath->state_lock);
mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->dev->dev_addr,
- cpu_to_le32(ifsta->dsn), dst_flags, mpath->dst,
+ cpu_to_le32(ifmsh->dsn), dst_flags, mpath->dst,
cpu_to_le32(mpath->dsn), sdata->dev->broadcast, 0,
ttl, cpu_to_le32(lifetime), 0,
- cpu_to_le32(ifsta->preq_id++), sdata);
+ cpu_to_le32(ifmsh->preq_id++), sdata);
mod_timer(&mpath->timer, jiffies + mpath->discovery_timeout);
enddiscovery:
@@ -783,7 +783,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
mpath = mesh_path_lookup(dst_addr, sdata);
if (!mpath) {
dev_kfree_skb(skb);
- sdata->u.sta.mshstats.dropped_frames_no_route++;
+ sdata->u.mesh.mshstats.dropped_frames_no_route++;
err = -ENOSPC;
goto endlookup;
}
@@ -791,7 +791,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
if (mpath->flags & MESH_PATH_ACTIVE) {
if (time_after(jiffies, mpath->exp_time -
- msecs_to_jiffies(sdata->u.sta.mshcfg.path_refresh_time))
+ msecs_to_jiffies(sdata->u.mesh.mshcfg.path_refresh_time))
&& !memcmp(sdata->dev->dev_addr, hdr->addr4,
ETH_ALEN)
&& !(mpath->flags & MESH_PATH_RESOLVING)
@@ -799,7 +799,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
mesh_queue_preq(mpath,
PREQ_Q_F_START | PREQ_Q_F_REFRESH);
}
- memcpy(hdr->addr1, mpath->next_hop->addr,
+ memcpy(hdr->addr1, mpath->next_hop->sta.addr,
ETH_ALEN);
} else {
if (!(mpath->flags & MESH_PATH_RESOLVING)) {
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 0a60f55f32ab..e4fa2905fadc 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -153,7 +153,7 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata)
if (is_multicast_ether_addr(dst))
return -ENOTSUPP;
- if (atomic_add_unless(&sdata->u.sta.mpaths, 1, MESH_MAX_MPATHS) == 0)
+ if (atomic_add_unless(&sdata->u.mesh.mpaths, 1, MESH_MAX_MPATHS) == 0)
return -ENOSPC;
err = -ENOMEM;
@@ -221,7 +221,7 @@ err_exists:
err_node_alloc:
kfree(new_mpath);
err_path_alloc:
- atomic_dec(&sdata->u.sta.mpaths);
+ atomic_dec(&sdata->u.mesh.mpaths);
return err;
}
@@ -306,7 +306,7 @@ static void mesh_path_node_reclaim(struct rcu_head *rp)
struct ieee80211_sub_if_data *sdata = node->mpath->sdata;
del_timer_sync(&node->mpath->timer);
- atomic_dec(&sdata->u.sta.mpaths);
+ atomic_dec(&sdata->u.mesh.mpaths);
kfree(node->mpath);
kfree(node);
}
@@ -401,7 +401,7 @@ void mesh_path_discard_frame(struct sk_buff *skb,
}
kfree_skb(skb);
- sdata->u.sta.mshstats.dropped_frames_no_route++;
+ sdata->u.mesh.mshstats.dropped_frames_no_route++;
}
/**
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 7356462dee96..faac101c0f85 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -36,11 +36,11 @@
#define MESH_SECURITY_AUTHENTICATION_IMPOSSIBLE 9
#define MESH_SECURITY_FAILED_VERIFICATION 10
-#define dot11MeshMaxRetries(s) (s->u.sta.mshcfg.dot11MeshMaxRetries)
-#define dot11MeshRetryTimeout(s) (s->u.sta.mshcfg.dot11MeshRetryTimeout)
-#define dot11MeshConfirmTimeout(s) (s->u.sta.mshcfg.dot11MeshConfirmTimeout)
-#define dot11MeshHoldingTimeout(s) (s->u.sta.mshcfg.dot11MeshHoldingTimeout)
-#define dot11MeshMaxPeerLinks(s) (s->u.sta.mshcfg.dot11MeshMaxPeerLinks)
+#define dot11MeshMaxRetries(s) (s->u.mesh.mshcfg.dot11MeshMaxRetries)
+#define dot11MeshRetryTimeout(s) (s->u.mesh.mshcfg.dot11MeshRetryTimeout)
+#define dot11MeshConfirmTimeout(s) (s->u.mesh.mshcfg.dot11MeshConfirmTimeout)
+#define dot11MeshHoldingTimeout(s) (s->u.mesh.mshcfg.dot11MeshHoldingTimeout)
+#define dot11MeshMaxPeerLinks(s) (s->u.mesh.mshcfg.dot11MeshMaxPeerLinks)
enum plink_frame_type {
PLINK_OPEN = 0,
@@ -63,14 +63,14 @@ enum plink_event {
static inline
void mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata)
{
- atomic_inc(&sdata->u.sta.mshstats.estab_plinks);
+ atomic_inc(&sdata->u.mesh.mshstats.estab_plinks);
mesh_accept_plinks_update(sdata);
}
static inline
void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata)
{
- atomic_dec(&sdata->u.sta.mshstats.estab_plinks);
+ atomic_dec(&sdata->u.mesh.mshstats.estab_plinks);
mesh_accept_plinks_update(sdata);
}
@@ -106,7 +106,7 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
return NULL;
sta->flags = WLAN_STA_AUTHORIZED;
- sta->supp_rates[local->hw.conf.channel->band] = rates;
+ sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
return sta;
}
@@ -243,10 +243,10 @@ void mesh_neighbour_update(u8 *hw_addr, u64 rates, struct ieee80211_sub_if_data
}
sta->last_rx = jiffies;
- sta->supp_rates[local->hw.conf.channel->band] = rates;
+ sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
if (peer_accepting_plinks && sta->plink_state == PLINK_LISTEN &&
- sdata->u.sta.accepting_plinks &&
- sdata->u.sta.mshcfg.auto_open_plinks)
+ sdata->u.mesh.accepting_plinks &&
+ sdata->u.mesh.mshcfg.auto_open_plinks)
mesh_plink_open(sta);
rcu_read_unlock();
@@ -275,7 +275,7 @@ static void mesh_plink_timer(unsigned long data)
return;
}
mpl_dbg("Mesh plink timer for %s fired on state %d\n",
- print_mac(mac, sta->addr), sta->plink_state);
+ print_mac(mac, sta->sta.addr), sta->plink_state);
reason = 0;
llid = sta->llid;
plid = sta->plid;
@@ -288,7 +288,7 @@ static void mesh_plink_timer(unsigned long data)
if (sta->plink_retries < dot11MeshMaxRetries(sdata)) {
u32 rand;
mpl_dbg("Mesh plink for %s (retry, timeout): %d %d\n",
- print_mac(mac, sta->addr),
+ print_mac(mac, sta->sta.addr),
sta->plink_retries, sta->plink_timeout);
get_random_bytes(&rand, sizeof(u32));
sta->plink_timeout = sta->plink_timeout +
@@ -296,7 +296,7 @@ static void mesh_plink_timer(unsigned long data)
++sta->plink_retries;
mod_plink_timer(sta, sta->plink_timeout);
spin_unlock_bh(&sta->lock);
- mesh_plink_frame_tx(sdata, PLINK_OPEN, sta->addr, llid,
+ mesh_plink_frame_tx(sdata, PLINK_OPEN, sta->sta.addr, llid,
0, 0);
break;
}
@@ -309,7 +309,7 @@ static void mesh_plink_timer(unsigned long data)
sta->plink_state = PLINK_HOLDING;
mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
spin_unlock_bh(&sta->lock);
- mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->addr, llid, plid,
+ mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid, plid,
reason);
break;
case PLINK_HOLDING:
@@ -352,10 +352,10 @@ int mesh_plink_open(struct sta_info *sta)
mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata));
spin_unlock_bh(&sta->lock);
mpl_dbg("Mesh plink: starting establishment with %s\n",
- print_mac(mac, sta->addr));
+ print_mac(mac, sta->sta.addr));
return mesh_plink_frame_tx(sdata, PLINK_OPEN,
- sta->addr, llid, 0, 0);
+ sta->sta.addr, llid, 0, 0);
}
void mesh_plink_block(struct sta_info *sta)
@@ -379,7 +379,7 @@ int mesh_plink_close(struct sta_info *sta)
#endif
mpl_dbg("Mesh plink: closing link with %s\n",
- print_mac(mac, sta->addr));
+ print_mac(mac, sta->sta.addr));
spin_lock_bh(&sta->lock);
sta->reason = cpu_to_le16(MESH_LINK_CANCELLED);
reason = sta->reason;
@@ -400,7 +400,7 @@ int mesh_plink_close(struct sta_info *sta)
llid = sta->llid;
plid = sta->plid;
spin_unlock_bh(&sta->lock);
- mesh_plink_frame_tx(sta->sdata, PLINK_CLOSE, sta->addr, llid,
+ mesh_plink_frame_tx(sta->sdata, PLINK_CLOSE, sta->sta.addr, llid,
plid, reason);
return 0;
}
@@ -577,9 +577,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
sta->llid = llid;
mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata));
spin_unlock_bh(&sta->lock);
- mesh_plink_frame_tx(sdata, PLINK_OPEN, sta->addr, llid,
+ mesh_plink_frame_tx(sdata, PLINK_OPEN, sta->sta.addr, llid,
0, 0);
- mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->addr,
+ mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr,
llid, plid, 0);
break;
default:
@@ -604,7 +604,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
llid = sta->llid;
spin_unlock_bh(&sta->lock);
- mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->addr, llid,
+ mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid,
plid, reason);
break;
case OPN_ACPT:
@@ -613,7 +613,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
sta->plid = plid;
llid = sta->llid;
spin_unlock_bh(&sta->lock);
- mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->addr, llid,
+ mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr, llid,
plid, 0);
break;
case CNF_ACPT:
@@ -646,13 +646,13 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
llid = sta->llid;
spin_unlock_bh(&sta->lock);
- mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->addr, llid,
+ mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid,
plid, reason);
break;
case OPN_ACPT:
llid = sta->llid;
spin_unlock_bh(&sta->lock);
- mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->addr, llid,
+ mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr, llid,
plid, 0);
break;
case CNF_ACPT:
@@ -661,7 +661,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
mesh_plink_inc_estab_count(sdata);
spin_unlock_bh(&sta->lock);
mpl_dbg("Mesh plink with %s ESTABLISHED\n",
- print_mac(mac, sta->addr));
+ print_mac(mac, sta->sta.addr));
break;
default:
spin_unlock_bh(&sta->lock);
@@ -685,7 +685,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
llid = sta->llid;
spin_unlock_bh(&sta->lock);
- mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->addr, llid,
+ mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid,
plid, reason);
break;
case OPN_ACPT:
@@ -694,8 +694,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
mesh_plink_inc_estab_count(sdata);
spin_unlock_bh(&sta->lock);
mpl_dbg("Mesh plink with %s ESTABLISHED\n",
- print_mac(mac, sta->addr));
- mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->addr, llid,
+ print_mac(mac, sta->sta.addr));
+ mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr, llid,
plid, 0);
break;
default:
@@ -714,13 +714,13 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
llid = sta->llid;
mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
spin_unlock_bh(&sta->lock);
- mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->addr, llid,
+ mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid,
plid, reason);
break;
case OPN_ACPT:
llid = sta->llid;
spin_unlock_bh(&sta->lock);
- mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->addr, llid,
+ mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr, llid,
plid, 0);
break;
default:
@@ -743,8 +743,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
llid = sta->llid;
reason = sta->reason;
spin_unlock_bh(&sta->lock);
- mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->addr, llid,
- plid, reason);
+ mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr,
+ llid, plid, reason);
break;
default:
spin_unlock_bh(&sta->lock);
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 2c06f6965b7d..8611a8318c9c 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -22,11 +22,11 @@
#include
#include
#include
+#include
#include "ieee80211_i.h"
#include "rate.h"
#include "led.h"
-#include "mesh.h"
#define IEEE80211_ASSOC_SCANS_MAX_TRIES 2
#define IEEE80211_AUTH_TIMEOUT (HZ / 5)
@@ -34,7 +34,6 @@
#define IEEE80211_ASSOC_TIMEOUT (HZ / 5)
#define IEEE80211_ASSOC_MAX_TRIES 3
#define IEEE80211_MONITORING_INTERVAL (2 * HZ)
-#define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ)
#define IEEE80211_PROBE_INTERVAL (60 * HZ)
#define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ)
#define IEEE80211_SCAN_INTERVAL (2 * HZ)
@@ -43,7 +42,6 @@
#define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ)
#define IEEE80211_IBSS_INACTIVITY_LIMIT (60 * HZ)
-#define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ)
#define IEEE80211_IBSS_MAX_STA_ENTRIES 128
@@ -54,7 +52,7 @@ static int ecw2cw(int ecw)
return (1 << ecw) - 1;
}
-static u8 *ieee80211_bss_get_ie(struct ieee80211_sta_bss *bss, u8 ie)
+static u8 *ieee80211_bss_get_ie(struct ieee80211_bss *bss, u8 ie)
{
u8 *end, *pos;
@@ -74,7 +72,7 @@ static u8 *ieee80211_bss_get_ie(struct ieee80211_sta_bss *bss, u8 ie)
return NULL;
}
-static int ieee80211_compatible_rates(struct ieee80211_sta_bss *bss,
+static int ieee80211_compatible_rates(struct ieee80211_bss *bss,
struct ieee80211_supported_band *sband,
u64 *rates)
{
@@ -95,44 +93,46 @@ static int ieee80211_compatible_rates(struct ieee80211_sta_bss *bss,
return count;
}
-/* frame sending functions */
-static void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_if_sta *ifsta,
- int transaction, u8 *extra, size_t extra_len,
- int encrypt)
+/* also used by mesh code */
+u64 ieee80211_sta_get_rates(struct ieee80211_local *local,
+ struct ieee802_11_elems *elems,
+ enum ieee80211_band band)
{
- struct ieee80211_local *local = sdata->local;
- struct sk_buff *skb;
- struct ieee80211_mgmt *mgmt;
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_rate *bitrates;
+ size_t num_rates;
+ u64 supp_rates;
+ int i, j;
+ sband = local->hw.wiphy->bands[band];
- skb = dev_alloc_skb(local->hw.extra_tx_headroom +
- sizeof(*mgmt) + 6 + extra_len);
- if (!skb) {
- printk(KERN_DEBUG "%s: failed to allocate buffer for auth "
- "frame\n", sdata->dev->name);
- return;
+ if (!sband) {
+ WARN_ON(1);
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
}
- skb_reserve(skb, local->hw.extra_tx_headroom);
- mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6);
- memset(mgmt, 0, 24 + 6);
- mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
- IEEE80211_STYPE_AUTH);
- if (encrypt)
- mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
- memcpy(mgmt->da, ifsta->bssid, ETH_ALEN);
- memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
- memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
- mgmt->u.auth.auth_alg = cpu_to_le16(ifsta->auth_alg);
- mgmt->u.auth.auth_transaction = cpu_to_le16(transaction);
- ifsta->auth_transaction = transaction + 1;
- mgmt->u.auth.status_code = cpu_to_le16(0);
- if (extra)
- memcpy(skb_put(skb, extra_len), extra, extra_len);
-
- ieee80211_tx_skb(sdata, skb, encrypt);
+ bitrates = sband->bitrates;
+ num_rates = sband->n_bitrates;
+ supp_rates = 0;
+ for (i = 0; i < elems->supp_rates_len +
+ elems->ext_supp_rates_len; i++) {
+ u8 rate = 0;
+ int own_rate;
+ if (i < elems->supp_rates_len)
+ rate = elems->supp_rates[i];
+ else if (elems->ext_supp_rates)
+ rate = elems->ext_supp_rates
+ [i - elems->supp_rates_len];
+ own_rate = 5 * (rate & 0x7f);
+ for (j = 0; j < num_rates; j++)
+ if (bitrates[j].bitrate == own_rate)
+ supp_rates |= BIT(j);
+ }
+ return supp_rates;
}
+/* frame sending functions */
+
+/* also used by scanning code */
void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
u8 *ssid, size_t ssid_len)
{
@@ -193,6 +193,43 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
ieee80211_tx_skb(sdata, skb, 0);
}
+static void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_if_sta *ifsta,
+ int transaction, u8 *extra, size_t extra_len,
+ int encrypt)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct sk_buff *skb;
+ struct ieee80211_mgmt *mgmt;
+
+ skb = dev_alloc_skb(local->hw.extra_tx_headroom +
+ sizeof(*mgmt) + 6 + extra_len);
+ if (!skb) {
+ printk(KERN_DEBUG "%s: failed to allocate buffer for auth "
+ "frame\n", sdata->dev->name);
+ return;
+ }
+ skb_reserve(skb, local->hw.extra_tx_headroom);
+
+ mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6);
+ memset(mgmt, 0, 24 + 6);
+ mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_AUTH);
+ if (encrypt)
+ mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+ memcpy(mgmt->da, ifsta->bssid, ETH_ALEN);
+ memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
+ memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
+ mgmt->u.auth.auth_alg = cpu_to_le16(ifsta->auth_alg);
+ mgmt->u.auth.auth_transaction = cpu_to_le16(transaction);
+ ifsta->auth_transaction = transaction + 1;
+ mgmt->u.auth.status_code = cpu_to_le16(0);
+ if (extra)
+ memcpy(skb_put(skb, extra_len), extra, extra_len);
+
+ ieee80211_tx_skb(sdata, skb, encrypt);
+}
+
static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_sta *ifsta)
{
@@ -202,7 +239,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
u8 *pos, *ies, *ht_add_ie;
int i, len, count, rates_len, supp_rates_len;
u16 capab;
- struct ieee80211_sta_bss *bss;
+ struct ieee80211_bss *bss;
int wmm = 0;
struct ieee80211_supported_band *sband;
u64 rates = 0;
@@ -433,7 +470,7 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
/* MLME */
static void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_sta_bss *bss)
+ struct ieee80211_bss *bss)
{
struct ieee80211_local *local = sdata->local;
int i, have_higher_than_11mbit = 0;
@@ -584,7 +621,7 @@ static u32 ieee80211_handle_erp_ie(struct ieee80211_sub_if_data *sdata,
}
static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_sta_bss *bss)
+ struct ieee80211_bss *bss)
{
u32 changed = 0;
@@ -637,11 +674,11 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
struct ieee80211_conf *conf = &local_to_hw(local)->conf;
u32 changed = BSS_CHANGED_ASSOC;
- struct ieee80211_sta_bss *bss;
+ struct ieee80211_bss *bss;
ifsta->flags |= IEEE80211_STA_ASSOCIATED;
- if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
+ if (sdata->vif.type != NL80211_IFTYPE_STATION)
return;
bss = ieee80211_rx_bss_get(local, ifsta->bssid,
@@ -673,6 +710,12 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
ieee80211_led_assoc(local, 1);
sdata->bss_conf.assoc = 1;
+ /*
+ * For now just always ask the driver to update the basic rateset
+ * when we have associated, we aren't checking whether it actually
+ * changed or not.
+ */
+ changed |= BSS_CHANGED_BASIC_RATES;
ieee80211_bss_info_change_notify(sdata, changed);
netif_tx_start_all_queues(sdata->dev);
@@ -761,7 +804,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
netif_tx_stop_all_queues(sdata->dev);
netif_carrier_off(sdata->dev);
- ieee80211_sta_tear_down_BA_sessions(sdata, sta->addr);
+ ieee80211_sta_tear_down_BA_sessions(sdata, sta->sta.addr);
if (self_disconnected) {
if (deauth)
@@ -809,7 +852,7 @@ static int ieee80211_privacy_mismatch(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_sta *ifsta)
{
struct ieee80211_local *local = sdata->local;
- struct ieee80211_sta_bss *bss;
+ struct ieee80211_bss *bss;
int bss_privacy;
int wep_privacy;
int privacy_invoked;
@@ -959,17 +1002,17 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
DECLARE_MAC_BUF(mac);
if (ifsta->state != IEEE80211_STA_MLME_AUTHENTICATE &&
- sdata->vif.type != IEEE80211_IF_TYPE_IBSS)
+ sdata->vif.type != NL80211_IFTYPE_ADHOC)
return;
if (len < 24 + 6)
return;
- if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
+ if (sdata->vif.type != NL80211_IFTYPE_ADHOC &&
memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0)
return;
- if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
+ if (sdata->vif.type != NL80211_IFTYPE_ADHOC &&
memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0)
return;
@@ -977,7 +1020,7 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction);
status_code = le16_to_cpu(mgmt->u.auth.status_code);
- if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
+ if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
/*
* IEEE 802.11 standard does not require authentication in IBSS
* networks and most implementations do not seem to use it.
@@ -1182,7 +1225,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
/* Add STA entry for the AP */
sta = sta_info_get(local, ifsta->bssid);
if (!sta) {
- struct ieee80211_sta_bss *bss;
+ struct ieee80211_bss *bss;
int err;
sta = sta_info_alloc(sdata, ifsta->bssid, GFP_ATOMIC);
@@ -1258,8 +1301,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
}
}
- sta->supp_rates[local->hw.conf.channel->band] = rates;
- sdata->basic_rates = basic_rates;
+ sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
+ sdata->bss_conf.basic_rates = basic_rates;
/* cf. IEEE 802.11 9.2.12 */
if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ &&
@@ -1273,11 +1316,11 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
struct ieee80211_ht_bss_info bss_info;
ieee80211_ht_cap_ie_to_ht_info(
(struct ieee80211_ht_cap *)
- elems.ht_cap_elem, &sta->ht_info);
+ elems.ht_cap_elem, &sta->sta.ht_info);
ieee80211_ht_addt_info_ie_to_ht_bss_info(
(struct ieee80211_ht_addt_info *)
elems.ht_info_elem, &bss_info);
- ieee80211_handle_ht(local, 1, &sta->ht_info, &bss_info);
+ ieee80211_handle_ht(local, 1, &sta->sta.ht_info, &bss_info);
}
rate_control_rate_init(sta, local);
@@ -1302,7 +1345,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_sta *ifsta,
- struct ieee80211_sta_bss *bss)
+ struct ieee80211_bss *bss)
{
struct ieee80211_local *local = sdata->local;
int res, rates, i, j;
@@ -1416,70 +1459,6 @@ static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
return res;
}
-u64 ieee80211_sta_get_rates(struct ieee80211_local *local,
- struct ieee802_11_elems *elems,
- enum ieee80211_band band)
-{
- struct ieee80211_supported_band *sband;
- struct ieee80211_rate *bitrates;
- size_t num_rates;
- u64 supp_rates;
- int i, j;
- sband = local->hw.wiphy->bands[band];
-
- if (!sband) {
- WARN_ON(1);
- sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
- }
-
- bitrates = sband->bitrates;
- num_rates = sband->n_bitrates;
- supp_rates = 0;
- for (i = 0; i < elems->supp_rates_len +
- elems->ext_supp_rates_len; i++) {
- u8 rate = 0;
- int own_rate;
- if (i < elems->supp_rates_len)
- rate = elems->supp_rates[i];
- else if (elems->ext_supp_rates)
- rate = elems->ext_supp_rates
- [i - elems->supp_rates_len];
- own_rate = 5 * (rate & 0x7f);
- for (j = 0; j < num_rates; j++)
- if (bitrates[j].bitrate == own_rate)
- supp_rates |= BIT(j);
- }
- return supp_rates;
-}
-
-static u64 ieee80211_sta_get_mandatory_rates(struct ieee80211_local *local,
- enum ieee80211_band band)
-{
- struct ieee80211_supported_band *sband;
- struct ieee80211_rate *bitrates;
- u64 mandatory_rates;
- enum ieee80211_rate_flags mandatory_flag;
- int i;
-
- sband = local->hw.wiphy->bands[band];
- if (!sband) {
- WARN_ON(1);
- sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
- }
-
- if (band == IEEE80211_BAND_2GHZ)
- mandatory_flag = IEEE80211_RATE_MANDATORY_B;
- else
- mandatory_flag = IEEE80211_RATE_MANDATORY_A;
-
- bitrates = sband->bitrates;
- mandatory_rates = 0;
- for (i = 0; i < sband->n_bitrates; i++)
- if (bitrates[i].flags & mandatory_flag)
- mandatory_rates |= BIT(i);
- return mandatory_rates;
-}
-
static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt,
size_t len,
@@ -1489,7 +1468,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
{
struct ieee80211_local *local = sdata->local;
int freq;
- struct ieee80211_sta_bss *bss;
+ struct ieee80211_bss *bss;
struct sta_info *sta;
struct ieee80211_channel *channel;
u64 beacon_timestamp, rx_timestamp;
@@ -1508,15 +1487,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
return;
- if (ieee80211_vif_is_mesh(&sdata->vif) && elems->mesh_id &&
- elems->mesh_config && mesh_matches_local(elems, sdata)) {
- supp_rates = ieee80211_sta_get_rates(local, elems, band);
-
- mesh_neighbour_update(mgmt->sa, supp_rates, sdata,
- mesh_peer_accepts_plinks(elems));
- }
-
- if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems->supp_rates &&
+ if (sdata->vif.type == NL80211_IFTYPE_ADHOC && elems->supp_rates &&
memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0) {
supp_rates = ieee80211_sta_get_rates(local, elems, band);
@@ -1526,20 +1497,21 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
if (sta) {
u64 prev_rates;
- prev_rates = sta->supp_rates[band];
+ prev_rates = sta->sta.supp_rates[band];
/* make sure mandatory rates are always added */
- sta->supp_rates[band] = supp_rates |
- ieee80211_sta_get_mandatory_rates(local, band);
+ sta->sta.supp_rates[band] = supp_rates |
+ ieee80211_mandatory_rates(local, band);
#ifdef CONFIG_MAC80211_IBSS_DEBUG
- if (sta->supp_rates[band] != prev_rates)
+ if (sta->sta.supp_rates[band] != prev_rates)
printk(KERN_DEBUG "%s: updated supp_rates set "
"for %s based on beacon info (0x%llx | "
"0x%llx -> 0x%llx)\n",
- sdata->dev->name, print_mac(mac, sta->addr),
+ sdata->dev->name,
+ print_mac(mac, sta->sta.addr),
(unsigned long long) prev_rates,
(unsigned long long) supp_rates,
- (unsigned long long) sta->supp_rates[band]);
+ (unsigned long long) sta->sta.supp_rates[band]);
#endif
} else {
ieee80211_ibss_add_sta(sdata, NULL, mgmt->bssid,
@@ -1561,14 +1533,14 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
* In STA mode, the remaining parameters should not be overridden
* by beacons because they're not necessarily accurate there.
*/
- if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
+ if (sdata->vif.type != NL80211_IFTYPE_ADHOC &&
bss->last_probe_resp && beacon) {
ieee80211_rx_bss_put(local, bss);
return;
}
/* check if we need to merge IBSS */
- if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && beacon &&
+ if (sdata->vif.type == NL80211_IFTYPE_ADHOC && beacon &&
bss->capability & WLAN_CAPABILITY_IBSS &&
bss->freq == local->oper_channel->center_freq &&
elems->ssid_len == sdata->u.sta.ssid_len &&
@@ -1678,7 +1650,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, true);
- if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
+ if (sdata->vif.type != NL80211_IFTYPE_STATION)
return;
ifsta = &sdata->u.sta;
@@ -1729,7 +1701,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
DECLARE_MAC_BUF(mac3);
#endif
- if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS ||
+ if (sdata->vif.type != NL80211_IFTYPE_ADHOC ||
ifsta->state != IEEE80211_STA_MLME_IBSS_JOINED ||
len < 24 + 2 || !ifsta->probe_resp)
return;
@@ -1785,26 +1757,6 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
ieee80211_tx_skb(sdata, skb, 0);
}
-static void ieee80211_rx_mgmt_action(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_if_sta *ifsta,
- struct ieee80211_mgmt *mgmt,
- size_t len,
- struct ieee80211_rx_status *rx_status)
-{
- /* currently we only handle mesh interface action frames here */
- if (!ieee80211_vif_is_mesh(&sdata->vif))
- return;
-
- switch (mgmt->u.action.category) {
- case PLINK_CATEGORY:
- mesh_rx_plink_frame(sdata, mgmt, len, rx_status);
- break;
- case MESH_PATH_SEL_CATEGORY:
- mesh_rx_path_sel_frame(sdata, mgmt, len);
- break;
- }
-}
-
void ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
struct ieee80211_rx_status *rx_status)
{
@@ -1825,7 +1777,6 @@ void ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *
case IEEE80211_STYPE_PROBE_REQ:
case IEEE80211_STYPE_PROBE_RESP:
case IEEE80211_STYPE_BEACON:
- case IEEE80211_STYPE_ACTION:
memcpy(skb->cb, rx_status, sizeof(*rx_status));
case IEEE80211_STYPE_AUTH:
case IEEE80211_STYPE_ASSOC_RESP:
@@ -1881,9 +1832,6 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
case IEEE80211_STYPE_DISASSOC:
ieee80211_rx_mgmt_disassoc(sdata, ifsta, mgmt, skb->len);
break;
- case IEEE80211_STYPE_ACTION:
- ieee80211_rx_mgmt_action(sdata, ifsta, mgmt, skb->len, rx_status);
- break;
}
kfree_skb(skb);
@@ -1913,32 +1861,6 @@ static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata)
}
-static void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, unsigned long exp_time)
-{
- struct ieee80211_local *local = sdata->local;
- struct sta_info *sta, *tmp;
- LIST_HEAD(tmp_list);
- DECLARE_MAC_BUF(mac);
- unsigned long flags;
-
- spin_lock_irqsave(&local->sta_lock, flags);
- list_for_each_entry_safe(sta, tmp, &local->sta_list, list)
- if (time_after(jiffies, sta->last_rx + exp_time)) {
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
- printk(KERN_DEBUG "%s: expiring inactive STA %s\n",
- sdata->dev->name, print_mac(mac, sta->addr));
-#endif
- __sta_info_unlink(&sta);
- if (sta)
- list_add(&sta->list, &tmp_list);
- }
- spin_unlock_irqrestore(&local->sta_lock, flags);
-
- list_for_each_entry_safe(sta, tmp, &tmp_list, list)
- sta_info_destroy(sta);
-}
-
-
static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_sta *ifsta)
{
@@ -1950,40 +1872,11 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata,
printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other "
"IBSS networks with same SSID (merge)\n", sdata->dev->name);
- ieee80211_sta_req_scan(sdata, ifsta->ssid, ifsta->ssid_len);
+ ieee80211_request_scan(sdata, ifsta->ssid, ifsta->ssid_len);
}
-#ifdef CONFIG_MAC80211_MESH
-static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_if_sta *ifsta)
-{
- bool free_plinks;
-
- ieee80211_sta_expire(sdata, IEEE80211_MESH_PEER_INACTIVITY_LIMIT);
- mesh_path_expire(sdata);
-
- free_plinks = mesh_plink_availables(sdata);
- if (free_plinks != sdata->u.sta.accepting_plinks)
- ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON);
-
- mod_timer(&ifsta->timer, jiffies +
- IEEE80211_MESH_HOUSEKEEPING_INTERVAL);
-}
-
-
-void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
-{
- struct ieee80211_if_sta *ifsta;
- ifsta = &sdata->u.sta;
- ifsta->state = IEEE80211_STA_MLME_MESH_UP;
- ieee80211_sta_timer((unsigned long)sdata);
- ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON);
-}
-#endif
-
-
-void ieee80211_sta_timer(unsigned long data)
+static void ieee80211_sta_timer(unsigned long data)
{
struct ieee80211_sub_if_data *sdata =
(struct ieee80211_sub_if_data *) data;
@@ -2026,28 +1919,6 @@ static void ieee80211_sta_reset_auth(struct ieee80211_sub_if_data *sdata,
}
-void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_if_sta *ifsta)
-{
- struct ieee80211_local *local = sdata->local;
-
- if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
- return;
-
- if ((ifsta->flags & (IEEE80211_STA_BSSID_SET |
- IEEE80211_STA_AUTO_BSSID_SEL)) &&
- (ifsta->flags & (IEEE80211_STA_SSID_SET |
- IEEE80211_STA_AUTO_SSID_SEL))) {
-
- if (ifsta->state == IEEE80211_STA_MLME_ASSOCIATED)
- ieee80211_set_disassoc(sdata, ifsta, true, true,
- WLAN_REASON_DEAUTH_LEAVING);
-
- set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request);
- queue_work(local->hw.workqueue, &ifsta->work);
- }
-}
-
static int ieee80211_sta_match_ssid(struct ieee80211_if_sta *ifsta,
const char *ssid, int ssid_len)
{
@@ -2082,7 +1953,7 @@ static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_sta *ifsta)
{
struct ieee80211_local *local = sdata->local;
- struct ieee80211_sta_bss *bss;
+ struct ieee80211_bss *bss;
struct ieee80211_supported_band *sband;
u8 bssid[ETH_ALEN], *pos;
int i;
@@ -2143,7 +2014,7 @@ static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_sta *ifsta)
{
struct ieee80211_local *local = sdata->local;
- struct ieee80211_sta_bss *bss;
+ struct ieee80211_bss *bss;
int found = 0;
u8 bssid[ETH_ALEN];
int active_ibss;
@@ -2158,8 +2029,8 @@ static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata,
printk(KERN_DEBUG "%s: sta_find_ibss (active_ibss=%d)\n",
sdata->dev->name, active_ibss);
#endif /* CONFIG_MAC80211_IBSS_DEBUG */
- spin_lock_bh(&local->sta_bss_lock);
- list_for_each_entry(bss, &local->sta_bss_list, list) {
+ spin_lock_bh(&local->bss_lock);
+ list_for_each_entry(bss, &local->bss_list, list) {
if (ifsta->ssid_len != bss->ssid_len ||
memcmp(ifsta->ssid, bss->ssid, bss->ssid_len) != 0
|| !(bss->capability & WLAN_CAPABILITY_IBSS))
@@ -2173,7 +2044,7 @@ static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata,
if (active_ibss || memcmp(bssid, ifsta->bssid, ETH_ALEN) != 0)
break;
}
- spin_unlock_bh(&local->sta_bss_lock);
+ spin_unlock_bh(&local->bss_lock);
#ifdef CONFIG_MAC80211_IBSS_DEBUG
if (found)
@@ -2218,7 +2089,7 @@ dont_join:
IEEE80211_SCAN_INTERVAL)) {
printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to "
"join\n", sdata->dev->name);
- return ieee80211_sta_req_scan(sdata, ifsta->ssid,
+ return ieee80211_request_scan(sdata, ifsta->ssid,
ifsta->ssid_len);
} else if (ifsta->state != IEEE80211_STA_MLME_IBSS_JOINED) {
int interval = IEEE80211_SCAN_INTERVAL;
@@ -2249,6 +2120,259 @@ dont_join:
}
+static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_if_sta *ifsta)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_bss *bss, *selected = NULL;
+ int top_rssi = 0, freq;
+
+ spin_lock_bh(&local->bss_lock);
+ freq = local->oper_channel->center_freq;
+ list_for_each_entry(bss, &local->bss_list, list) {
+ if (!(bss->capability & WLAN_CAPABILITY_ESS))
+ continue;
+
+ if ((ifsta->flags & (IEEE80211_STA_AUTO_SSID_SEL |
+ IEEE80211_STA_AUTO_BSSID_SEL |
+ IEEE80211_STA_AUTO_CHANNEL_SEL)) &&
+ (!!(bss->capability & WLAN_CAPABILITY_PRIVACY) ^
+ !!sdata->default_key))
+ continue;
+
+ if (!(ifsta->flags & IEEE80211_STA_AUTO_CHANNEL_SEL) &&
+ bss->freq != freq)
+ continue;
+
+ if (!(ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL) &&
+ memcmp(bss->bssid, ifsta->bssid, ETH_ALEN))
+ continue;
+
+ if (!(ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL) &&
+ !ieee80211_sta_match_ssid(ifsta, bss->ssid, bss->ssid_len))
+ continue;
+
+ if (!selected || top_rssi < bss->signal) {
+ selected = bss;
+ top_rssi = bss->signal;
+ }
+ }
+ if (selected)
+ atomic_inc(&selected->users);
+ spin_unlock_bh(&local->bss_lock);
+
+ if (selected) {
+ ieee80211_set_freq(sdata, selected->freq);
+ if (!(ifsta->flags & IEEE80211_STA_SSID_SET))
+ ieee80211_sta_set_ssid(sdata, selected->ssid,
+ selected->ssid_len);
+ ieee80211_sta_set_bssid(sdata, selected->bssid);
+ ieee80211_sta_def_wmm_params(sdata, selected);
+
+ /* Send out direct probe if no probe resp was received or
+ * the one we have is outdated
+ */
+ if (!selected->last_probe_resp ||
+ time_after(jiffies, selected->last_probe_resp
+ + IEEE80211_SCAN_RESULT_EXPIRE))
+ ifsta->state = IEEE80211_STA_MLME_DIRECT_PROBE;
+ else
+ ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE;
+
+ ieee80211_rx_bss_put(local, selected);
+ ieee80211_sta_reset_auth(sdata, ifsta);
+ return 0;
+ } else {
+ if (ifsta->assoc_scan_tries < IEEE80211_ASSOC_SCANS_MAX_TRIES) {
+ ifsta->assoc_scan_tries++;
+ if (ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL)
+ ieee80211_start_scan(sdata, NULL, 0);
+ else
+ ieee80211_start_scan(sdata, ifsta->ssid,
+ ifsta->ssid_len);
+ ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE;
+ set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request);
+ } else
+ ifsta->state = IEEE80211_STA_MLME_DISABLED;
+ }
+ return -1;
+}
+
+
+static void ieee80211_sta_work(struct work_struct *work)
+{
+ struct ieee80211_sub_if_data *sdata =
+ container_of(work, struct ieee80211_sub_if_data, u.sta.work);
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_if_sta *ifsta;
+ struct sk_buff *skb;
+
+ if (!netif_running(sdata->dev))
+ return;
+
+ if (local->sw_scanning || local->hw_scanning)
+ return;
+
+ if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION &&
+ sdata->vif.type != NL80211_IFTYPE_ADHOC))
+ return;
+ ifsta = &sdata->u.sta;
+
+ while ((skb = skb_dequeue(&ifsta->skb_queue)))
+ ieee80211_sta_rx_queued_mgmt(sdata, skb);
+
+ if (ifsta->state != IEEE80211_STA_MLME_DIRECT_PROBE &&
+ ifsta->state != IEEE80211_STA_MLME_AUTHENTICATE &&
+ ifsta->state != IEEE80211_STA_MLME_ASSOCIATE &&
+ test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request)) {
+ ieee80211_start_scan(sdata, ifsta->scan_ssid,
+ ifsta->scan_ssid_len);
+ return;
+ }
+
+ if (test_and_clear_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request)) {
+ if (ieee80211_sta_config_auth(sdata, ifsta))
+ return;
+ clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request);
+ } else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request))
+ return;
+
+ switch (ifsta->state) {
+ case IEEE80211_STA_MLME_DISABLED:
+ break;
+ case IEEE80211_STA_MLME_DIRECT_PROBE:
+ ieee80211_direct_probe(sdata, ifsta);
+ break;
+ case IEEE80211_STA_MLME_AUTHENTICATE:
+ ieee80211_authenticate(sdata, ifsta);
+ break;
+ case IEEE80211_STA_MLME_ASSOCIATE:
+ ieee80211_associate(sdata, ifsta);
+ break;
+ case IEEE80211_STA_MLME_ASSOCIATED:
+ ieee80211_associated(sdata, ifsta);
+ break;
+ case IEEE80211_STA_MLME_IBSS_SEARCH:
+ ieee80211_sta_find_ibss(sdata, ifsta);
+ break;
+ case IEEE80211_STA_MLME_IBSS_JOINED:
+ ieee80211_sta_merge_ibss(sdata, ifsta);
+ break;
+ default:
+ WARN_ON(1);
+ break;
+ }
+
+ if (ieee80211_privacy_mismatch(sdata, ifsta)) {
+ printk(KERN_DEBUG "%s: privacy configuration mismatch and "
+ "mixed-cell disabled - disassociate\n", sdata->dev->name);
+
+ ieee80211_set_disassoc(sdata, ifsta, false, true,
+ WLAN_REASON_UNSPECIFIED);
+ }
+}
+
+static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata)
+{
+ if (sdata->vif.type == NL80211_IFTYPE_STATION)
+ queue_work(sdata->local->hw.workqueue,
+ &sdata->u.sta.work);
+}
+
+/* interface setup */
+void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_if_sta *ifsta;
+
+ ifsta = &sdata->u.sta;
+ INIT_WORK(&ifsta->work, ieee80211_sta_work);
+ setup_timer(&ifsta->timer, ieee80211_sta_timer,
+ (unsigned long) sdata);
+ skb_queue_head_init(&ifsta->skb_queue);
+
+ ifsta->capab = WLAN_CAPABILITY_ESS;
+ ifsta->auth_algs = IEEE80211_AUTH_ALG_OPEN |
+ IEEE80211_AUTH_ALG_SHARED_KEY;
+ ifsta->flags |= IEEE80211_STA_CREATE_IBSS |
+ IEEE80211_STA_AUTO_BSSID_SEL |
+ IEEE80211_STA_AUTO_CHANNEL_SEL;
+ if (ieee80211_num_regular_queues(&sdata->local->hw) >= 4)
+ ifsta->flags |= IEEE80211_STA_WMM_ENABLED;
+}
+
+/*
+ * Add a new IBSS station, will also be called by the RX code when,
+ * in IBSS mode, receiving a frame from a yet-unknown station, hence
+ * must be callable in atomic context.
+ */
+struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
+ struct sk_buff *skb, u8 *bssid,
+ u8 *addr, u64 supp_rates)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct sta_info *sta;
+ DECLARE_MAC_BUF(mac);
+ int band = local->hw.conf.channel->band;
+
+ /* TODO: Could consider removing the least recently used entry and
+ * allow new one to be added. */
+ if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) {
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "%s: No room for a new IBSS STA "
+ "entry %s\n", sdata->dev->name, print_mac(mac, addr));
+ }
+ return NULL;
+ }
+
+ if (compare_ether_addr(bssid, sdata->u.sta.bssid))
+ return NULL;
+
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+ printk(KERN_DEBUG "%s: Adding new IBSS station %s (dev=%s)\n",
+ wiphy_name(local->hw.wiphy), print_mac(mac, addr), sdata->dev->name);
+#endif
+
+ sta = sta_info_alloc(sdata, addr, GFP_ATOMIC);
+ if (!sta)
+ return NULL;
+
+ set_sta_flags(sta, WLAN_STA_AUTHORIZED);
+
+ /* make sure mandatory rates are always added */
+ sta->sta.supp_rates[band] = supp_rates |
+ ieee80211_mandatory_rates(local, band);
+
+ rate_control_rate_init(sta, local);
+
+ if (sta_info_insert(sta))
+ return NULL;
+
+ return sta;
+}
+
+/* configuration hooks */
+void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_if_sta *ifsta)
+{
+ struct ieee80211_local *local = sdata->local;
+
+ if (sdata->vif.type != NL80211_IFTYPE_STATION)
+ return;
+
+ if ((ifsta->flags & (IEEE80211_STA_BSSID_SET |
+ IEEE80211_STA_AUTO_BSSID_SEL)) &&
+ (ifsta->flags & (IEEE80211_STA_SSID_SET |
+ IEEE80211_STA_AUTO_SSID_SEL))) {
+
+ if (ifsta->state == IEEE80211_STA_MLME_ASSOCIATED)
+ ieee80211_set_disassoc(sdata, ifsta, true, true,
+ WLAN_REASON_DEAUTH_LEAVING);
+
+ set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request);
+ queue_work(local->hw.workqueue, &ifsta->work);
+ }
+}
+
int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len)
{
struct ieee80211_if_sta *ifsta;
@@ -2284,7 +2408,7 @@ int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size
else
ifsta->flags &= ~IEEE80211_STA_SSID_SET;
- if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS &&
+ if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
!(ifsta->flags & IEEE80211_STA_BSSID_SET)) {
ifsta->ibss_join_req = jiffies;
ifsta->state = IEEE80211_STA_MLME_IBSS_SEARCH;
@@ -2294,7 +2418,6 @@ int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size
return 0;
}
-
int ieee80211_sta_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len)
{
struct ieee80211_if_sta *ifsta = &sdata->u.sta;
@@ -2303,7 +2426,6 @@ int ieee80211_sta_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size
return 0;
}
-
int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid)
{
struct ieee80211_if_sta *ifsta;
@@ -2334,7 +2456,6 @@ int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid)
return 0;
}
-
int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, char *ie, size_t len)
{
struct ieee80211_if_sta *ifsta = &sdata->u.sta;
@@ -2355,132 +2476,6 @@ int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, char *ie, si
return 0;
}
-
-struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
- struct sk_buff *skb, u8 *bssid,
- u8 *addr, u64 supp_rates)
-{
- struct ieee80211_local *local = sdata->local;
- struct sta_info *sta;
- DECLARE_MAC_BUF(mac);
- int band = local->hw.conf.channel->band;
-
- /* TODO: Could consider removing the least recently used entry and
- * allow new one to be added. */
- if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) {
- if (net_ratelimit()) {
- printk(KERN_DEBUG "%s: No room for a new IBSS STA "
- "entry %s\n", sdata->dev->name, print_mac(mac, addr));
- }
- return NULL;
- }
-
- if (compare_ether_addr(bssid, sdata->u.sta.bssid))
- return NULL;
-
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- printk(KERN_DEBUG "%s: Adding new IBSS station %s (dev=%s)\n",
- wiphy_name(local->hw.wiphy), print_mac(mac, addr), sdata->dev->name);
-#endif
-
- sta = sta_info_alloc(sdata, addr, GFP_ATOMIC);
- if (!sta)
- return NULL;
-
- set_sta_flags(sta, WLAN_STA_AUTHORIZED);
-
- /* make sure mandatory rates are always added */
- sta->supp_rates[band] = supp_rates |
- ieee80211_sta_get_mandatory_rates(local, band);
-
- rate_control_rate_init(sta, local);
-
- if (sta_info_insert(sta))
- return NULL;
-
- return sta;
-}
-
-
-static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_if_sta *ifsta)
-{
- struct ieee80211_local *local = sdata->local;
- struct ieee80211_sta_bss *bss, *selected = NULL;
- int top_rssi = 0, freq;
-
- spin_lock_bh(&local->sta_bss_lock);
- freq = local->oper_channel->center_freq;
- list_for_each_entry(bss, &local->sta_bss_list, list) {
- if (!(bss->capability & WLAN_CAPABILITY_ESS))
- continue;
-
- if ((ifsta->flags & (IEEE80211_STA_AUTO_SSID_SEL |
- IEEE80211_STA_AUTO_BSSID_SEL |
- IEEE80211_STA_AUTO_CHANNEL_SEL)) &&
- (!!(bss->capability & WLAN_CAPABILITY_PRIVACY) ^
- !!sdata->default_key))
- continue;
-
- if (!(ifsta->flags & IEEE80211_STA_AUTO_CHANNEL_SEL) &&
- bss->freq != freq)
- continue;
-
- if (!(ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL) &&
- memcmp(bss->bssid, ifsta->bssid, ETH_ALEN))
- continue;
-
- if (!(ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL) &&
- !ieee80211_sta_match_ssid(ifsta, bss->ssid, bss->ssid_len))
- continue;
-
- if (!selected || top_rssi < bss->signal) {
- selected = bss;
- top_rssi = bss->signal;
- }
- }
- if (selected)
- atomic_inc(&selected->users);
- spin_unlock_bh(&local->sta_bss_lock);
-
- if (selected) {
- ieee80211_set_freq(sdata, selected->freq);
- if (!(ifsta->flags & IEEE80211_STA_SSID_SET))
- ieee80211_sta_set_ssid(sdata, selected->ssid,
- selected->ssid_len);
- ieee80211_sta_set_bssid(sdata, selected->bssid);
- ieee80211_sta_def_wmm_params(sdata, selected);
-
- /* Send out direct probe if no probe resp was received or
- * the one we have is outdated
- */
- if (!selected->last_probe_resp ||
- time_after(jiffies, selected->last_probe_resp
- + IEEE80211_SCAN_RESULT_EXPIRE))
- ifsta->state = IEEE80211_STA_MLME_DIRECT_PROBE;
- else
- ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE;
-
- ieee80211_rx_bss_put(local, selected);
- ieee80211_sta_reset_auth(sdata, ifsta);
- return 0;
- } else {
- if (ifsta->assoc_scan_tries < IEEE80211_ASSOC_SCANS_MAX_TRIES) {
- ifsta->assoc_scan_tries++;
- if (ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL)
- ieee80211_sta_start_scan(sdata, NULL, 0);
- else
- ieee80211_sta_start_scan(sdata, ifsta->ssid,
- ifsta->ssid_len);
- ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE;
- set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request);
- } else
- ifsta->state = IEEE80211_STA_MLME_DISABLED;
- }
- return -1;
-}
-
-
int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason)
{
struct ieee80211_if_sta *ifsta = &sdata->u.sta;
@@ -2488,15 +2483,14 @@ int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason
printk(KERN_DEBUG "%s: deauthenticating by local choice (reason=%d)\n",
sdata->dev->name, reason);
- if (sdata->vif.type != IEEE80211_IF_TYPE_STA &&
- sdata->vif.type != IEEE80211_IF_TYPE_IBSS)
+ if (sdata->vif.type != NL80211_IFTYPE_STATION &&
+ sdata->vif.type != NL80211_IFTYPE_ADHOC)
return -EINVAL;
ieee80211_set_disassoc(sdata, ifsta, true, true, reason);
return 0;
}
-
int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason)
{
struct ieee80211_if_sta *ifsta = &sdata->u.sta;
@@ -2504,7 +2498,7 @@ int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason)
printk(KERN_DEBUG "%s: disassociating by local choice (reason=%d)\n",
sdata->dev->name, reason);
- if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
+ if (sdata->vif.type != NL80211_IFTYPE_STATION)
return -EINVAL;
if (!(ifsta->flags & IEEE80211_STA_ASSOCIATED))
@@ -2514,6 +2508,28 @@ int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason)
return 0;
}
+/* scan finished notification */
+void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local)
+{
+ struct ieee80211_sub_if_data *sdata = local->scan_sdata;
+ struct ieee80211_if_sta *ifsta;
+
+ if (sdata && sdata->vif.type == NL80211_IFTYPE_ADHOC) {
+ ifsta = &sdata->u.sta;
+ if (!(ifsta->flags & IEEE80211_STA_BSSID_SET) ||
+ (!(ifsta->state == IEEE80211_STA_MLME_IBSS_JOINED) &&
+ !ieee80211_sta_active_ibss(sdata)))
+ ieee80211_sta_find_ibss(sdata, ifsta);
+ }
+
+ /* Restart STA timers */
+ rcu_read_lock();
+ list_for_each_entry_rcu(sdata, &local->interfaces, list)
+ ieee80211_restart_sta_timer(sdata);
+ rcu_read_unlock();
+}
+
+/* driver notification call */
void ieee80211_notify_mac(struct ieee80211_hw *hw,
enum ieee80211_notification_types notif_type)
{
@@ -2524,7 +2540,7 @@ void ieee80211_notify_mac(struct ieee80211_hw *hw,
case IEEE80211_NOTIFY_RE_ASSOC:
rcu_read_lock();
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
- if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
+ if (sdata->vif.type != NL80211_IFTYPE_STATION)
continue;
ieee80211_sta_req_auth(sdata, &sdata->u.sta);
@@ -2534,102 +2550,3 @@ void ieee80211_notify_mac(struct ieee80211_hw *hw,
}
}
EXPORT_SYMBOL(ieee80211_notify_mac);
-
-void ieee80211_sta_work(struct work_struct *work)
-{
- struct ieee80211_sub_if_data *sdata =
- container_of(work, struct ieee80211_sub_if_data, u.sta.work);
- struct ieee80211_local *local = sdata->local;
- struct ieee80211_if_sta *ifsta;
- struct sk_buff *skb;
-
- if (!netif_running(sdata->dev))
- return;
-
- if (local->sta_sw_scanning || local->sta_hw_scanning)
- return;
-
- if (WARN_ON(sdata->vif.type != IEEE80211_IF_TYPE_STA &&
- sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
- sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT))
- return;
- ifsta = &sdata->u.sta;
-
- while ((skb = skb_dequeue(&ifsta->skb_queue)))
- ieee80211_sta_rx_queued_mgmt(sdata, skb);
-
-#ifdef CONFIG_MAC80211_MESH
- if (ifsta->preq_queue_len &&
- time_after(jiffies,
- ifsta->last_preq + msecs_to_jiffies(ifsta->mshcfg.dot11MeshHWMPpreqMinInterval)))
- mesh_path_start_discovery(sdata);
-#endif
-
- if (ifsta->state != IEEE80211_STA_MLME_DIRECT_PROBE &&
- ifsta->state != IEEE80211_STA_MLME_AUTHENTICATE &&
- ifsta->state != IEEE80211_STA_MLME_ASSOCIATE &&
- test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request)) {
- ieee80211_sta_start_scan(sdata, ifsta->scan_ssid, ifsta->scan_ssid_len);
- return;
- }
-
- if (test_and_clear_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request)) {
- if (ieee80211_sta_config_auth(sdata, ifsta))
- return;
- clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request);
- } else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request))
- return;
-
- switch (ifsta->state) {
- case IEEE80211_STA_MLME_DISABLED:
- break;
- case IEEE80211_STA_MLME_DIRECT_PROBE:
- ieee80211_direct_probe(sdata, ifsta);
- break;
- case IEEE80211_STA_MLME_AUTHENTICATE:
- ieee80211_authenticate(sdata, ifsta);
- break;
- case IEEE80211_STA_MLME_ASSOCIATE:
- ieee80211_associate(sdata, ifsta);
- break;
- case IEEE80211_STA_MLME_ASSOCIATED:
- ieee80211_associated(sdata, ifsta);
- break;
- case IEEE80211_STA_MLME_IBSS_SEARCH:
- ieee80211_sta_find_ibss(sdata, ifsta);
- break;
- case IEEE80211_STA_MLME_IBSS_JOINED:
- ieee80211_sta_merge_ibss(sdata, ifsta);
- break;
-#ifdef CONFIG_MAC80211_MESH
- case IEEE80211_STA_MLME_MESH_UP:
- ieee80211_mesh_housekeeping(sdata, ifsta);
- break;
-#endif
- default:
- WARN_ON(1);
- break;
- }
-
- if (ieee80211_privacy_mismatch(sdata, ifsta)) {
- printk(KERN_DEBUG "%s: privacy configuration mismatch and "
- "mixed-cell disabled - disassociate\n", sdata->dev->name);
-
- ieee80211_set_disassoc(sdata, ifsta, false, true,
- WLAN_REASON_UNSPECIFIED);
- }
-}
-
-void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local)
-{
- struct ieee80211_sub_if_data *sdata = local->scan_sdata;
- struct ieee80211_if_sta *ifsta;
-
- if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
- ifsta = &sdata->u.sta;
- if (!(ifsta->flags & IEEE80211_STA_BSSID_SET) ||
- (!(ifsta->state == IEEE80211_STA_MLME_IBSS_JOINED) &&
- !ieee80211_sta_active_ibss(sdata)))
- ieee80211_sta_find_ibss(sdata, ifsta);
- }
-}
diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h
index ede7ab56f65b..5f18c27eb900 100644
--- a/net/mac80211/rate.h
+++ b/net/mac80211/rate.h
@@ -134,7 +134,7 @@ static inline int rate_supported(struct sta_info *sta,
enum ieee80211_band band,
int index)
{
- return (sta == NULL || sta->supp_rates[band] & BIT(index));
+ return (sta == NULL || sta->sta.supp_rates[band] & BIT(index));
}
static inline s8
diff --git a/net/mac80211/rc80211_pid.h b/net/mac80211/rc80211_pid.h
index 0a9135b974b5..ffafc5da572e 100644
--- a/net/mac80211/rc80211_pid.h
+++ b/net/mac80211/rc80211_pid.h
@@ -180,6 +180,8 @@ struct rc_pid_sta_info {
u32 tx_num_failed;
u32 tx_num_xmit;
+ int txrate_idx;
+
/* Average failed frames percentage error (i.e. actual vs. target
* percentage), scaled by RC_PID_SMOOTHING. This value is computed
* using using an exponential weighted average technique:
diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c
index a914ba73ccf5..bc1c4569caa1 100644
--- a/net/mac80211/rc80211_pid_algo.c
+++ b/net/mac80211/rc80211_pid_algo.c
@@ -75,7 +75,8 @@ static void rate_control_pid_adjust_rate(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata;
struct ieee80211_supported_band *sband;
int cur_sorted, new_sorted, probe, tmp, n_bitrates, band;
- int cur = sta->txrate_idx;
+ struct rc_pid_sta_info *spinfo = (void *)sta->rate_ctrl_priv;
+ int cur = spinfo->txrate_idx;
sdata = sta->sdata;
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
@@ -111,7 +112,7 @@ static void rate_control_pid_adjust_rate(struct ieee80211_local *local,
/* Fit the rate found to the nearest supported rate. */
do {
if (rate_supported(sta, band, rinfo[tmp].index)) {
- sta->txrate_idx = rinfo[tmp].index;
+ spinfo->txrate_idx = rinfo[tmp].index;
break;
}
if (adj < 0)
@@ -121,9 +122,9 @@ static void rate_control_pid_adjust_rate(struct ieee80211_local *local,
} while (tmp < n_bitrates && tmp >= 0);
#ifdef CONFIG_MAC80211_DEBUGFS
- rate_control_pid_event_rate_change(
- &((struct rc_pid_sta_info *)sta->rate_ctrl_priv)->events,
- sta->txrate_idx, sband->bitrates[sta->txrate_idx].bitrate);
+ rate_control_pid_event_rate_change(&spinfo->events,
+ spinfo->txrate_idx,
+ sband->bitrates[spinfo->txrate_idx].bitrate);
#endif
}
@@ -148,9 +149,7 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo,
struct ieee80211_local *local,
struct sta_info *sta)
{
-#ifdef CONFIG_MAC80211_MESH
struct ieee80211_sub_if_data *sdata = sta->sdata;
-#endif
struct rc_pid_sta_info *spinfo = sta->rate_ctrl_priv;
struct rc_pid_rateinfo *rinfo = pinfo->rinfo;
struct ieee80211_supported_band *sband;
@@ -181,11 +180,8 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo,
pf = spinfo->last_pf;
else {
pf = spinfo->tx_num_failed * 100 / spinfo->tx_num_xmit;
-#ifdef CONFIG_MAC80211_MESH
- if (pf == 100 &&
- sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT)
+ if (ieee80211_vif_is_mesh(&sdata->vif) && pf == 100)
mesh_plink_broken(sta);
-#endif
pf <<= RC_PID_ARITH_SHIFT;
sta->fail_avg = ((pf + (spinfo->last_pf << 3)) / 9)
>> RC_PID_ARITH_SHIFT;
@@ -195,16 +191,16 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo,
spinfo->tx_num_failed = 0;
/* If we just switched rate, update the rate behaviour info. */
- if (pinfo->oldrate != sta->txrate_idx) {
+ if (pinfo->oldrate != spinfo->txrate_idx) {
i = rinfo[pinfo->oldrate].rev_index;
- j = rinfo[sta->txrate_idx].rev_index;
+ j = rinfo[spinfo->txrate_idx].rev_index;
tmp = (pf - spinfo->last_pf);
tmp = RC_PID_DO_ARITH_RIGHT_SHIFT(tmp, RC_PID_ARITH_SHIFT);
rinfo[j].diff = rinfo[i].diff + tmp;
- pinfo->oldrate = sta->txrate_idx;
+ pinfo->oldrate = spinfo->txrate_idx;
}
rate_control_pid_normalize(pinfo, sband->n_bitrates);
@@ -257,19 +253,20 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev,
if (!sta)
goto unlock;
+ spinfo = sta->rate_ctrl_priv;
+
/* Don't update the state if we're not controlling the rate. */
sdata = sta->sdata;
if (sdata->force_unicast_rateidx > -1) {
- sta->txrate_idx = sdata->max_ratectrl_rateidx;
+ spinfo->txrate_idx = sdata->max_ratectrl_rateidx;
goto unlock;
}
/* Ignore all frames that were sent with a different rate than the rate
* we currently advise mac80211 to use. */
- if (info->tx_rate_idx != sta->txrate_idx)
+ if (info->tx_rate_idx != spinfo->txrate_idx)
goto unlock;
- spinfo = sta->rate_ctrl_priv;
spinfo->tx_num_xmit++;
#ifdef CONFIG_MAC80211_DEBUGFS
@@ -287,17 +284,6 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev,
spinfo->tx_num_xmit++;
}
- if (info->status.excessive_retries) {
- sta->tx_retry_failed++;
- sta->tx_num_consecutive_failures++;
- sta->tx_num_mpdu_fail++;
- } else {
- sta->tx_num_consecutive_failures = 0;
- sta->tx_num_mpdu_ok++;
- }
- sta->tx_retry_count += info->status.retry_count;
- sta->tx_num_mpdu_fail += info->status.retry_count;
-
/* Update PID controller state. */
period = (HZ * pinfo->sampling_period + 500) / 1000;
if (!period)
@@ -317,6 +303,7 @@ static void rate_control_pid_get_rate(void *priv, struct net_device *dev,
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct ieee80211_sub_if_data *sdata;
+ struct rc_pid_sta_info *spinfo;
struct sta_info *sta;
int rateidx;
u16 fc;
@@ -337,16 +324,15 @@ static void rate_control_pid_get_rate(void *priv, struct net_device *dev,
/* If a forced rate is in effect, select it. */
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ spinfo = (struct rc_pid_sta_info *)sta->rate_ctrl_priv;
if (sdata->force_unicast_rateidx > -1)
- sta->txrate_idx = sdata->force_unicast_rateidx;
+ spinfo->txrate_idx = sdata->force_unicast_rateidx;
- rateidx = sta->txrate_idx;
+ rateidx = spinfo->txrate_idx;
if (rateidx >= sband->n_bitrates)
rateidx = sband->n_bitrates - 1;
- sta->last_txrate_idx = rateidx;
-
rcu_read_unlock();
sel->rate_idx = rateidx;
@@ -367,9 +353,10 @@ static void rate_control_pid_rate_init(void *priv, void *priv_sta,
* Until that method is implemented, we will use the lowest supported
* rate as a workaround. */
struct ieee80211_supported_band *sband;
+ struct rc_pid_sta_info *spinfo = (void *)sta->rate_ctrl_priv;
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
- sta->txrate_idx = rate_lowest_index(local, sband, sta);
+ spinfo->txrate_idx = rate_lowest_index(local, sband, sta);
sta->fail_avg = 0;
}
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index d0803797902b..92d898b901e9 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -295,7 +295,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
if (!netif_running(sdata->dev))
continue;
- if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR)
+ if (sdata->vif.type != NL80211_IFTYPE_MONITOR)
continue;
if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES)
@@ -403,12 +403,12 @@ ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx)
struct ieee80211_local *local = rx->local;
struct sk_buff *skb = rx->skb;
- if (unlikely(local->sta_hw_scanning))
- return ieee80211_sta_rx_scan(rx->sdata, skb, rx->status);
+ if (unlikely(local->hw_scanning))
+ return ieee80211_scan_rx(rx->sdata, skb, rx->status);
- if (unlikely(local->sta_sw_scanning)) {
+ if (unlikely(local->sw_scanning)) {
/* drop all the other packets during a software scan anyway */
- if (ieee80211_sta_rx_scan(rx->sdata, skb, rx->status)
+ if (ieee80211_scan_rx(rx->sdata, skb, rx->status)
!= RX_QUEUED)
dev_kfree_skb(skb);
return RX_QUEUED;
@@ -501,8 +501,8 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
/* Drop disallowed frame classes based on STA auth/assoc state;
* IEEE 802.11, Chap 5.5.
*
- * 80211.o does filtering only based on association state, i.e., it
- * drops Class 3 frames from not associated stations. hostapd sends
+ * mac80211 filters only based on association state, i.e. it drops
+ * Class 3 frames from not associated stations. hostapd sends
* deauth/disassoc frames when needed. In addition, hostapd is
* responsible for filtering on both auth and assoc states.
*/
@@ -512,7 +512,7 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
if (unlikely((ieee80211_is_data(hdr->frame_control) ||
ieee80211_is_pspoll(hdr->frame_control)) &&
- rx->sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
+ rx->sdata->vif.type != NL80211_IFTYPE_ADHOC &&
(!rx->sta || !test_sta_flags(rx->sta, WLAN_STA_ASSOC)))) {
if ((!ieee80211_has_fromds(hdr->frame_control) &&
!ieee80211_has_tods(hdr->frame_control) &&
@@ -661,7 +661,7 @@ static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta)
set_and_clear_sta_flags(sta, WLAN_STA_PS, WLAN_STA_PSPOLL);
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
printk(KERN_DEBUG "%s: STA %s aid %d enters power save mode\n",
- dev->name, print_mac(mac, sta->addr), sta->aid);
+ dev->name, print_mac(mac, sta->sta.addr), sta->sta.aid);
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
}
@@ -685,7 +685,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta)
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
printk(KERN_DEBUG "%s: STA %s aid %d exits power save mode\n",
- dev->name, print_mac(mac, sta->addr), sta->aid);
+ dev->name, print_mac(mac, sta->sta.addr), sta->sta.aid);
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
/* Send all buffered frames to the station */
@@ -702,7 +702,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta)
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
printk(KERN_DEBUG "%s: STA %s aid %d send PS frame "
"since STA not sleeping anymore\n", dev->name,
- print_mac(mac, sta->addr), sta->aid);
+ print_mac(mac, sta->sta.addr), sta->sta.aid);
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
info->flags |= IEEE80211_TX_CTL_REQUEUE;
dev_queue_xmit(skb);
@@ -724,14 +724,14 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
/* Update last_rx only for IBSS packets which are for the current
* BSSID to avoid keeping the current IBSS network alive in cases where
* other STAs are using different BSSID. */
- if (rx->sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
+ if (rx->sdata->vif.type == NL80211_IFTYPE_ADHOC) {
u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len,
- IEEE80211_IF_TYPE_IBSS);
+ NL80211_IFTYPE_ADHOC);
if (compare_ether_addr(bssid, rx->sdata->u.sta.bssid) == 0)
sta->last_rx = jiffies;
} else
if (!is_multicast_ether_addr(hdr->addr1) ||
- rx->sdata->vif.type == IEEE80211_IF_TYPE_STA) {
+ rx->sdata->vif.type == NL80211_IFTYPE_STATION) {
/* Update last_rx only for unicast frames in order to prevent
* the Probe Request frames (the only broadcast frames from a
* STA in infrastructure mode) from keeping a connection alive.
@@ -751,8 +751,8 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
sta->last_noise = rx->status->noise;
if (!ieee80211_has_morefrags(hdr->frame_control) &&
- (rx->sdata->vif.type == IEEE80211_IF_TYPE_AP ||
- rx->sdata->vif.type == IEEE80211_IF_TYPE_VLAN)) {
+ (rx->sdata->vif.type == NL80211_IFTYPE_AP ||
+ rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) {
/* Change STA power saving mode only in the end of a frame
* exchange sequence */
if (test_sta_flags(sta, WLAN_STA_PS) &&
@@ -982,8 +982,8 @@ ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx)
!(rx->flags & IEEE80211_RX_RA_MATCH)))
return RX_CONTINUE;
- if ((sdata->vif.type != IEEE80211_IF_TYPE_AP) &&
- (sdata->vif.type != IEEE80211_IF_TYPE_VLAN))
+ if ((sdata->vif.type != NL80211_IFTYPE_AP) &&
+ (sdata->vif.type != NL80211_IFTYPE_AP_VLAN))
return RX_DROP_UNUSABLE;
skb = skb_dequeue(&rx->sta->tx_filtered);
@@ -1007,7 +1007,7 @@ ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx)
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
printk(KERN_DEBUG "STA %s aid %d: PS Poll (entries after %d)\n",
- print_mac(mac, rx->sta->addr), rx->sta->aid,
+ print_mac(mac, rx->sta->sta.addr), rx->sta->sta.aid,
skb_queue_len(&rx->sta->ps_tx_buf));
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
@@ -1032,7 +1032,7 @@ ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx)
*/
printk(KERN_DEBUG "%s: STA %s sent PS Poll even "
"though there are no buffered frames for it\n",
- rx->dev->name, print_mac(mac, rx->sta->addr));
+ rx->dev->name, print_mac(mac, rx->sta->sta.addr));
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
}
@@ -1131,23 +1131,23 @@ ieee80211_data_to_8023(struct ieee80211_rx_data *rx)
switch (hdr->frame_control &
cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) {
case __constant_cpu_to_le16(IEEE80211_FCTL_TODS):
- if (unlikely(sdata->vif.type != IEEE80211_IF_TYPE_AP &&
- sdata->vif.type != IEEE80211_IF_TYPE_VLAN))
+ if (unlikely(sdata->vif.type != NL80211_IFTYPE_AP &&
+ sdata->vif.type != NL80211_IFTYPE_AP_VLAN))
return -1;
break;
case __constant_cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS):
- if (unlikely(sdata->vif.type != IEEE80211_IF_TYPE_WDS &&
- sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT))
+ if (unlikely(sdata->vif.type != NL80211_IFTYPE_WDS &&
+ sdata->vif.type != NL80211_IFTYPE_MESH_POINT))
return -1;
break;
case __constant_cpu_to_le16(IEEE80211_FCTL_FROMDS):
- if (sdata->vif.type != IEEE80211_IF_TYPE_STA ||
+ if (sdata->vif.type != NL80211_IFTYPE_STATION ||
(is_multicast_ether_addr(dst) &&
!compare_ether_addr(src, dev->dev_addr)))
return -1;
break;
case __constant_cpu_to_le16(0):
- if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS)
+ if (sdata->vif.type != NL80211_IFTYPE_ADHOC)
return -1;
break;
}
@@ -1221,8 +1221,9 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
skb = rx->skb;
xmit_skb = NULL;
- if (local->bridge_packets && (sdata->vif.type == IEEE80211_IF_TYPE_AP ||
- sdata->vif.type == IEEE80211_IF_TYPE_VLAN) &&
+ if ((sdata->vif.type == NL80211_IFTYPE_AP ||
+ sdata->vif.type == NL80211_IFTYPE_AP_VLAN) &&
+ !(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) &&
(rx->flags & IEEE80211_RX_RA_MATCH)) {
if (is_multicast_ether_addr(ehdr->h_dest)) {
/*
@@ -1404,7 +1405,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
if (rx->flags & IEEE80211_RX_RA_MATCH) {
if (!mesh_hdr->ttl)
- IEEE80211_IFSTA_MESH_CTR_INC(&rx->sdata->u.sta,
+ IEEE80211_IFSTA_MESH_CTR_INC(&rx->sdata->u.mesh,
dropped_frames_ttl);
else {
struct ieee80211_hdr *fwd_hdr;
@@ -1535,8 +1536,8 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
* FIXME: revisit this, I'm sure we should handle most
* of these frames in other modes as well!
*/
- if (sdata->vif.type != IEEE80211_IF_TYPE_STA &&
- sdata->vif.type != IEEE80211_IF_TYPE_IBSS)
+ if (sdata->vif.type != NL80211_IFTYPE_STATION &&
+ sdata->vif.type != NL80211_IFTYPE_ADHOC)
return RX_DROP_MONITOR;
switch (mgmt->u.action.category) {
@@ -1591,9 +1592,11 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
if (!(rx->flags & IEEE80211_RX_RA_MATCH))
return RX_DROP_MONITOR;
- if (sdata->vif.type != IEEE80211_IF_TYPE_STA &&
- sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
- sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)
+ if (ieee80211_vif_is_mesh(&sdata->vif))
+ return ieee80211_mesh_rx_mgmt(sdata, rx->skb, rx->status);
+
+ if (sdata->vif.type != NL80211_IFTYPE_STATION &&
+ sdata->vif.type != NL80211_IFTYPE_ADHOC)
return RX_DROP_MONITOR;
if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)
@@ -1629,7 +1632,7 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev,
if (!ieee80211_has_protected(hdr->frame_control))
goto ignore;
- if (rx->sdata->vif.type == IEEE80211_IF_TYPE_AP && keyidx) {
+ if (rx->sdata->vif.type == NL80211_IFTYPE_AP && keyidx) {
/*
* APs with pairwise keys should never receive Michael MIC
* errors for non-zero keyidx because these are reserved for
@@ -1699,7 +1702,7 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx)
if (!netif_running(sdata->dev))
continue;
- if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR ||
+ if (sdata->vif.type != NL80211_IFTYPE_MONITOR ||
!(sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES))
continue;
@@ -1798,7 +1801,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
int multicast = is_multicast_ether_addr(hdr->addr1);
switch (sdata->vif.type) {
- case IEEE80211_IF_TYPE_STA:
+ case NL80211_IFTYPE_STATION:
if (!bssid)
return 0;
if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) {
@@ -1813,7 +1816,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
rx->flags &= ~IEEE80211_RX_RA_MATCH;
}
break;
- case IEEE80211_IF_TYPE_IBSS:
+ case NL80211_IFTYPE_ADHOC:
if (!bssid)
return 0;
if (ieee80211_is_beacon(hdr->frame_control)) {
@@ -1834,7 +1837,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
bssid, hdr->addr2,
BIT(rx->status->rate_idx));
break;
- case IEEE80211_IF_TYPE_MESH_POINT:
+ case NL80211_IFTYPE_MESH_POINT:
if (!multicast &&
compare_ether_addr(sdata->dev->dev_addr,
hdr->addr1) != 0) {
@@ -1844,8 +1847,8 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
rx->flags &= ~IEEE80211_RX_RA_MATCH;
}
break;
- case IEEE80211_IF_TYPE_VLAN:
- case IEEE80211_IF_TYPE_AP:
+ case NL80211_IFTYPE_AP_VLAN:
+ case NL80211_IFTYPE_AP:
if (!bssid) {
if (compare_ether_addr(sdata->dev->dev_addr,
hdr->addr1))
@@ -1857,16 +1860,17 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
rx->flags &= ~IEEE80211_RX_RA_MATCH;
}
break;
- case IEEE80211_IF_TYPE_WDS:
+ case NL80211_IFTYPE_WDS:
if (bssid || !ieee80211_is_data(hdr->frame_control))
return 0;
if (compare_ether_addr(sdata->u.wds.remote_addr, hdr->addr2))
return 0;
break;
- case IEEE80211_IF_TYPE_MNTR:
+ case NL80211_IFTYPE_MONITOR:
/* take everything */
break;
- case IEEE80211_IF_TYPE_INVALID:
+ case NL80211_IFTYPE_UNSPECIFIED:
+ case __NL80211_IFTYPE_AFTER_LAST:
/* should never get here */
WARN_ON(1);
break;
@@ -1915,7 +1919,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
return;
}
- if (unlikely(local->sta_sw_scanning || local->sta_hw_scanning))
+ if (unlikely(local->sw_scanning || local->hw_scanning))
rx.flags |= IEEE80211_RX_IN_SCAN;
ieee80211_parse_qos(&rx);
@@ -1927,7 +1931,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
if (!netif_running(sdata->dev))
continue;
- if (sdata->vif.type == IEEE80211_IF_TYPE_MNTR)
+ if (sdata->vif.type == NL80211_IFTYPE_MONITOR)
continue;
bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type);
@@ -2136,7 +2140,7 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
/* if this mpdu is fragmented - terminate rx aggregation session */
sc = le16_to_cpu(hdr->seq_ctrl);
if (sc & IEEE80211_SCTL_FRAG) {
- ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->addr,
+ ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->sta.addr,
tid, 0, WLAN_REASON_QSTA_REQUIRE_SETUP);
ret = 1;
goto end_reorder;
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 010781b806f3..8e6685e7ae85 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -32,26 +32,26 @@
void ieee80211_rx_bss_list_init(struct ieee80211_local *local)
{
- spin_lock_init(&local->sta_bss_lock);
- INIT_LIST_HEAD(&local->sta_bss_list);
+ spin_lock_init(&local->bss_lock);
+ INIT_LIST_HEAD(&local->bss_list);
}
void ieee80211_rx_bss_list_deinit(struct ieee80211_local *local)
{
- struct ieee80211_sta_bss *bss, *tmp;
+ struct ieee80211_bss *bss, *tmp;
- list_for_each_entry_safe(bss, tmp, &local->sta_bss_list, list)
+ list_for_each_entry_safe(bss, tmp, &local->bss_list, list)
ieee80211_rx_bss_put(local, bss);
}
-struct ieee80211_sta_bss *
+struct ieee80211_bss *
ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq,
u8 *ssid, u8 ssid_len)
{
- struct ieee80211_sta_bss *bss;
+ struct ieee80211_bss *bss;
- spin_lock_bh(&local->sta_bss_lock);
- bss = local->sta_bss_hash[STA_HASH(bssid)];
+ spin_lock_bh(&local->bss_lock);
+ bss = local->bss_hash[STA_HASH(bssid)];
while (bss) {
if (!bss_mesh_cfg(bss) &&
!memcmp(bss->bssid, bssid, ETH_ALEN) &&
@@ -63,13 +63,13 @@ ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq,
}
bss = bss->hnext;
}
- spin_unlock_bh(&local->sta_bss_lock);
+ spin_unlock_bh(&local->bss_lock);
return bss;
}
-/* Caller must hold local->sta_bss_lock */
+/* Caller must hold local->bss_lock */
static void __ieee80211_rx_bss_hash_add(struct ieee80211_local *local,
- struct ieee80211_sta_bss *bss)
+ struct ieee80211_bss *bss)
{
u8 hash_idx;
@@ -79,20 +79,20 @@ static void __ieee80211_rx_bss_hash_add(struct ieee80211_local *local,
else
hash_idx = STA_HASH(bss->bssid);
- bss->hnext = local->sta_bss_hash[hash_idx];
- local->sta_bss_hash[hash_idx] = bss;
+ bss->hnext = local->bss_hash[hash_idx];
+ local->bss_hash[hash_idx] = bss;
}
-/* Caller must hold local->sta_bss_lock */
+/* Caller must hold local->bss_lock */
static void __ieee80211_rx_bss_hash_del(struct ieee80211_local *local,
- struct ieee80211_sta_bss *bss)
+ struct ieee80211_bss *bss)
{
- struct ieee80211_sta_bss *b, *prev = NULL;
- b = local->sta_bss_hash[STA_HASH(bss->bssid)];
+ struct ieee80211_bss *b, *prev = NULL;
+ b = local->bss_hash[STA_HASH(bss->bssid)];
while (b) {
if (b == bss) {
if (!prev)
- local->sta_bss_hash[STA_HASH(bss->bssid)] =
+ local->bss_hash[STA_HASH(bss->bssid)] =
bss->hnext;
else
prev->hnext = bss->hnext;
@@ -103,11 +103,11 @@ static void __ieee80211_rx_bss_hash_del(struct ieee80211_local *local,
}
}
-struct ieee80211_sta_bss *
+struct ieee80211_bss *
ieee80211_rx_bss_add(struct ieee80211_local *local, u8 *bssid, int freq,
u8 *ssid, u8 ssid_len)
{
- struct ieee80211_sta_bss *bss;
+ struct ieee80211_bss *bss;
bss = kzalloc(sizeof(*bss), GFP_ATOMIC);
if (!bss)
@@ -120,23 +120,23 @@ ieee80211_rx_bss_add(struct ieee80211_local *local, u8 *bssid, int freq,
bss->ssid_len = ssid_len;
}
- spin_lock_bh(&local->sta_bss_lock);
+ spin_lock_bh(&local->bss_lock);
/* TODO: order by RSSI? */
- list_add_tail(&bss->list, &local->sta_bss_list);
+ list_add_tail(&bss->list, &local->bss_list);
__ieee80211_rx_bss_hash_add(local, bss);
- spin_unlock_bh(&local->sta_bss_lock);
+ spin_unlock_bh(&local->bss_lock);
return bss;
}
#ifdef CONFIG_MAC80211_MESH
-static struct ieee80211_sta_bss *
+static struct ieee80211_bss *
ieee80211_rx_mesh_bss_get(struct ieee80211_local *local, u8 *mesh_id, int mesh_id_len,
u8 *mesh_cfg, int freq)
{
- struct ieee80211_sta_bss *bss;
+ struct ieee80211_bss *bss;
- spin_lock_bh(&local->sta_bss_lock);
- bss = local->sta_bss_hash[mesh_id_hash(mesh_id, mesh_id_len)];
+ spin_lock_bh(&local->bss_lock);
+ bss = local->bss_hash[mesh_id_hash(mesh_id, mesh_id_len)];
while (bss) {
if (bss_mesh_cfg(bss) &&
!memcmp(bss_mesh_cfg(bss), mesh_cfg, MESH_CFG_CMP_LEN) &&
@@ -149,15 +149,15 @@ ieee80211_rx_mesh_bss_get(struct ieee80211_local *local, u8 *mesh_id, int mesh_i
}
bss = bss->hnext;
}
- spin_unlock_bh(&local->sta_bss_lock);
+ spin_unlock_bh(&local->bss_lock);
return bss;
}
-static struct ieee80211_sta_bss *
+static struct ieee80211_bss *
ieee80211_rx_mesh_bss_add(struct ieee80211_local *local, u8 *mesh_id, int mesh_id_len,
u8 *mesh_cfg, int mesh_config_len, int freq)
{
- struct ieee80211_sta_bss *bss;
+ struct ieee80211_bss *bss;
if (mesh_config_len != MESH_CFG_LEN)
return NULL;
@@ -186,16 +186,16 @@ ieee80211_rx_mesh_bss_add(struct ieee80211_local *local, u8 *mesh_id, int mesh_i
memcpy(bss->mesh_cfg, mesh_cfg, MESH_CFG_CMP_LEN);
bss->mesh_id_len = mesh_id_len;
bss->freq = freq;
- spin_lock_bh(&local->sta_bss_lock);
+ spin_lock_bh(&local->bss_lock);
/* TODO: order by RSSI? */
- list_add_tail(&bss->list, &local->sta_bss_list);
+ list_add_tail(&bss->list, &local->bss_list);
__ieee80211_rx_bss_hash_add(local, bss);
- spin_unlock_bh(&local->sta_bss_lock);
+ spin_unlock_bh(&local->bss_lock);
return bss;
}
#endif
-static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss)
+static void ieee80211_rx_bss_free(struct ieee80211_bss *bss)
{
kfree(bss->ies);
kfree(bss_mesh_id(bss));
@@ -204,21 +204,21 @@ static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss)
}
void ieee80211_rx_bss_put(struct ieee80211_local *local,
- struct ieee80211_sta_bss *bss)
+ struct ieee80211_bss *bss)
{
local_bh_disable();
- if (!atomic_dec_and_lock(&bss->users, &local->sta_bss_lock)) {
+ if (!atomic_dec_and_lock(&bss->users, &local->bss_lock)) {
local_bh_enable();
return;
}
__ieee80211_rx_bss_hash_del(local, bss);
list_del(&bss->list);
- spin_unlock_bh(&local->sta_bss_lock);
+ spin_unlock_bh(&local->bss_lock);
ieee80211_rx_bss_free(bss);
}
-struct ieee80211_sta_bss *
+struct ieee80211_bss *
ieee80211_bss_info_update(struct ieee80211_local *local,
struct ieee80211_rx_status *rx_status,
struct ieee80211_mgmt *mgmt,
@@ -226,7 +226,7 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
struct ieee802_11_elems *elems,
int freq, bool beacon)
{
- struct ieee80211_sta_bss *bss;
+ struct ieee80211_bss *bss;
int clen;
#ifdef CONFIG_MAC80211_MESH
@@ -252,9 +252,9 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
} else {
#if 0
/* TODO: order by RSSI? */
- spin_lock_bh(&local->sta_bss_lock);
- list_move_tail(&bss->list, &local->sta_bss_list);
- spin_unlock_bh(&local->sta_bss_lock);
+ spin_lock_bh(&local->bss_lock);
+ list_move_tail(&bss->list, &local->bss_list);
+ spin_unlock_bh(&local->bss_lock);
#endif
}
@@ -327,11 +327,11 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
}
ieee80211_rx_result
-ieee80211_sta_rx_scan(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
- struct ieee80211_rx_status *rx_status)
+ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
+ struct ieee80211_rx_status *rx_status)
{
struct ieee80211_mgmt *mgmt;
- struct ieee80211_sta_bss *bss;
+ struct ieee80211_bss *bss;
u8 *elements;
struct ieee80211_channel *channel;
size_t baselen;
@@ -424,38 +424,37 @@ static void ieee80211_send_nullfunc(struct ieee80211_local *local,
ieee80211_tx_skb(sdata, skb, 0);
}
-static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata)
-{
- if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
- ieee80211_vif_is_mesh(&sdata->vif))
- ieee80211_sta_timer((unsigned long)sdata);
-}
-
void ieee80211_scan_completed(struct ieee80211_hw *hw)
{
struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_sub_if_data *sdata;
union iwreq_data wrqu;
+ if (WARN_ON(!local->hw_scanning && !local->sw_scanning))
+ return;
+
local->last_scan_completed = jiffies;
memset(&wrqu, 0, sizeof(wrqu));
- wireless_send_event(local->scan_sdata->dev, SIOCGIWSCAN, &wrqu, NULL);
- if (local->sta_hw_scanning) {
- local->sta_hw_scanning = 0;
+ /*
+ * local->scan_sdata could have been NULLed by the interface
+ * down code in case we were scanning on an interface that is
+ * being taken down.
+ */
+ sdata = local->scan_sdata;
+ if (sdata)
+ wireless_send_event(sdata->dev, SIOCGIWSCAN, &wrqu, NULL);
+
+ if (local->hw_scanning) {
+ local->hw_scanning = false;
if (ieee80211_hw_config(local))
printk(KERN_DEBUG "%s: failed to restore operational "
"channel after scan\n", wiphy_name(local->hw.wiphy));
- /* Restart STA timer for HW scan case */
- rcu_read_lock();
- list_for_each_entry_rcu(sdata, &local->interfaces, list)
- ieee80211_restart_sta_timer(sdata);
- rcu_read_unlock();
goto done;
}
- local->sta_sw_scanning = 0;
+ local->sw_scanning = false;
if (ieee80211_hw_config(local))
printk(KERN_DEBUG "%s: failed to restore operational "
"channel after scan\n", wiphy_name(local->hw.wiphy));
@@ -476,25 +475,24 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw)
rcu_read_lock();
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
/* Tell AP we're back */
- if (sdata->vif.type == IEEE80211_IF_TYPE_STA) {
+ if (sdata->vif.type == NL80211_IFTYPE_STATION) {
if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) {
ieee80211_send_nullfunc(local, sdata, 0);
netif_tx_wake_all_queues(sdata->dev);
}
} else
netif_tx_wake_all_queues(sdata->dev);
-
- ieee80211_restart_sta_timer(sdata);
}
rcu_read_unlock();
done:
ieee80211_mlme_notify_scan_completed(local);
+ ieee80211_mesh_notify_scan_completed(local);
}
EXPORT_SYMBOL(ieee80211_scan_completed);
-void ieee80211_sta_scan_work(struct work_struct *work)
+void ieee80211_scan_work(struct work_struct *work)
{
struct ieee80211_local *local =
container_of(work, struct ieee80211_local, scan_work.work);
@@ -504,7 +502,10 @@ void ieee80211_sta_scan_work(struct work_struct *work)
int skip;
unsigned long next_delay = 0;
- if (!local->sta_sw_scanning)
+ /*
+ * Avoid re-scheduling when the sdata is going away.
+ */
+ if (!netif_running(sdata->dev))
return;
switch (local->scan_state) {
@@ -538,7 +539,7 @@ void ieee80211_sta_scan_work(struct work_struct *work)
chan = &sband->channels[local->scan_channel_idx];
if (chan->flags & IEEE80211_CHAN_DISABLED ||
- (sdata->vif.type == IEEE80211_IF_TYPE_IBSS &&
+ (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
chan->flags & IEEE80211_CHAN_NO_IBSS))
skip = 1;
@@ -583,14 +584,13 @@ void ieee80211_sta_scan_work(struct work_struct *work)
break;
}
- if (local->sta_sw_scanning)
- queue_delayed_work(local->hw.workqueue, &local->scan_work,
- next_delay);
+ queue_delayed_work(local->hw.workqueue, &local->scan_work,
+ next_delay);
}
-int ieee80211_sta_start_scan(struct ieee80211_sub_if_data *scan_sdata,
- u8 *ssid, size_t ssid_len)
+int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata,
+ u8 *ssid, size_t ssid_len)
{
struct ieee80211_local *local = scan_sdata->local;
struct ieee80211_sub_if_data *sdata;
@@ -615,27 +615,30 @@ int ieee80211_sta_start_scan(struct ieee80211_sub_if_data *scan_sdata,
* ResultCode: SUCCESS, INVALID_PARAMETERS
*/
- if (local->sta_sw_scanning || local->sta_hw_scanning) {
+ if (local->sw_scanning || local->hw_scanning) {
if (local->scan_sdata == scan_sdata)
return 0;
return -EBUSY;
}
if (local->ops->hw_scan) {
- int rc = local->ops->hw_scan(local_to_hw(local),
- ssid, ssid_len);
- if (!rc) {
- local->sta_hw_scanning = 1;
- local->scan_sdata = scan_sdata;
+ int rc;
+
+ local->hw_scanning = true;
+ rc = local->ops->hw_scan(local_to_hw(local), ssid, ssid_len);
+ if (rc) {
+ local->hw_scanning = false;
+ return rc;
}
- return rc;
+ local->scan_sdata = scan_sdata;
+ return 0;
}
- local->sta_sw_scanning = 1;
+ local->sw_scanning = true;
rcu_read_lock();
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
- if (sdata->vif.type == IEEE80211_IF_TYPE_STA) {
+ if (sdata->vif.type == NL80211_IFTYPE_STATION) {
if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) {
netif_tx_stop_all_queues(sdata->dev);
ieee80211_send_nullfunc(local, sdata, 1);
@@ -672,13 +675,14 @@ int ieee80211_sta_start_scan(struct ieee80211_sub_if_data *scan_sdata,
}
-int ieee80211_sta_req_scan(struct ieee80211_sub_if_data *sdata, u8 *ssid, size_t ssid_len)
+int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
+ u8 *ssid, size_t ssid_len)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_if_sta *ifsta;
- if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
- return ieee80211_sta_start_scan(sdata, ssid, ssid_len);
+ if (sdata->vif.type != NL80211_IFTYPE_STATION)
+ return ieee80211_start_scan(sdata, ssid, ssid_len);
/*
* STA has a state machine that might need to defer scanning
@@ -686,7 +690,7 @@ int ieee80211_sta_req_scan(struct ieee80211_sub_if_data *sdata, u8 *ssid, size_t
* queue it up to the state machine in that case.
*/
- if (local->sta_sw_scanning || local->sta_hw_scanning) {
+ if (local->sw_scanning || local->hw_scanning) {
if (local->scan_sdata == sdata)
return 0;
return -EBUSY;
@@ -704,9 +708,9 @@ int ieee80211_sta_req_scan(struct ieee80211_sub_if_data *sdata, u8 *ssid, size_t
}
-static void ieee80211_sta_add_scan_ies(struct iw_request_info *info,
- struct ieee80211_sta_bss *bss,
- char **current_ev, char *end_buf)
+static void ieee80211_scan_add_ies(struct iw_request_info *info,
+ struct ieee80211_bss *bss,
+ char **current_ev, char *end_buf)
{
u8 *pos, *end, *next;
struct iw_event iwe;
@@ -746,10 +750,10 @@ static void ieee80211_sta_add_scan_ies(struct iw_request_info *info,
static char *
-ieee80211_sta_scan_result(struct ieee80211_local *local,
- struct iw_request_info *info,
- struct ieee80211_sta_bss *bss,
- char *current_ev, char *end_buf)
+ieee80211_scan_result(struct ieee80211_local *local,
+ struct iw_request_info *info,
+ struct ieee80211_bss *bss,
+ char *current_ev, char *end_buf)
{
struct iw_event iwe;
char *buf;
@@ -825,7 +829,7 @@ ieee80211_sta_scan_result(struct ieee80211_local *local,
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
&iwe, "");
- ieee80211_sta_add_scan_ies(info, bss, ¤t_ev, end_buf);
+ ieee80211_scan_add_ies(info, bss, ¤t_ev, end_buf);
if (bss->supp_rates_len > 0) {
/* display all supported rates in readable format */
@@ -911,23 +915,23 @@ ieee80211_sta_scan_result(struct ieee80211_local *local,
}
-int ieee80211_sta_scan_results(struct ieee80211_local *local,
- struct iw_request_info *info,
- char *buf, size_t len)
+int ieee80211_scan_results(struct ieee80211_local *local,
+ struct iw_request_info *info,
+ char *buf, size_t len)
{
char *current_ev = buf;
char *end_buf = buf + len;
- struct ieee80211_sta_bss *bss;
+ struct ieee80211_bss *bss;
- spin_lock_bh(&local->sta_bss_lock);
- list_for_each_entry(bss, &local->sta_bss_list, list) {
+ spin_lock_bh(&local->bss_lock);
+ list_for_each_entry(bss, &local->bss_list, list) {
if (buf + len - current_ev <= IW_EV_ADDR_LEN) {
- spin_unlock_bh(&local->sta_bss_lock);
+ spin_unlock_bh(&local->bss_lock);
return -E2BIG;
}
- current_ev = ieee80211_sta_scan_result(local, info, bss,
+ current_ev = ieee80211_scan_result(local, info, bss,
current_ev, end_buf);
}
- spin_unlock_bh(&local->sta_bss_lock);
+ spin_unlock_bh(&local->bss_lock);
return current_ev - buf;
}
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index f2ba653b9d69..d9774ac2e0f7 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -73,11 +73,11 @@ static int sta_info_hash_del(struct ieee80211_local *local,
{
struct sta_info *s;
- s = local->sta_hash[STA_HASH(sta->addr)];
+ s = local->sta_hash[STA_HASH(sta->sta.addr)];
if (!s)
return -ENOENT;
if (s == sta) {
- rcu_assign_pointer(local->sta_hash[STA_HASH(sta->addr)],
+ rcu_assign_pointer(local->sta_hash[STA_HASH(sta->sta.addr)],
s->hnext);
return 0;
}
@@ -94,13 +94,13 @@ static int sta_info_hash_del(struct ieee80211_local *local,
/* protected by RCU */
static struct sta_info *__sta_info_find(struct ieee80211_local *local,
- u8 *addr)
+ const u8 *addr)
{
struct sta_info *sta;
sta = rcu_dereference(local->sta_hash[STA_HASH(addr)]);
while (sta) {
- if (compare_ether_addr(sta->addr, addr) == 0)
+ if (compare_ether_addr(sta->sta.addr, addr) == 0)
break;
sta = rcu_dereference(sta->hnext);
}
@@ -151,7 +151,7 @@ static void __sta_info_free(struct ieee80211_local *local,
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
printk(KERN_DEBUG "%s: Destroyed STA %s\n",
- wiphy_name(local->hw.wiphy), print_mac(mbuf, sta->addr));
+ wiphy_name(local->hw.wiphy), print_mac(mbuf, sta->sta.addr));
#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
kfree(sta);
@@ -219,8 +219,8 @@ void sta_info_destroy(struct sta_info *sta)
static void sta_info_hash_add(struct ieee80211_local *local,
struct sta_info *sta)
{
- sta->hnext = local->sta_hash[STA_HASH(sta->addr)];
- rcu_assign_pointer(local->sta_hash[STA_HASH(sta->addr)], sta);
+ sta->hnext = local->sta_hash[STA_HASH(sta->sta.addr)];
+ rcu_assign_pointer(local->sta_hash[STA_HASH(sta->sta.addr)], sta);
}
struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
@@ -231,14 +231,14 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
int i;
DECLARE_MAC_BUF(mbuf);
- sta = kzalloc(sizeof(*sta), gfp);
+ sta = kzalloc(sizeof(*sta) + local->hw.sta_data_size, gfp);
if (!sta)
return NULL;
spin_lock_init(&sta->lock);
spin_lock_init(&sta->flaglock);
- memcpy(sta->addr, addr, ETH_ALEN);
+ memcpy(sta->sta.addr, addr, ETH_ALEN);
sta->local = local;
sta->sdata = sdata;
@@ -271,7 +271,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
printk(KERN_DEBUG "%s: Allocated STA %s\n",
- wiphy_name(local->hw.wiphy), print_mac(mbuf, sta->addr));
+ wiphy_name(local->hw.wiphy), print_mac(mbuf, sta->sta.addr));
#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
#ifdef CONFIG_MAC80211_MESH
@@ -300,15 +300,15 @@ int sta_info_insert(struct sta_info *sta)
goto out_free;
}
- if (WARN_ON(compare_ether_addr(sta->addr, sdata->dev->dev_addr) == 0 ||
- is_multicast_ether_addr(sta->addr))) {
+ if (WARN_ON(compare_ether_addr(sta->sta.addr, sdata->dev->dev_addr) == 0 ||
+ is_multicast_ether_addr(sta->sta.addr))) {
err = -EINVAL;
goto out_free;
}
spin_lock_irqsave(&local->sta_lock, flags);
/* check if STA exists already */
- if (__sta_info_find(local, sta->addr)) {
+ if (__sta_info_find(local, sta->sta.addr)) {
spin_unlock_irqrestore(&local->sta_lock, flags);
err = -EEXIST;
goto out_free;
@@ -319,18 +319,18 @@ int sta_info_insert(struct sta_info *sta)
/* notify driver */
if (local->ops->sta_notify) {
- if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
+ if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
sdata = container_of(sdata->bss,
struct ieee80211_sub_if_data,
u.ap);
local->ops->sta_notify(local_to_hw(local), &sdata->vif,
- STA_NOTIFY_ADD, sta->addr);
+ STA_NOTIFY_ADD, &sta->sta);
}
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
printk(KERN_DEBUG "%s: Inserted STA %s\n",
- wiphy_name(local->hw.wiphy), print_mac(mac, sta->addr));
+ wiphy_name(local->hw.wiphy), print_mac(mac, sta->sta.addr));
#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
spin_unlock_irqrestore(&local->sta_lock, flags);
@@ -379,11 +379,12 @@ static void __sta_info_set_tim_bit(struct ieee80211_if_ap *bss,
{
BUG_ON(!bss);
- __bss_tim_set(bss, sta->aid);
+ __bss_tim_set(bss, sta->sta.aid);
if (sta->local->ops->set_tim) {
sta->local->tim_in_locked_section = true;
- sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 1);
+ sta->local->ops->set_tim(local_to_hw(sta->local),
+ &sta->sta, true);
sta->local->tim_in_locked_section = false;
}
}
@@ -404,11 +405,12 @@ static void __sta_info_clear_tim_bit(struct ieee80211_if_ap *bss,
{
BUG_ON(!bss);
- __bss_tim_clear(bss, sta->aid);
+ __bss_tim_clear(bss, sta->sta.aid);
if (sta->local->ops->set_tim) {
sta->local->tim_in_locked_section = true;
- sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 0);
+ sta->local->ops->set_tim(local_to_hw(sta->local),
+ &sta->sta, false);
sta->local->tim_in_locked_section = false;
}
}
@@ -424,7 +426,7 @@ void sta_info_clear_tim_bit(struct sta_info *sta)
spin_unlock_irqrestore(&sta->local->sta_lock, flags);
}
-void __sta_info_unlink(struct sta_info **sta)
+static void __sta_info_unlink(struct sta_info **sta)
{
struct ieee80211_local *local = (*sta)->local;
struct ieee80211_sub_if_data *sdata = (*sta)->sdata;
@@ -456,13 +458,13 @@ void __sta_info_unlink(struct sta_info **sta)
local->num_sta--;
if (local->ops->sta_notify) {
- if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
+ if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
sdata = container_of(sdata->bss,
struct ieee80211_sub_if_data,
u.ap);
local->ops->sta_notify(local_to_hw(local), &sdata->vif,
- STA_NOTIFY_REMOVE, (*sta)->addr);
+ STA_NOTIFY_REMOVE, &(*sta)->sta);
}
if (ieee80211_vif_is_mesh(&sdata->vif)) {
@@ -474,7 +476,7 @@ void __sta_info_unlink(struct sta_info **sta)
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
printk(KERN_DEBUG "%s: Removed STA %s\n",
- wiphy_name(local->hw.wiphy), print_mac(mbuf, (*sta)->addr));
+ wiphy_name(local->hw.wiphy), print_mac(mbuf, (*sta)->sta.addr));
#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
/*
@@ -570,7 +572,7 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
local->total_ps_buffered--;
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
printk(KERN_DEBUG "Buffered frame expired (STA "
- "%s)\n", print_mac(mac, sta->addr));
+ "%s)\n", print_mac(mac, sta->sta.addr));
#endif
dev_kfree_skb(skb);
@@ -802,3 +804,40 @@ void sta_info_flush_delayed(struct ieee80211_sub_if_data *sdata)
schedule_work(&local->sta_flush_work);
spin_unlock_irqrestore(&local->sta_lock, flags);
}
+
+void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
+ unsigned long exp_time)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct sta_info *sta, *tmp;
+ LIST_HEAD(tmp_list);
+ DECLARE_MAC_BUF(mac);
+ unsigned long flags;
+
+ spin_lock_irqsave(&local->sta_lock, flags);
+ list_for_each_entry_safe(sta, tmp, &local->sta_list, list)
+ if (time_after(jiffies, sta->last_rx + exp_time)) {
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
+ printk(KERN_DEBUG "%s: expiring inactive STA %s\n",
+ sdata->dev->name, print_mac(mac, sta->sta.addr));
+#endif
+ __sta_info_unlink(&sta);
+ if (sta)
+ list_add(&sta->list, &tmp_list);
+ }
+ spin_unlock_irqrestore(&local->sta_lock, flags);
+
+ list_for_each_entry_safe(sta, tmp, &tmp_list, list)
+ sta_info_destroy(sta);
+}
+
+struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_hw *hw,
+ const u8 *addr)
+{
+ struct sta_info *sta = __sta_info_find(hw_to_local(hw), addr);
+
+ if (!sta)
+ return NULL;
+ return &sta->sta;
+}
+EXPORT_SYMBOL(ieee80211_find_sta);
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 4a581a5b5766..daedfa9e1c63 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -167,8 +167,6 @@ struct sta_ampdu_mlme {
* @lock: used for locking all fields that require locking, see comments
* in the header file.
* @flaglock: spinlock for flags accesses
- * @ht_info: HT capabilities of this STA
- * @supp_rates: Bitmap of supported rates (per band)
* @addr: MAC address of this STA
* @aid: STA's unique AID (1..2007, 0 = not assigned yet),
* only used in AP (and IBSS?) mode
@@ -195,15 +193,11 @@ struct sta_ampdu_mlme {
* @tx_filtered_count: TBD
* @tx_retry_failed: TBD
* @tx_retry_count: TBD
- * @tx_num_consecutive_failures: TBD
- * @tx_num_mpdu_ok: TBD
- * @tx_num_mpdu_fail: TBD
* @fail_avg: moving percentage of failed MSDUs
* @tx_packets: number of RX/TX MSDUs
* @tx_bytes: TBD
* @tx_fragments: number of transmitted MPDUs
- * @txrate_idx: TBD
- * @last_txrate_idx: TBD
+ * @last_txrate_idx: Index of the last used transmit rate
* @tid_seq: TBD
* @wme_tx_queue: TBD
* @ampdu_mlme: TBD
@@ -218,6 +212,7 @@ struct sta_ampdu_mlme {
* @plink_timeout: TBD
* @plink_timer: TBD
* @debugfs: debug filesystem info
+ * @sta: station information we share with the driver
*/
struct sta_info {
/* General information, mostly static */
@@ -230,10 +225,7 @@ struct sta_info {
void *rate_ctrl_priv;
spinlock_t lock;
spinlock_t flaglock;
- struct ieee80211_ht_info ht_info;
- u64 supp_rates[IEEE80211_NUM_BANDS];
- u8 addr[ETH_ALEN];
- u16 aid;
+
u16 listen_interval;
/*
@@ -273,10 +265,6 @@ struct sta_info {
/* Updated from TX status path only, no locking requirements */
unsigned long tx_filtered_count;
unsigned long tx_retry_failed, tx_retry_count;
- /* TODO: update in generic code not rate control? */
- u32 tx_num_consecutive_failures;
- u32 tx_num_mpdu_ok;
- u32 tx_num_mpdu_fail;
/* moving percentage of failed MSDUs */
unsigned int fail_avg;
@@ -284,8 +272,7 @@ struct sta_info {
unsigned long tx_packets;
unsigned long tx_bytes;
unsigned long tx_fragments;
- int txrate_idx;
- int last_txrate_idx;
+ unsigned int last_txrate_idx;
u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1];
#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
unsigned int wme_tx_queue[NUM_RX_DATA_QUEUES];
@@ -327,6 +314,9 @@ struct sta_info {
struct dentry *agg_status;
} debugfs;
#endif
+
+ /* keep last! */
+ struct ieee80211_sta sta;
};
static inline enum plink_state sta_plink_state(struct sta_info *sta)
@@ -452,7 +442,6 @@ int sta_info_insert(struct sta_info *sta);
* has already unlinked it.
*/
void sta_info_unlink(struct sta_info **sta);
-void __sta_info_unlink(struct sta_info **sta);
void sta_info_destroy(struct sta_info *sta);
void sta_info_set_tim_bit(struct sta_info *sta);
@@ -464,5 +453,7 @@ void sta_info_stop(struct ieee80211_local *local);
int sta_info_flush(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata);
void sta_info_flush_delayed(struct ieee80211_sub_if_data *sdata);
+void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
+ unsigned long exp_time);
#endif /* STA_INFO_H */
diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c
index 995f7af3d25e..34b32bc8f609 100644
--- a/net/mac80211/tkip.c
+++ b/net/mac80211/tkip.c
@@ -304,7 +304,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
u8 bcast[ETH_ALEN] =
{0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
- u8 *sta_addr = key->sta->addr;
+ u8 *sta_addr = key->sta->sta.addr;
if (is_multicast_ether_addr(ra))
sta_addr = bcast;
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index c413d4836afe..20d683641b42 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -38,43 +38,6 @@
/* misc utils */
-#ifdef CONFIG_MAC80211_LOWTX_FRAME_DUMP
-static void ieee80211_dump_frame(const char *ifname, const char *title,
- const struct sk_buff *skb)
-{
- const struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- unsigned int hdrlen;
- DECLARE_MAC_BUF(mac);
-
- printk(KERN_DEBUG "%s: %s (len=%d)", ifname, title, skb->len);
- if (skb->len < 4) {
- printk("\n");
- return;
- }
-
- hdrlen = ieee80211_hdrlen(hdr->frame_control);
- if (hdrlen > skb->len)
- hdrlen = skb->len;
- if (hdrlen >= 4)
- printk(" FC=0x%04x DUR=0x%04x",
- le16_to_cpu(hdr->frame_control), le16_to_cpu(hdr->duration_id));
- if (hdrlen >= 10)
- printk(" A1=%s", print_mac(mac, hdr->addr1));
- if (hdrlen >= 16)
- printk(" A2=%s", print_mac(mac, hdr->addr2));
- if (hdrlen >= 24)
- printk(" A3=%s", print_mac(mac, hdr->addr3));
- if (hdrlen >= 30)
- printk(" A4=%s", print_mac(mac, hdr->addr4));
- printk("\n");
-}
-#else /* CONFIG_MAC80211_LOWTX_FRAME_DUMP */
-static inline void ieee80211_dump_frame(const char *ifname, const char *title,
- struct sk_buff *skb)
-{
-}
-#endif /* CONFIG_MAC80211_LOWTX_FRAME_DUMP */
-
static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr,
int next_frag_len)
{
@@ -111,7 +74,7 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr,
hdr = (struct ieee80211_hdr *)tx->skb->data;
if (ieee80211_is_ctl(hdr->frame_control)) {
/* TODO: These control frames are not currently sent by
- * 80211.o, but should they be implemented, this function
+ * mac80211, but should they be implemented, this function
* needs to be updated to support duration field calculation.
*
* RTS: time needed to transmit pending data/mgmt frame plus
@@ -153,7 +116,7 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr,
if (r->bitrate > txrate->bitrate)
break;
- if (tx->sdata->basic_rates & BIT(i))
+ if (tx->sdata->bss_conf.basic_rates & BIT(i))
rate = r->bitrate;
switch (sband->band) {
@@ -222,11 +185,11 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED))
return TX_CONTINUE;
- if (unlikely(tx->local->sta_sw_scanning) &&
+ if (unlikely(tx->local->sw_scanning) &&
!ieee80211_is_probe_req(hdr->frame_control))
return TX_DROP;
- if (tx->sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT)
+ if (tx->sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
return TX_CONTINUE;
if (tx->flags & IEEE80211_TX_PS_BUFFERED)
@@ -236,7 +199,7 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
if (likely(tx->flags & IEEE80211_TX_UNICAST)) {
if (unlikely(!(sta_flags & WLAN_STA_ASSOC) &&
- tx->sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
+ tx->sdata->vif.type != NL80211_IFTYPE_ADHOC &&
ieee80211_is_data(hdr->frame_control))) {
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
DECLARE_MAC_BUF(mac);
@@ -250,7 +213,7 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
} else {
if (unlikely(ieee80211_is_data(hdr->frame_control) &&
tx->local->num_sta == 0 &&
- tx->sdata->vif.type != IEEE80211_IF_TYPE_IBSS)) {
+ tx->sdata->vif.type != NL80211_IFTYPE_ADHOC)) {
/*
* No associated STAs - no need to send multicast
* frames.
@@ -281,7 +244,7 @@ static void purge_old_ps_buffers(struct ieee80211_local *local)
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
struct ieee80211_if_ap *ap;
- if (sdata->vif.type != IEEE80211_IF_TYPE_AP)
+ if (sdata->vif.type != NL80211_IFTYPE_AP)
continue;
ap = &sdata->u.ap;
skb = skb_dequeue(&ap->ps_bc_buf);
@@ -381,7 +344,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
printk(KERN_DEBUG "STA %s aid %d: PS buffer (entries "
"before %d)\n",
- print_mac(mac, sta->addr), sta->aid,
+ print_mac(mac, sta->sta.addr), sta->sta.aid,
skb_queue_len(&sta->ps_tx_buf));
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
@@ -392,7 +355,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
if (net_ratelimit()) {
printk(KERN_DEBUG "%s: STA %s TX "
"buffer full - dropping oldest frame\n",
- tx->dev->name, print_mac(mac, sta->addr));
+ tx->dev->name, print_mac(mac, sta->sta.addr));
}
#endif
dev_kfree_skb(old);
@@ -411,7 +374,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
else if (unlikely(test_sta_flags(sta, WLAN_STA_PS))) {
printk(KERN_DEBUG "%s: STA %s in PS mode, but pspoll "
"set -> send frame\n", tx->dev->name,
- print_mac(mac, sta->addr));
+ print_mac(mac, sta->sta.addr));
}
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
clear_sta_flags(sta, WLAN_STA_PSPOLL);
@@ -485,6 +448,8 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
if (likely(tx->rate_idx < 0)) {
rate_control_get_rate(tx->dev, sband, tx->skb, &rsel);
+ if (tx->sta)
+ tx->sta->last_txrate_idx = rsel.rate_idx;
tx->rate_idx = rsel.rate_idx;
if (unlikely(rsel.probe_idx >= 0)) {
info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
@@ -528,7 +493,7 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx)
sband = tx->local->hw.wiphy->bands[tx->channel->band];
if (tx->sta)
- info->control.aid = tx->sta->aid;
+ info->control.sta = &tx->sta->sta;
if (!info->control.retry_limit) {
if (!is_multicast_ether_addr(hdr->addr1)) {
@@ -594,7 +559,7 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx)
for (idx = 0; idx < sband->n_bitrates; idx++) {
if (sband->bitrates[idx].bitrate > rate->bitrate)
continue;
- if (tx->sdata->basic_rates & BIT(idx) &&
+ if (tx->sdata->bss_conf.basic_rates & BIT(idx) &&
(baserate < 0 ||
(sband->bitrates[baserate].bitrate
< sband->bitrates[idx].bitrate)))
@@ -608,7 +573,7 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx)
}
if (tx->sta)
- info->control.aid = tx->sta->aid;
+ info->control.sta = &tx->sta->sta;
return TX_CONTINUE;
}
@@ -622,7 +587,14 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx)
u8 *qc;
int tid;
- /* only for injected frames */
+ /*
+ * Packet injection may want to control the sequence
+ * number, if we have no matching interface then we
+ * neither assign one ourselves nor ask the driver to.
+ */
+ if (unlikely(!info->control.vif))
+ return TX_CONTINUE;
+
if (unlikely(ieee80211_is_ctl(hdr->frame_control)))
return TX_CONTINUE;
@@ -847,7 +819,6 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
sband = tx->local->hw.wiphy->bands[tx->channel->band];
skb->do_not_encrypt = 1;
- info->flags |= IEEE80211_TX_CTL_INJECTED;
tx->flags &= ~IEEE80211_TX_FRAGMENTED;
/*
@@ -979,7 +950,7 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
/* process and remove the injection radiotap header */
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- if (unlikely(sdata->vif.type == IEEE80211_IF_TYPE_MNTR)) {
+ if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED)) {
if (__ieee80211_parse_tx_radiotap(tx, skb) == TX_DROP)
return TX_DROP;
@@ -1060,8 +1031,6 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb,
return IEEE80211_TX_AGAIN;
info = IEEE80211_SKB_CB(skb);
- ieee80211_dump_frame(wiphy_name(local->hw.wiphy),
- "TX to low-level driver", skb);
ret = local->ops->tx(local_to_hw(local), skb);
if (ret)
return IEEE80211_TX_AGAIN;
@@ -1091,9 +1060,6 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb,
~IEEE80211_TX_CTL_RATE_CTRL_PROBE;
}
- ieee80211_dump_frame(wiphy_name(local->hw.wiphy),
- "TX to low-level driver",
- tx->extra_frag[i]);
ret = local->ops->tx(local_to_hw(local),
tx->extra_frag[i]);
if (ret)
@@ -1298,6 +1264,11 @@ int ieee80211_master_start_xmit(struct sk_buff *skb,
struct ieee80211_sub_if_data *osdata;
int headroom;
bool may_encrypt;
+ enum {
+ NOT_MONITOR,
+ FOUND_SDATA,
+ UNKNOWN_ADDRESS,
+ } monitor_iface = NOT_MONITOR;
int ret;
if (skb->iif)
@@ -1330,9 +1301,53 @@ int ieee80211_master_start_xmit(struct sk_buff *skb,
if (mesh_nexthop_lookup(skb, osdata))
return 0;
if (memcmp(odev->dev_addr, hdr->addr4, ETH_ALEN) != 0)
- IEEE80211_IFSTA_MESH_CTR_INC(&osdata->u.sta,
+ IEEE80211_IFSTA_MESH_CTR_INC(&osdata->u.mesh,
fwded_frames);
}
+ } else if (unlikely(osdata->vif.type == NL80211_IFTYPE_MONITOR)) {
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_local *local = osdata->local;
+ struct ieee80211_hdr *hdr;
+ int hdrlen;
+ u16 len_rthdr;
+
+ info->flags |= IEEE80211_TX_CTL_INJECTED;
+ monitor_iface = UNKNOWN_ADDRESS;
+
+ len_rthdr = ieee80211_get_radiotap_len(skb->data);
+ hdr = (struct ieee80211_hdr *)skb->data + len_rthdr;
+ hdrlen = ieee80211_hdrlen(hdr->frame_control);
+
+ /* check the header is complete in the frame */
+ if (likely(skb->len >= len_rthdr + hdrlen)) {
+ /*
+ * We process outgoing injected frames that have a
+ * local address we handle as though they are our
+ * own frames.
+ * This code here isn't entirely correct, the local
+ * MAC address is not necessarily enough to find
+ * the interface to use; for that proper VLAN/WDS
+ * support we will need a different mechanism.
+ */
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(sdata, &local->interfaces,
+ list) {
+ if (!netif_running(sdata->dev))
+ continue;
+ if (compare_ether_addr(sdata->dev->dev_addr,
+ hdr->addr2)) {
+ dev_hold(sdata->dev);
+ dev_put(odev);
+ osdata = sdata;
+ odev = osdata->dev;
+ skb->iif = sdata->dev->ifindex;
+ monitor_iface = FOUND_SDATA;
+ break;
+ }
+ }
+ rcu_read_unlock();
+ }
}
may_encrypt = !skb->do_not_encrypt;
@@ -1349,7 +1364,12 @@ int ieee80211_master_start_xmit(struct sk_buff *skb,
return 0;
}
- info->control.vif = &osdata->vif;
+ if (osdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+ osdata = container_of(osdata->bss,
+ struct ieee80211_sub_if_data,
+ u.ap);
+ if (likely(monitor_iface != UNKNOWN_ADDRESS))
+ info->control.vif = &osdata->vif;
ret = ieee80211_tx(odev, skb);
dev_put(odev);
@@ -1457,8 +1477,8 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA);
switch (sdata->vif.type) {
- case IEEE80211_IF_TYPE_AP:
- case IEEE80211_IF_TYPE_VLAN:
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_AP_VLAN:
fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
/* DA BSSID SA */
memcpy(hdr.addr1, skb->data, ETH_ALEN);
@@ -1466,7 +1486,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN);
hdrlen = 24;
break;
- case IEEE80211_IF_TYPE_WDS:
+ case NL80211_IFTYPE_WDS:
fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
/* RA TA DA SA */
memcpy(hdr.addr1, sdata->u.wds.remote_addr, ETH_ALEN);
@@ -1476,16 +1496,16 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
hdrlen = 30;
break;
#ifdef CONFIG_MAC80211_MESH
- case IEEE80211_IF_TYPE_MESH_POINT:
+ case NL80211_IFTYPE_MESH_POINT:
fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
/* RA TA DA SA */
memset(hdr.addr1, 0, ETH_ALEN);
memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
memcpy(hdr.addr3, skb->data, ETH_ALEN);
memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
- if (!sdata->u.sta.mshcfg.dot11MeshTTL) {
+ if (!sdata->u.mesh.mshcfg.dot11MeshTTL) {
/* Do not send frames with mesh_ttl == 0 */
- sdata->u.sta.mshstats.dropped_frames_ttl++;
+ sdata->u.mesh.mshstats.dropped_frames_ttl++;
ret = 0;
goto fail;
}
@@ -1493,7 +1513,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
hdrlen = 30;
break;
#endif
- case IEEE80211_IF_TYPE_STA:
+ case NL80211_IFTYPE_STATION:
fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
/* BSSID SA DA */
memcpy(hdr.addr1, sdata->u.sta.bssid, ETH_ALEN);
@@ -1501,7 +1521,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
memcpy(hdr.addr3, skb->data, ETH_ALEN);
hdrlen = 24;
break;
- case IEEE80211_IF_TYPE_IBSS:
+ case NL80211_IFTYPE_ADHOC:
/* DA SA BSSID */
memcpy(hdr.addr1, skb->data, ETH_ALEN);
memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
@@ -1580,19 +1600,6 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
nh_pos -= skip_header_bytes;
h_pos -= skip_header_bytes;
- /* TODO: implement support for fragments so that there is no need to
- * reallocate and copy payload; it might be enough to support one
- * extra fragment that would be copied in the beginning of the frame
- * data.. anyway, it would be nice to include this into skb structure
- * somehow
- *
- * There are few options for this:
- * use skb->cb as an extra space for 802.11 header
- * allocate new buffer if not enough headroom
- * make sure that there is enough headroom in every skb by increasing
- * build in headroom in __dev_alloc_skb() (linux/skbuff.h) and
- * alloc_skb() (net/core/skbuff.c)
- */
head_need = hdrlen + encaps_len + meshhdrlen - skb_headroom(skb);
/*
@@ -1815,10 +1822,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
struct rate_selection rsel;
struct beacon_data *beacon;
struct ieee80211_supported_band *sband;
- struct ieee80211_mgmt *mgmt;
- int *num_beacons;
enum ieee80211_band band = local->hw.conf.channel->band;
- u8 *pos;
sband = local->hw.wiphy->bands[band];
@@ -1827,7 +1831,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
sdata = vif_to_sdata(vif);
bdev = sdata->dev;
- if (sdata->vif.type == IEEE80211_IF_TYPE_AP) {
+ if (sdata->vif.type == NL80211_IFTYPE_AP) {
ap = &sdata->u.ap;
beacon = rcu_dereference(ap->beacon);
if (ap && beacon) {
@@ -1865,11 +1869,9 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
if (beacon->tail)
memcpy(skb_put(skb, beacon->tail_len),
beacon->tail, beacon->tail_len);
-
- num_beacons = &ap->num_beacons;
} else
goto out;
- } else if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
+ } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
struct ieee80211_hdr *hdr;
ifsta = &sdata->u.sta;
@@ -1884,8 +1886,10 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_BEACON);
- num_beacons = &ifsta->num_beacons;
} else if (ieee80211_vif_is_mesh(&sdata->vif)) {
+ struct ieee80211_mgmt *mgmt;
+ u8 *pos;
+
/* headroom, head length, tail length and maximum TIM length */
skb = dev_alloc_skb(local->tx_headroom + 400);
if (!skb)
@@ -1909,8 +1913,6 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
*pos++ = 0x0;
mesh_mgmt_ies_add(skb, sdata);
-
- num_beacons = &sdata->u.sta.num_beacons;
} else {
WARN_ON(1);
goto out;
@@ -1947,7 +1949,6 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
info->antenna_sel_tx = local->hw.conf.antenna_sel_tx;
info->control.retry_limit = 1;
- (*num_beacons)++;
out:
rcu_read_unlock();
return skb;
@@ -2009,7 +2010,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
rcu_read_lock();
beacon = rcu_dereference(bss->beacon);
- if (sdata->vif.type != IEEE80211_IF_TYPE_AP || !beacon || !beacon->head)
+ if (sdata->vif.type != NL80211_IFTYPE_AP || !beacon || !beacon->head)
goto out;
if (bss->dtim_count != 0)
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index c3a22ab2ad2e..f32561ec224c 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -43,7 +43,7 @@ const unsigned char bridge_tunnel_header[] __aligned(2) =
u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
- enum ieee80211_if_types type)
+ enum nl80211_iftype type)
{
__le16 fc = hdr->frame_control;
@@ -77,10 +77,10 @@ u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
if (ieee80211_is_back_req(fc)) {
switch (type) {
- case IEEE80211_IF_TYPE_STA:
+ case NL80211_IFTYPE_STATION:
return hdr->addr2;
- case IEEE80211_IF_TYPE_AP:
- case IEEE80211_IF_TYPE_VLAN:
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_AP_VLAN:
return hdr->addr1;
default:
break; /* fall through to the return */
@@ -231,16 +231,21 @@ __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw,
struct ieee80211_rate *rate)
{
struct ieee80211_local *local = hw_to_local(hw);
- struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+ struct ieee80211_sub_if_data *sdata;
u16 dur;
int erp;
+ bool short_preamble = false;
erp = 0;
- if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
- erp = rate->flags & IEEE80211_RATE_ERP_G;
+ if (vif) {
+ sdata = vif_to_sdata(vif);
+ short_preamble = sdata->bss_conf.use_short_preamble;
+ if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
+ erp = rate->flags & IEEE80211_RATE_ERP_G;
+ }
dur = ieee80211_frame_duration(local, frame_len, rate->bitrate, erp,
- sdata->bss_conf.use_short_preamble);
+ short_preamble);
return cpu_to_le16(dur);
}
@@ -252,7 +257,7 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
{
struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_rate *rate;
- struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+ struct ieee80211_sub_if_data *sdata;
bool short_preamble;
int erp;
u16 dur;
@@ -260,13 +265,17 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
- short_preamble = sdata->bss_conf.use_short_preamble;
+ short_preamble = false;
rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx];
erp = 0;
- if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
- erp = rate->flags & IEEE80211_RATE_ERP_G;
+ if (vif) {
+ sdata = vif_to_sdata(vif);
+ short_preamble = sdata->bss_conf.use_short_preamble;
+ if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
+ erp = rate->flags & IEEE80211_RATE_ERP_G;
+ }
/* CTS duration */
dur = ieee80211_frame_duration(local, 10, rate->bitrate,
@@ -289,7 +298,7 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
{
struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_rate *rate;
- struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+ struct ieee80211_sub_if_data *sdata;
bool short_preamble;
int erp;
u16 dur;
@@ -297,12 +306,16 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
- short_preamble = sdata->bss_conf.use_short_preamble;
+ short_preamble = false;
rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx];
erp = 0;
- if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
- erp = rate->flags & IEEE80211_RATE_ERP_G;
+ if (vif) {
+ sdata = vif_to_sdata(vif);
+ short_preamble = sdata->bss_conf.use_short_preamble;
+ if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
+ erp = rate->flags & IEEE80211_RATE_ERP_G;
+ }
/* Data frame duration */
dur = ieee80211_frame_duration(local, frame_len, rate->bitrate,
@@ -376,15 +389,16 @@ void ieee80211_iterate_active_interfaces(
list_for_each_entry(sdata, &local->interfaces, list) {
switch (sdata->vif.type) {
- case IEEE80211_IF_TYPE_INVALID:
- case IEEE80211_IF_TYPE_MNTR:
- case IEEE80211_IF_TYPE_VLAN:
+ case __NL80211_IFTYPE_AFTER_LAST:
+ case NL80211_IFTYPE_UNSPECIFIED:
+ case NL80211_IFTYPE_MONITOR:
+ case NL80211_IFTYPE_AP_VLAN:
continue;
- case IEEE80211_IF_TYPE_AP:
- case IEEE80211_IF_TYPE_STA:
- case IEEE80211_IF_TYPE_IBSS:
- case IEEE80211_IF_TYPE_WDS:
- case IEEE80211_IF_TYPE_MESH_POINT:
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_WDS:
+ case NL80211_IFTYPE_MESH_POINT:
break;
}
if (netif_running(sdata->dev))
@@ -409,15 +423,16 @@ void ieee80211_iterate_active_interfaces_atomic(
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
switch (sdata->vif.type) {
- case IEEE80211_IF_TYPE_INVALID:
- case IEEE80211_IF_TYPE_MNTR:
- case IEEE80211_IF_TYPE_VLAN:
+ case __NL80211_IFTYPE_AFTER_LAST:
+ case NL80211_IFTYPE_UNSPECIFIED:
+ case NL80211_IFTYPE_MONITOR:
+ case NL80211_IFTYPE_AP_VLAN:
continue;
- case IEEE80211_IF_TYPE_AP:
- case IEEE80211_IF_TYPE_STA:
- case IEEE80211_IF_TYPE_IBSS:
- case IEEE80211_IF_TYPE_WDS:
- case IEEE80211_IF_TYPE_MESH_POINT:
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_WDS:
+ case NL80211_IFTYPE_MESH_POINT:
break;
}
if (netif_running(sdata->dev))
@@ -612,3 +627,59 @@ void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
dev_queue_xmit(skb);
}
+
+int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freqMHz)
+{
+ int ret = -EINVAL;
+ struct ieee80211_channel *chan;
+ struct ieee80211_local *local = sdata->local;
+
+ chan = ieee80211_get_channel(local->hw.wiphy, freqMHz);
+
+ if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) {
+ if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
+ chan->flags & IEEE80211_CHAN_NO_IBSS) {
+ printk(KERN_DEBUG "%s: IBSS not allowed on frequency "
+ "%d MHz\n", sdata->dev->name, chan->center_freq);
+ return ret;
+ }
+ local->oper_channel = chan;
+
+ if (local->sw_scanning || local->hw_scanning)
+ ret = 0;
+ else
+ ret = ieee80211_hw_config(local);
+
+ rate_control_clear(local);
+ }
+
+ return ret;
+}
+
+u64 ieee80211_mandatory_rates(struct ieee80211_local *local,
+ enum ieee80211_band band)
+{
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_rate *bitrates;
+ u64 mandatory_rates;
+ enum ieee80211_rate_flags mandatory_flag;
+ int i;
+
+ sband = local->hw.wiphy->bands[band];
+ if (!sband) {
+ WARN_ON(1);
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+ }
+
+ if (band == IEEE80211_BAND_2GHZ)
+ mandatory_flag = IEEE80211_RATE_MANDATORY_B;
+ else
+ mandatory_flag = IEEE80211_RATE_MANDATORY_A;
+
+ bitrates = sband->bitrates;
+ mandatory_rates = 0;
+ for (i = 0; i < sband->n_bitrates; i++)
+ if (bitrates[i].flags & mandatory_flag)
+ mandatory_rates |= BIT(i);
+ return mandatory_rates;
+}
diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c
index beae664ab480..7e0d53abde24 100644
--- a/net/mac80211/wext.c
+++ b/net/mac80211/wext.c
@@ -122,8 +122,8 @@ static int ieee80211_ioctl_siwgenie(struct net_device *dev,
if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)
return -EOPNOTSUPP;
- if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
- sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
+ if (sdata->vif.type == NL80211_IFTYPE_STATION ||
+ sdata->vif.type == NL80211_IFTYPE_ADHOC) {
int ret = ieee80211_sta_set_extra_ie(sdata, extra, data->length);
if (ret)
return ret;
@@ -273,21 +273,21 @@ static int ieee80211_ioctl_siwmode(struct net_device *dev,
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
int type;
- if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
+ if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
return -EOPNOTSUPP;
switch (*mode) {
case IW_MODE_INFRA:
- type = IEEE80211_IF_TYPE_STA;
+ type = NL80211_IFTYPE_STATION;
break;
case IW_MODE_ADHOC:
- type = IEEE80211_IF_TYPE_IBSS;
+ type = NL80211_IFTYPE_ADHOC;
break;
case IW_MODE_REPEAT:
- type = IEEE80211_IF_TYPE_WDS;
+ type = NL80211_IFTYPE_WDS;
break;
case IW_MODE_MONITOR:
- type = IEEE80211_IF_TYPE_MNTR;
+ type = NL80211_IFTYPE_MONITOR;
break;
default:
return -EINVAL;
@@ -305,22 +305,22 @@ static int ieee80211_ioctl_giwmode(struct net_device *dev,
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
switch (sdata->vif.type) {
- case IEEE80211_IF_TYPE_AP:
+ case NL80211_IFTYPE_AP:
*mode = IW_MODE_MASTER;
break;
- case IEEE80211_IF_TYPE_STA:
+ case NL80211_IFTYPE_STATION:
*mode = IW_MODE_INFRA;
break;
- case IEEE80211_IF_TYPE_IBSS:
+ case NL80211_IFTYPE_ADHOC:
*mode = IW_MODE_ADHOC;
break;
- case IEEE80211_IF_TYPE_MNTR:
+ case NL80211_IFTYPE_MONITOR:
*mode = IW_MODE_MONITOR;
break;
- case IEEE80211_IF_TYPE_WDS:
+ case NL80211_IFTYPE_WDS:
*mode = IW_MODE_REPEAT;
break;
- case IEEE80211_IF_TYPE_VLAN:
+ case NL80211_IFTYPE_AP_VLAN:
*mode = IW_MODE_SECOND; /* FIXME */
break;
default:
@@ -330,47 +330,19 @@ static int ieee80211_ioctl_giwmode(struct net_device *dev,
return 0;
}
-int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freqMHz)
-{
- int ret = -EINVAL;
- struct ieee80211_channel *chan;
- struct ieee80211_local *local = sdata->local;
-
- chan = ieee80211_get_channel(local->hw.wiphy, freqMHz);
-
- if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) {
- if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS &&
- chan->flags & IEEE80211_CHAN_NO_IBSS) {
- printk(KERN_DEBUG "%s: IBSS not allowed on frequency "
- "%d MHz\n", sdata->dev->name, chan->center_freq);
- return ret;
- }
- local->oper_channel = chan;
-
- if (local->sta_sw_scanning || local->sta_hw_scanning)
- ret = 0;
- else
- ret = ieee80211_hw_config(local);
-
- rate_control_clear(local);
- }
-
- return ret;
-}
-
static int ieee80211_ioctl_siwfreq(struct net_device *dev,
struct iw_request_info *info,
struct iw_freq *freq, char *extra)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- if (sdata->vif.type == IEEE80211_IF_TYPE_STA)
+ if (sdata->vif.type == NL80211_IFTYPE_STATION)
sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_CHANNEL_SEL;
/* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */
if (freq->e == 0) {
if (freq->m < 0) {
- if (sdata->vif.type == IEEE80211_IF_TYPE_STA)
+ if (sdata->vif.type == NL80211_IFTYPE_STATION)
sdata->u.sta.flags |=
IEEE80211_STA_AUTO_CHANNEL_SEL;
return 0;
@@ -414,8 +386,8 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev,
len--;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
- sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
+ if (sdata->vif.type == NL80211_IFTYPE_STATION ||
+ sdata->vif.type == NL80211_IFTYPE_ADHOC) {
int ret;
if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) {
if (len > IEEE80211_MAX_SSID_LEN)
@@ -435,7 +407,7 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev,
return 0;
}
- if (sdata->vif.type == IEEE80211_IF_TYPE_AP) {
+ if (sdata->vif.type == NL80211_IFTYPE_AP) {
memcpy(sdata->u.ap.ssid, ssid, len);
memset(sdata->u.ap.ssid + len, 0,
IEEE80211_MAX_SSID_LEN - len);
@@ -454,8 +426,8 @@ static int ieee80211_ioctl_giwessid(struct net_device *dev,
struct ieee80211_sub_if_data *sdata;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
- sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
+ if (sdata->vif.type == NL80211_IFTYPE_STATION ||
+ sdata->vif.type == NL80211_IFTYPE_ADHOC) {
int res = ieee80211_sta_get_ssid(sdata, ssid, &len);
if (res == 0) {
data->length = len;
@@ -465,7 +437,7 @@ static int ieee80211_ioctl_giwessid(struct net_device *dev,
return res;
}
- if (sdata->vif.type == IEEE80211_IF_TYPE_AP) {
+ if (sdata->vif.type == NL80211_IFTYPE_AP) {
len = sdata->u.ap.ssid_len;
if (len > IW_ESSID_MAX_SIZE)
len = IW_ESSID_MAX_SIZE;
@@ -485,8 +457,8 @@ static int ieee80211_ioctl_siwap(struct net_device *dev,
struct ieee80211_sub_if_data *sdata;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
- sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
+ if (sdata->vif.type == NL80211_IFTYPE_STATION ||
+ sdata->vif.type == NL80211_IFTYPE_ADHOC) {
int ret;
if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) {
memcpy(sdata->u.sta.bssid, (u8 *) &ap_addr->sa_data,
@@ -505,7 +477,7 @@ static int ieee80211_ioctl_siwap(struct net_device *dev,
return ret;
ieee80211_sta_req_auth(sdata, &sdata->u.sta);
return 0;
- } else if (sdata->vif.type == IEEE80211_IF_TYPE_WDS) {
+ } else if (sdata->vif.type == NL80211_IFTYPE_WDS) {
/*
* If it is necessary to update the WDS peer address
* while the interface is running, then we need to do
@@ -533,8 +505,8 @@ static int ieee80211_ioctl_giwap(struct net_device *dev,
struct ieee80211_sub_if_data *sdata;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
- sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
+ if (sdata->vif.type == NL80211_IFTYPE_STATION ||
+ sdata->vif.type == NL80211_IFTYPE_ADHOC) {
if (sdata->u.sta.state == IEEE80211_STA_MLME_ASSOCIATED ||
sdata->u.sta.state == IEEE80211_STA_MLME_IBSS_JOINED) {
ap_addr->sa_family = ARPHRD_ETHER;
@@ -544,7 +516,7 @@ static int ieee80211_ioctl_giwap(struct net_device *dev,
memset(&ap_addr->sa_data, 0, ETH_ALEN);
return 0;
}
- } else if (sdata->vif.type == IEEE80211_IF_TYPE_WDS) {
+ } else if (sdata->vif.type == NL80211_IFTYPE_WDS) {
ap_addr->sa_family = ARPHRD_ETHER;
memcpy(&ap_addr->sa_data, sdata->u.wds.remote_addr, ETH_ALEN);
return 0;
@@ -566,10 +538,10 @@ static int ieee80211_ioctl_siwscan(struct net_device *dev,
if (!netif_running(dev))
return -ENETDOWN;
- if (sdata->vif.type != IEEE80211_IF_TYPE_STA &&
- sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
- sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT &&
- sdata->vif.type != IEEE80211_IF_TYPE_AP)
+ if (sdata->vif.type != NL80211_IFTYPE_STATION &&
+ sdata->vif.type != NL80211_IFTYPE_ADHOC &&
+ sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
+ sdata->vif.type != NL80211_IFTYPE_AP)
return -EOPNOTSUPP;
/* if SSID was specified explicitly then use that */
@@ -580,7 +552,7 @@ static int ieee80211_ioctl_siwscan(struct net_device *dev,
ssid_len = req->essid_len;
}
- return ieee80211_sta_req_scan(sdata, ssid, ssid_len);
+ return ieee80211_request_scan(sdata, ssid, ssid_len);
}
@@ -594,10 +566,10 @@ static int ieee80211_ioctl_giwscan(struct net_device *dev,
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- if (local->sta_sw_scanning || local->sta_hw_scanning)
+ if (local->sw_scanning || local->hw_scanning)
return -EAGAIN;
- res = ieee80211_sta_scan_results(local, info, extra, data->length);
+ res = ieee80211_scan_results(local, info, extra, data->length);
if (res >= 0) {
data->length = res;
return 0;
@@ -655,7 +627,7 @@ static int ieee80211_ioctl_giwrate(struct net_device *dev,
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
+ if (sdata->vif.type != NL80211_IFTYPE_STATION)
return -EOPNOTSUPP;
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
@@ -664,8 +636,8 @@ static int ieee80211_ioctl_giwrate(struct net_device *dev,
sta = sta_info_get(local, sdata->u.sta.bssid);
- if (sta && sta->txrate_idx < sband->n_bitrates)
- rate->value = sband->bitrates[sta->txrate_idx].bitrate;
+ if (sta && sta->last_txrate_idx < sband->n_bitrates)
+ rate->value = sband->bitrates[sta->last_txrate_idx].bitrate;
else
rate->value = 0;
@@ -886,8 +858,8 @@ static int ieee80211_ioctl_siwmlme(struct net_device *dev,
struct iw_mlme *mlme = (struct iw_mlme *) extra;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- if (sdata->vif.type != IEEE80211_IF_TYPE_STA &&
- sdata->vif.type != IEEE80211_IF_TYPE_IBSS)
+ if (sdata->vif.type != NL80211_IFTYPE_STATION &&
+ sdata->vif.type != NL80211_IFTYPE_ADHOC)
return -EINVAL;
switch (mlme->cmd) {
@@ -982,7 +954,7 @@ static int ieee80211_ioctl_giwencode(struct net_device *dev,
erq->length = sdata->keys[idx]->conf.keylen;
erq->flags |= IW_ENCODE_ENABLED;
- if (sdata->vif.type == IEEE80211_IF_TYPE_STA) {
+ if (sdata->vif.type == NL80211_IFTYPE_STATION) {
struct ieee80211_if_sta *ifsta = &sdata->u.sta;
switch (ifsta->auth_alg) {
case WLAN_AUTH_OPEN:
@@ -1056,7 +1028,7 @@ static int ieee80211_ioctl_siwauth(struct net_device *dev,
sdata->drop_unencrypted = !!data->value;
break;
case IW_AUTH_PRIVACY_INVOKED:
- if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
+ if (sdata->vif.type != NL80211_IFTYPE_STATION)
ret = -EINVAL;
else {
sdata->u.sta.flags &= ~IEEE80211_STA_PRIVACY_INVOKED;
@@ -1071,8 +1043,8 @@ static int ieee80211_ioctl_siwauth(struct net_device *dev,
}
break;
case IW_AUTH_80211_AUTH_ALG:
- if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
- sdata->vif.type == IEEE80211_IF_TYPE_IBSS)
+ if (sdata->vif.type == NL80211_IFTYPE_STATION ||
+ sdata->vif.type == NL80211_IFTYPE_ADHOC)
sdata->u.sta.auth_algs = data->value;
else
ret = -EOPNOTSUPP;
@@ -1094,8 +1066,8 @@ static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev
rcu_read_lock();
- if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
- sdata->vif.type == IEEE80211_IF_TYPE_IBSS)
+ if (sdata->vif.type == NL80211_IFTYPE_STATION ||
+ sdata->vif.type == NL80211_IFTYPE_ADHOC)
sta = sta_info_get(local, sdata->u.sta.bssid);
if (!sta) {
wstats->discard.fragment = 0;
@@ -1125,8 +1097,8 @@ static int ieee80211_ioctl_giwauth(struct net_device *dev,
switch (data->flags & IW_AUTH_INDEX) {
case IW_AUTH_80211_AUTH_ALG:
- if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
- sdata->vif.type == IEEE80211_IF_TYPE_IBSS)
+ if (sdata->vif.type == NL80211_IFTYPE_STATION ||
+ sdata->vif.type == NL80211_IFTYPE_ADHOC)
data->value = sdata->u.sta.auth_algs;
else
ret = -EOPNOTSUPP;
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c
index 7229e958879d..6748dedcab50 100644
--- a/net/mac80211/wme.c
+++ b/net/mac80211/wme.c
@@ -210,7 +210,7 @@ int ieee80211_ht_agg_queue_add(struct ieee80211_local *local,
DECLARE_MAC_BUF(mac);
printk(KERN_DEBUG "allocated aggregation queue"
" %d tid %d addr %s pool=0x%lX\n",
- i, tid, print_mac(mac, sta->addr),
+ i, tid, print_mac(mac, sta->sta.addr),
local->queue_pool[0]);
}
#endif /* CONFIG_MAC80211_HT_DEBUG */
diff --git a/net/mac80211/wme.h b/net/mac80211/wme.h
index 465e274df7c5..bc62f28a4d3d 100644
--- a/net/mac80211/wme.h
+++ b/net/mac80211/wme.h
@@ -1,5 +1,4 @@
/*
- * IEEE 802.11 driver (80211.o) - QoS datatypes
* Copyright 2004, Instant802 Networks, Inc.
* Copyright 2005, Devicescape Software, Inc.
*
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
index 78021780b885..37ae9a959f63 100644
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -256,7 +256,7 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx)
res = ieee80211_tkip_decrypt_data(rx->local->wep_rx_tfm,
key, skb->data + hdrlen,
- skb->len - hdrlen, rx->sta->addr,
+ skb->len - hdrlen, rx->sta->sta.addr,
hdr->addr1, hwaccel, rx->queue,
&rx->tkip_iv32,
&rx->tkip_iv16);
diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c
index d5735799ccd9..ea0dc04b3c77 100644
--- a/net/rfkill/rfkill.c
+++ b/net/rfkill/rfkill.c
@@ -512,21 +512,9 @@ static void rfkill_release(struct device *dev)
#ifdef CONFIG_PM
static int rfkill_suspend(struct device *dev, pm_message_t state)
{
- struct rfkill *rfkill = to_rfkill(dev);
-
- if (dev->power.power_state.event != state.event) {
- if (state.event & PM_EVENT_SLEEP) {
- /* Stop transmitter, keep state, no notifies */
- update_rfkill_state(rfkill);
-
- mutex_lock(&rfkill->mutex);
- rfkill->toggle_radio(rfkill->data,
- RFKILL_STATE_SOFT_BLOCKED);
- mutex_unlock(&rfkill->mutex);
- }
-
+ /* mark class device as suspended */
+ if (dev->power.power_state.event != state.event)
dev->power.power_state = state;
- }
return 0;
}
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig
index 833b024f8f66..b97bd9fe6b79 100644
--- a/net/wireless/Kconfig
+++ b/net/wireless/Kconfig
@@ -14,6 +14,38 @@ config NL80211
If unsure, say Y.
+config WIRELESS_OLD_REGULATORY
+ bool "Old wireless static regulatory defintions"
+ default n
+ ---help---
+ This option enables the old static regulatory information
+ and uses it within the new framework. This is available
+ temporarily as an option to help prevent immediate issues
+ due to the switch to the new regulatory framework which
+ does require a new userspace application which has the
+ database of regulatory information (CRDA) and another for
+ setting regulatory domains (iw).
+
+ For more information see:
+
+ http://wireless.kernel.org/en/developers/Regulatory/CRDA
+ http://wireless.kernel.org/en/users/Documentation/iw
+
+ It is important to note though that if you *do* have CRDA present
+ and if this option is enabled CRDA *will* be called to update the
+ regulatory domain (for US and JP only). Support for letting the user
+ set the regulatory domain through iw is also supported. This option
+ mainly exists to leave around for a kernel release some old static
+ regulatory domains that were defined and to keep around the old
+ ieee80211_regdom module parameter. This is being phased out and you
+ should stop using them ASAP.
+
+ Say N unless you cannot install a new userspace application
+ or have one currently depending on the ieee80211_regdom module
+ parameter and cannot port it to use the new userspace interfaces.
+
+ This is scheduled for removal for 2.6.29.
+
config WIRELESS_EXT
bool "Wireless extensions"
default n
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 7e995ac06a0c..a910cd2d0fd1 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -13,12 +13,14 @@
#include
#include
#include
+#include
#include
#include
#include
#include "nl80211.h"
#include "core.h"
#include "sysfs.h"
+#include "reg.h"
/* name for sysfs, %d is appended */
#define PHY_NAME "phy"
@@ -27,6 +29,107 @@ MODULE_AUTHOR("Johannes Berg");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("wireless configuration support");
+struct list_head regulatory_requests;
+
+/* Central wireless core regulatory domains, we only need two,
+ * the current one and a world regulatory domain in case we have no
+ * information to give us an alpha2 */
+struct ieee80211_regdomain *cfg80211_regdomain;
+
+/* We keep a static world regulatory domain in case of the absence of CRDA */
+const struct ieee80211_regdomain world_regdom = {
+ .n_reg_rules = 1,
+ .alpha2 = "00",
+ .reg_rules = {
+ REG_RULE(2402, 2472, 40, 6, 20,
+ NL80211_RRF_PASSIVE_SCAN |
+ NL80211_RRF_NO_IBSS),
+ }
+};
+
+#ifdef CONFIG_WIRELESS_OLD_REGULATORY
+/* All this fucking static junk will be removed soon, so
+ * don't fucking count on it !@#$ */
+
+static char *ieee80211_regdom = "US";
+module_param(ieee80211_regdom, charp, 0444);
+MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");
+
+/* We assume 40 MHz bandwidth for the old regulatory work.
+ * We make emphasis we are using the exact same frequencies
+ * as before */
+
+const struct ieee80211_regdomain us_regdom = {
+ .n_reg_rules = 6,
+ .alpha2 = "US",
+ .reg_rules = {
+ /* IEEE 802.11b/g, channels 1..11 */
+ REG_RULE(2412-20, 2462+20, 40, 6, 27, 0),
+ /* IEEE 802.11a, channel 36 */
+ REG_RULE(5180-20, 5180+20, 40, 6, 23, 0),
+ /* IEEE 802.11a, channel 40 */
+ REG_RULE(5200-20, 5200+20, 40, 6, 23, 0),
+ /* IEEE 802.11a, channel 44 */
+ REG_RULE(5220-20, 5220+20, 40, 6, 23, 0),
+ /* IEEE 802.11a, channels 48..64 */
+ REG_RULE(5240-20, 5320+20, 40, 6, 23, 0),
+ /* IEEE 802.11a, channels 149..165, outdoor */
+ REG_RULE(5745-20, 5825+20, 40, 6, 30, 0),
+ }
+};
+
+const struct ieee80211_regdomain jp_regdom = {
+ .n_reg_rules = 3,
+ .alpha2 = "JP",
+ .reg_rules = {
+ /* IEEE 802.11b/g, channels 1..14 */
+ REG_RULE(2412-20, 2484+20, 40, 6, 20, 0),
+ /* IEEE 802.11a, channels 34..48 */
+ REG_RULE(5170-20, 5240+20, 40, 6, 20,
+ NL80211_RRF_PASSIVE_SCAN),
+ /* IEEE 802.11a, channels 52..64 */
+ REG_RULE(5260-20, 5320+20, 40, 6, 20,
+ NL80211_RRF_NO_IBSS |
+ NL80211_RRF_DFS),
+ }
+};
+
+const struct ieee80211_regdomain eu_regdom = {
+ .n_reg_rules = 6,
+ /* This alpha2 is bogus, we leave it here just for stupid
+ * backward compatibility */
+ .alpha2 = "EU",
+ .reg_rules = {
+ /* IEEE 802.11b/g, channels 1..13 */
+ REG_RULE(2412-20, 2472+20, 40, 6, 20, 0),
+ /* IEEE 802.11a, channel 36 */
+ REG_RULE(5180-20, 5180+20, 40, 6, 23,
+ NL80211_RRF_PASSIVE_SCAN),
+ /* IEEE 802.11a, channel 40 */
+ REG_RULE(5200-20, 5200+20, 40, 6, 23,
+ NL80211_RRF_PASSIVE_SCAN),
+ /* IEEE 802.11a, channel 44 */
+ REG_RULE(5220-20, 5220+20, 40, 6, 23,
+ NL80211_RRF_PASSIVE_SCAN),
+ /* IEEE 802.11a, channels 48..64 */
+ REG_RULE(5240-20, 5320+20, 40, 6, 20,
+ NL80211_RRF_NO_IBSS |
+ NL80211_RRF_DFS),
+ /* IEEE 802.11a, channels 100..140 */
+ REG_RULE(5500-20, 5700+20, 40, 6, 30,
+ NL80211_RRF_NO_IBSS |
+ NL80211_RRF_DFS),
+ }
+};
+
+#endif
+
+struct ieee80211_regdomain *cfg80211_world_regdom =
+ (struct ieee80211_regdomain *) &world_regdom;
+
+LIST_HEAD(regulatory_requests);
+DEFINE_MUTEX(cfg80211_reg_mutex);
+
/* RCU might be appropriate here since we usually
* only read the list, and that can happen quite
* often because we need to do it for each command */
@@ -302,7 +405,9 @@ int wiphy_register(struct wiphy *wiphy)
ieee80211_set_bitrate_flags(wiphy);
/* set up regulatory info */
- wiphy_update_regulatory(wiphy);
+ mutex_lock(&cfg80211_reg_mutex);
+ wiphy_update_regulatory(wiphy, REGDOM_SET_BY_CORE);
+ mutex_unlock(&cfg80211_reg_mutex);
mutex_lock(&cfg80211_drv_mutex);
@@ -409,9 +514,35 @@ static struct notifier_block cfg80211_netdev_notifier = {
.notifier_call = cfg80211_netdev_notifier_call,
};
+#ifdef CONFIG_WIRELESS_OLD_REGULATORY
+const struct ieee80211_regdomain *static_regdom(char *alpha2)
+{
+ if (alpha2[0] == 'U' && alpha2[1] == 'S')
+ return &us_regdom;
+ if (alpha2[0] == 'J' && alpha2[1] == 'P')
+ return &jp_regdom;
+ if (alpha2[0] == 'E' && alpha2[1] == 'U')
+ return &eu_regdom;
+ /* Default, as per the old rules */
+ return &us_regdom;
+}
+#endif
+
static int cfg80211_init(void)
{
- int err = wiphy_sysfs_init();
+ int err;
+
+#ifdef CONFIG_WIRELESS_OLD_REGULATORY
+ cfg80211_regdomain =
+ (struct ieee80211_regdomain *) static_regdom(ieee80211_regdom);
+ /* Used during reset_regdomains_static() */
+ cfg80211_world_regdom = cfg80211_regdomain;
+#else
+ cfg80211_regdomain =
+ (struct ieee80211_regdomain *) cfg80211_world_regdom;
+#endif
+
+ err = wiphy_sysfs_init();
if (err)
goto out_fail_sysfs;
@@ -425,8 +556,33 @@ static int cfg80211_init(void)
ieee80211_debugfs_dir = debugfs_create_dir("ieee80211", NULL);
+ err = regulatory_init();
+ if (err)
+ goto out_fail_reg;
+
+#ifdef CONFIG_WIRELESS_OLD_REGULATORY
+ printk(KERN_INFO "cfg80211: Using old static regulatory domain:\n");
+ print_regdomain_info(cfg80211_regdomain);
+ /* The old code still requests for a new regdomain and if
+ * you have CRDA you get it updated, otherwise you get
+ * stuck with the static values. We ignore "EU" code as
+ * that is not a valid ISO / IEC 3166 alpha2 */
+ if (ieee80211_regdom[0] != 'E' &&
+ ieee80211_regdom[1] != 'U')
+ err = __regulatory_hint(NULL, REGDOM_SET_BY_CORE,
+ ieee80211_regdom, NULL);
+#else
+ err = __regulatory_hint(NULL, REGDOM_SET_BY_CORE, "00", NULL);
+ if (err)
+ printk(KERN_ERR "cfg80211: calling CRDA failed - "
+ "unable to update world regulatory domain, "
+ "using static definition\n");
+#endif
+
return 0;
+out_fail_reg:
+ debugfs_remove(ieee80211_debugfs_dir);
out_fail_nl80211:
unregister_netdevice_notifier(&cfg80211_netdev_notifier);
out_fail_notifier:
@@ -434,6 +590,7 @@ out_fail_notifier:
out_fail_sysfs:
return err;
}
+
subsys_initcall(cfg80211_init);
static void cfg80211_exit(void)
@@ -442,5 +599,6 @@ static void cfg80211_exit(void)
nl80211_exit();
unregister_netdevice_notifier(&cfg80211_netdev_notifier);
wiphy_sysfs_exit();
+ regulatory_exit();
}
module_exit(cfg80211_exit);
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 7a02c356d63d..771cc5cc7658 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -79,6 +79,6 @@ extern int cfg80211_dev_rename(struct cfg80211_registered_device *drv,
char *newname);
void ieee80211_set_bitrate_flags(struct wiphy *wiphy);
-void wiphy_update_regulatory(struct wiphy *wiphy);
+void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby);
#endif /* __NET_WIRELESS_CORE_H */
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 77880ba8b619..1221d726ed50 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -18,6 +18,7 @@
#include
#include "core.h"
#include "nl80211.h"
+#include "reg.h"
/* the netlink family */
static struct genl_family nl80211_fam = {
@@ -88,6 +89,9 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
.len = IEEE80211_MAX_MESH_ID_LEN },
[NL80211_ATTR_MPATH_NEXT_HOP] = { .type = NLA_U32 },
+ [NL80211_ATTR_REG_ALPHA2] = { .type = NLA_STRING, .len = 2 },
+ [NL80211_ATTR_REG_RULES] = { .type = NLA_NESTED },
+
[NL80211_ATTR_BSS_CTS_PROT] = { .type = NLA_U8 },
[NL80211_ATTR_BSS_SHORT_PREAMBLE] = { .type = NLA_U8 },
[NL80211_ATTR_BSS_SHORT_SLOT_TIME] = { .type = NLA_U8 },
@@ -1599,6 +1603,141 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
return err;
}
+static const struct nla_policy
+ reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = {
+ [NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 },
+ [NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 },
+ [NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 },
+ [NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 },
+ [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 },
+ [NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 },
+};
+
+static int parse_reg_rule(struct nlattr *tb[],
+ struct ieee80211_reg_rule *reg_rule)
+{
+ struct ieee80211_freq_range *freq_range = ®_rule->freq_range;
+ struct ieee80211_power_rule *power_rule = ®_rule->power_rule;
+
+ if (!tb[NL80211_ATTR_REG_RULE_FLAGS])
+ return -EINVAL;
+ if (!tb[NL80211_ATTR_FREQ_RANGE_START])
+ return -EINVAL;
+ if (!tb[NL80211_ATTR_FREQ_RANGE_END])
+ return -EINVAL;
+ if (!tb[NL80211_ATTR_FREQ_RANGE_MAX_BW])
+ return -EINVAL;
+ if (!tb[NL80211_ATTR_POWER_RULE_MAX_EIRP])
+ return -EINVAL;
+
+ reg_rule->flags = nla_get_u32(tb[NL80211_ATTR_REG_RULE_FLAGS]);
+
+ freq_range->start_freq_khz =
+ nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]);
+ freq_range->end_freq_khz =
+ nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]);
+ freq_range->max_bandwidth_khz =
+ nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]);
+
+ power_rule->max_eirp =
+ nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]);
+
+ if (tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN])
+ power_rule->max_antenna_gain =
+ nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]);
+
+ return 0;
+}
+
+static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
+{
+ int r;
+ char *data = NULL;
+
+ if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
+ return -EINVAL;
+
+ data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
+
+#ifdef CONFIG_WIRELESS_OLD_REGULATORY
+ /* We ignore world regdom requests with the old regdom setup */
+ if (is_world_regdom(data))
+ return -EINVAL;
+#endif
+ mutex_lock(&cfg80211_drv_mutex);
+ r = __regulatory_hint(NULL, REGDOM_SET_BY_USER, data, NULL);
+ mutex_unlock(&cfg80211_drv_mutex);
+ return r;
+}
+
+static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
+{
+ struct nlattr *tb[NL80211_REG_RULE_ATTR_MAX + 1];
+ struct nlattr *nl_reg_rule;
+ char *alpha2 = NULL;
+ int rem_reg_rules = 0, r = 0;
+ u32 num_rules = 0, rule_idx = 0, size_of_regd;
+ struct ieee80211_regdomain *rd = NULL;
+
+ if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
+ return -EINVAL;
+
+ if (!info->attrs[NL80211_ATTR_REG_RULES])
+ return -EINVAL;
+
+ alpha2 = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
+
+ nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES],
+ rem_reg_rules) {
+ num_rules++;
+ if (num_rules > NL80211_MAX_SUPP_REG_RULES)
+ goto bad_reg;
+ }
+
+ if (!reg_is_valid_request(alpha2))
+ return -EINVAL;
+
+ size_of_regd = sizeof(struct ieee80211_regdomain) +
+ (num_rules * sizeof(struct ieee80211_reg_rule));
+
+ rd = kzalloc(size_of_regd, GFP_KERNEL);
+ if (!rd)
+ return -ENOMEM;
+
+ rd->n_reg_rules = num_rules;
+ rd->alpha2[0] = alpha2[0];
+ rd->alpha2[1] = alpha2[1];
+
+ nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES],
+ rem_reg_rules) {
+ nla_parse(tb, NL80211_REG_RULE_ATTR_MAX,
+ nla_data(nl_reg_rule), nla_len(nl_reg_rule),
+ reg_rule_policy);
+ r = parse_reg_rule(tb, &rd->reg_rules[rule_idx]);
+ if (r)
+ goto bad_reg;
+
+ rule_idx++;
+
+ if (rule_idx > NL80211_MAX_SUPP_REG_RULES)
+ goto bad_reg;
+ }
+
+ BUG_ON(rule_idx != num_rules);
+
+ mutex_lock(&cfg80211_drv_mutex);
+ r = set_regdom(rd);
+ mutex_unlock(&cfg80211_drv_mutex);
+ if (r)
+ goto bad_reg;
+
+ return r;
+
+bad_reg:
+ kfree(rd);
+ return -EINVAL;
+}
+
static struct genl_ops nl80211_ops[] = {
{
.cmd = NL80211_CMD_GET_WIPHY,
@@ -1736,6 +1875,18 @@ static struct genl_ops nl80211_ops[] = {
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
},
+ {
+ .cmd = NL80211_CMD_SET_REG,
+ .doit = nl80211_set_reg,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
+ {
+ .cmd = NL80211_CMD_REQ_SET_REG,
+ .doit = nl80211_req_set_reg,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
};
/* multicast groups */
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 855bff4b3250..592b2e391d42 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -2,179 +2,758 @@
* Copyright 2002-2005, Instant802 Networks, Inc.
* Copyright 2005-2006, Devicescape Software, Inc.
* Copyright 2007 Johannes Berg
+ * Copyright 2008 Luis R. Rodriguez
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-/*
- * This regulatory domain control implementation is highly incomplete, it
- * only exists for the purpose of not regressing mac80211.
- *
- * For now, drivers can restrict the set of allowed channels by either
- * not registering those channels or setting the IEEE80211_CHAN_DISABLED
- * flag; that flag will only be *set* by this code, never *cleared.
+/**
+ * DOC: Wireless regulatory infrastructure
*
* The usual implementation is for a driver to read a device EEPROM to
* determine which regulatory domain it should be operating under, then
* looking up the allowable channels in a driver-local table and finally
* registering those channels in the wiphy structure.
*
- * Alternatively, drivers that trust the regulatory domain control here
- * will register a complete set of capabilities and the control code
- * will restrict the set by setting the IEEE80211_CHAN_* flags.
+ * Another set of compliance enforcement is for drivers to use their
+ * own compliance limits which can be stored on the EEPROM. The host
+ * driver or firmware may ensure these are used.
+ *
+ * In addition to all this we provide an extra layer of regulatory
+ * conformance. For drivers which do not have any regulatory
+ * information CRDA provides the complete regulatory solution.
+ * For others it provides a community effort on further restrictions
+ * to enhance compliance.
+ *
+ * Note: When number of rules --> infinity we will not be able to
+ * index on alpha2 any more, instead we'll probably have to
+ * rely on some SHA1 checksum of the regdomain for example.
+ *
*/
#include
+#include
+#include
+#include
+#include
#include
+#include
#include "core.h"
+#include "reg.h"
-static char *ieee80211_regdom = "US";
-module_param(ieee80211_regdom, charp, 0444);
-MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");
+/* To trigger userspace events */
+static struct platform_device *reg_pdev;
-struct ieee80211_channel_range {
- short start_freq;
- short end_freq;
- int max_power;
- int max_antenna_gain;
- u32 flags;
+/* Keep the ordering from large to small */
+static u32 supported_bandwidths[] = {
+ MHZ_TO_KHZ(40),
+ MHZ_TO_KHZ(20),
};
-struct ieee80211_regdomain {
- const char *code;
- const struct ieee80211_channel_range *ranges;
- int n_ranges;
-};
-
-#define RANGE_PWR(_start, _end, _pwr, _ag, _flags) \
- { _start, _end, _pwr, _ag, _flags }
-
-
-/*
- * Ideally, in the future, these definitions will be loaded from a
- * userspace table via some daemon.
- */
-static const struct ieee80211_channel_range ieee80211_US_channels[] = {
- /* IEEE 802.11b/g, channels 1..11 */
- RANGE_PWR(2412, 2462, 27, 6, 0),
- /* IEEE 802.11a, channel 36*/
- RANGE_PWR(5180, 5180, 23, 6, 0),
- /* IEEE 802.11a, channel 40*/
- RANGE_PWR(5200, 5200, 23, 6, 0),
- /* IEEE 802.11a, channel 44*/
- RANGE_PWR(5220, 5220, 23, 6, 0),
- /* IEEE 802.11a, channels 48..64 */
- RANGE_PWR(5240, 5320, 23, 6, 0),
- /* IEEE 802.11a, channels 149..165, outdoor */
- RANGE_PWR(5745, 5825, 30, 6, 0),
-};
-
-static const struct ieee80211_channel_range ieee80211_JP_channels[] = {
- /* IEEE 802.11b/g, channels 1..14 */
- RANGE_PWR(2412, 2484, 20, 6, 0),
- /* IEEE 802.11a, channels 34..48 */
- RANGE_PWR(5170, 5240, 20, 6, IEEE80211_CHAN_PASSIVE_SCAN),
- /* IEEE 802.11a, channels 52..64 */
- RANGE_PWR(5260, 5320, 20, 6, IEEE80211_CHAN_NO_IBSS |
- IEEE80211_CHAN_RADAR),
-};
-
-static const struct ieee80211_channel_range ieee80211_EU_channels[] = {
- /* IEEE 802.11b/g, channels 1..13 */
- RANGE_PWR(2412, 2472, 20, 6, 0),
- /* IEEE 802.11a, channel 36*/
- RANGE_PWR(5180, 5180, 23, 6, IEEE80211_CHAN_PASSIVE_SCAN),
- /* IEEE 802.11a, channel 40*/
- RANGE_PWR(5200, 5200, 23, 6, IEEE80211_CHAN_PASSIVE_SCAN),
- /* IEEE 802.11a, channel 44*/
- RANGE_PWR(5220, 5220, 23, 6, IEEE80211_CHAN_PASSIVE_SCAN),
- /* IEEE 802.11a, channels 48..64 */
- RANGE_PWR(5240, 5320, 23, 6, IEEE80211_CHAN_NO_IBSS |
- IEEE80211_CHAN_RADAR),
- /* IEEE 802.11a, channels 100..140 */
- RANGE_PWR(5500, 5700, 30, 6, IEEE80211_CHAN_NO_IBSS |
- IEEE80211_CHAN_RADAR),
-};
-
-#define REGDOM(_code) \
- { \
- .code = __stringify(_code), \
- .ranges = ieee80211_ ##_code## _channels, \
- .n_ranges = ARRAY_SIZE(ieee80211_ ##_code## _channels), \
- }
-
-static const struct ieee80211_regdomain ieee80211_regdoms[] = {
- REGDOM(US),
- REGDOM(JP),
- REGDOM(EU),
-};
-
-
-static const struct ieee80211_regdomain *get_regdom(void)
+bool is_world_regdom(char *alpha2)
{
- static const struct ieee80211_channel_range
- ieee80211_world_channels[] = {
- /* IEEE 802.11b/g, channels 1..11 */
- RANGE_PWR(2412, 2462, 27, 6, 0),
- };
- static const struct ieee80211_regdomain regdom_world = REGDOM(world);
- int i;
-
- for (i = 0; i < ARRAY_SIZE(ieee80211_regdoms); i++)
- if (strcmp(ieee80211_regdom, ieee80211_regdoms[i].code) == 0)
- return &ieee80211_regdoms[i];
-
- return ®dom_world;
+ if (!alpha2)
+ return false;
+ if (alpha2[0] == '0' && alpha2[1] == '0')
+ return true;
+ return false;
}
+static bool is_alpha2_set(char *alpha2)
+{
+ if (!alpha2)
+ return false;
+ if (alpha2[0] != 0 && alpha2[1] != 0)
+ return true;
+ return false;
+}
-static void handle_channel(struct ieee80211_channel *chan,
- const struct ieee80211_regdomain *rd)
+static bool is_alpha_upper(char letter)
+{
+ /* ASCII A - Z */
+ if (letter >= 65 && letter <= 90)
+ return true;
+ return false;
+}
+
+static bool is_unknown_alpha2(char *alpha2)
+{
+ if (!alpha2)
+ return false;
+ /* Special case where regulatory domain was built by driver
+ * but a specific alpha2 cannot be determined */
+ if (alpha2[0] == '9' && alpha2[1] == '9')
+ return true;
+ return false;
+}
+
+static bool is_an_alpha2(char *alpha2)
+{
+ if (!alpha2)
+ return false;
+ if (is_alpha_upper(alpha2[0]) && is_alpha_upper(alpha2[1]))
+ return true;
+ return false;
+}
+
+static bool alpha2_equal(char *alpha2_x, char *alpha2_y)
+{
+ if (!alpha2_x || !alpha2_y)
+ return false;
+ if (alpha2_x[0] == alpha2_y[0] &&
+ alpha2_x[1] == alpha2_y[1])
+ return true;
+ return false;
+}
+
+static bool regdom_changed(char *alpha2)
+{
+ if (!cfg80211_regdomain)
+ return true;
+ if (alpha2_equal(cfg80211_regdomain->alpha2, alpha2))
+ return false;
+ return true;
+}
+
+/* This lets us keep regulatory code which is updated on a regulatory
+ * basis in userspace. */
+static int call_crda(const char *alpha2)
+{
+ char country_env[9 + 2] = "COUNTRY=";
+ char *envp[] = {
+ country_env,
+ NULL
+ };
+
+ if (!is_world_regdom((char *) alpha2))
+ printk(KERN_INFO "cfg80211: Calling CRDA for country: %c%c\n",
+ alpha2[0], alpha2[1]);
+ else
+#ifdef CONFIG_WIRELESS_OLD_REGULATORY
+ return -EINVAL;
+#else
+ printk(KERN_INFO "cfg80211: Calling CRDA to update world "
+ "regulatory domain\n");
+#endif
+
+ country_env[8] = alpha2[0];
+ country_env[9] = alpha2[1];
+
+ return kobject_uevent_env(®_pdev->dev.kobj, KOBJ_CHANGE, envp);
+}
+
+/* This has the logic which determines when a new request
+ * should be ignored. */
+static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,
+ char *alpha2, struct ieee80211_regdomain *rd)
+{
+ struct regulatory_request *last_request = NULL;
+
+ /* All initial requests are respected */
+ if (list_empty(®ulatory_requests))
+ return 0;
+
+ last_request = list_first_entry(®ulatory_requests,
+ struct regulatory_request, list);
+
+ switch (set_by) {
+ case REGDOM_SET_BY_INIT:
+ return -EINVAL;
+ case REGDOM_SET_BY_CORE:
+ /* Always respect new wireless core hints, should only
+ * come in for updating the world regulatory domain at init
+ * anyway */
+ return 0;
+ case REGDOM_SET_BY_COUNTRY_IE:
+ if (last_request->initiator == set_by) {
+ if (last_request->wiphy != wiphy) {
+ /* Two cards with two APs claiming different
+ * different Country IE alpha2s!
+ * You're special!! */
+ if (!alpha2_equal(last_request->alpha2,
+ cfg80211_regdomain->alpha2)) {
+ /* XXX: Deal with conflict, consider
+ * building a new one out of the
+ * intersection */
+ WARN_ON(1);
+ return -EOPNOTSUPP;
+ }
+ return -EALREADY;
+ }
+ /* Two consecutive Country IE hints on the same wiphy */
+ if (!alpha2_equal(cfg80211_regdomain->alpha2, alpha2))
+ return 0;
+ return -EALREADY;
+ }
+ if (WARN_ON(!is_alpha2_set(alpha2) || !is_an_alpha2(alpha2)),
+ "Invalid Country IE regulatory hint passed "
+ "to the wireless core\n")
+ return -EINVAL;
+ /* We ignore Country IE hints for now, as we haven't yet
+ * added the dot11MultiDomainCapabilityEnabled flag
+ * for wiphys */
+ return 1;
+ case REGDOM_SET_BY_DRIVER:
+ BUG_ON(!wiphy);
+ if (last_request->initiator == set_by) {
+ /* Two separate drivers hinting different things,
+ * this is possible if you have two devices present
+ * on a system with different EEPROM regulatory
+ * readings. XXX: Do intersection, we support only
+ * the first regulatory hint for now */
+ if (last_request->wiphy != wiphy)
+ return -EALREADY;
+ if (rd)
+ return -EALREADY;
+ /* Driver should not be trying to hint different
+ * regulatory domains! */
+ BUG_ON(!alpha2_equal(alpha2,
+ cfg80211_regdomain->alpha2));
+ return -EALREADY;
+ }
+ if (last_request->initiator == REGDOM_SET_BY_CORE)
+ return 0;
+ /* XXX: Handle intersection, and add the
+ * dot11MultiDomainCapabilityEnabled flag to wiphy. For now
+ * we assume the driver has this set to false, following the
+ * 802.11d dot11MultiDomainCapabilityEnabled documentation */
+ if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE)
+ return 0;
+ return 0;
+ case REGDOM_SET_BY_USER:
+ if (last_request->initiator == set_by ||
+ last_request->initiator == REGDOM_SET_BY_CORE)
+ return 0;
+ /* Drivers can use their wiphy's reg_notifier()
+ * to override any information */
+ if (last_request->initiator == REGDOM_SET_BY_DRIVER)
+ return 0;
+ /* XXX: Handle intersection */
+ if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE)
+ return -EOPNOTSUPP;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static bool __reg_is_valid_request(char *alpha2,
+ struct regulatory_request **request)
+{
+ struct regulatory_request *req;
+ if (list_empty(®ulatory_requests))
+ return false;
+ list_for_each_entry(req, ®ulatory_requests, list) {
+ if (alpha2_equal(req->alpha2, alpha2)) {
+ *request = req;
+ return true;
+ }
+ }
+ return false;
+}
+
+/* Used by nl80211 before kmalloc'ing our regulatory domain */
+bool reg_is_valid_request(char *alpha2)
+{
+ struct regulatory_request *request = NULL;
+ return __reg_is_valid_request(alpha2, &request);
+}
+
+/* Sanity check on a regulatory rule */
+static bool is_valid_reg_rule(struct ieee80211_reg_rule *rule)
+{
+ struct ieee80211_freq_range *freq_range = &rule->freq_range;
+ u32 freq_diff;
+
+ if (freq_range->start_freq_khz == 0 || freq_range->end_freq_khz == 0)
+ return false;
+
+ if (freq_range->start_freq_khz > freq_range->end_freq_khz)
+ return false;
+
+ freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz;
+
+ if (freq_range->max_bandwidth_khz > freq_diff)
+ return false;
+
+ return true;
+}
+
+static bool is_valid_rd(struct ieee80211_regdomain *rd)
+{
+ struct ieee80211_reg_rule *reg_rule = NULL;
+ unsigned int i;
+
+ if (!rd->n_reg_rules)
+ return false;
+
+ for (i = 0; i < rd->n_reg_rules; i++) {
+ reg_rule = &rd->reg_rules[i];
+ if (!is_valid_reg_rule(reg_rule))
+ return false;
+ }
+
+ return true;
+}
+
+/* Returns value in KHz */
+static u32 freq_max_bandwidth(const struct ieee80211_freq_range *freq_range,
+ u32 freq)
+{
+ unsigned int i;
+ for (i = 0; i < ARRAY_SIZE(supported_bandwidths); i++) {
+ u32 start_freq_khz = freq - supported_bandwidths[i]/2;
+ u32 end_freq_khz = freq + supported_bandwidths[i]/2;
+ if (start_freq_khz >= freq_range->start_freq_khz &&
+ end_freq_khz <= freq_range->end_freq_khz)
+ return supported_bandwidths[i];
+ }
+ return 0;
+}
+
+/* XXX: add support for the rest of enum nl80211_reg_rule_flags, we may
+ * want to just have the channel structure use these */
+static u32 map_regdom_flags(u32 rd_flags)
+{
+ u32 channel_flags = 0;
+ if (rd_flags & NL80211_RRF_PASSIVE_SCAN)
+ channel_flags |= IEEE80211_CHAN_PASSIVE_SCAN;
+ if (rd_flags & NL80211_RRF_NO_IBSS)
+ channel_flags |= IEEE80211_CHAN_NO_IBSS;
+ if (rd_flags & NL80211_RRF_DFS)
+ channel_flags |= IEEE80211_CHAN_RADAR;
+ return channel_flags;
+}
+
+/**
+ * freq_reg_info - get regulatory information for the given frequency
+ * @center_freq: Frequency in KHz for which we want regulatory information for
+ * @bandwidth: the bandwidth requirement you have in KHz, if you do not have one
+ * you can set this to 0. If this frequency is allowed we then set
+ * this value to the maximum allowed bandwidth.
+ * @reg_rule: the regulatory rule which we have for this frequency
+ *
+ * Use this function to get the regulatory rule for a specific frequency.
+ */
+static int freq_reg_info(u32 center_freq, u32 *bandwidth,
+ const struct ieee80211_reg_rule **reg_rule)
{
int i;
- u32 flags = chan->orig_flags;
- const struct ieee80211_channel_range *rg = NULL;
+ u32 max_bandwidth = 0;
- for (i = 0; i < rd->n_ranges; i++) {
- if (rd->ranges[i].start_freq <= chan->center_freq &&
- chan->center_freq <= rd->ranges[i].end_freq) {
- rg = &rd->ranges[i];
+ if (!cfg80211_regdomain)
+ return -EINVAL;
+
+ for (i = 0; i < cfg80211_regdomain->n_reg_rules; i++) {
+ const struct ieee80211_reg_rule *rr;
+ const struct ieee80211_freq_range *fr = NULL;
+ const struct ieee80211_power_rule *pr = NULL;
+
+ rr = &cfg80211_regdomain->reg_rules[i];
+ fr = &rr->freq_range;
+ pr = &rr->power_rule;
+ max_bandwidth = freq_max_bandwidth(fr, center_freq);
+ if (max_bandwidth && *bandwidth <= max_bandwidth) {
+ *reg_rule = rr;
+ *bandwidth = max_bandwidth;
break;
}
}
- if (!rg) {
- /* not found */
+ return !max_bandwidth;
+}
+
+static void handle_channel(struct ieee80211_channel *chan)
+{
+ int r;
+ u32 flags = chan->orig_flags;
+ u32 max_bandwidth = 0;
+ const struct ieee80211_reg_rule *reg_rule = NULL;
+ const struct ieee80211_power_rule *power_rule = NULL;
+
+ r = freq_reg_info(MHZ_TO_KHZ(chan->center_freq),
+ &max_bandwidth, ®_rule);
+
+ if (r) {
flags |= IEEE80211_CHAN_DISABLED;
chan->flags = flags;
return;
}
- chan->flags = flags;
+ power_rule = ®_rule->power_rule;
+
+ chan->flags = flags | map_regdom_flags(reg_rule->flags);
chan->max_antenna_gain = min(chan->orig_mag,
- rg->max_antenna_gain);
+ (int) MBI_TO_DBI(power_rule->max_antenna_gain));
+ chan->max_bandwidth = KHZ_TO_MHZ(max_bandwidth);
if (chan->orig_mpwr)
- chan->max_power = min(chan->orig_mpwr, rg->max_power);
+ chan->max_power = min(chan->orig_mpwr,
+ (int) MBM_TO_DBM(power_rule->max_eirp));
else
- chan->max_power = rg->max_power;
+ chan->max_power = (int) MBM_TO_DBM(power_rule->max_eirp);
}
-static void handle_band(struct ieee80211_supported_band *sband,
- const struct ieee80211_regdomain *rd)
+static void handle_band(struct ieee80211_supported_band *sband)
{
int i;
for (i = 0; i < sband->n_channels; i++)
- handle_channel(&sband->channels[i], rd);
+ handle_channel(&sband->channels[i]);
}
-void wiphy_update_regulatory(struct wiphy *wiphy)
+static void update_all_wiphy_regulatory(enum reg_set_by setby)
+{
+ struct cfg80211_registered_device *drv;
+
+ list_for_each_entry(drv, &cfg80211_drv_list, list)
+ wiphy_update_regulatory(&drv->wiphy, setby);
+}
+
+void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby)
{
enum ieee80211_band band;
- const struct ieee80211_regdomain *rd = get_regdom();
-
- for (band = 0; band < IEEE80211_NUM_BANDS; band++)
+ for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
if (wiphy->bands[band])
- handle_band(wiphy->bands[band], rd);
+ handle_band(wiphy->bands[band]);
+ if (wiphy->reg_notifier)
+ wiphy->reg_notifier(wiphy, setby);
+ }
+}
+
+/* Caller must hold &cfg80211_drv_mutex */
+int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
+ const char *alpha2, struct ieee80211_regdomain *rd)
+{
+ struct regulatory_request *request;
+ char *rd_alpha2;
+ int r = 0;
+
+ r = ignore_request(wiphy, set_by, (char *) alpha2, rd);
+ if (r)
+ return r;
+
+ if (rd)
+ rd_alpha2 = rd->alpha2;
+ else
+ rd_alpha2 = (char *) alpha2;
+
+ switch (set_by) {
+ case REGDOM_SET_BY_CORE:
+ case REGDOM_SET_BY_COUNTRY_IE:
+ case REGDOM_SET_BY_DRIVER:
+ case REGDOM_SET_BY_USER:
+ request = kzalloc(sizeof(struct regulatory_request),
+ GFP_KERNEL);
+ if (!request)
+ return -ENOMEM;
+
+ request->alpha2[0] = rd_alpha2[0];
+ request->alpha2[1] = rd_alpha2[1];
+ request->initiator = set_by;
+ request->wiphy = wiphy;
+
+ list_add_tail(&request->list, ®ulatory_requests);
+ if (rd)
+ break;
+ r = call_crda(alpha2);
+#ifndef CONFIG_WIRELESS_OLD_REGULATORY
+ if (r)
+ printk(KERN_ERR "cfg80211: Failed calling CRDA\n");
+#endif
+ break;
+ default:
+ r = -ENOTSUPP;
+ break;
+ }
+
+ return r;
+}
+
+/* If rd is not NULL and if this call fails the caller must free it */
+int regulatory_hint(struct wiphy *wiphy, const char *alpha2,
+ struct ieee80211_regdomain *rd)
+{
+ int r;
+ BUG_ON(!rd && !alpha2);
+
+ mutex_lock(&cfg80211_drv_mutex);
+
+ r = __regulatory_hint(wiphy, REGDOM_SET_BY_DRIVER, alpha2, rd);
+ if (r || !rd)
+ goto unlock_and_exit;
+
+ /* If the driver passed a regulatory domain we skipped asking
+ * userspace for one so we can now go ahead and set it */
+ r = set_regdom(rd);
+
+unlock_and_exit:
+ mutex_unlock(&cfg80211_drv_mutex);
+ return r;
+}
+EXPORT_SYMBOL(regulatory_hint);
+
+
+static void print_rd_rules(struct ieee80211_regdomain *rd)
+{
+ unsigned int i;
+ struct ieee80211_reg_rule *reg_rule = NULL;
+ struct ieee80211_freq_range *freq_range = NULL;
+ struct ieee80211_power_rule *power_rule = NULL;
+
+ printk(KERN_INFO "\t(start_freq - end_freq @ bandwidth), "
+ "(max_antenna_gain, max_eirp)\n");
+
+ for (i = 0; i < rd->n_reg_rules; i++) {
+ reg_rule = &rd->reg_rules[i];
+ freq_range = ®_rule->freq_range;
+ power_rule = ®_rule->power_rule;
+
+ /* There may not be documentation for max antenna gain
+ * in certain regions */
+ if (power_rule->max_antenna_gain)
+ printk(KERN_INFO "\t(%d KHz - %d KHz @ %d KHz), "
+ "(%d mBi, %d mBm)\n",
+ freq_range->start_freq_khz,
+ freq_range->end_freq_khz,
+ freq_range->max_bandwidth_khz,
+ power_rule->max_antenna_gain,
+ power_rule->max_eirp);
+ else
+ printk(KERN_INFO "\t(%d KHz - %d KHz @ %d KHz), "
+ "(N/A, %d mBm)\n",
+ freq_range->start_freq_khz,
+ freq_range->end_freq_khz,
+ freq_range->max_bandwidth_khz,
+ power_rule->max_eirp);
+ }
+}
+
+static void print_regdomain(struct ieee80211_regdomain *rd)
+{
+
+ if (is_world_regdom(rd->alpha2))
+ printk(KERN_INFO "cfg80211: World regulatory "
+ "domain updated:\n");
+ else {
+ if (is_unknown_alpha2(rd->alpha2))
+ printk(KERN_INFO "cfg80211: Regulatory domain "
+ "changed to driver built-in settings "
+ "(unknown country)\n");
+ else
+ printk(KERN_INFO "cfg80211: Regulatory domain "
+ "changed to country: %c%c\n",
+ rd->alpha2[0], rd->alpha2[1]);
+ }
+ print_rd_rules(rd);
+}
+
+void print_regdomain_info(struct ieee80211_regdomain *rd)
+{
+ printk(KERN_INFO "cfg80211: Regulatory domain: %c%c\n",
+ rd->alpha2[0], rd->alpha2[1]);
+ print_rd_rules(rd);
+}
+
+#ifdef CONFIG_WIRELESS_OLD_REGULATORY
+
+static bool is_old_static_regdom(struct ieee80211_regdomain *rd)
+{
+ if (rd == &us_regdom || rd == &jp_regdom || rd == &eu_regdom)
+ return true;
+ return false;
+}
+
+/* The old crap never deals with a world regulatory domain, it only
+ * deals with the static regulatory domain passed and if possible
+ * an updated "US" or "JP" regulatory domain. We do however store the
+ * old static regulatory domain in cfg80211_world_regdom for convenience
+ * of use here */
+static void reset_regdomains_static(void)
+{
+ if (!is_old_static_regdom(cfg80211_regdomain))
+ kfree(cfg80211_regdomain);
+ /* This is setting the regdom to the old static regdom */
+ cfg80211_regdomain =
+ (struct ieee80211_regdomain *) cfg80211_world_regdom;
+}
+#else
+static void reset_regdomains(void)
+{
+ if (cfg80211_world_regdom && cfg80211_world_regdom != &world_regdom) {
+ if (cfg80211_world_regdom == cfg80211_regdomain) {
+ kfree(cfg80211_regdomain);
+ } else {
+ kfree(cfg80211_world_regdom);
+ kfree(cfg80211_regdomain);
+ }
+ } else if (cfg80211_regdomain && cfg80211_regdomain != &world_regdom)
+ kfree(cfg80211_regdomain);
+
+ cfg80211_world_regdom = (struct ieee80211_regdomain *) &world_regdom;
+ cfg80211_regdomain = NULL;
+}
+
+/* Dynamic world regulatory domain requested by the wireless
+ * core upon initialization */
+static void update_world_regdomain(struct ieee80211_regdomain *rd)
+{
+ BUG_ON(list_empty(®ulatory_requests));
+
+ reset_regdomains();
+
+ cfg80211_world_regdom = rd;
+ cfg80211_regdomain = rd;
+}
+#endif
+
+static int __set_regdom(struct ieee80211_regdomain *rd)
+{
+ struct regulatory_request *request = NULL;
+
+ /* Some basic sanity checks first */
+
+#ifdef CONFIG_WIRELESS_OLD_REGULATORY
+ /* We ignore the world regdom with the old static regdomains setup
+ * as there is no point to it with satic regulatory definitions :(
+ * Don't worry this shit will be removed soon... */
+ if (is_world_regdom(rd->alpha2))
+ return -EINVAL;
+#else
+ if (is_world_regdom(rd->alpha2)) {
+ if (WARN_ON(!__reg_is_valid_request(rd->alpha2, &request)))
+ return -EINVAL;
+ update_world_regdomain(rd);
+ return 0;
+ }
+#endif
+
+ if (!is_alpha2_set(rd->alpha2) && !is_an_alpha2(rd->alpha2) &&
+ !is_unknown_alpha2(rd->alpha2))
+ return -EINVAL;
+
+ if (list_empty(®ulatory_requests))
+ return -EINVAL;
+
+#ifdef CONFIG_WIRELESS_OLD_REGULATORY
+ /* Static "US" and "JP" will be overridden, but just once */
+ if (!is_old_static_regdom(cfg80211_regdomain) &&
+ !regdom_changed(rd->alpha2))
+ return -EINVAL;
+#else
+ if (!regdom_changed(rd->alpha2))
+ return -EINVAL;
+#endif
+
+ /* Now lets set the regulatory domain, update all driver channels
+ * and finally inform them of what we have done, in case they want
+ * to review or adjust their own settings based on their own
+ * internal EEPROM data */
+
+ if (WARN_ON(!__reg_is_valid_request(rd->alpha2, &request)))
+ return -EINVAL;
+
+#ifdef CONFIG_WIRELESS_OLD_REGULATORY
+ reset_regdomains_static();
+#else
+ reset_regdomains();
+#endif
+
+ /* Country IE parsing coming soon */
+ switch (request->initiator) {
+ case REGDOM_SET_BY_CORE:
+ case REGDOM_SET_BY_DRIVER:
+ case REGDOM_SET_BY_USER:
+ if (!is_valid_rd(rd)) {
+ printk(KERN_ERR "cfg80211: Invalid "
+ "regulatory domain detected:\n");
+ print_regdomain_info(rd);
+ return -EINVAL;
+ }
+ break;
+ case REGDOM_SET_BY_COUNTRY_IE: /* Not yet */
+ WARN_ON(1);
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ /* Tada! */
+ cfg80211_regdomain = rd;
+ request->granted = 1;
+
+ return 0;
+}
+
+
+/* Use this call to set the current regulatory domain. Conflicts with
+ * multiple drivers can be ironed out later. Caller must've already
+ * kmalloc'd the rd structure. If this calls fails you should kfree()
+ * the passed rd. Caller must hold cfg80211_drv_mutex */
+int set_regdom(struct ieee80211_regdomain *rd)
+{
+ struct regulatory_request *this_request = NULL, *prev_request = NULL;
+ int r;
+
+ if (!list_empty(®ulatory_requests))
+ prev_request = list_first_entry(®ulatory_requests,
+ struct regulatory_request, list);
+
+ /* Note that this doesn't update the wiphys, this is done below */
+ r = __set_regdom(rd);
+ if (r)
+ return r;
+
+ BUG_ON((!__reg_is_valid_request(rd->alpha2, &this_request)));
+
+ /* The initial standard core update of the world regulatory domain, no
+ * need to keep that request info around if it didn't fail. */
+ if (is_world_regdom(rd->alpha2) &&
+ this_request->initiator == REGDOM_SET_BY_CORE &&
+ this_request->granted) {
+ list_del(&this_request->list);
+ kfree(this_request);
+ this_request = NULL;
+ }
+
+ /* Remove old requests, we only leave behind the last one */
+ if (prev_request) {
+ list_del(&prev_request->list);
+ kfree(prev_request);
+ prev_request = NULL;
+ }
+
+ /* This would make this whole thing pointless */
+ BUG_ON(rd != cfg80211_regdomain);
+
+ /* update all wiphys now with the new established regulatory domain */
+ update_all_wiphy_regulatory(this_request->initiator);
+
+ print_regdomain(rd);
+
+ return r;
+}
+
+int regulatory_init(void)
+{
+ reg_pdev = platform_device_register_simple("regulatory", 0, NULL, 0);
+ if (IS_ERR(reg_pdev))
+ return PTR_ERR(reg_pdev);
+ return 0;
+}
+
+void regulatory_exit(void)
+{
+ struct regulatory_request *req, *req_tmp;
+ mutex_lock(&cfg80211_drv_mutex);
+#ifdef CONFIG_WIRELESS_OLD_REGULATORY
+ reset_regdomains_static();
+#else
+ reset_regdomains();
+#endif
+ list_for_each_entry_safe(req, req_tmp, ®ulatory_requests, list) {
+ list_del(&req->list);
+ kfree(req);
+ }
+ platform_device_unregister(reg_pdev);
+ mutex_unlock(&cfg80211_drv_mutex);
}
diff --git a/net/wireless/reg.h b/net/wireless/reg.h
new file mode 100644
index 000000000000..d75fd0232972
--- /dev/null
+++ b/net/wireless/reg.h
@@ -0,0 +1,44 @@
+#ifndef __NET_WIRELESS_REG_H
+#define __NET_WIRELESS_REG_H
+
+extern const struct ieee80211_regdomain world_regdom;
+#ifdef CONFIG_WIRELESS_OLD_REGULATORY
+extern const struct ieee80211_regdomain us_regdom;
+extern const struct ieee80211_regdomain jp_regdom;
+extern const struct ieee80211_regdomain eu_regdom;
+#endif
+
+extern struct ieee80211_regdomain *cfg80211_regdomain;
+extern struct ieee80211_regdomain *cfg80211_world_regdom;
+extern struct list_head regulatory_requests;
+
+struct regdom_last_setby {
+ struct wiphy *wiphy;
+ u8 initiator;
+};
+
+/* wiphy is set if this request's initiator is REGDOM_SET_BY_DRIVER */
+struct regulatory_request {
+ struct list_head list;
+ struct wiphy *wiphy;
+ int granted;
+ enum reg_set_by initiator;
+ char alpha2[2];
+};
+
+bool is_world_regdom(char *alpha2);
+bool reg_is_valid_request(char *alpha2);
+
+int set_regdom(struct ieee80211_regdomain *rd);
+int __regulatory_hint_alpha2(struct wiphy *wiphy, enum reg_set_by set_by,
+ const char *alpha2);
+
+int regulatory_init(void);
+void regulatory_exit(void);
+
+void print_regdomain_info(struct ieee80211_regdomain *);
+
+/* If a char is A-Z */
+#define IS_ALPHA(letter) (letter >= 65 && letter <= 90)
+
+#endif /* __NET_WIRELESS_REG_H */