#include "debugfs.h"
#include "debugfs_netdev.h"
-#define SUPP_MCS_SET_LEN 16
-
/*
* For seeing transmitted packets on monitor interfaces
* we have a radiotap header too.
break;
}
}
- return res;
+
+ if (res)
+ return res;
+
+ netif_start_queue(local->mdev);
+
+ return 0;
}
static int ieee80211_master_stop(struct net_device *dev)
/* 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) {
- printk(KERN_WARNING "%s: invalid MTU %d\n",
- dev->name, new_mtu);
+ new_mtu > IEEE80211_MAX_DATA_LEN - 24 - 6 - meshhdrlen) {
return -EINVAL;
}
{
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;
- struct sta_info *sta;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
goto err_stop;
ieee80211_if_config(dev);
- ieee80211_reset_erp_info(dev);
+ changed |= ieee80211_reset_erp_info(dev);
+ ieee80211_bss_info_change_notify(sdata, changed);
ieee80211_enable_keys(sdata);
if (sdata->vif.type == IEEE80211_IF_TYPE_STA &&
goto err_del_interface;
}
+ /* no locking required since STA is not live yet */
sta->flags |= WLAN_STA_AUTHORIZED;
res = sta_info_insert(sta);
* 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) {
+ 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);
}
local->sta_hw_scanning = 0;
}
- flush_workqueue(local->hw.workqueue);
-
sdata->u.sta.flags &= ~IEEE80211_STA_PRIVACY_INVOKED;
kfree(sdata->u.sta.extra_ie);
sdata->u.sta.extra_ie = NULL;
ieee80211_led_radio(local, 0);
+ flush_workqueue(local->hw.workqueue);
+
tasklet_disable(&local->tx_pending_tasklet);
tasklet_disable(&local->tasklet);
}
sta = sta_info_get(local, ra);
if (!sta) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "Could not find the station\n");
- rcu_read_unlock();
- return -ENOENT;
+#endif
+ ret = -ENOENT;
+ goto exit;
}
- spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_lock_bh(&sta->lock);
/* 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;
- goto start_ba_exit;
+ goto err_unlock_sta;
}
state = &sta->ampdu_mlme.tid_state_tx[tid];
"idle on tid %u\n", tid);
#endif /* CONFIG_MAC80211_HT_DEBUG */
ret = -EAGAIN;
- goto start_ba_exit;
+ goto err_unlock_sta;
}
/* prepare A-MPDU MLME for Tx aggregation */
sta->ampdu_mlme.tid_tx[tid] =
kmalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC);
if (!sta->ampdu_mlme.tid_tx[tid]) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
if (net_ratelimit())
printk(KERN_ERR "allocate tx mlme to tid %d failed\n",
tid);
+#endif
ret = -ENOMEM;
- goto start_ba_exit;
+ goto err_unlock_sta;
}
/* Tx timer */
sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function =
printk(KERN_DEBUG "BA request denied - queue unavailable for"
" tid %d\n", tid);
#endif /* CONFIG_MAC80211_HT_DEBUG */
- goto start_ba_err;
+ goto err_unlock_queue;
}
sdata = sta->sdata;
" tid %d\n", tid);
#endif /* CONFIG_MAC80211_HT_DEBUG */
*state = HT_AGG_STATE_IDLE;
- goto start_ba_err;
+ goto err_unlock_queue;
}
/* Will put all the packets in the new SW queue */
ieee80211_requeue(local, ieee802_1d_to_ac[tid]);
spin_unlock_bh(&local->mdev->queue_lock);
+ spin_unlock_bh(&sta->lock);
/* send an addBA request */
sta->ampdu_mlme.dialog_token_allocator++;
sta->ampdu_mlme.dialog_token_allocator;
sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num;
+
ieee80211_send_addba_request(sta->sdata->dev, ra, tid,
sta->ampdu_mlme.tid_tx[tid]->dialog_token,
sta->ampdu_mlme.tid_tx[tid]->ssn,
0x40, 5000);
-
/* activate the timer for the recipient's addBA response */
sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires =
jiffies + ADDBA_RESP_INTERVAL;
add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
+#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
- goto start_ba_exit;
+#endif
+ goto exit;
-start_ba_err:
+err_unlock_queue:
kfree(sta->ampdu_mlme.tid_tx[tid]);
sta->ampdu_mlme.tid_tx[tid] = NULL;
spin_unlock_bh(&local->mdev->queue_lock);
ret = -EBUSY;
-start_ba_exit:
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+err_unlock_sta:
+ spin_unlock_bh(&sta->lock);
+exit:
rcu_read_unlock();
return ret;
}
/* check if the TID is in aggregation */
state = &sta->ampdu_mlme.tid_state_tx[tid];
- spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_lock_bh(&sta->lock);
if (*state != HT_AGG_STATE_OPERATIONAL) {
ret = -ENOENT;
}
stop_BA_exit:
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_unlock_bh(&sta->lock);
rcu_read_unlock();
return ret;
}
DECLARE_MAC_BUF(mac);
if (tid >= STA_TID_NUM) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
tid, STA_TID_NUM);
+#endif
return;
}
sta = sta_info_get(local, ra);
if (!sta) {
rcu_read_unlock();
+#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "Could not find station: %s\n",
print_mac(mac, ra));
+#endif
return;
}
state = &sta->ampdu_mlme.tid_state_tx[tid];
- spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_lock_bh(&sta->lock);
if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "addBA was not requested yet, state is %d\n",
*state);
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+#endif
+ spin_unlock_bh(&sta->lock);
rcu_read_unlock();
return;
}
*state |= HT_ADDBA_DRV_READY_MSK;
if (*state == HT_AGG_STATE_OPERATIONAL) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid);
+#endif
ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
}
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_unlock_bh(&sta->lock);
rcu_read_unlock();
}
EXPORT_SYMBOL(ieee80211_start_tx_ba_cb);
DECLARE_MAC_BUF(mac);
if (tid >= STA_TID_NUM) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
tid, STA_TID_NUM);
+#endif
return;
}
rcu_read_lock();
sta = sta_info_get(local, ra);
if (!sta) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "Could not find station: %s\n",
print_mac(mac, ra));
+#endif
rcu_read_unlock();
return;
}
state = &sta->ampdu_mlme.tid_state_tx[tid];
- spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+ /* NOTE: no need to use sta->lock in this state check, as
+ * ieee80211_stop_tx_ba_session will let only
+ * one stop call to pass through per sta/tid */
if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n");
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+#endif
rcu_read_unlock();
return;
}
* ieee80211_wake_queue is not used here as this queue is not
* necessarily stopped */
netif_schedule(local->mdev);
+ 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]);
sta->ampdu_mlme.tid_tx[tid] = NULL;
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_unlock_bh(&sta->lock);
rcu_read_unlock();
}
struct sk_buff *skb = dev_alloc_skb(0);
if (unlikely(!skb)) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
if (net_ratelimit())
printk(KERN_WARNING "%s: Not enough memory, "
"dropping start BA session", skb->dev->name);
+#endif
return;
}
ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
struct sk_buff *skb = dev_alloc_skb(0);
if (unlikely(!skb)) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
if (net_ratelimit())
printk(KERN_WARNING "%s: Not enough memory, "
"dropping stop BA session", skb->dev->name);
+#endif
return;
}
ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
/* everything else */
static int __ieee80211_if_config(struct net_device *dev,
- struct sk_buff *beacon,
- struct ieee80211_tx_control *control)
+ struct sk_buff *beacon)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
conf.ssid_len = sdata->u.sta.ssid_len;
} else if (ieee80211_vif_is_mesh(&sdata->vif)) {
conf.beacon = beacon;
- conf.beacon_control = control;
ieee80211_start_mesh(dev);
} else if (sdata->vif.type == IEEE80211_IF_TYPE_AP) {
conf.ssid = sdata->u.ap.ssid;
conf.ssid_len = sdata->u.ap.ssid_len;
conf.beacon = beacon;
- conf.beacon_control = control;
}
return local->ops->config_interface(local_to_hw(local),
&sdata->vif, &conf);
if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT &&
(local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE))
return ieee80211_if_config_beacon(dev);
- return __ieee80211_if_config(dev, NULL, NULL);
+ return __ieee80211_if_config(dev, NULL);
}
int ieee80211_if_config_beacon(struct net_device *dev)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee80211_tx_control control;
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct sk_buff *skb;
if (!(local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE))
return 0;
- skb = ieee80211_beacon_get(local_to_hw(local), &sdata->vif,
- &control);
+ skb = ieee80211_beacon_get(local_to_hw(local), &sdata->vif);
if (!skb)
return -ENOMEM;
- return __ieee80211_if_config(dev, skb, &control);
+ return __ieee80211_if_config(dev, skb);
}
int ieee80211_hw_config(struct ieee80211_local *local)
struct ieee80211_supported_band *sband;
struct ieee80211_ht_info ht_conf;
struct ieee80211_ht_bss_info ht_bss_conf;
- int i;
u32 changed = 0;
+ int i;
+ u8 max_tx_streams = IEEE80211_HT_CAP_MAX_STREAMS;
+ u8 tx_mcs_set_cap;
sband = local->hw.wiphy->bands[conf->channel->band];
+ memset(&ht_conf, 0, sizeof(struct ieee80211_ht_info));
+ memset(&ht_bss_conf, 0, sizeof(struct ieee80211_ht_bss_info));
+
/* HT is not supported */
if (!sband->ht_info.ht_supported) {
conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
- return 0;
+ goto out;
}
- memset(&ht_conf, 0, sizeof(struct ieee80211_ht_info));
- memset(&ht_bss_conf, 0, sizeof(struct ieee80211_ht_bss_info));
-
- if (enable_ht) {
- if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE))
+ /* disable HT */
+ if (!enable_ht) {
+ if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)
changed |= BSS_CHANGED_HT;
+ conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
+ conf->ht_conf.ht_supported = 0;
+ goto out;
+ }
- conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE;
- ht_conf.ht_supported = 1;
- ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap;
- ht_conf.cap &= ~(IEEE80211_HT_CAP_MIMO_PS);
- ht_conf.cap |= sband->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS;
+ if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE))
+ changed |= BSS_CHANGED_HT;
- for (i = 0; i < SUPP_MCS_SET_LEN; i++)
- ht_conf.supp_mcs_set[i] =
- sband->ht_info.supp_mcs_set[i] &
- req_ht_cap->supp_mcs_set[i];
+ conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE;
+ ht_conf.ht_supported = 1;
- ht_bss_conf.primary_channel = req_bss_cap->primary_channel;
- ht_bss_conf.bss_cap = req_bss_cap->bss_cap;
- ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode;
+ ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap;
+ ht_conf.cap &= ~(IEEE80211_HT_CAP_MIMO_PS);
+ ht_conf.cap |= sband->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS;
+ ht_bss_conf.primary_channel = req_bss_cap->primary_channel;
+ ht_bss_conf.bss_cap = req_bss_cap->bss_cap;
+ ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode;
- ht_conf.ampdu_factor = req_ht_cap->ampdu_factor;
- ht_conf.ampdu_density = req_ht_cap->ampdu_density;
+ ht_conf.ampdu_factor = req_ht_cap->ampdu_factor;
+ ht_conf.ampdu_density = req_ht_cap->ampdu_density;
- /* if bss configuration changed store the new one */
- if (memcmp(&conf->ht_conf, &ht_conf, sizeof(ht_conf)) ||
- memcmp(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf))) {
- changed |= BSS_CHANGED_HT;
- memcpy(&conf->ht_conf, &ht_conf, sizeof(ht_conf));
- memcpy(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf));
- }
- } else {
- if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)
- changed |= BSS_CHANGED_HT;
- conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
- }
+ /* Bits 96-100 */
+ tx_mcs_set_cap = sband->ht_info.supp_mcs_set[12];
+
+ /* configure suppoerted Tx MCS according to requested MCS
+ * (based in most cases on Rx capabilities of peer) and self
+ * Tx MCS capabilities (as defined by low level driver HW
+ * Tx capabilities) */
+ if (!(tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_DEFINED))
+ goto check_changed;
+
+ /* Counting from 0 therfore + 1 */
+ if (tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_RX_DIFF)
+ max_tx_streams = ((tx_mcs_set_cap &
+ IEEE80211_HT_CAP_MCS_TX_STREAMS) >> 2) + 1;
+
+ for (i = 0; i < max_tx_streams; i++)
+ ht_conf.supp_mcs_set[i] =
+ sband->ht_info.supp_mcs_set[i] &
+ req_ht_cap->supp_mcs_set[i];
+ if (tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_UEQM)
+ for (i = IEEE80211_SUPP_MCS_SET_UEQM;
+ i < IEEE80211_SUPP_MCS_SET_LEN; i++)
+ ht_conf.supp_mcs_set[i] =
+ sband->ht_info.supp_mcs_set[i] &
+ req_ht_cap->supp_mcs_set[i];
+
+check_changed:
+ /* if bss configuration changed store the new one */
+ if (memcmp(&conf->ht_conf, &ht_conf, sizeof(ht_conf)) ||
+ memcmp(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf))) {
+ changed |= BSS_CHANGED_HT;
+ memcpy(&conf->ht_conf, &ht_conf, sizeof(ht_conf));
+ memcpy(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf));
+ }
+out:
return changed;
}
changed);
}
-void ieee80211_reset_erp_info(struct net_device *dev)
+u32 ieee80211_reset_erp_info(struct net_device *dev)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
sdata->bss_conf.use_cts_prot = 0;
sdata->bss_conf.use_short_preamble = 0;
- ieee80211_bss_info_change_notify(sdata,
- BSS_CHANGED_ERP_CTS_PROT |
- BSS_CHANGED_ERP_PREAMBLE);
+ return BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_ERP_PREAMBLE;
}
void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
- struct sk_buff *skb,
- struct ieee80211_tx_status *status)
+ struct sk_buff *skb)
{
struct ieee80211_local *local = hw_to_local(hw);
- struct ieee80211_tx_status *saved;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
int tmp;
skb->dev = local->mdev;
- saved = kmalloc(sizeof(struct ieee80211_tx_status), GFP_ATOMIC);
- if (unlikely(!saved)) {
- if (net_ratelimit())
- printk(KERN_WARNING "%s: Not enough memory, "
- "dropping tx status", skb->dev->name);
- /* should be dev_kfree_skb_irq, but due to this function being
- * named _irqsafe instead of just _irq we can't be sure that
- * people won't call it from non-irq contexts */
- dev_kfree_skb_any(skb);
- return;
- }
- memcpy(saved, status, sizeof(struct ieee80211_tx_status));
- /* copy pointer to saved status into skb->cb for use by tasklet */
- memcpy(skb->cb, &saved, sizeof(saved));
-
skb->pkt_type = IEEE80211_TX_STATUS_MSG;
- skb_queue_tail(status->control.flags & IEEE80211_TXCTL_REQ_TX_STATUS ?
+ skb_queue_tail(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS ?
&local->skb_queue : &local->skb_queue_unreliable, skb);
tmp = skb_queue_len(&local->skb_queue) +
skb_queue_len(&local->skb_queue_unreliable);
while (tmp > IEEE80211_IRQSAFE_QUEUE_LIMIT &&
(skb = skb_dequeue(&local->skb_queue_unreliable))) {
- memcpy(&saved, skb->cb, sizeof(saved));
- kfree(saved);
dev_kfree_skb_irq(skb);
tmp--;
I802_DEBUG_INC(local->tx_status_drop);
struct ieee80211_local *local = (struct ieee80211_local *) data;
struct sk_buff *skb;
struct ieee80211_rx_status rx_status;
- struct ieee80211_tx_status *tx_status;
struct ieee80211_ra_tid *ra_tid;
while ((skb = skb_dequeue(&local->skb_queue)) ||
__ieee80211_rx(local_to_hw(local), skb, &rx_status);
break;
case IEEE80211_TX_STATUS_MSG:
- /* get pointer to saved status out of skb->cb */
- memcpy(&tx_status, skb->cb, sizeof(tx_status));
skb->pkt_type = 0;
- ieee80211_tx_status(local_to_hw(local),
- skb, tx_status);
- kfree(tx_status);
+ ieee80211_tx_status(local_to_hw(local), skb);
break;
case IEEE80211_DELBA_MSG:
ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
ra_tid->ra, ra_tid->tid);
dev_kfree_skb(skb);
break ;
- default: /* should never get here! */
- printk(KERN_ERR "%s: Unknown message type (%d)\n",
- wiphy_name(local->hw.wiphy), skb->pkt_type);
+ default:
+ WARN_ON(1);
dev_kfree_skb(skb);
break;
}
* Also, tx_packet_data in cb is restored from tx_control. */
static void ieee80211_remove_tx_extra(struct ieee80211_local *local,
struct ieee80211_key *key,
- struct sk_buff *skb,
- struct ieee80211_tx_control *control)
+ struct sk_buff *skb)
{
int hdrlen, iv_len, mic_len;
- struct ieee80211_tx_packet_data *pkt_data;
-
- pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
- pkt_data->ifindex = vif_to_sdata(control->vif)->dev->ifindex;
- pkt_data->flags = 0;
- if (control->flags & IEEE80211_TXCTL_REQ_TX_STATUS)
- pkt_data->flags |= IEEE80211_TXPD_REQ_TX_STATUS;
- if (control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)
- pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT;
- if (control->flags & IEEE80211_TXCTL_REQUEUE)
- pkt_data->flags |= IEEE80211_TXPD_REQUEUE;
- if (control->flags & IEEE80211_TXCTL_EAPOL_FRAME)
- pkt_data->flags |= IEEE80211_TXPD_EAPOL_FRAME;
- pkt_data->queue = control->queue;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+ info->flags &= IEEE80211_TX_CTL_REQ_TX_STATUS |
+ IEEE80211_TX_CTL_DO_NOT_ENCRYPT |
+ IEEE80211_TX_CTL_REQUEUE |
+ IEEE80211_TX_CTL_EAPOL_FRAME;
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
struct sta_info *sta,
- struct sk_buff *skb,
- struct ieee80211_tx_status *status)
+ struct sk_buff *skb)
{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
sta->tx_filtered_count++;
/*
* packet. If the STA went to power save mode, this will happen
* when it wakes up for the next time.
*/
- sta->flags |= WLAN_STA_CLEAR_PS_FILT;
+ set_sta_flags(sta, WLAN_STA_CLEAR_PS_FILT);
/*
* This code races in the following way:
* can be unknown, for example with different interrupt status
* bits.
*/
- if (sta->flags & WLAN_STA_PS &&
+ if (test_sta_flags(sta, WLAN_STA_PS) &&
skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) {
- ieee80211_remove_tx_extra(local, sta->key, skb,
- &status->control);
+ ieee80211_remove_tx_extra(local, sta->key, skb);
skb_queue_tail(&sta->tx_filtered, skb);
return;
}
- if (!(sta->flags & WLAN_STA_PS) &&
- !(status->control.flags & IEEE80211_TXCTL_REQUEUE)) {
+ if (!test_sta_flags(sta, WLAN_STA_PS) &&
+ !(info->flags & IEEE80211_TX_CTL_REQUEUE)) {
/* Software retry the packet once */
- status->control.flags |= IEEE80211_TXCTL_REQUEUE;
- ieee80211_remove_tx_extra(local, sta->key, skb,
- &status->control);
+ info->flags |= IEEE80211_TX_CTL_REQUEUE;
+ ieee80211_remove_tx_extra(local, sta->key, skb);
dev_queue_xmit(skb);
return;
}
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
if (net_ratelimit())
printk(KERN_DEBUG "%s: dropped TX filtered frame, "
"queue_len=%d PS=%d @%lu\n",
wiphy_name(local->hw.wiphy),
skb_queue_len(&sta->tx_filtered),
- !!(sta->flags & WLAN_STA_PS), jiffies);
+ !!test_sta_flags(sta, WLAN_STA_PS), jiffies);
+#endif
dev_kfree_skb(skb);
}
-void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct ieee80211_tx_status *status)
+void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct sk_buff *skb2;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct ieee80211_local *local = hw_to_local(hw);
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
u16 frag, type;
+ __le16 fc;
struct ieee80211_tx_status_rtap_hdr *rthdr;
struct ieee80211_sub_if_data *sdata;
struct net_device *prev_dev = NULL;
-
- if (!status) {
- printk(KERN_ERR
- "%s: ieee80211_tx_status called with NULL status\n",
- wiphy_name(local->hw.wiphy));
- dev_kfree_skb(skb);
- return;
- }
+ struct sta_info *sta;
rcu_read_lock();
- if (status->excessive_retries) {
- struct sta_info *sta;
+ if (info->status.excessive_retries) {
sta = sta_info_get(local, hdr->addr1);
if (sta) {
- if (sta->flags & WLAN_STA_PS) {
+ 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.
*/
- status->excessive_retries = 0;
- status->flags |= IEEE80211_TX_STATUS_TX_FILTERED;
- ieee80211_handle_filtered_frame(local, sta,
- skb, status);
+ ieee80211_handle_filtered_frame(local, sta, skb);
rcu_read_unlock();
return;
}
}
}
- if (status->flags & IEEE80211_TX_STATUS_TX_FILTERED) {
- struct sta_info *sta;
+ fc = hdr->frame_control;
+
+ 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)
+ & IEEE80211_SCTL_SEQ);
+ ieee80211_send_bar(sta->sdata->dev, hdr->addr1,
+ tid, ssn);
+ }
+ }
+
+ if (info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
sta = sta_info_get(local, hdr->addr1);
if (sta) {
- ieee80211_handle_filtered_frame(local, sta, skb,
- status);
+ ieee80211_handle_filtered_frame(local, sta, skb);
rcu_read_unlock();
return;
}
} else
- rate_control_tx_status(local->mdev, skb, status);
+ rate_control_tx_status(local->mdev, skb);
rcu_read_unlock();
frag = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG;
type = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_FTYPE;
- if (status->flags & IEEE80211_TX_STATUS_ACK) {
+ if (info->flags & IEEE80211_TX_STAT_ACK) {
if (frag == 0) {
local->dot11TransmittedFrameCount++;
if (is_multicast_ether_addr(hdr->addr1))
local->dot11MulticastTransmittedFrameCount++;
- if (status->retry_count > 0)
+ if (info->status.retry_count > 0)
local->dot11RetryCount++;
- if (status->retry_count > 1)
+ if (info->status.retry_count > 1)
local->dot11MultipleRetryCount++;
}
return;
}
- rthdr = (struct ieee80211_tx_status_rtap_hdr*)
+ rthdr = (struct ieee80211_tx_status_rtap_hdr *)
skb_push(skb, sizeof(*rthdr));
memset(rthdr, 0, sizeof(*rthdr));
cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) |
(1 << IEEE80211_RADIOTAP_DATA_RETRIES));
- if (!(status->flags & IEEE80211_TX_STATUS_ACK) &&
+ if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
!is_multicast_ether_addr(hdr->addr1))
rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL);
- if ((status->control.flags & IEEE80211_TXCTL_USE_RTS_CTS) &&
- (status->control.flags & IEEE80211_TXCTL_USE_CTS_PROTECT))
+ if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) &&
+ (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT))
rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS);
- else if (status->control.flags & IEEE80211_TXCTL_USE_RTS_CTS)
+ else if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS);
- rthdr->data_retries = status->retry_count;
+ rthdr->data_retries = info->status.retry_count;
/* XXX: is this sufficient for BPF? */
skb_set_mac_header(skb, 0);
if (result < 0)
return result;
+ /*
+ * We use the number of queues for feature tests (QoS, HT) internally
+ * so restrict them appropriately.
+ */
+#ifdef CONFIG_MAC80211_QOS
+ if (hw->queues > IEEE80211_MAX_QUEUES)
+ hw->queues = IEEE80211_MAX_QUEUES;
+ if (hw->ampdu_queues > IEEE80211_MAX_AMPDU_QUEUES)
+ hw->ampdu_queues = IEEE80211_MAX_AMPDU_QUEUES;
+ if (hw->queues < 4)
+ hw->ampdu_queues = 0;
+#else
+ hw->queues = 1;
+ hw->ampdu_queues = 0;
+#endif
+
/* for now, mdev needs sub_if_data :/ */
- mdev = alloc_netdev(sizeof(struct ieee80211_sub_if_data),
- "wmaster%d", ether_setup);
+ mdev = alloc_netdev_mq(sizeof(struct ieee80211_sub_if_data),
+ "wmaster%d", ether_setup,
+ ieee80211_num_queues(hw));
if (!mdev)
goto fail_mdev_alloc;
+ if (ieee80211_num_queues(hw) > 1)
+ mdev->features |= NETIF_F_MULTI_QUEUE;
+
sdata = IEEE80211_DEV_TO_SUB_IF(mdev);
mdev->ieee80211_ptr = &sdata->wdev;
sdata->wdev.wiphy = local->hw.wiphy;
list_add_tail(&sdata->list, &local->interfaces);
name = wiphy_dev(local->hw.wiphy)->driver->name;
- local->hw.workqueue = create_singlethread_workqueue(name);
+ local->hw.workqueue = create_freezeable_workqueue(name);
if (!local->hw.workqueue) {
result = -ENOMEM;
goto fail_workqueue;
debugfs_hw_add(local);
- local->hw.conf.beacon_int = 1000;
+ if (local->hw.conf.beacon_int < 10)
+ local->hw.conf.beacon_int = 100;
- local->wstats_flags |= local->hw.max_rssi ?
- IW_QUAL_LEVEL_UPDATED : IW_QUAL_LEVEL_INVALID;
- local->wstats_flags |= local->hw.max_signal ?
+ local->wstats_flags |= local->hw.flags & (IEEE80211_HW_SIGNAL_UNSPEC |
+ IEEE80211_HW_SIGNAL_DB |
+ IEEE80211_HW_SIGNAL_DBM) ?
IW_QUAL_QUAL_UPDATED : IW_QUAL_QUAL_INVALID;
- local->wstats_flags |= local->hw.max_noise ?
+ local->wstats_flags |= local->hw.flags & IEEE80211_HW_NOISE_DBM ?
IW_QUAL_NOISE_UPDATED : IW_QUAL_NOISE_INVALID;
- if (local->hw.max_rssi < 0 || local->hw.max_noise < 0)
+ if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
local->wstats_flags |= IW_QUAL_DBM;
result = sta_info_start(local);
struct sk_buff *skb;
int ret;
- BUILD_BUG_ON(sizeof(struct ieee80211_tx_packet_data) > sizeof(skb->cb));
+ BUILD_BUG_ON(sizeof(struct ieee80211_tx_info) > sizeof(skb->cb));
+ BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, driver_data) +
+ IEEE80211_TX_INFO_DRIVER_DATA_SIZE > sizeof(skb->cb));
ret = rc80211_pid_init();
if (ret)
u8 *ssid, size_t ssid_len);
static int ieee80211_sta_config_auth(struct net_device *dev,
struct ieee80211_if_sta *ifsta);
+static void sta_rx_agg_session_timer_expired(unsigned long data);
void ieee802_11_parse_elems(u8 *start, size_t len,
elems->perr = pos;
elems->perr_len = elen;
break;
+ case WLAN_EID_CHANNEL_SWITCH:
+ elems->ch_switch_elem = pos;
+ elems->ch_switch_elem_len = elen;
+ break;
+ case WLAN_EID_QUIET:
+ if (!elems->quiet_elem) {
+ elems->quiet_elem = pos;
+ elems->quiet_elem_len = elen;
+ }
+ elems->num_of_quiet_elem++;
+ break;
+ case WLAN_EID_COUNTRY:
+ elems->country_elem = pos;
+ elems->country_elem_len = elen;
+ break;
+ case WLAN_EID_PWR_CONSTRAINT:
+ elems->pwr_constr_elem = pos;
+ elems->pwr_constr_elem_len = elen;
+ break;
default:
break;
}
qparam.cw_max = 1023;
qparam.txop = 0;
- for (i = IEEE80211_TX_QUEUE_DATA0; i < NUM_TX_DATA_QUEUES; i++)
- local->ops->conf_tx(local_to_hw(local),
- i + IEEE80211_TX_QUEUE_DATA0,
- &qparam);
-
- if (ibss) {
- /* IBSS uses different parameters for Beacon sending */
- qparam.cw_min++;
- qparam.cw_min *= 2;
- qparam.cw_min--;
- local->ops->conf_tx(local_to_hw(local),
- IEEE80211_TX_QUEUE_BEACON, &qparam);
- }
+ for (i = 0; i < local_to_hw(local)->queues; i++)
+ local->ops->conf_tx(local_to_hw(local), i, &qparam);
}
}
int count;
u8 *pos;
+ if (!(ifsta->flags & IEEE80211_STA_WMM_ENABLED))
+ return;
+
+ if (!wmm_param)
+ return;
+
if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1)
return;
count = wmm_param[6] & 0x0f;
switch (aci) {
case 1:
- queue = IEEE80211_TX_QUEUE_DATA3;
- if (acm) {
+ queue = 3;
+ if (acm)
local->wmm_acm |= BIT(0) | BIT(3);
- }
break;
case 2:
- queue = IEEE80211_TX_QUEUE_DATA1;
- if (acm) {
+ queue = 1;
+ if (acm)
local->wmm_acm |= BIT(4) | BIT(5);
- }
break;
case 3:
- queue = IEEE80211_TX_QUEUE_DATA0;
- if (acm) {
+ queue = 0;
+ if (acm)
local->wmm_acm |= BIT(6) | BIT(7);
- }
break;
case 0:
default:
- queue = IEEE80211_TX_QUEUE_DATA2;
- if (acm) {
+ queue = 2;
+ if (acm)
local->wmm_acm |= BIT(1) | BIT(2);
- }
break;
}
params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4);
params.cw_min = ecw2cw(pos[1] & 0x0f);
params.txop = pos[2] | (pos[3] << 8);
-#ifdef CONFIG_MAC80211_DEBUG
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d "
"cWmin=%d cWmax=%d txop=%d\n",
dev->name, queue, aci, acm, params.aifs, params.cw_min,
bool use_short_preamble)
{
struct ieee80211_bss_conf *bss_conf = &sdata->bss_conf;
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
struct ieee80211_if_sta *ifsta = &sdata->u.sta;
DECLARE_MAC_BUF(mac);
+#endif
u32 changed = 0;
if (use_protection != bss_conf->use_cts_prot) {
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
if (net_ratelimit()) {
printk(KERN_DEBUG "%s: CTS protection %s (BSSID="
"%s)\n",
use_protection ? "enabled" : "disabled",
print_mac(mac, ifsta->bssid));
}
+#endif
bss_conf->use_cts_prot = use_protection;
changed |= BSS_CHANGED_ERP_CTS_PROT;
}
if (use_short_preamble != bss_conf->use_short_preamble) {
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
if (net_ratelimit()) {
printk(KERN_DEBUG "%s: switched to %s barker preamble"
" (BSSID=%s)\n",
use_short_preamble ? "short" : "long",
print_mac(mac, ifsta->bssid));
}
+#endif
bss_conf->use_short_preamble = use_short_preamble;
changed |= BSS_CHANGED_ERP_PREAMBLE;
}
sdata->bss_conf.ht_bss_conf = &conf->ht_bss_conf;
}
- netif_carrier_on(dev);
ifsta->flags |= IEEE80211_STA_PREV_BSSID_SET;
memcpy(ifsta->prev_bssid, sdata->u.sta.bssid, ETH_ALEN);
memcpy(wrqu.ap_addr.sa_data, sdata->u.sta.bssid, ETH_ALEN);
ieee80211_sta_send_associnfo(dev, ifsta);
} else {
+ netif_carrier_off(dev);
ieee80211_sta_tear_down_BA_sessions(dev, ifsta->bssid);
ifsta->flags &= ~IEEE80211_STA_ASSOCIATED;
- netif_carrier_off(dev);
- ieee80211_reset_erp_info(dev);
+ changed |= ieee80211_reset_erp_info(dev);
sdata->bss_conf.assoc_ht = 0;
sdata->bss_conf.ht_conf = NULL;
sdata->bss_conf.assoc = assoc;
ieee80211_bss_info_change_notify(sdata, changed);
+
+ if (assoc)
+ netif_carrier_on(dev);
+
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
}
int encrypt)
{
struct ieee80211_sub_if_data *sdata;
- struct ieee80211_tx_packet_data *pkt_data;
+ struct ieee80211_tx_info *info;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
skb->dev = sdata->local->mdev;
skb_set_network_header(skb, 0);
skb_set_transport_header(skb, 0);
- pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
- memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));
- pkt_data->ifindex = sdata->dev->ifindex;
+ info = IEEE80211_SKB_CB(skb);
+ memset(info, 0, sizeof(struct ieee80211_tx_info));
+ info->control.ifindex = sdata->dev->ifindex;
if (!encrypt)
- pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT;
+ info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT;
dev_queue_xmit(skb);
}
if (bss) {
if (bss->capability & WLAN_CAPABILITY_PRIVACY)
capab |= WLAN_CAPABILITY_PRIVACY;
- if (bss->wmm_ie) {
+ if (bss->wmm_ie)
wmm = 1;
- }
/* get all rates supported by the device and the AP as
* some APs don't like getting a superset of their rates
* b-only mode) */
rates_len = ieee80211_compatible_rates(bss, sband, &rates);
+ if ((bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT) &&
+ (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT))
+ capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
+
ieee80211_rx_bss_put(dev, bss);
} else {
rates = ~0;
}
}
+ if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) {
+ /* 1. power capabilities */
+ pos = skb_put(skb, 4);
+ *pos++ = WLAN_EID_PWR_CAPABILITY;
+ *pos++ = 2;
+ *pos++ = 0; /* min tx power */
+ *pos++ = local->hw.conf.channel->max_power; /* max tx power */
+
+ /* 2. supported channels */
+ /* TODO: get this in reg domain format */
+ pos = skb_put(skb, 2 * sband->n_channels + 2);
+ *pos++ = WLAN_EID_SUPPORTED_CHANNELS;
+ *pos++ = 2 * sband->n_channels;
+ for (i = 0; i < sband->n_channels; i++) {
+ *pos++ = ieee80211_frequency_to_channel(
+ sband->channels[i].center_freq);
+ *pos++ = 1; /* one channel in the subband*/
+ }
+ }
+
if (ifsta->extra_ie) {
pos = skb_put(skb, ifsta->extra_ie_len);
memcpy(pos, ifsta->extra_ie, ifsta->extra_ie_len);
*pos++ = 1; /* WME ver */
*pos++ = 0;
}
+
/* wmm support is a must to HT */
- if (wmm && sband->ht_info.ht_supported) {
- __le16 tmp = cpu_to_le16(sband->ht_info.cap);
+ if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED) &&
+ sband->ht_info.ht_supported && bss->ht_add_ie) {
+ struct ieee80211_ht_addt_info *ht_add_info =
+ (struct ieee80211_ht_addt_info *)bss->ht_add_ie;
+ u16 cap = sband->ht_info.cap;
+ __le16 tmp;
+ u32 flags = local->hw.conf.channel->flags;
+
+ switch (ht_add_info->ht_param & IEEE80211_HT_IE_CHA_SEC_OFFSET) {
+ case IEEE80211_HT_IE_CHA_SEC_ABOVE:
+ if (flags & IEEE80211_CHAN_NO_FAT_ABOVE) {
+ cap &= ~IEEE80211_HT_CAP_SUP_WIDTH;
+ cap &= ~IEEE80211_HT_CAP_SGI_40;
+ }
+ break;
+ case IEEE80211_HT_IE_CHA_SEC_BELOW:
+ if (flags & IEEE80211_CHAN_NO_FAT_BELOW) {
+ cap &= ~IEEE80211_HT_CAP_SUP_WIDTH;
+ cap &= ~IEEE80211_HT_CAP_SGI_40;
+ }
+ break;
+ }
+
+ tmp = cpu_to_le16(cap);
pos = skb_put(skb, sizeof(struct ieee80211_ht_cap)+2);
*pos++ = WLAN_EID_HT_CAPABILITY;
*pos++ = sizeof(struct ieee80211_ht_cap);
u8 *pos;
struct ieee802_11_elems elems;
- printk(KERN_DEBUG "%s: replying to auth challenge\n", dev->name);
pos = mgmt->u.auth.variable;
ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
- if (!elems.challenge) {
- printk(KERN_DEBUG "%s: no challenge IE in shared key auth "
- "frame\n", dev->name);
+ if (!elems.challenge)
return;
- }
ieee80211_send_auth(dev, ifsta, 3, elems.challenge - 2,
elems.challenge_len + 2, 1);
}
struct ieee80211_mgmt *mgmt;
u16 capab;
- skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom + 1 +
- sizeof(mgmt->u.action.u.addba_resp));
+ skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
+
if (!skb) {
printk(KERN_DEBUG "%s: failed to allocate buffer "
"for addba resp frame\n", dev->name);
struct ieee80211_mgmt *mgmt;
u16 capab;
- skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom + 1 +
- sizeof(mgmt->u.action.u.addba_req));
-
+ skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
if (!skb) {
printk(KERN_ERR "%s: failed to allocate buffer "
/* examine state machine */
- spin_lock_bh(&sta->ampdu_mlme.ampdu_rx);
+ spin_lock_bh(&sta->lock);
if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_IDLE) {
#ifdef CONFIG_MAC80211_HT_DEBUG
sta->ampdu_mlme.tid_rx[tid] =
kmalloc(sizeof(struct tid_ampdu_rx), GFP_ATOMIC);
if (!sta->ampdu_mlme.tid_rx[tid]) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
if (net_ratelimit())
printk(KERN_ERR "allocate rx mlme to tid %d failed\n",
tid);
+#endif
goto end;
}
/* rx timer */
tid_agg_rx->reorder_buf =
kmalloc(buf_size * sizeof(struct sk_buff *), GFP_ATOMIC);
if (!tid_agg_rx->reorder_buf) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
if (net_ratelimit())
printk(KERN_ERR "can not allocate reordering buffer "
"to tid %d\n", tid);
+#endif
kfree(sta->ampdu_mlme.tid_rx[tid]);
goto end;
}
tid_agg_rx->stored_mpdu_num = 0;
status = WLAN_STATUS_SUCCESS;
end:
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx);
+ spin_unlock_bh(&sta->lock);
end_no_lock:
ieee80211_send_addba_resp(sta->sdata->dev, sta->addr, tid,
state = &sta->ampdu_mlme.tid_state_tx[tid];
- spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_lock_bh(&sta->lock);
if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
- printk(KERN_DEBUG "state not HT_ADDBA_REQUESTED_MSK:"
- "%d\n", *state);
+ spin_unlock_bh(&sta->lock);
goto addba_resp_exit;
}
if (mgmt->u.action.u.addba_resp.dialog_token !=
sta->ampdu_mlme.tid_tx[tid]->dialog_token) {
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_unlock_bh(&sta->lock);
#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid);
#endif /* CONFIG_MAC80211_HT_DEBUG */
#endif /* CONFIG_MAC80211_HT_DEBUG */
if (le16_to_cpu(mgmt->u.action.u.addba_resp.status)
== WLAN_STATUS_SUCCESS) {
- if (*state & HT_ADDBA_RECEIVED_MSK)
- printk(KERN_DEBUG "double addBA response\n");
-
*state |= HT_ADDBA_RECEIVED_MSK;
sta->ampdu_mlme.addba_req_num[tid] = 0;
- if (*state == HT_AGG_STATE_OPERATIONAL) {
- printk(KERN_DEBUG "Aggregation on for tid %d \n", tid);
+ if (*state == HT_AGG_STATE_OPERATIONAL)
ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
- }
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
- printk(KERN_DEBUG "recipient accepted agg: tid %d \n", tid);
+ spin_unlock_bh(&sta->lock);
} else {
- printk(KERN_DEBUG "recipient rejected agg: tid %d \n", tid);
-
sta->ampdu_mlme.addba_req_num[tid]++;
/* this will allow the state check in stop_BA_session */
*state = HT_AGG_STATE_OPERATIONAL;
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_unlock_bh(&sta->lock);
ieee80211_stop_tx_ba_session(hw, sta->addr, tid,
WLAN_BACK_INITIATOR);
}
struct ieee80211_mgmt *mgmt;
u16 params;
- skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom + 1 +
- sizeof(mgmt->u.action.u.delba));
+ skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
if (!skb) {
printk(KERN_ERR "%s: failed to allocate buffer "
ieee80211_sta_tx(dev, skb, 0);
}
+void ieee80211_send_bar(struct net_device *dev, u8 *ra, u16 tid, u16 ssn)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct sk_buff *skb;
+ struct ieee80211_bar *bar;
+ u16 bar_control = 0;
+
+ skb = dev_alloc_skb(sizeof(*bar) + local->hw.extra_tx_headroom);
+ if (!skb) {
+ printk(KERN_ERR "%s: failed to allocate buffer for "
+ "bar frame\n", dev->name);
+ return;
+ }
+ skb_reserve(skb, local->hw.extra_tx_headroom);
+ bar = (struct ieee80211_bar *)skb_put(skb, sizeof(*bar));
+ memset(bar, 0, sizeof(*bar));
+ bar->frame_control = IEEE80211_FC(IEEE80211_FTYPE_CTL,
+ IEEE80211_STYPE_BACK_REQ);
+ memcpy(bar->ra, ra, ETH_ALEN);
+ memcpy(bar->ta, dev->dev_addr, ETH_ALEN);
+ bar_control |= (u16)IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL;
+ bar_control |= (u16)IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA;
+ bar_control |= (u16)(tid << 12);
+ bar->control = cpu_to_le16(bar_control);
+ bar->start_seq_num = cpu_to_le16(ssn);
+
+ ieee80211_sta_tx(dev, skb, 0);
+}
+
void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid,
u16 initiator, u16 reason)
{
}
/* check if TID is in operational state */
- spin_lock_bh(&sta->ampdu_mlme.ampdu_rx);
+ spin_lock_bh(&sta->lock);
if (sta->ampdu_mlme.tid_state_rx[tid]
!= HT_AGG_STATE_OPERATIONAL) {
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx);
+ spin_unlock_bh(&sta->lock);
rcu_read_unlock();
return;
}
sta->ampdu_mlme.tid_state_rx[tid] =
HT_AGG_STATE_REQ_STOP_BA_MSK |
(initiator << HT_AGG_STATE_INITIATOR_SHIFT);
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx);
+ spin_unlock_bh(&sta->lock);
/* stop HW Rx aggregation. ampdu_action existence
* already verified in session init so we add the BUG_ON */
ra, tid, NULL);
if (ret)
printk(KERN_DEBUG "HW problem - can not stop rx "
- "aggergation for tid %d\n", tid);
+ "aggregation for tid %d\n", tid);
/* shutdown timer has not expired */
if (initiator != WLAN_BACK_TIMER)
ieee80211_sta_stop_rx_ba_session(dev, sta->addr, tid,
WLAN_BACK_INITIATOR, 0);
else { /* WLAN_BACK_RECIPIENT */
- spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_lock_bh(&sta->lock);
sta->ampdu_mlme.tid_state_tx[tid] =
HT_AGG_STATE_OPERATIONAL;
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_unlock_bh(&sta->lock);
ieee80211_stop_tx_ba_session(&local->hw, sta->addr, tid,
WLAN_BACK_RECIPIENT);
}
state = &sta->ampdu_mlme.tid_state_tx[tid];
/* check if the TID waits for addBA response */
- spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_lock_bh(&sta->lock);
if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_unlock_bh(&sta->lock);
*state = HT_AGG_STATE_IDLE;
+#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "timer expired on tid %d but we are not "
"expecting addBA response there", tid);
+#endif
goto timer_expired_exit;
}
+#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid);
+#endif
/* go through the state check in stop_BA_session */
*state = HT_AGG_STATE_OPERATIONAL;
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_unlock_bh(&sta->lock);
ieee80211_stop_tx_ba_session(hw, temp_sta->addr, tid,
WLAN_BACK_INITIATOR);
* resetting it after each frame that arrives from the originator.
* if this timer expires ieee80211_sta_stop_rx_ba_session will be executed.
*/
-void sta_rx_agg_session_timer_expired(unsigned long data)
+static void sta_rx_agg_session_timer_expired(unsigned long data)
{
/* not an elegant detour, but there is no choice as the timer passes
* only one argument, and various sta_info are needed here, so init
struct sta_info *sta = container_of(timer_to_id, struct sta_info,
timer_to_tid[0]);
+#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->dev, sta->addr,
(u16)*ptid, WLAN_BACK_TIMER,
WLAN_REASON_QSTA_TIMEOUT);
}
}
+static void ieee80211_send_refuse_measurement_request(struct net_device *dev,
+ struct ieee80211_msrment_ie *request_ie,
+ const u8 *da, const u8 *bssid,
+ u8 dialog_token)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct sk_buff *skb;
+ struct ieee80211_mgmt *msr_report;
+
+ skb = dev_alloc_skb(sizeof(*msr_report) + local->hw.extra_tx_headroom +
+ sizeof(struct ieee80211_msrment_ie));
+
+ if (!skb) {
+ printk(KERN_ERR "%s: failed to allocate buffer for "
+ "measurement report frame\n", dev->name);
+ return;
+ }
+
+ skb_reserve(skb, local->hw.extra_tx_headroom);
+ msr_report = (struct ieee80211_mgmt *)skb_put(skb, 24);
+ memset(msr_report, 0, 24);
+ memcpy(msr_report->da, da, ETH_ALEN);
+ memcpy(msr_report->sa, dev->dev_addr, ETH_ALEN);
+ memcpy(msr_report->bssid, bssid, ETH_ALEN);
+ msr_report->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+ IEEE80211_STYPE_ACTION);
+
+ skb_put(skb, 1 + sizeof(msr_report->u.action.u.measurement));
+ msr_report->u.action.category = WLAN_CATEGORY_SPECTRUM_MGMT;
+ msr_report->u.action.u.measurement.action_code =
+ WLAN_ACTION_SPCT_MSR_RPRT;
+ msr_report->u.action.u.measurement.dialog_token = dialog_token;
+
+ msr_report->u.action.u.measurement.element_id = WLAN_EID_MEASURE_REPORT;
+ msr_report->u.action.u.measurement.length =
+ sizeof(struct ieee80211_msrment_ie);
+
+ memset(&msr_report->u.action.u.measurement.msr_elem, 0,
+ sizeof(struct ieee80211_msrment_ie));
+ msr_report->u.action.u.measurement.msr_elem.token = request_ie->token;
+ msr_report->u.action.u.measurement.msr_elem.mode |=
+ IEEE80211_SPCT_MSR_RPRT_MODE_REFUSED;
+ msr_report->u.action.u.measurement.msr_elem.type = request_ie->type;
+
+ ieee80211_sta_tx(dev, skb, 0);
+}
+
+static void ieee80211_sta_process_measurement_req(struct net_device *dev,
+ struct ieee80211_mgmt *mgmt,
+ size_t len)
+{
+ /*
+ * Ignoring measurement request is spec violation.
+ * Mandatory measurements must be reported optional
+ * measurements might be refused or reported incapable
+ * For now just refuse
+ * TODO: Answer basic measurement as unmeasured
+ */
+ ieee80211_send_refuse_measurement_request(dev,
+ &mgmt->u.action.u.measurement.msr_elem,
+ mgmt->sa, mgmt->bssid,
+ mgmt->u.action.u.measurement.dialog_token);
+}
+
+
static void ieee80211_rx_mgmt_auth(struct net_device *dev,
struct ieee80211_if_sta *ifsta,
struct ieee80211_mgmt *mgmt,
DECLARE_MAC_BUF(mac);
if (ifsta->state != IEEE80211_AUTHENTICATE &&
- sdata->vif.type != IEEE80211_IF_TYPE_IBSS) {
- printk(KERN_DEBUG "%s: authentication frame received from "
- "%s, but not in authenticate state - ignored\n",
- dev->name, print_mac(mac, mgmt->sa));
+ sdata->vif.type != IEEE80211_IF_TYPE_IBSS)
return;
- }
- if (len < 24 + 6) {
- printk(KERN_DEBUG "%s: too short (%zd) authentication frame "
- "received from %s - ignored\n",
- dev->name, len, print_mac(mac, mgmt->sa));
+ if (len < 24 + 6)
return;
- }
if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
- memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) {
- printk(KERN_DEBUG "%s: authentication frame received from "
- "unknown AP (SA=%s BSSID=%s) - "
- "ignored\n", dev->name, print_mac(mac, mgmt->sa),
- print_mac(mac, mgmt->bssid));
+ memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0)
return;
- }
if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
- memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0) {
- printk(KERN_DEBUG "%s: authentication frame received from "
- "unknown BSSID (SA=%s BSSID=%s) - "
- "ignored\n", dev->name, print_mac(mac, mgmt->sa),
- print_mac(mac, mgmt->bssid));
+ memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0)
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);
- printk(KERN_DEBUG "%s: RX authentication from %s (alg=%d "
- "transaction=%d status=%d)\n",
- dev->name, print_mac(mac, mgmt->sa), auth_alg,
- auth_transaction, status_code);
-
if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
- /* IEEE 802.11 standard does not require authentication in IBSS
+ /*
+ * 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.
- * TODO: Could implement shared key authentication. */
- if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1) {
- printk(KERN_DEBUG "%s: unexpected IBSS authentication "
- "frame (alg=%d transaction=%d)\n",
- dev->name, auth_alg, auth_transaction);
+ */
+ if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1)
return;
- }
ieee80211_send_auth(dev, ifsta, 2, NULL, 0, 0);
}
if (auth_alg != ifsta->auth_alg ||
- auth_transaction != ifsta->auth_transaction) {
- printk(KERN_DEBUG "%s: unexpected authentication frame "
- "(alg=%d transaction=%d)\n",
- dev->name, auth_alg, auth_transaction);
+ auth_transaction != ifsta->auth_transaction)
return;
- }
if (status_code != WLAN_STATUS_SUCCESS) {
- printk(KERN_DEBUG "%s: AP denied authentication (auth_alg=%d "
- "code=%d)\n", dev->name, ifsta->auth_alg, status_code);
if (status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG) {
u8 algs[3];
const int num_algs = ARRAY_SIZE(algs);
!ieee80211_sta_wep_configured(dev))
continue;
ifsta->auth_alg = algs[pos];
- printk(KERN_DEBUG "%s: set auth_alg=%d for "
- "next try\n",
- dev->name, ifsta->auth_alg);
break;
}
}
u16 reason_code;
DECLARE_MAC_BUF(mac);
- if (len < 24 + 2) {
- printk(KERN_DEBUG "%s: too short (%zd) deauthentication frame "
- "received from %s - ignored\n",
- dev->name, len, print_mac(mac, mgmt->sa));
+ if (len < 24 + 2)
return;
- }
- if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) {
- printk(KERN_DEBUG "%s: deauthentication frame received from "
- "unknown AP (SA=%s BSSID=%s) - "
- "ignored\n", dev->name, print_mac(mac, mgmt->sa),
- print_mac(mac, mgmt->bssid));
+ if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN))
return;
- }
reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
- printk(KERN_DEBUG "%s: RX deauthentication from %s"
- " (reason=%d)\n",
- dev->name, print_mac(mac, mgmt->sa), reason_code);
-
- if (ifsta->flags & IEEE80211_STA_AUTHENTICATED) {
+ if (ifsta->flags & IEEE80211_STA_AUTHENTICATED)
printk(KERN_DEBUG "%s: deauthenticated\n", dev->name);
- }
if (ifsta->state == IEEE80211_AUTHENTICATE ||
ifsta->state == IEEE80211_ASSOCIATE ||
u16 reason_code;
DECLARE_MAC_BUF(mac);
- if (len < 24 + 2) {
- printk(KERN_DEBUG "%s: too short (%zd) disassociation frame "
- "received from %s - ignored\n",
- dev->name, len, print_mac(mac, mgmt->sa));
+ if (len < 24 + 2)
return;
- }
- if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) {
- printk(KERN_DEBUG "%s: disassociation frame received from "
- "unknown AP (SA=%s BSSID=%s) - "
- "ignored\n", dev->name, print_mac(mac, mgmt->sa),
- print_mac(mac, mgmt->bssid));
+ if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN))
return;
- }
reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
- printk(KERN_DEBUG "%s: RX disassociation from %s"
- " (reason=%d)\n",
- dev->name, print_mac(mac, mgmt->sa), reason_code);
-
if (ifsta->flags & IEEE80211_STA_ASSOCIATED)
printk(KERN_DEBUG "%s: disassociated\n", dev->name);
/* AssocResp and ReassocResp have identical structure, so process both
* of them in this function. */
- if (ifsta->state != IEEE80211_ASSOCIATE) {
- printk(KERN_DEBUG "%s: association frame received from "
- "%s, but not in associate state - ignored\n",
- dev->name, print_mac(mac, mgmt->sa));
+ if (ifsta->state != IEEE80211_ASSOCIATE)
return;
- }
- if (len < 24 + 6) {
- printk(KERN_DEBUG "%s: too short (%zd) association frame "
- "received from %s - ignored\n",
- dev->name, len, print_mac(mac, mgmt->sa));
+ if (len < 24 + 6)
return;
- }
- if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) {
- printk(KERN_DEBUG "%s: association frame received from "
- "unknown AP (SA=%s BSSID=%s) - "
- "ignored\n", dev->name, print_mac(mac, mgmt->sa),
- print_mac(mac, mgmt->bssid));
+ if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0)
return;
- }
capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
local->hw.conf.channel->center_freq,
ifsta->ssid, ifsta->ssid_len);
if (bss) {
- sta->last_rssi = bss->rssi;
sta->last_signal = bss->signal;
+ sta->last_qual = bss->qual;
sta->last_noise = bss->noise;
ieee80211_rx_bss_put(dev, bss);
}
* to between the sta_info_alloc() and sta_info_insert() above.
*/
- sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP |
- WLAN_STA_AUTHORIZED;
+ set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP |
+ WLAN_STA_AUTHORIZED);
rates = 0;
basic_rates = 0;
else
sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
- if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param) {
+ if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param &&
+ (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) {
struct ieee80211_ht_bss_info bss_info;
ieee80211_ht_cap_ie_to_ht_info(
(struct ieee80211_ht_cap *)
rate_control_rate_init(sta, local);
- if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) {
- sta->flags |= WLAN_STA_WME;
+ if (elems.wmm_param) {
+ set_sta_flags(sta, WLAN_STA_WME);
rcu_read_unlock();
ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param,
elems.wmm_param_len);
kfree(bss->rsn_ie);
kfree(bss->wmm_ie);
kfree(bss->ht_ie);
+ kfree(bss->ht_add_ie);
kfree(bss_mesh_id(bss));
kfree(bss_mesh_cfg(bss));
kfree(bss);
int res, rates, i, j;
struct sk_buff *skb;
struct ieee80211_mgmt *mgmt;
- struct ieee80211_tx_control control;
+ struct ieee80211_tx_info *control;
struct rate_selection ratesel;
u8 *pos;
struct ieee80211_sub_if_data *sdata;
memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
mgmt->u.beacon.beacon_int =
cpu_to_le16(local->hw.conf.beacon_int);
+ mgmt->u.beacon.timestamp = cpu_to_le64(bss->timestamp);
mgmt->u.beacon.capab_info = cpu_to_le16(bss->capability);
pos = skb_put(skb, 2 + ifsta->ssid_len);
memcpy(pos, &bss->supp_rates[8], rates);
}
- memset(&control, 0, sizeof(control));
+ control = IEEE80211_SKB_CB(skb);
+
rate_control_get_rate(dev, sband, skb, &ratesel);
- if (!ratesel.rate) {
+ if (ratesel.rate_idx < 0) {
printk(KERN_DEBUG "%s: Failed to determine TX rate "
"for IBSS beacon\n", dev->name);
break;
}
- control.vif = &sdata->vif;
- control.tx_rate = ratesel.rate;
+ control->control.vif = &sdata->vif;
+ control->tx_rate_idx = ratesel.rate_idx;
if (sdata->bss_conf.use_short_preamble &&
- ratesel.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)
- control.flags |= IEEE80211_TXCTL_SHORT_PREAMBLE;
- control.antenna_sel_tx = local->hw.conf.antenna_sel_tx;
- control.flags |= IEEE80211_TXCTL_NO_ACK;
- control.retry_limit = 1;
+ sband->bitrates[ratesel.rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE)
+ control->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE;
+ control->antenna_sel_tx = local->hw.conf.antenna_sel_tx;
+ control->flags |= IEEE80211_TX_CTL_NO_ACK;
+ control->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT;
+ control->control.retry_limit = 1;
ifsta->probe_resp = skb_copy(skb, GFP_ATOMIC);
if (ifsta->probe_resp) {
}
if (local->ops->beacon_update &&
- local->ops->beacon_update(local_to_hw(local),
- skb, &control) == 0) {
+ local->ops->beacon_update(local_to_hw(local), skb) == 0) {
printk(KERN_DEBUG "%s: Configured IBSS beacon "
"template\n", dev->name);
skb = NULL;
struct ieee80211_mgmt *mgmt,
size_t len,
struct ieee80211_rx_status *rx_status,
+ struct ieee802_11_elems *elems,
int beacon)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee802_11_elems elems;
- size_t baselen;
int freq, clen;
struct ieee80211_sta_bss *bss;
struct sta_info *sta;
if (!beacon && memcmp(mgmt->da, dev->dev_addr, ETH_ALEN))
return; /* ignore ProbeResp to foreign address */
-#if 0
- printk(KERN_DEBUG "%s: RX %s from %s to %s\n",
- dev->name, beacon ? "Beacon" : "Probe Response",
- print_mac(mac, mgmt->sa), print_mac(mac2, mgmt->da));
-#endif
-
- baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
- if (baselen > len)
- return;
-
beacon_timestamp = le64_to_cpu(mgmt->u.beacon.timestamp);
- ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);
- if (ieee80211_vif_is_mesh(&sdata->vif) && elems.mesh_id &&
- elems.mesh_config && mesh_matches_local(&elems, dev)) {
- u64 rates = ieee80211_sta_get_rates(local, &elems,
+ if (ieee80211_vif_is_mesh(&sdata->vif) && elems->mesh_id &&
+ elems->mesh_config && mesh_matches_local(elems, dev)) {
+ u64 rates = ieee80211_sta_get_rates(local, elems,
rx_status->band);
mesh_neighbour_update(mgmt->sa, rates, dev,
- mesh_peer_accepts_plinks(&elems, dev));
+ mesh_peer_accepts_plinks(elems, dev));
}
rcu_read_lock();
- if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates &&
+ if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems->supp_rates &&
memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0 &&
(sta = sta_info_get(local, mgmt->sa))) {
u64 prev_rates;
- u64 supp_rates = ieee80211_sta_get_rates(local, &elems,
+ u64 supp_rates = ieee80211_sta_get_rates(local, elems,
rx_status->band);
prev_rates = sta->supp_rates[rx_status->band];
sta->supp_rates[rx_status->band] =
sdata->u.sta.supp_rates_bits[rx_status->band];
}
- if (sta->supp_rates[rx_status->band] != prev_rates) {
- printk(KERN_DEBUG "%s: updated supp_rates set for "
- "%s based on beacon info (0x%llx & 0x%llx -> "
- "0x%llx)\n",
- dev->name, print_mac(mac, sta->addr),
- (unsigned long long) prev_rates,
- (unsigned long long) supp_rates,
- (unsigned long long) sta->supp_rates[rx_status->band]);
- }
}
rcu_read_unlock();
- if (elems.ds_params && elems.ds_params_len == 1)
- freq = ieee80211_channel_to_frequency(elems.ds_params[0]);
+ if (elems->ds_params && elems->ds_params_len == 1)
+ freq = ieee80211_channel_to_frequency(elems->ds_params[0]);
else
freq = rx_status->freq;
return;
#ifdef CONFIG_MAC80211_MESH
- if (elems.mesh_config)
- bss = ieee80211_rx_mesh_bss_get(dev, elems.mesh_id,
- elems.mesh_id_len, elems.mesh_config, freq);
+ if (elems->mesh_config)
+ bss = ieee80211_rx_mesh_bss_get(dev, elems->mesh_id,
+ elems->mesh_id_len, elems->mesh_config, freq);
else
#endif
bss = ieee80211_rx_bss_get(dev, mgmt->bssid, freq,
- elems.ssid, elems.ssid_len);
+ elems->ssid, elems->ssid_len);
if (!bss) {
#ifdef CONFIG_MAC80211_MESH
- if (elems.mesh_config)
- bss = ieee80211_rx_mesh_bss_add(dev, elems.mesh_id,
- elems.mesh_id_len, elems.mesh_config,
- elems.mesh_config_len, freq);
+ if (elems->mesh_config)
+ bss = ieee80211_rx_mesh_bss_add(dev, elems->mesh_id,
+ elems->mesh_id_len, elems->mesh_config,
+ elems->mesh_config_len, freq);
else
#endif
bss = ieee80211_rx_bss_add(dev, mgmt->bssid, freq,
- elems.ssid, elems.ssid_len);
+ elems->ssid, elems->ssid_len);
if (!bss)
return;
} else {
}
/* save the ERP value so that it is available at association time */
- if (elems.erp_info && elems.erp_info_len >= 1) {
- bss->erp_value = elems.erp_info[0];
+ if (elems->erp_info && elems->erp_info_len >= 1) {
+ bss->erp_value = elems->erp_info[0];
bss->has_erp_value = 1;
}
- if (elems.ht_cap_elem &&
- (!bss->ht_ie || bss->ht_ie_len != elems.ht_cap_elem_len ||
- memcmp(bss->ht_ie, elems.ht_cap_elem, elems.ht_cap_elem_len))) {
+ if (elems->ht_cap_elem &&
+ (!bss->ht_ie || bss->ht_ie_len != elems->ht_cap_elem_len ||
+ memcmp(bss->ht_ie, elems->ht_cap_elem, elems->ht_cap_elem_len))) {
kfree(bss->ht_ie);
- bss->ht_ie = kmalloc(elems.ht_cap_elem_len + 2, GFP_ATOMIC);
+ bss->ht_ie = kmalloc(elems->ht_cap_elem_len + 2, GFP_ATOMIC);
if (bss->ht_ie) {
- memcpy(bss->ht_ie, elems.ht_cap_elem - 2,
- elems.ht_cap_elem_len + 2);
- bss->ht_ie_len = elems.ht_cap_elem_len + 2;
+ memcpy(bss->ht_ie, elems->ht_cap_elem - 2,
+ elems->ht_cap_elem_len + 2);
+ bss->ht_ie_len = elems->ht_cap_elem_len + 2;
} else
bss->ht_ie_len = 0;
- } else if (!elems.ht_cap_elem && bss->ht_ie) {
+ } else if (!elems->ht_cap_elem && bss->ht_ie) {
kfree(bss->ht_ie);
bss->ht_ie = NULL;
bss->ht_ie_len = 0;
}
+ if (elems->ht_info_elem &&
+ (!bss->ht_add_ie ||
+ bss->ht_add_ie_len != elems->ht_info_elem_len ||
+ memcmp(bss->ht_add_ie, elems->ht_info_elem,
+ elems->ht_info_elem_len))) {
+ kfree(bss->ht_add_ie);
+ bss->ht_add_ie =
+ kmalloc(elems->ht_info_elem_len + 2, GFP_ATOMIC);
+ if (bss->ht_add_ie) {
+ memcpy(bss->ht_add_ie, elems->ht_info_elem - 2,
+ elems->ht_info_elem_len + 2);
+ bss->ht_add_ie_len = elems->ht_info_elem_len + 2;
+ } else
+ bss->ht_add_ie_len = 0;
+ } else if (!elems->ht_info_elem && bss->ht_add_ie) {
+ kfree(bss->ht_add_ie);
+ bss->ht_add_ie = NULL;
+ bss->ht_add_ie_len = 0;
+ }
+
bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int);
bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info);
bss->supp_rates_len = 0;
- if (elems.supp_rates) {
+ if (elems->supp_rates) {
clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len;
- if (clen > elems.supp_rates_len)
- clen = elems.supp_rates_len;
- memcpy(&bss->supp_rates[bss->supp_rates_len], elems.supp_rates,
+ if (clen > elems->supp_rates_len)
+ clen = elems->supp_rates_len;
+ memcpy(&bss->supp_rates[bss->supp_rates_len], elems->supp_rates,
clen);
bss->supp_rates_len += clen;
}
- if (elems.ext_supp_rates) {
+ if (elems->ext_supp_rates) {
clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len;
- if (clen > elems.ext_supp_rates_len)
- clen = elems.ext_supp_rates_len;
+ if (clen > elems->ext_supp_rates_len)
+ clen = elems->ext_supp_rates_len;
memcpy(&bss->supp_rates[bss->supp_rates_len],
- elems.ext_supp_rates, clen);
+ elems->ext_supp_rates, clen);
bss->supp_rates_len += clen;
}
bss->timestamp = beacon_timestamp;
bss->last_update = jiffies;
- bss->rssi = rx_status->ssi;
bss->signal = rx_status->signal;
bss->noise = rx_status->noise;
+ bss->qual = rx_status->qual;
if (!beacon && !bss->probe_resp)
bss->probe_resp = true;
return;
}
- if (elems.wpa &&
- (!bss->wpa_ie || bss->wpa_ie_len != elems.wpa_len ||
- memcmp(bss->wpa_ie, elems.wpa, elems.wpa_len))) {
+ if (elems->wpa &&
+ (!bss->wpa_ie || bss->wpa_ie_len != elems->wpa_len ||
+ memcmp(bss->wpa_ie, elems->wpa, elems->wpa_len))) {
kfree(bss->wpa_ie);
- bss->wpa_ie = kmalloc(elems.wpa_len + 2, GFP_ATOMIC);
+ bss->wpa_ie = kmalloc(elems->wpa_len + 2, GFP_ATOMIC);
if (bss->wpa_ie) {
- memcpy(bss->wpa_ie, elems.wpa - 2, elems.wpa_len + 2);
- bss->wpa_ie_len = elems.wpa_len + 2;
+ memcpy(bss->wpa_ie, elems->wpa - 2, elems->wpa_len + 2);
+ bss->wpa_ie_len = elems->wpa_len + 2;
} else
bss->wpa_ie_len = 0;
- } else if (!elems.wpa && bss->wpa_ie) {
+ } else if (!elems->wpa && bss->wpa_ie) {
kfree(bss->wpa_ie);
bss->wpa_ie = NULL;
bss->wpa_ie_len = 0;
}
- if (elems.rsn &&
- (!bss->rsn_ie || bss->rsn_ie_len != elems.rsn_len ||
- memcmp(bss->rsn_ie, elems.rsn, elems.rsn_len))) {
+ if (elems->rsn &&
+ (!bss->rsn_ie || bss->rsn_ie_len != elems->rsn_len ||
+ memcmp(bss->rsn_ie, elems->rsn, elems->rsn_len))) {
kfree(bss->rsn_ie);
- bss->rsn_ie = kmalloc(elems.rsn_len + 2, GFP_ATOMIC);
+ bss->rsn_ie = kmalloc(elems->rsn_len + 2, GFP_ATOMIC);
if (bss->rsn_ie) {
- memcpy(bss->rsn_ie, elems.rsn - 2, elems.rsn_len + 2);
- bss->rsn_ie_len = elems.rsn_len + 2;
+ memcpy(bss->rsn_ie, elems->rsn - 2, elems->rsn_len + 2);
+ bss->rsn_ie_len = elems->rsn_len + 2;
} else
bss->rsn_ie_len = 0;
- } else if (!elems.rsn && bss->rsn_ie) {
+ } else if (!elems->rsn && bss->rsn_ie) {
kfree(bss->rsn_ie);
bss->rsn_ie = NULL;
bss->rsn_ie_len = 0;
* inclusion of the WMM Parameters in beacons, however, is optional.
*/
- if (elems.wmm_param &&
- (!bss->wmm_ie || bss->wmm_ie_len != elems.wmm_param_len ||
- memcmp(bss->wmm_ie, elems.wmm_param, elems.wmm_param_len))) {
+ if (elems->wmm_param &&
+ (!bss->wmm_ie || bss->wmm_ie_len != elems->wmm_param_len ||
+ memcmp(bss->wmm_ie, elems->wmm_param, elems->wmm_param_len))) {
kfree(bss->wmm_ie);
- bss->wmm_ie = kmalloc(elems.wmm_param_len + 2, GFP_ATOMIC);
+ bss->wmm_ie = kmalloc(elems->wmm_param_len + 2, GFP_ATOMIC);
if (bss->wmm_ie) {
- memcpy(bss->wmm_ie, elems.wmm_param - 2,
- elems.wmm_param_len + 2);
- bss->wmm_ie_len = elems.wmm_param_len + 2;
+ memcpy(bss->wmm_ie, elems->wmm_param - 2,
+ elems->wmm_param_len + 2);
+ bss->wmm_ie_len = elems->wmm_param_len + 2;
} else
bss->wmm_ie_len = 0;
- } else if (elems.wmm_info &&
- (!bss->wmm_ie || bss->wmm_ie_len != elems.wmm_info_len ||
- memcmp(bss->wmm_ie, elems.wmm_info, elems.wmm_info_len))) {
+ } else if (elems->wmm_info &&
+ (!bss->wmm_ie || bss->wmm_ie_len != elems->wmm_info_len ||
+ memcmp(bss->wmm_ie, elems->wmm_info,
+ elems->wmm_info_len))) {
/* As for certain AP's Fifth bit is not set in WMM IE in
* beacon frames.So while parsing the beacon frame the
* wmm_info structure is used instead of wmm_param.
* n-band association.
*/
kfree(bss->wmm_ie);
- bss->wmm_ie = kmalloc(elems.wmm_info_len + 2, GFP_ATOMIC);
+ bss->wmm_ie = kmalloc(elems->wmm_info_len + 2, GFP_ATOMIC);
if (bss->wmm_ie) {
- memcpy(bss->wmm_ie, elems.wmm_info - 2,
- elems.wmm_info_len + 2);
- bss->wmm_ie_len = elems.wmm_info_len + 2;
+ memcpy(bss->wmm_ie, elems->wmm_info - 2,
+ elems->wmm_info_len + 2);
+ bss->wmm_ie_len = elems->wmm_info_len + 2;
} else
bss->wmm_ie_len = 0;
- } else if (!elems.wmm_param && !elems.wmm_info && bss->wmm_ie) {
+ } else if (!elems->wmm_param && !elems->wmm_info && bss->wmm_ie) {
kfree(bss->wmm_ie);
bss->wmm_ie = NULL;
bss->wmm_ie_len = 0;
!local->sta_sw_scanning && !local->sta_hw_scanning &&
bss->capability & WLAN_CAPABILITY_IBSS &&
bss->freq == local->oper_channel->center_freq &&
- elems.ssid_len == sdata->u.sta.ssid_len &&
- memcmp(elems.ssid, sdata->u.sta.ssid, sdata->u.sta.ssid_len) == 0) {
+ elems->ssid_len == sdata->u.sta.ssid_len &&
+ memcmp(elems->ssid, sdata->u.sta.ssid,
+ sdata->u.sta.ssid_len) == 0) {
if (rx_status->flag & RX_FLAG_TSFT) {
/* in order for correct IBSS merging we need mactime
*
#endif /* CONFIG_MAC80211_IBSS_DEBUG */
if (beacon_timestamp > rx_timestamp) {
#ifndef CONFIG_MAC80211_IBSS_DEBUG
- if (net_ratelimit())
+ printk(KERN_DEBUG "%s: beacon TSF higher than "
+ "local TSF - IBSS merge with BSSID %s\n",
+ dev->name, print_mac(mac, mgmt->bssid));
#endif
- printk(KERN_DEBUG "%s: beacon TSF higher than "
- "local TSF - IBSS merge with BSSID %s\n",
- dev->name, print_mac(mac, mgmt->bssid));
ieee80211_sta_join_ibss(dev, &sdata->u.sta, bss);
ieee80211_ibss_add_sta(dev, NULL,
- mgmt->bssid, mgmt->sa);
+ mgmt->bssid, mgmt->sa,
+ BIT(rx_status->rate_idx));
}
}
size_t len,
struct ieee80211_rx_status *rx_status)
{
- ieee80211_rx_bss_info(dev, mgmt, len, rx_status, 0);
+ size_t baselen;
+ struct ieee802_11_elems elems;
+
+ 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);
+
+ ieee80211_rx_bss_info(dev, mgmt, len, rx_status, &elems, 0);
}
struct ieee80211_conf *conf = &local->hw.conf;
u32 changed = 0;
- ieee80211_rx_bss_info(dev, mgmt, len, rx_status, 1);
+ /* Process beacon from the current BSS */
+ baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
+ if (baselen > len)
+ return;
+
+ ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);
+
+ ieee80211_rx_bss_info(dev, mgmt, len, rx_status, &elems, 1);
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0)
return;
- /* Process beacon from the current BSS */
- baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
- if (baselen > len)
- return;
-
- ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);
-
- if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) {
- ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param,
- elems.wmm_param_len);
- }
+ ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param,
+ elems.wmm_param_len);
/* Do not send changes to driver if we are scanning. This removes
* requirement that driver's bss_info_changed function needs to be
pos = mgmt->u.probe_req.variable;
if (pos[0] != WLAN_EID_SSID ||
pos + 2 + pos[1] > end) {
- if (net_ratelimit()) {
- printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq "
- "from %s\n",
- dev->name, print_mac(mac, mgmt->sa));
- }
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
+ printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq "
+ "from %s\n",
+ dev->name, print_mac(mac, mgmt->sa));
+#endif
return;
}
if (pos[1] != 0 &&
struct ieee80211_rx_status *rx_status)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
if (len < IEEE80211_MIN_ACTION_SIZE)
return;
switch (mgmt->u.action.category) {
+ case WLAN_CATEGORY_SPECTRUM_MGMT:
+ if (local->hw.conf.channel->band != IEEE80211_BAND_5GHZ)
+ break;
+ switch (mgmt->u.action.u.chan_switch.action_code) {
+ case WLAN_ACTION_SPCT_MSR_REQ:
+ if (len < (IEEE80211_MIN_ACTION_SIZE +
+ sizeof(mgmt->u.action.u.measurement)))
+ break;
+ ieee80211_sta_process_measurement_req(dev, mgmt, len);
+ break;
+ }
+ break;
case WLAN_CATEGORY_BACK:
switch (mgmt->u.action.u.addba_req.action_code) {
case WLAN_ACTION_ADDBA_REQ:
break;
ieee80211_sta_process_delba(dev, mgmt, len);
break;
- default:
- if (net_ratelimit())
- printk(KERN_DEBUG "%s: Rx unknown A-MPDU action\n",
- dev->name);
- break;
}
break;
case PLINK_CATEGORY:
if (ieee80211_vif_is_mesh(&sdata->vif))
mesh_rx_path_sel_frame(dev, mgmt, len);
break;
- default:
- if (net_ratelimit())
- printk(KERN_DEBUG "%s: Rx unknown action frame - "
- "category=%d\n", dev->name, mgmt->u.action.category);
- break;
}
}
skb_queue_tail(&ifsta->skb_queue, skb);
queue_work(local->hw.workqueue, &ifsta->work);
return;
- default:
- printk(KERN_DEBUG "%s: received unknown management frame - "
- "stype=%d\n", dev->name,
- (fc & IEEE80211_FCTL_STYPE) >> 4);
- break;
}
fail:
struct ieee80211_rx_status *rx_status)
{
struct ieee80211_mgmt *mgmt;
- u16 fc;
+ __le16 fc;
if (skb->len < 2)
return RX_DROP_UNUSABLE;
mgmt = (struct ieee80211_mgmt *) skb->data;
- fc = le16_to_cpu(mgmt->frame_control);
+ fc = mgmt->frame_control;
- if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL)
+ if (ieee80211_is_ctl(fc))
return RX_CONTINUE;
if (skb->len < 24)
return RX_DROP_MONITOR;
- if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
- if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP) {
- ieee80211_rx_mgmt_probe_resp(dev, mgmt,
- skb->len, rx_status);
- dev_kfree_skb(skb);
- return RX_QUEUED;
- } else if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) {
- ieee80211_rx_mgmt_beacon(dev, mgmt, skb->len,
- rx_status);
- dev_kfree_skb(skb);
- return RX_QUEUED;
- }
+ if (ieee80211_is_probe_resp(fc)) {
+ ieee80211_rx_mgmt_probe_resp(dev, mgmt, skb->len, rx_status);
+ dev_kfree_skb(skb);
+ return RX_QUEUED;
+ }
+
+ if (ieee80211_is_beacon(fc)) {
+ ieee80211_rx_mgmt_beacon(dev, mgmt, skb->len, rx_status);
+ dev_kfree_skb(skb);
+ return RX_QUEUED;
}
+
return RX_CONTINUE;
}
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",
dev->name, print_mac(mac, sta->addr));
+#endif
__sta_info_unlink(&sta);
if (sta)
list_add(&sta->list, &tmp_list);
if (local->sta_sw_scanning || local->sta_hw_scanning)
return;
- if (sdata->vif.type != IEEE80211_IF_TYPE_STA &&
- sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
- sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) {
- printk(KERN_DEBUG "%s: ieee80211_sta_work: non-STA interface "
- "(type=%d)\n", dev->name, sdata->vif.type);
+ 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)))
break;
#endif
default:
- printk(KERN_DEBUG "ieee80211_sta_work: Unknown state %d\n",
- ifsta->state);
+ WARN_ON(1);
break;
}
ifsta->auth_alg = WLAN_AUTH_LEAP;
else
ifsta->auth_alg = WLAN_AUTH_OPEN;
- printk(KERN_DEBUG "%s: Initial auth_alg=%d\n", dev->name,
- ifsta->auth_alg);
ifsta->auth_transaction = -1;
ifsta->flags &= ~IEEE80211_STA_ASSOCIATED;
ifsta->auth_tries = ifsta->assoc_tries = 0;
!ieee80211_sta_match_ssid(ifsta, bss->ssid, bss->ssid_len))
continue;
- if (!selected || top_rssi < bss->rssi) {
+ if (!selected || top_rssi < bss->signal) {
selected = bss;
- top_rssi = bss->rssi;
+ top_rssi = bss->signal;
}
}
if (selected)
sband = local->hw.wiphy->bands[bss->band];
if (local->hw.conf.beacon_int == 0)
- local->hw.conf.beacon_int = 10000;
+ local->hw.conf.beacon_int = 100;
bss->beacon_int = local->hw.conf.beacon_int;
bss->last_update = jiffies;
bss->capability = WLAN_CAPABILITY_IBSS;
- if (sdata->default_key) {
+
+ if (sdata->default_key)
bss->capability |= WLAN_CAPABILITY_PRIVACY;
- } else
+ else
sdata->drop_unencrypted = 0;
+
bss->supp_rates_len = sband->n_bitrates;
pos = bss->supp_rates;
for (i = 0; i < sband->n_bitrates; i++) {
spin_unlock_bh(&local->sta_bss_lock);
#ifdef CONFIG_MAC80211_IBSS_DEBUG
- printk(KERN_DEBUG " sta_find_ibss: selected %s current "
- "%s\n", print_mac(mac, bssid), print_mac(mac2, ifsta->bssid));
+ if (found)
+ printk(KERN_DEBUG " sta_find_ibss: selected %s current "
+ "%s\n", print_mac(mac, bssid),
+ print_mac(mac2, ifsta->bssid));
#endif /* CONFIG_MAC80211_IBSS_DEBUG */
if (found && memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0 &&
(bss = ieee80211_rx_bss_get(dev, bssid,
{
struct sk_buff *skb;
struct ieee80211_hdr *nullfunc;
- u16 fc;
+ __le16 fc;
skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24);
if (!skb) {
nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24);
memset(nullfunc, 0, 24);
- fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC |
- IEEE80211_FCTL_TODS;
+ fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC |
+ IEEE80211_FCTL_TODS);
if (powersave)
- fc |= IEEE80211_FCTL_PM;
- nullfunc->frame_control = cpu_to_le16(fc);
+ fc |= cpu_to_le16(IEEE80211_FCTL_PM);
+ nullfunc->frame_control = fc;
memcpy(nullfunc->addr1, sdata->u.sta.bssid, ETH_ALEN);
memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN);
memcpy(nullfunc->addr3, sdata->u.sta.bssid, ETH_ALEN);
static char *
ieee80211_sta_scan_result(struct net_device *dev,
+ struct iw_request_info *info,
struct ieee80211_sta_bss *bss,
char *current_ev, char *end_buf)
{
iwe.cmd = SIOCGIWAP;
iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN);
- current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
+ current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
IW_EV_ADDR_LEN);
memset(&iwe, 0, sizeof(iwe));
if (bss_mesh_cfg(bss)) {
iwe.u.data.length = bss_mesh_id_len(bss);
iwe.u.data.flags = 1;
- current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
- bss_mesh_id(bss));
+ current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+ &iwe, bss_mesh_id(bss));
} else {
iwe.u.data.length = bss->ssid_len;
iwe.u.data.flags = 1;
- current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
- bss->ssid);
+ current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+ &iwe, bss->ssid);
}
if (bss->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)
iwe.u.mode = IW_MODE_MASTER;
else
iwe.u.mode = IW_MODE_ADHOC;
- current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
- IW_EV_UINT_LEN);
+ current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+ &iwe, IW_EV_UINT_LEN);
}
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = SIOCGIWFREQ;
iwe.u.freq.m = ieee80211_frequency_to_channel(bss->freq);
iwe.u.freq.e = 0;
- current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
+ current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
IW_EV_FREQ_LEN);
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = SIOCGIWFREQ;
iwe.u.freq.m = bss->freq;
iwe.u.freq.e = 6;
- current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
+ current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
IW_EV_FREQ_LEN);
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = IWEVQUAL;
- iwe.u.qual.qual = bss->signal;
- iwe.u.qual.level = bss->rssi;
+ iwe.u.qual.qual = bss->qual;
+ iwe.u.qual.level = bss->signal;
iwe.u.qual.noise = bss->noise;
iwe.u.qual.updated = local->wstats_flags;
- current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
+ current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
IW_EV_QUAL_LEN);
memset(&iwe, 0, sizeof(iwe));
else
iwe.u.data.flags = IW_ENCODE_DISABLED;
iwe.u.data.length = 0;
- current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, "");
+ current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+ &iwe, "");
if (bss && bss->wpa_ie) {
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = IWEVGENIE;
iwe.u.data.length = bss->wpa_ie_len;
- current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
- bss->wpa_ie);
+ current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+ &iwe, bss->wpa_ie);
}
if (bss && bss->rsn_ie) {
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = IWEVGENIE;
iwe.u.data.length = bss->rsn_ie_len;
- current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
- bss->rsn_ie);
+ current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+ &iwe, bss->rsn_ie);
+ }
+
+ if (bss && bss->ht_ie) {
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = IWEVGENIE;
+ iwe.u.data.length = bss->ht_ie_len;
+ current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+ &iwe, bss->ht_ie);
}
if (bss && bss->supp_rates_len > 0) {
/* display all supported rates in readable format */
- char *p = current_ev + IW_EV_LCP_LEN;
+ char *p = current_ev + iwe_stream_lcp_len(info);
int i;
memset(&iwe, 0, sizeof(iwe));
for (i = 0; i < bss->supp_rates_len; i++) {
iwe.u.bitrate.value = ((bss->supp_rates[i] &
0x7f) * 500000);
- p = iwe_stream_add_value(current_ev, p,
+ p = iwe_stream_add_value(info, current_ev, p,
end_buf, &iwe, IW_EV_PARAM_LEN);
}
current_ev = p;
iwe.cmd = IWEVCUSTOM;
sprintf(buf, "tsf=%016llx", (unsigned long long)(bss->timestamp));
iwe.u.data.length = strlen(buf);
- current_ev = iwe_stream_add_point(current_ev, end_buf,
+ current_ev = iwe_stream_add_point(info, current_ev,
+ end_buf,
&iwe, buf);
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = IWEVCUSTOM;
+ sprintf(buf, " Last beacon: %dms ago",
+ jiffies_to_msecs(jiffies - bss->last_update));
+ iwe.u.data.length = strlen(buf);
+ current_ev = iwe_stream_add_point(info, current_ev,
+ end_buf, &iwe, buf);
kfree(buf);
}
}
iwe.cmd = IWEVCUSTOM;
sprintf(buf, "Mesh network (version %d)", cfg[0]);
iwe.u.data.length = strlen(buf);
- current_ev = iwe_stream_add_point(current_ev, end_buf,
+ current_ev = iwe_stream_add_point(info, current_ev,
+ end_buf,
&iwe, buf);
sprintf(buf, "Path Selection Protocol ID: "
"0x%02X%02X%02X%02X", cfg[1], cfg[2], cfg[3],
cfg[4]);
iwe.u.data.length = strlen(buf);
- current_ev = iwe_stream_add_point(current_ev, end_buf,
+ current_ev = iwe_stream_add_point(info, current_ev,
+ end_buf,
&iwe, buf);
sprintf(buf, "Path Selection Metric ID: "
"0x%02X%02X%02X%02X", cfg[5], cfg[6], cfg[7],
cfg[8]);
iwe.u.data.length = strlen(buf);
- current_ev = iwe_stream_add_point(current_ev, end_buf,
+ current_ev = iwe_stream_add_point(info, current_ev,
+ end_buf,
&iwe, buf);
sprintf(buf, "Congestion Control Mode ID: "
"0x%02X%02X%02X%02X", cfg[9], cfg[10],
cfg[11], cfg[12]);
iwe.u.data.length = strlen(buf);
- current_ev = iwe_stream_add_point(current_ev, end_buf,
+ current_ev = iwe_stream_add_point(info, current_ev,
+ end_buf,
&iwe, buf);
sprintf(buf, "Channel Precedence: "
"0x%02X%02X%02X%02X", cfg[13], cfg[14],
cfg[15], cfg[16]);
iwe.u.data.length = strlen(buf);
- current_ev = iwe_stream_add_point(current_ev, end_buf,
+ current_ev = iwe_stream_add_point(info, current_ev,
+ end_buf,
&iwe, buf);
kfree(buf);
}
}
-int ieee80211_sta_scan_results(struct net_device *dev, char *buf, size_t len)
+int ieee80211_sta_scan_results(struct net_device *dev,
+ struct iw_request_info *info,
+ char *buf, size_t len)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
char *current_ev = buf;
spin_unlock_bh(&local->sta_bss_lock);
return -E2BIG;
}
- current_ev = ieee80211_sta_scan_result(dev, bss, current_ev,
- end_buf);
+ current_ev = ieee80211_sta_scan_result(dev, info, bss,
+ current_ev, end_buf);
}
spin_unlock_bh(&local->sta_bss_lock);
return current_ev - buf;
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+
kfree(ifsta->extra_ie);
if (len == 0) {
ifsta->extra_ie = NULL;
}
-struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev,
- struct sk_buff *skb, u8 *bssid,
- u8 *addr)
+struct sta_info *ieee80211_ibss_add_sta(struct net_device *dev,
+ struct sk_buff *skb, u8 *bssid,
+ u8 *addr, u64 supp_rates)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct sta_info *sta;
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
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. */
return NULL;
}
+ if (!ieee80211_bssid_match(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), dev->name);
+#endif
sta = sta_info_alloc(sdata, addr, GFP_ATOMIC);
if (!sta)
return NULL;
- sta->flags |= WLAN_STA_AUTHORIZED;
+ set_sta_flags(sta, WLAN_STA_AUTHORIZED);
- sta->supp_rates[local->hw.conf.channel->band] =
- sdata->u.sta.supp_rates_bits[local->hw.conf.channel->band];
+ if (supp_rates)
+ sta->supp_rates[band] = supp_rates;
+ else
+ sta->supp_rates[band] = sdata->u.sta.supp_rates_bits[band];
rate_control_rate_init(sta, local);
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_if_sta *ifsta = &sdata->u.sta;
- printk(KERN_DEBUG "%s: deauthenticate(reason=%d)\n",
+ printk(KERN_DEBUG "%s: deauthenticating by local choice (reason=%d)\n",
dev->name, reason);
if (sdata->vif.type != IEEE80211_IF_TYPE_STA &&
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_if_sta *ifsta = &sdata->u.sta;
- printk(KERN_DEBUG "%s: disassociate(reason=%d)\n",
+ printk(KERN_DEBUG "%s: disassociating by local choice (reason=%d)\n",
dev->name, reason);
if (sdata->vif.type != IEEE80211_IF_TYPE_STA)