aboutsummaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2009-02-28 22:32:16 -0800
committerDavid S. Miller <davem@davemloft.net>2009-02-28 22:32:16 -0800
commit8010dc306ba39a8cdb3993d1e809fcb7dfdf089a (patch)
treed1fa3fe2e1501a6780fc007f2f57b1fe0995e18e /net
parent5d242f1cee2c85721bbe9d8205e98c1c01f5d805 (diff)
parent2a07954b83a3d4dc93031d3ce030fb9380a8e15a (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/Makefile1
-rw-r--r--net/mac80211/agg-rx.c6
-rw-r--r--net/mac80211/agg-tx.c191
-rw-r--r--net/mac80211/cfg.c49
-rw-r--r--net/mac80211/debugfs_netdev.c48
-rw-r--r--net/mac80211/ht.c19
-rw-r--r--net/mac80211/ibss.c905
-rw-r--r--net/mac80211/ieee80211_i.h140
-rw-r--r--net/mac80211/iface.c77
-rw-r--r--net/mac80211/key.c2
-rw-r--r--net/mac80211/main.c24
-rw-r--r--net/mac80211/mlme.c1665
-rw-r--r--net/mac80211/rate.h12
-rw-r--r--net/mac80211/rx.c37
-rw-r--r--net/mac80211/scan.c62
-rw-r--r--net/mac80211/spectmgmt.c26
-rw-r--r--net/mac80211/sta_info.c15
-rw-r--r--net/mac80211/sta_info.h5
-rw-r--r--net/mac80211/tx.c29
-rw-r--r--net/mac80211/util.c254
-rw-r--r--net/mac80211/wext.c262
-rw-r--r--net/mac80211/wme.c161
-rw-r--r--net/mac80211/wme.h6
-rw-r--r--net/wireless/core.c103
-rw-r--r--net/wireless/core.h36
-rw-r--r--net/wireless/nl80211.c75
-rw-r--r--net/wireless/nl80211.h4
-rw-r--r--net/wireless/reg.c945
-rw-r--r--net/wireless/reg.h36
-rw-r--r--net/wireless/scan.c64
-rw-r--r--net/wireless/sysfs.c9
-rw-r--r--net/wireless/wext-compat.c97
32 files changed, 3216 insertions, 2149 deletions
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile
index 3503a3d2131..0e3ab88bb70 100644
--- a/net/mac80211/Makefile
+++ b/net/mac80211/Makefile
@@ -9,6 +9,7 @@ mac80211-y := \
wpa.o \
scan.o \
ht.o agg-tx.o agg-rx.o \
+ ibss.o \
mlme.o \
iface.o \
rate.o \
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c
index 3112bfd441b..a95affc9462 100644
--- a/net/mac80211/agg-rx.c
+++ b/net/mac80211/agg-rx.c
@@ -129,7 +129,6 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d
u8 dialog_token, u16 status, u16 policy,
u16 buf_size, u16 timeout)
{
- struct ieee80211_if_sta *ifsta = &sdata->u.sta;
struct ieee80211_local *local = sdata->local;
struct sk_buff *skb;
struct ieee80211_mgmt *mgmt;
@@ -151,8 +150,9 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d
if (sdata->vif.type == NL80211_IFTYPE_AP ||
sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
- else
- memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
+ else if (sdata->vif.type == NL80211_IFTYPE_STATION)
+ memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
+
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_ACTION);
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index 1232d9f01ca..1df116d4d6e 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -49,7 +49,6 @@ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
u16 agg_size, u16 timeout)
{
struct ieee80211_local *local = sdata->local;
- struct ieee80211_if_sta *ifsta = &sdata->u.sta;
struct sk_buff *skb;
struct ieee80211_mgmt *mgmt;
u16 capab;
@@ -69,8 +68,8 @@ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
if (sdata->vif.type == NL80211_IFTYPE_AP ||
sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
- else
- memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
+ else if (sdata->vif.type == NL80211_IFTYPE_STATION)
+ memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_ACTION);
@@ -132,9 +131,24 @@ static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
state = &sta->ampdu_mlme.tid_state_tx[tid];
- if (local->hw.ampdu_queues)
- ieee80211_stop_queue(&local->hw, sta->tid_to_tx_q[tid]);
+ if (local->hw.ampdu_queues) {
+ if (initiator) {
+ /*
+ * Stop the AC queue to avoid issues where we send
+ * unaggregated frames already before the delba.
+ */
+ ieee80211_stop_queue_by_reason(&local->hw,
+ local->hw.queues + sta->tid_to_tx_q[tid],
+ IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
+ }
+ /*
+ * Pretend the driver woke the queue, just in case
+ * it disabled it before the session was stopped.
+ */
+ ieee80211_wake_queue(
+ &local->hw, local->hw.queues + sta->tid_to_tx_q[tid]);
+ }
*state = HT_AGG_STATE_REQ_STOP_BA_MSK |
(initiator << HT_AGG_STATE_INITIATOR_SHIFT);
@@ -144,8 +158,6 @@ static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
/* HW shall not deny going back to legacy */
if (WARN_ON(ret)) {
*state = HT_AGG_STATE_OPERATIONAL;
- if (local->hw.ampdu_queues)
- ieee80211_wake_queue(&local->hw, sta->tid_to_tx_q[tid]);
}
return ret;
@@ -189,14 +201,19 @@ static void sta_addba_resp_timer_expired(unsigned long data)
spin_unlock_bh(&sta->lock);
}
+static inline int ieee80211_ac_from_tid(int tid)
+{
+ return ieee802_1d_to_ac[tid & 7];
+}
+
int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
{
struct ieee80211_local *local = hw_to_local(hw);
struct sta_info *sta;
struct ieee80211_sub_if_data *sdata;
- u16 start_seq_num;
u8 *state;
- int ret = 0;
+ int i, qn = -1, ret = 0;
+ u16 start_seq_num;
if (WARN_ON(!local->ops->ampdu_action))
return -EINVAL;
@@ -209,6 +226,13 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
ra, tid);
#endif /* CONFIG_MAC80211_HT_DEBUG */
+ if (hw->ampdu_queues && ieee80211_ac_from_tid(tid) == 0) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ printk(KERN_DEBUG "rejecting on voice AC\n");
+#endif
+ return -EINVAL;
+ }
+
rcu_read_lock();
sta = sta_info_get(local, ra);
@@ -217,7 +241,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
printk(KERN_DEBUG "Could not find the station\n");
#endif
ret = -ENOENT;
- goto exit;
+ goto unlock;
}
/*
@@ -230,11 +254,13 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
sta->sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
sta->sdata->vif.type != NL80211_IFTYPE_AP) {
ret = -EINVAL;
- goto exit;
+ goto unlock;
}
spin_lock_bh(&sta->lock);
+ sdata = sta->sdata;
+
/* we have tried too many times, receiver does not want A-MPDU */
if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) {
ret = -EBUSY;
@@ -252,6 +278,42 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
goto err_unlock_sta;
}
+ if (hw->ampdu_queues) {
+ spin_lock(&local->queue_stop_reason_lock);
+ /* reserve a new queue for this session */
+ for (i = 0; i < local->hw.ampdu_queues; i++) {
+ if (local->ampdu_ac_queue[i] < 0) {
+ qn = i;
+ local->ampdu_ac_queue[qn] =
+ ieee80211_ac_from_tid(tid);
+ break;
+ }
+ }
+ spin_unlock(&local->queue_stop_reason_lock);
+
+ if (qn < 0) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ printk(KERN_DEBUG "BA request denied - "
+ "queue unavailable for tid %d\n", tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+ ret = -ENOSPC;
+ goto err_unlock_sta;
+ }
+
+ /*
+ * If we successfully allocate the session, we can't have
+ * anything going on on the queue this TID maps into, so
+ * stop it for now. This is a "virtual" stop using the same
+ * mechanism that drivers will use.
+ *
+ * XXX: queue up frames for this session in the sta_info
+ * struct instead to avoid hitting all other STAs.
+ */
+ ieee80211_stop_queue_by_reason(
+ &local->hw, hw->queues + qn,
+ IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
+ }
+
/* prepare A-MPDU MLME for Tx aggregation */
sta->ampdu_mlme.tid_tx[tid] =
kmalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC);
@@ -262,8 +324,9 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
tid);
#endif
ret = -ENOMEM;
- goto err_unlock_sta;
+ goto err_return_queue;
}
+
/* Tx timer */
sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function =
sta_addba_resp_timer_expired;
@@ -271,49 +334,25 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
(unsigned long)&sta->timer_to_tid[tid];
init_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
- if (hw->ampdu_queues) {
- /* create a new queue for this aggregation */
- ret = ieee80211_ht_agg_queue_add(local, sta, tid);
-
- /* case no queue is available to aggregation
- * don't switch to aggregation */
- if (ret) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "BA request denied - "
- "queue unavailable for tid %d\n", tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
- goto err_unlock_queue;
- }
- }
- sdata = sta->sdata;
-
/* Ok, the Addba frame hasn't been sent yet, but if the driver calls the
* call back right away, it must see that the flow has begun */
*state |= HT_ADDBA_REQUESTED_MSK;
- /* This is slightly racy because the queue isn't stopped */
start_seq_num = sta->tid_seq[tid];
ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_START,
&sta->sta, tid, &start_seq_num);
if (ret) {
- /* No need to requeue the packets in the agg queue, since we
- * held the tx lock: no packet could be enqueued to the newly
- * allocated queue */
- if (hw->ampdu_queues)
- ieee80211_ht_agg_queue_remove(local, sta, tid, 0);
#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "BA request denied - HW unavailable for"
" tid %d\n", tid);
#endif /* CONFIG_MAC80211_HT_DEBUG */
*state = HT_AGG_STATE_IDLE;
- goto err_unlock_queue;
+ goto err_free;
}
+ sta->tid_to_tx_q[tid] = qn;
- /* Will put all the packets in the new SW queue */
- if (hw->ampdu_queues)
- ieee80211_requeue(local, ieee802_1d_to_ac[tid]);
spin_unlock_bh(&sta->lock);
/* send an addBA request */
@@ -322,7 +361,6 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
sta->ampdu_mlme.dialog_token_allocator;
sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num;
-
ieee80211_send_addba_request(sta->sdata, ra, tid,
sta->ampdu_mlme.tid_tx[tid]->dialog_token,
sta->ampdu_mlme.tid_tx[tid]->ssn,
@@ -334,15 +372,24 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
#endif
- goto exit;
+ goto unlock;
-err_unlock_queue:
+ err_free:
kfree(sta->ampdu_mlme.tid_tx[tid]);
sta->ampdu_mlme.tid_tx[tid] = NULL;
- ret = -EBUSY;
-err_unlock_sta:
+ err_return_queue:
+ if (qn >= 0) {
+ /* We failed, so start queue again right away. */
+ ieee80211_wake_queue_by_reason(hw, hw->queues + qn,
+ IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
+ /* give queue back to pool */
+ spin_lock(&local->queue_stop_reason_lock);
+ local->ampdu_ac_queue[qn] = -1;
+ spin_unlock(&local->queue_stop_reason_lock);
+ }
+ err_unlock_sta:
spin_unlock_bh(&sta->lock);
-exit:
+ unlock:
rcu_read_unlock();
return ret;
}
@@ -375,7 +422,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
state = &sta->ampdu_mlme.tid_state_tx[tid];
spin_lock_bh(&sta->lock);
- if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
+ if (WARN_ON(!(*state & HT_ADDBA_REQUESTED_MSK))) {
#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "addBA was not requested yet, state is %d\n",
*state);
@@ -385,7 +432,8 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
return;
}
- WARN_ON_ONCE(*state & HT_ADDBA_DRV_READY_MSK);
+ if (WARN_ON(*state & HT_ADDBA_DRV_READY_MSK))
+ goto out;
*state |= HT_ADDBA_DRV_READY_MSK;
@@ -393,9 +441,18 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid);
#endif
- if (hw->ampdu_queues)
- ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
+ if (hw->ampdu_queues) {
+ /*
+ * Wake up this queue, we stopped it earlier,
+ * this will in turn wake the entire AC.
+ */
+ ieee80211_wake_queue_by_reason(hw,
+ hw->queues + sta->tid_to_tx_q[tid],
+ IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
+ }
}
+
+ out:
spin_unlock_bh(&sta->lock);
rcu_read_unlock();
}
@@ -485,7 +542,6 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
struct ieee80211_local *local = hw_to_local(hw);
struct sta_info *sta;
u8 *state;
- int agg_queue;
if (tid >= STA_TID_NUM) {
#ifdef CONFIG_MAC80211_HT_DEBUG
@@ -527,19 +583,19 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
ieee80211_send_delba(sta->sdata, ra, tid,
WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);
- if (hw->ampdu_queues) {
- agg_queue = sta->tid_to_tx_q[tid];
- ieee80211_ht_agg_queue_remove(local, sta, tid, 1);
+ spin_lock_bh(&sta->lock);
- /* We just requeued the all the frames that were in the
- * removed queue, and since we might miss a softirq we do
- * netif_schedule_queue. ieee80211_wake_queue is not used
- * here as this queue is not necessarily stopped
+ if (*state & HT_AGG_STATE_INITIATOR_MSK &&
+ hw->ampdu_queues) {
+ /*
+ * Wake up this queue, we stopped it earlier,
+ * this will in turn wake the entire AC.
*/
- netif_schedule_queue(netdev_get_tx_queue(local->mdev,
- agg_queue));
+ ieee80211_wake_queue_by_reason(hw,
+ hw->queues + sta->tid_to_tx_q[tid],
+ IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
}
- spin_lock_bh(&sta->lock);
+
*state = HT_AGG_STATE_IDLE;
sta->ampdu_mlme.addba_req_num[tid] = 0;
kfree(sta->ampdu_mlme.tid_tx[tid]);
@@ -613,12 +669,21 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
#endif /* CONFIG_MAC80211_HT_DEBUG */
if (le16_to_cpu(mgmt->u.action.u.addba_resp.status)
== WLAN_STATUS_SUCCESS) {
+ u8 curstate = *state;
+
*state |= HT_ADDBA_RECEIVED_MSK;
- sta->ampdu_mlme.addba_req_num[tid] = 0;
- if (*state == HT_AGG_STATE_OPERATIONAL &&
- local->hw.ampdu_queues)
- ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
+ if (hw->ampdu_queues && *state != curstate &&
+ *state == HT_AGG_STATE_OPERATIONAL) {
+ /*
+ * Wake up this queue, we stopped it earlier,
+ * this will in turn wake the entire AC.
+ */
+ ieee80211_wake_queue_by_reason(hw,
+ hw->queues + sta->tid_to_tx_q[tid],
+ IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
+ }
+ sta->ampdu_mlme.addba_req_num[tid] = 0;
if (local->ops->ampdu_action) {
(void)local->ops->ampdu_action(hw,
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index c8d969be440..c43129efc3b 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -341,11 +341,15 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
sinfo->filled = STATION_INFO_INACTIVE_TIME |
STATION_INFO_RX_BYTES |
STATION_INFO_TX_BYTES |
+ STATION_INFO_RX_PACKETS |
+ STATION_INFO_TX_PACKETS |
STATION_INFO_TX_BITRATE;
sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
sinfo->rx_bytes = sta->rx_bytes;
sinfo->tx_bytes = sta->tx_bytes;
+ sinfo->rx_packets = sta->rx_packets;
+ sinfo->tx_packets = sta->tx_packets;
if (sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) {
sinfo->filled |= STATION_INFO_SIGNAL;
@@ -1180,45 +1184,45 @@ static int set_mgmt_extra_ie_sta(struct ieee80211_sub_if_data *sdata,
u8 subtype, u8 *ies, size_t ies_len)
{
struct ieee80211_local *local = sdata->local;
- struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
switch (subtype) {
case IEEE80211_STYPE_PROBE_REQ >> 4:
if (local->ops->hw_scan)
break;
- kfree(ifsta->ie_probereq);
- ifsta->ie_probereq = ies;
- ifsta->ie_probereq_len = ies_len;
+ kfree(ifmgd->ie_probereq);
+ ifmgd->ie_probereq = ies;
+ ifmgd->ie_probereq_len = ies_len;
return 0;
case IEEE80211_STYPE_PROBE_RESP >> 4:
- kfree(ifsta->ie_proberesp);
- ifsta->ie_proberesp = ies;
- ifsta->ie_proberesp_len = ies_len;
+ kfree(ifmgd->ie_proberesp);
+ ifmgd->ie_proberesp = ies;
+ ifmgd->ie_proberesp_len = ies_len;
return 0;
case IEEE80211_STYPE_AUTH >> 4:
- kfree(ifsta->ie_auth);
- ifsta->ie_auth = ies;
- ifsta->ie_auth_len = ies_len;
+ kfree(ifmgd->ie_auth);
+ ifmgd->ie_auth = ies;
+ ifmgd->ie_auth_len = ies_len;
return 0;
case IEEE80211_STYPE_ASSOC_REQ >> 4:
- kfree(ifsta->ie_assocreq);
- ifsta->ie_assocreq = ies;
- ifsta->ie_assocreq_len = ies_len;
+ kfree(ifmgd->ie_assocreq);
+ ifmgd->ie_assocreq = ies;
+ ifmgd->ie_assocreq_len = ies_len;
return 0;
case IEEE80211_STYPE_REASSOC_REQ >> 4:
- kfree(ifsta->ie_reassocreq);
- ifsta->ie_reassocreq = ies;
- ifsta->ie_reassocreq_len = ies_len;
+ kfree(ifmgd->ie_reassocreq);
+ ifmgd->ie_reassocreq = ies;
+ ifmgd->ie_reassocreq_len = ies_len;
return 0;
case IEEE80211_STYPE_DEAUTH >> 4:
- kfree(ifsta->ie_deauth);
- ifsta->ie_deauth = ies;
- ifsta->ie_deauth_len = ies_len;
+ kfree(ifmgd->ie_deauth);
+ ifmgd->ie_deauth = ies;
+ ifmgd->ie_deauth_len = ies_len;
return 0;
case IEEE80211_STYPE_DISASSOC >> 4:
- kfree(ifsta->ie_disassoc);
- ifsta->ie_disassoc = ies;
- ifsta->ie_disassoc_len = ies_len;
+ kfree(ifmgd->ie_disassoc);
+ ifmgd->ie_disassoc = ies;
+ ifmgd->ie_disassoc_len = ies_len;
return 0;
}
@@ -1248,7 +1252,6 @@ static int ieee80211_set_mgmt_extra_ie(struct wiphy *wiphy,
switch (sdata->vif.type) {
case NL80211_IFTYPE_STATION:
- case NL80211_IFTYPE_ADHOC:
ret = set_mgmt_extra_ie_sta(sdata, params->subtype,
ies, ies_len);
break;
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index c5421930172..e3420329f4e 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -94,31 +94,31 @@ IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC);
IEEE80211_IF_FILE(force_unicast_rateidx, force_unicast_rateidx, DEC);
IEEE80211_IF_FILE(max_ratectrl_rateidx, max_ratectrl_rateidx, DEC);
-/* STA/IBSS attributes */
-IEEE80211_IF_FILE(state, u.sta.state, DEC);
-IEEE80211_IF_FILE(bssid, u.sta.bssid, MAC);
-IEEE80211_IF_FILE(prev_bssid, u.sta.prev_bssid, MAC);
-IEEE80211_IF_FILE(ssid_len, u.sta.ssid_len, SIZE);
-IEEE80211_IF_FILE(aid, u.sta.aid, DEC);
-IEEE80211_IF_FILE(ap_capab, u.sta.ap_capab, HEX);
-IEEE80211_IF_FILE(capab, u.sta.capab, HEX);
-IEEE80211_IF_FILE(extra_ie_len, u.sta.extra_ie_len, SIZE);
-IEEE80211_IF_FILE(auth_tries, u.sta.auth_tries, DEC);
-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);
+/* STA attributes */
+IEEE80211_IF_FILE(state, u.mgd.state, DEC);
+IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC);
+IEEE80211_IF_FILE(prev_bssid, u.mgd.prev_bssid, MAC);
+IEEE80211_IF_FILE(ssid_len, u.mgd.ssid_len, SIZE);
+IEEE80211_IF_FILE(aid, u.mgd.aid, DEC);
+IEEE80211_IF_FILE(ap_capab, u.mgd.ap_capab, HEX);
+IEEE80211_IF_FILE(capab, u.mgd.capab, HEX);
+IEEE80211_IF_FILE(extra_ie_len, u.mgd.extra_ie_len, SIZE);
+IEEE80211_IF_FILE(auth_tries, u.mgd.auth_tries, DEC);
+IEEE80211_IF_FILE(assoc_tries, u.mgd.assoc_tries, DEC);
+IEEE80211_IF_FILE(auth_algs, u.mgd.auth_algs, HEX);
+IEEE80211_IF_FILE(auth_alg, u.mgd.auth_alg, DEC);
+IEEE80211_IF_FILE(auth_transaction, u.mgd.auth_transaction, DEC);
static ssize_t ieee80211_if_fmt_flags(
const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
{
return scnprintf(buf, buflen, "%s%s%s%s%s%s%s\n",
- sdata->u.sta.flags & IEEE80211_STA_SSID_SET ? "SSID\n" : "",
- sdata->u.sta.flags & IEEE80211_STA_BSSID_SET ? "BSSID\n" : "",
- sdata->u.sta.flags & IEEE80211_STA_PREV_BSSID_SET ? "prev BSSID\n" : "",
- sdata->u.sta.flags & IEEE80211_STA_AUTHENTICATED ? "AUTH\n" : "",
- sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED ? "ASSOC\n" : "",
- sdata->u.sta.flags & IEEE80211_STA_PROBEREQ_POLL ? "PROBEREQ POLL\n" : "",
+ sdata->u.mgd.flags & IEEE80211_STA_SSID_SET ? "SSID\n" : "",
+ sdata->u.mgd.flags & IEEE80211_STA_BSSID_SET ? "BSSID\n" : "",
+ sdata->u.mgd.flags & IEEE80211_STA_PREV_BSSID_SET ? "prev BSSID\n" : "",
+ sdata->u.mgd.flags & IEEE80211_STA_AUTHENTICATED ? "AUTH\n" : "",
+ sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED ? "ASSOC\n" : "",
+ sdata->u.mgd.flags & IEEE80211_STA_PROBEREQ_POLL ? "PROBEREQ POLL\n" : "",
sdata->vif.bss_conf.use_cts_prot ? "CTS prot\n" : "");
}
__IEEE80211_IF_FILE(flags);
@@ -283,9 +283,11 @@ static void add_files(struct ieee80211_sub_if_data *sdata)
#endif
break;
case NL80211_IFTYPE_STATION:
- case NL80211_IFTYPE_ADHOC:
add_sta_files(sdata);
break;
+ case NL80211_IFTYPE_ADHOC:
+ /* XXX */
+ break;
case NL80211_IFTYPE_AP:
add_ap_files(sdata);
break;
@@ -418,9 +420,11 @@ static void del_files(struct ieee80211_sub_if_data *sdata)
#endif
break;
case NL80211_IFTYPE_STATION:
- case NL80211_IFTYPE_ADHOC:
del_sta_files(sdata);
break;
+ case NL80211_IFTYPE_ADHOC:
+ /* XXX */
+ break;
case NL80211_IFTYPE_AP:
del_ap_files(sdata);
break;
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
index 82ea0b63a38..4e3c72f20de 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -17,6 +17,7 @@
#include <net/wireless.h>
#include <net/mac80211.h>
#include "ieee80211_i.h"
+#include "rate.h"
void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
struct ieee80211_ht_cap *ht_cap_ie,
@@ -93,7 +94,9 @@ u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_supported_band *sband;
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct ieee80211_bss_ht_conf ht;
+ struct sta_info *sta;
u32 changed = 0;
bool enable_ht = true, ht_changed;
enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
@@ -136,6 +139,16 @@ u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
if (ht_changed) {
/* channel_type change automatically detected */
ieee80211_hw_config(local, 0);
+
+ rcu_read_lock();
+
+ sta = sta_info_get(local, ifmgd->bssid);
+ if (sta)
+ rate_control_rate_update(local, sband, sta,
+ IEEE80211_RC_HT_CHANGED);
+
+ rcu_read_unlock();
+
}
/* disable HT */
@@ -169,7 +182,6 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
u16 initiator, u16 reason_code)
{
struct ieee80211_local *local = sdata->local;
- struct ieee80211_if_sta *ifsta = &sdata->u.sta;
struct sk_buff *skb;
struct ieee80211_mgmt *mgmt;
u16 params;
@@ -190,8 +202,9 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
if (sdata->vif.type == NL80211_IFTYPE_AP ||
sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
- else
- memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
+ else if (sdata->vif.type == NL80211_IFTYPE_STATION)
+ memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
+
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_ACTION);
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
new file mode 100644
index 00000000000..a96ce9dfc6b
--- /dev/null
+++ b/net/mac80211/ibss.c
@@ -0,0 +1,905 @@
+/*
+ * IBSS mode implementation
+ * Copyright 2003-2008, Jouni Malinen <j@w1.fi>
+ * Copyright 2004, Instant802 Networks, Inc.
+ * Copyright 2005, Devicescape Software, Inc.
+ * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
+ * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
+ * Copyright 2009, Johannes Berg <johannes@sipsolutions.net>
+ *
+ * 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.
+ */
+
+#include <linux/delay.h>
+#include <linux/if_ether.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <linux/rtnetlink.h>
+#include <net/mac80211.h>
+#include <asm/unaligned.h>
+
+#include "ieee80211_i.h"
+#include "rate.h"
+
+#define IEEE80211_SCAN_INTERVAL (2 * HZ)
+#define IEEE80211_SCAN_INTERVAL_SLOW (15 * HZ)
+#define IEEE80211_IBSS_JOIN_TIMEOUT (7 * HZ)
+
+#define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ)
+#define IEEE80211_IBSS_MERGE_DELAY 0x400000
+#define IEEE80211_IBSS_INACTIVITY_LIMIT (60 * HZ)
+
+#define IEEE80211_IBSS_MAX_STA_ENTRIES 128
+
+
+static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_mgmt *mgmt,
+ size_t len)
+{
+ u16 auth_alg, auth_transaction, status_code;
+
+ if (len < 24 + 6)
+ return;
+
+ auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg);
+ auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction);
+ status_code = le16_to_cpu(mgmt->u.auth.status_code);
+
+ /*
+ * IEEE 802.11 standard does not require authentication in IBSS
+ * networks and most implementations do not seem to use it.
+ * However, try to reply to authentication attempts if someone
+ * has actually implemented this.
+ */
+ if (auth_alg == WLAN_AUTH_OPEN && auth_transaction == 1)
+ ieee80211_send_auth(sdata, 2, WLAN_AUTH_OPEN, NULL, 0,
+ sdata->u.ibss.bssid, 0);
+}
+
+static int __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
+ const u8 *bssid, const int beacon_int,
+ const int freq,
+ const size_t supp_rates_len,
+ const u8 *supp_rates,
+ const u16 capability)
+{
+ struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+ struct ieee80211_local *local = sdata->local;
+ int res = 0, rates, i, j;
+ struct sk_buff *skb;
+ struct ieee80211_mgmt *mgmt;
+ u8 *pos;
+ struct ieee80211_supported_band *sband;
+ union iwreq_data wrqu;
+
+ if (local->ops->reset_tsf) {
+ /* Reset own TSF to allow time synchronization work. */
+ local->ops->reset_tsf(local_to_hw(local));
+ }
+
+ if ((ifibss->flags & IEEE80211_IBSS_PREV_BSSID_SET) &&
+ memcmp(ifibss->bssid, bssid, ETH_ALEN) == 0)
+ return res;
+
+ skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
+ if (!skb) {
+ printk(KERN_DEBUG "%s: failed to allocate buffer for probe "
+ "response\n", sdata->dev->name);
+ return -ENOMEM;
+ }
+
+ if (!(ifibss->flags & IEEE80211_IBSS_PREV_BSSID_SET)) {
+ /* Remove possible STA entries from other IBSS networks. */
+ sta_info_flush_delayed(sdata);
+ }
+
+ memcpy(ifibss->bssid, bssid, ETH_ALEN);
+ res = ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID);
+ if (res)
+ return res;
+
+ local->hw.conf.beacon_int = beacon_int >= 10 ? beacon_int : 10;
+
+ sdata->drop_unencrypted = capability &
+ WLAN_CAPABILITY_PRIVACY ? 1 : 0;
+
+ res = ieee80211_set_freq(sdata, freq);
+
+ if (res)
+ return res;
+
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
+ /* Build IBSS probe response */
+
+ skb_reserve(skb, local->hw.extra_tx_headroom);
+
+ mgmt = (struct ieee80211_mgmt *)
+ skb_put(skb, 24 + sizeof(mgmt->u.beacon));
+ memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
+ mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_PROBE_RESP);
+ memset(mgmt->da, 0xff, ETH_ALEN);
+ memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
+ memcpy(mgmt->bssid, ifibss->bssid, ETH_ALEN);
+ mgmt->u.beacon.beacon_int =
+ cpu_to_le16(local->hw.conf.beacon_int);
+ mgmt->u.beacon.capab_info = cpu_to_le16(capability);
+
+ pos = skb_put(skb, 2 + ifibss->ssid_len);
+ *pos++ = WLAN_EID_SSID;
+ *pos++ = ifibss->ssid_len;
+ memcpy(pos, ifibss->ssid, ifibss->ssid_len);
+
+ rates = supp_rates_len;
+ if (rates > 8)
+ rates = 8;
+ pos = skb_put(skb, 2 + rates);
+ *pos++ = WLAN_EID_SUPP_RATES;
+ *pos++ = rates;
+ memcpy(pos, supp_rates, rates);
+
+ if (sband->band == IEEE80211_BAND_2GHZ) {
+ pos = skb_put(skb, 2 + 1);
+ *pos++ = WLAN_EID_DS_PARAMS;
+ *pos++ = 1;
+ *pos++ = ieee80211_frequency_to_channel(freq);
+ }