#include <net/rtnetlink.h>
#include "ieee80211_i.h"
+#include "driver-ops.h"
#include "rate.h"
#include "mesh.h"
#include "wme.h"
/* privid for wiphys to determine whether they belong to us or not */
void *mac80211_wiphy_privid = &mac80211_wiphy_privid;
-/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
-/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
-const unsigned char rfc1042_header[] __aligned(2) =
- { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
-
-/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
-const unsigned char bridge_tunnel_header[] __aligned(2) =
- { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
-
struct ieee80211_hw *wiphy_to_ieee80211_hw(struct wiphy *wiphy)
{
struct ieee80211_local *local;
return NULL;
}
-unsigned int ieee80211_hdrlen(__le16 fc)
-{
- unsigned int hdrlen = 24;
-
- if (ieee80211_is_data(fc)) {
- if (ieee80211_has_a4(fc))
- hdrlen = 30;
- if (ieee80211_is_data_qos(fc))
- hdrlen += IEEE80211_QOS_CTL_LEN;
- goto out;
- }
-
- if (ieee80211_is_ctl(fc)) {
- /*
- * ACK and CTS are 10 bytes, all others 16. To see how
- * to get this condition consider
- * subtype mask: 0b0000000011110000 (0x00F0)
- * ACK subtype: 0b0000000011010000 (0x00D0)
- * CTS subtype: 0b0000000011000000 (0x00C0)
- * bits that matter: ^^^ (0x00E0)
- * value of those: 0b0000000011000000 (0x00C0)
- */
- if ((fc & cpu_to_le16(0x00E0)) == cpu_to_le16(0x00C0))
- hdrlen = 10;
- else
- hdrlen = 16;
- }
-out:
- return hdrlen;
-}
-EXPORT_SYMBOL(ieee80211_hdrlen);
-
-unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb)
-{
- const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *)skb->data;
- unsigned int hdrlen;
-
- if (unlikely(skb->len < 10))
- return 0;
- hdrlen = ieee80211_hdrlen(hdr->frame_control);
- if (unlikely(hdrlen > skb->len))
- return 0;
- return hdrlen;
-}
-EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb);
-
-int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
-{
- int ae = meshhdr->flags & IEEE80211S_FLAGS_AE;
- /* 7.1.3.5a.2 */
- switch (ae) {
- case 0:
- return 6;
- case 1:
- return 12;
- case 2:
- return 18;
- case 3:
- return 24;
- default:
- return 6;
- }
-}
-
void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx)
{
struct sk_buff *skb = tx->skb;
}
EXPORT_SYMBOL(ieee80211_stop_queue);
+void ieee80211_add_pending_skb(struct ieee80211_local *local,
+ struct sk_buff *skb)
+{
+ struct ieee80211_hw *hw = &local->hw;
+ unsigned long flags;
+ int queue = skb_get_queue_mapping(skb);
+
+ spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
+ __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
+ __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_PENDING);
+ skb_queue_tail(&local->pending[queue], skb);
+ __ieee80211_wake_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
+ spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+}
+
+int ieee80211_add_pending_skbs(struct ieee80211_local *local,
+ struct sk_buff_head *skbs)
+{
+ struct ieee80211_hw *hw = &local->hw;
+ struct sk_buff *skb;
+ unsigned long flags;
+ int queue, ret = 0, i;
+
+ spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
+ for (i = 0; i < hw->queues; i++)
+ __ieee80211_stop_queue(hw, i,
+ IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
+
+ while ((skb = skb_dequeue(skbs))) {
+ ret++;
+ queue = skb_get_queue_mapping(skb);
+ skb_queue_tail(&local->pending[queue], skb);
+ }
+
+ for (i = 0; i < hw->queues; i++) {
+ if (ret)
+ __ieee80211_stop_queue(hw, i,
+ IEEE80211_QUEUE_STOP_REASON_PENDING);
+ __ieee80211_wake_queue(hw, i,
+ IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
+ }
+ spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+
+ return ret;
+}
+
void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw,
enum queue_stop_reason reason)
{
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_tx_queue_params qparam;
- int i;
+ int queue;
+ bool use_11b;
+ int aCWmin, aCWmax;
if (!local->ops->conf_tx)
return;
memset(&qparam, 0, sizeof(qparam));
- qparam.aifs = 2;
-
- if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ &&
- !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE))
- qparam.cw_min = 31;
- else
- qparam.cw_min = 15;
+ use_11b = (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) &&
+ !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE);
- qparam.cw_max = 1023;
- qparam.txop = 0;
+ for (queue = 0; queue < local_to_hw(local)->queues; queue++) {
+ /* Set defaults according to 802.11-2007 Table 7-37 */
+ aCWmax = 1023;
+ if (use_11b)
+ aCWmin = 31;
+ else
+ aCWmin = 15;
+
+ switch (queue) {
+ case 3: /* AC_BK */
+ qparam.cw_max = aCWmax;
+ qparam.cw_min = aCWmin;
+ qparam.txop = 0;
+ qparam.aifs = 7;
+ break;
+ default: /* never happens but let's not leave undefined */
+ case 2: /* AC_BE */
+ qparam.cw_max = aCWmax;
+ qparam.cw_min = aCWmin;
+ qparam.txop = 0;
+ qparam.aifs = 3;
+ break;
+ case 1: /* AC_VI */
+ qparam.cw_max = aCWmin;
+ qparam.cw_min = (aCWmin + 1) / 2 - 1;
+ if (use_11b)
+ qparam.txop = 6016/32;
+ else
+ qparam.txop = 3008/32;
+ qparam.aifs = 2;
+ break;
+ case 0: /* AC_VO */
+ qparam.cw_max = (aCWmin + 1) / 2 - 1;
+ qparam.cw_min = (aCWmin + 1) / 4 - 1;
+ if (use_11b)
+ qparam.txop = 3264/32;
+ else
+ qparam.txop = 1504/32;
+ qparam.aifs = 2;
+ break;
+ }
- for (i = 0; i < local_to_hw(local)->queues; i++)
- local->ops->conf_tx(local_to_hw(local), i, &qparam);
+ drv_conf_tx(local, queue, &qparam);
+ }
}
void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
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)
- return ret;
- local->oper_channel = chan;
- local->oper_channel_type = NL80211_CHAN_NO_HT;
-
- if (local->sw_scanning || local->hw_scanning)
- ret = 0;
- else
- ret = ieee80211_hw_config(
- local, IEEE80211_CONF_CHANGE_CHANNEL);
- }
-
- return ret;
-}
-
u32 ieee80211_mandatory_rates(struct ieee80211_local *local,
enum ieee80211_band band)
{
struct sta_info *sta;
unsigned long flags;
int res;
+ bool from_suspend = local->suspended;
+
+ /*
+ * We're going to start the hardware, at that point
+ * we are no longer suspended and can RX frames.
+ */
+ local->suspended = false;
/* restart hardware */
if (local->open_count) {
- res = local->ops->start(hw);
+ res = drv_start(local);
- ieee80211_led_radio(local, hw->conf.radio_enabled);
+ ieee80211_led_radio(local, true);
}
/* add interfaces */
conf.vif = &sdata->vif;
conf.type = sdata->vif.type;
conf.mac_addr = sdata->dev->dev_addr;
- res = local->ops->add_interface(hw, &conf);
+ res = drv_add_interface(local, &conf);
}
}
if (local->ops->sta_notify) {
spin_lock_irqsave(&local->sta_lock, flags);
list_for_each_entry(sta, &local->sta_list, list) {
+ sdata = sta->sdata;
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
sdata = container_of(sdata->bss,
struct ieee80211_sub_if_data,
u.ap);
- local->ops->sta_notify(hw, &sdata->vif,
- STA_NOTIFY_ADD, &sta->sta);
+ drv_sta_notify(local, &sdata->vif, STA_NOTIFY_ADD,
+ &sta->sta);
}
spin_unlock_irqrestore(&local->sta_lock, flags);
}
rcu_read_unlock();
/* setup RTS threshold */
- if (local->ops->set_rts_threshold)
- local->ops->set_rts_threshold(hw, hw->wiphy->rts_threshold);
+ drv_set_rts_threshold(local, hw->wiphy->rts_threshold);
/* reconfigure hardware */
ieee80211_hw_config(local, ~0);
switch (sdata->vif.type) {
case NL80211_IFTYPE_STATION:
/* disable beacon change bits */
- changed &= ~IEEE80211_IFCC_BEACON;
+ changed &= ~(BSS_CHANGED_BEACON |
+ BSS_CHANGED_BEACON_ENABLED);
/* fall through */
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_MESH_POINT:
- /*
- * Driver's config_interface can fail if rfkill is
- * enabled. Accommodate this return code.
- * FIXME: When mac80211 has knowledge of rfkill
- * state the code below can change back to:
- * WARN(ieee80211_if_config(sdata, changed));
- * ieee80211_bss_info_change_notify(sdata, ~0);
- */
- if (ieee80211_if_config(sdata, changed))
- printk(KERN_DEBUG "%s: failed to configure interface during resume\n",
- sdata->dev->name);
- else
- ieee80211_bss_info_change_notify(sdata, ~0);
+ ieee80211_bss_info_change_notify(sdata, changed);
break;
case NL80211_IFTYPE_WDS:
break;
ieee80211_wake_queues_by_reason(hw,
IEEE80211_QUEUE_STOP_REASON_SUSPEND);
+ /*
+ * If this is for hw restart things are still running.
+ * We may want to change that later, however.
+ */
+ if (!from_suspend)
+ return 0;
+
+#ifdef CONFIG_PM
+ local->suspended = false;
+
+ list_for_each_entry(sdata, &local->interfaces, list) {
+ switch(sdata->vif.type) {
+ case NL80211_IFTYPE_STATION:
+ ieee80211_sta_restart(sdata);
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ ieee80211_ibss_restart(sdata);
+ break;
+ case NL80211_IFTYPE_MESH_POINT:
+ ieee80211_mesh_restart(sdata);
+ break;
+ default:
+ break;
+ }
+ }
+
+ add_timer(&local->sta_cleanup);
+
+ spin_lock_irqsave(&local->sta_lock, flags);
+ list_for_each_entry(sta, &local->sta_list, list)
+ mesh_plink_restart(sta);
+ spin_unlock_irqrestore(&local->sta_lock, flags);
+#else
+ WARN_ON(1);
+#endif
return 0;
}