diff options
51 files changed, 3855 insertions, 3328 deletions
diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 245b7308a9ad..57d7cc87cb0f 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c | |||
@@ -224,7 +224,7 @@ static void setup_ht_cap(struct ieee80211_ht_info *ht_info) | |||
224 | 224 | ||
225 | ht_info->ht_supported = 1; | 225 | ht_info->ht_supported = 1; |
226 | ht_info->cap = (u16)IEEE80211_HT_CAP_SUP_WIDTH | 226 | ht_info->cap = (u16)IEEE80211_HT_CAP_SUP_WIDTH |
227 | |(u16)IEEE80211_HT_CAP_MIMO_PS | 227 | |(u16)IEEE80211_HT_CAP_SM_PS |
228 | |(u16)IEEE80211_HT_CAP_SGI_40 | 228 | |(u16)IEEE80211_HT_CAP_SGI_40 |
229 | |(u16)IEEE80211_HT_CAP_DSSSCCK40; | 229 | |(u16)IEEE80211_HT_CAP_DSSSCCK40; |
230 | 230 | ||
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index f9c8161671d9..07d2825458ab 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h | |||
@@ -585,8 +585,6 @@ enum { | |||
585 | struct b43_qos_params { | 585 | struct b43_qos_params { |
586 | /* The QOS parameters */ | 586 | /* The QOS parameters */ |
587 | struct ieee80211_tx_queue_params p; | 587 | struct ieee80211_tx_queue_params p; |
588 | /* Does this need to get uploaded to hardware? */ | ||
589 | bool need_hw_update; | ||
590 | }; | 588 | }; |
591 | 589 | ||
592 | struct b43_wldev; | 590 | struct b43_wldev; |
@@ -648,11 +646,8 @@ struct b43_wl { | |||
648 | bool beacon_templates_virgin; /* Never wrote the templates? */ | 646 | bool beacon_templates_virgin; /* Never wrote the templates? */ |
649 | struct work_struct beacon_update_trigger; | 647 | struct work_struct beacon_update_trigger; |
650 | 648 | ||
651 | /* The current QOS parameters for the 4 queues. | 649 | /* The current QOS parameters for the 4 queues. */ |
652 | * This is protected by the irq_lock. */ | ||
653 | struct b43_qos_params qos_params[4]; | 650 | struct b43_qos_params qos_params[4]; |
654 | /* Workqueue for updating QOS parameters in hardware. */ | ||
655 | struct work_struct qos_update_work; | ||
656 | 651 | ||
657 | /* Work for adjustment of the transmission power. | 652 | /* Work for adjustment of the transmission power. |
658 | * This is scheduled when we determine that the actual TX output | 653 | * This is scheduled when we determine that the actual TX output |
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index c836beceb10d..d4a356b11636 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c | |||
@@ -3059,36 +3059,31 @@ static void b43_qos_params_upload(struct b43_wldev *dev, | |||
3059 | } | 3059 | } |
3060 | } | 3060 | } |
3061 | 3061 | ||
3062 | /* Update the QOS parameters in hardware. */ | 3062 | /* Mapping of mac80211 queue numbers to b43 QoS SHM offsets. */ |
3063 | static void b43_qos_update(struct b43_wldev *dev) | 3063 | static const u16 b43_qos_shm_offsets[] = { |
3064 | /* [mac80211-queue-nr] = SHM_OFFSET, */ | ||
3065 | [0] = B43_QOS_VOICE, | ||
3066 | [1] = B43_QOS_VIDEO, | ||
3067 | [2] = B43_QOS_BESTEFFORT, | ||
3068 | [3] = B43_QOS_BACKGROUND, | ||
3069 | }; | ||
3070 | |||
3071 | /* Update all QOS parameters in hardware. */ | ||
3072 | static void b43_qos_upload_all(struct b43_wldev *dev) | ||
3064 | { | 3073 | { |
3065 | struct b43_wl *wl = dev->wl; | 3074 | struct b43_wl *wl = dev->wl; |
3066 | struct b43_qos_params *params; | 3075 | struct b43_qos_params *params; |
3067 | unsigned long flags; | ||
3068 | unsigned int i; | 3076 | unsigned int i; |
3069 | 3077 | ||
3070 | /* Mapping of mac80211 queues to b43 SHM offsets. */ | 3078 | BUILD_BUG_ON(ARRAY_SIZE(b43_qos_shm_offsets) != |
3071 | static const u16 qos_shm_offsets[] = { | 3079 | ARRAY_SIZE(wl->qos_params)); |
3072 | [0] = B43_QOS_VOICE, | ||
3073 | [1] = B43_QOS_VIDEO, | ||
3074 | [2] = B43_QOS_BESTEFFORT, | ||
3075 | [3] = B43_QOS_BACKGROUND, | ||
3076 | }; | ||
3077 | BUILD_BUG_ON(ARRAY_SIZE(qos_shm_offsets) != ARRAY_SIZE(wl->qos_params)); | ||
3078 | 3080 | ||
3079 | b43_mac_suspend(dev); | 3081 | b43_mac_suspend(dev); |
3080 | spin_lock_irqsave(&wl->irq_lock, flags); | ||
3081 | |||
3082 | for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++) { | 3082 | for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++) { |
3083 | params = &(wl->qos_params[i]); | 3083 | params = &(wl->qos_params[i]); |
3084 | if (params->need_hw_update) { | 3084 | b43_qos_params_upload(dev, &(params->p), |
3085 | b43_qos_params_upload(dev, &(params->p), | 3085 | b43_qos_shm_offsets[i]); |
3086 | qos_shm_offsets[i]); | ||
3087 | params->need_hw_update = 0; | ||
3088 | } | ||
3089 | } | 3086 | } |
3090 | |||
3091 | spin_unlock_irqrestore(&wl->irq_lock, flags); | ||
3092 | b43_mac_enable(dev); | 3087 | b43_mac_enable(dev); |
3093 | } | 3088 | } |
3094 | 3089 | ||
@@ -3097,25 +3092,50 @@ static void b43_qos_clear(struct b43_wl *wl) | |||
3097 | struct b43_qos_params *params; | 3092 | struct b43_qos_params *params; |
3098 | unsigned int i; | 3093 | unsigned int i; |
3099 | 3094 | ||
3095 | /* Initialize QoS parameters to sane defaults. */ | ||
3096 | |||
3097 | BUILD_BUG_ON(ARRAY_SIZE(b43_qos_shm_offsets) != | ||
3098 | ARRAY_SIZE(wl->qos_params)); | ||
3099 | |||
3100 | for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++) { | 3100 | for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++) { |
3101 | params = &(wl->qos_params[i]); | 3101 | params = &(wl->qos_params[i]); |
3102 | 3102 | ||
3103 | memset(&(params->p), 0, sizeof(params->p)); | 3103 | switch (b43_qos_shm_offsets[i]) { |
3104 | params->p.aifs = -1; | 3104 | case B43_QOS_VOICE: |
3105 | params->need_hw_update = 1; | 3105 | params->p.txop = 0; |
3106 | params->p.aifs = 2; | ||
3107 | params->p.cw_min = 0x0001; | ||
3108 | params->p.cw_max = 0x0001; | ||
3109 | break; | ||
3110 | case B43_QOS_VIDEO: | ||
3111 | params->p.txop = 0; | ||
3112 | params->p.aifs = 2; | ||
3113 | params->p.cw_min = 0x0001; | ||
3114 | params->p.cw_max = 0x0001; | ||
3115 | break; | ||
3116 | case B43_QOS_BESTEFFORT: | ||
3117 | params->p.txop = 0; | ||
3118 | params->p.aifs = 3; | ||
3119 | params->p.cw_min = 0x0001; | ||
3120 | params->p.cw_max = 0x03FF; | ||
3121 | break; | ||
3122 | case B43_QOS_BACKGROUND: | ||
3123 | params->p.txop = 0; | ||
3124 | params->p.aifs = 7; | ||
3125 | params->p.cw_min = 0x0001; | ||
3126 | params->p.cw_max = 0x03FF; | ||
3127 | break; | ||
3128 | default: | ||
3129 | B43_WARN_ON(1); | ||
3130 | } | ||
3106 | } | 3131 | } |
3107 | } | 3132 | } |
3108 | 3133 | ||
3109 | /* Initialize the core's QOS capabilities */ | 3134 | /* Initialize the core's QOS capabilities */ |
3110 | static void b43_qos_init(struct b43_wldev *dev) | 3135 | static void b43_qos_init(struct b43_wldev *dev) |
3111 | { | 3136 | { |
3112 | struct b43_wl *wl = dev->wl; | ||
3113 | unsigned int i; | ||
3114 | |||
3115 | /* Upload the current QOS parameters. */ | 3137 | /* Upload the current QOS parameters. */ |
3116 | for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++) | 3138 | b43_qos_upload_all(dev); |
3117 | wl->qos_params[i].need_hw_update = 1; | ||
3118 | b43_qos_update(dev); | ||
3119 | 3139 | ||
3120 | /* Enable QOS support. */ | 3140 | /* Enable QOS support. */ |
3121 | b43_hf_write(dev, b43_hf_read(dev) | B43_HF_EDCF); | 3141 | b43_hf_write(dev, b43_hf_read(dev) | B43_HF_EDCF); |
@@ -3124,25 +3144,13 @@ static void b43_qos_init(struct b43_wldev *dev) | |||
3124 | | B43_MMIO_IFSCTL_USE_EDCF); | 3144 | | B43_MMIO_IFSCTL_USE_EDCF); |
3125 | } | 3145 | } |
3126 | 3146 | ||
3127 | static void b43_qos_update_work(struct work_struct *work) | ||
3128 | { | ||
3129 | struct b43_wl *wl = container_of(work, struct b43_wl, qos_update_work); | ||
3130 | struct b43_wldev *dev; | ||
3131 | |||
3132 | mutex_lock(&wl->mutex); | ||
3133 | dev = wl->current_dev; | ||
3134 | if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED))) | ||
3135 | b43_qos_update(dev); | ||
3136 | mutex_unlock(&wl->mutex); | ||
3137 | } | ||
3138 | |||
3139 | static int b43_op_conf_tx(struct ieee80211_hw *hw, u16 _queue, | 3147 | static int b43_op_conf_tx(struct ieee80211_hw *hw, u16 _queue, |
3140 | const struct ieee80211_tx_queue_params *params) | 3148 | const struct ieee80211_tx_queue_params *params) |
3141 | { | 3149 | { |
3142 | struct b43_wl *wl = hw_to_b43_wl(hw); | 3150 | struct b43_wl *wl = hw_to_b43_wl(hw); |
3143 | unsigned long flags; | 3151 | struct b43_wldev *dev; |
3144 | unsigned int queue = (unsigned int)_queue; | 3152 | unsigned int queue = (unsigned int)_queue; |
3145 | struct b43_qos_params *p; | 3153 | int err = -ENODEV; |
3146 | 3154 | ||
3147 | if (queue >= ARRAY_SIZE(wl->qos_params)) { | 3155 | if (queue >= ARRAY_SIZE(wl->qos_params)) { |
3148 | /* Queue not available or don't support setting | 3156 | /* Queue not available or don't support setting |
@@ -3150,16 +3158,25 @@ static int b43_op_conf_tx(struct ieee80211_hw *hw, u16 _queue, | |||
3150 | * confuse mac80211. */ | 3158 | * confuse mac80211. */ |
3151 | return 0; | 3159 | return 0; |
3152 | } | 3160 | } |
3161 | BUILD_BUG_ON(ARRAY_SIZE(b43_qos_shm_offsets) != | ||
3162 | ARRAY_SIZE(wl->qos_params)); | ||
3153 | 3163 | ||
3154 | spin_lock_irqsave(&wl->irq_lock, flags); | 3164 | mutex_lock(&wl->mutex); |
3155 | p = &(wl->qos_params[queue]); | 3165 | dev = wl->current_dev; |
3156 | memcpy(&(p->p), params, sizeof(p->p)); | 3166 | if (unlikely(!dev || (b43_status(dev) < B43_STAT_INITIALIZED))) |
3157 | p->need_hw_update = 1; | 3167 | goto out_unlock; |
3158 | spin_unlock_irqrestore(&wl->irq_lock, flags); | ||
3159 | 3168 | ||
3160 | queue_work(hw->workqueue, &wl->qos_update_work); | 3169 | memcpy(&(wl->qos_params[queue].p), params, sizeof(*params)); |
3170 | b43_mac_suspend(dev); | ||
3171 | b43_qos_params_upload(dev, &(wl->qos_params[queue].p), | ||
3172 | b43_qos_shm_offsets[queue]); | ||
3173 | b43_mac_enable(dev); | ||
3174 | err = 0; | ||
3161 | 3175 | ||
3162 | return 0; | 3176 | out_unlock: |
3177 | mutex_unlock(&wl->mutex); | ||
3178 | |||
3179 | return err; | ||
3163 | } | 3180 | } |
3164 | 3181 | ||
3165 | static int b43_op_get_tx_stats(struct ieee80211_hw *hw, | 3182 | static int b43_op_get_tx_stats(struct ieee80211_hw *hw, |
@@ -4186,7 +4203,6 @@ static void b43_op_stop(struct ieee80211_hw *hw) | |||
4186 | struct b43_wldev *dev = wl->current_dev; | 4203 | struct b43_wldev *dev = wl->current_dev; |
4187 | 4204 | ||
4188 | b43_rfkill_exit(dev); | 4205 | b43_rfkill_exit(dev); |
4189 | cancel_work_sync(&(wl->qos_update_work)); | ||
4190 | cancel_work_sync(&(wl->beacon_update_trigger)); | 4206 | cancel_work_sync(&(wl->beacon_update_trigger)); |
4191 | 4207 | ||
4192 | mutex_lock(&wl->mutex); | 4208 | mutex_lock(&wl->mutex); |
@@ -4585,7 +4601,6 @@ static int b43_wireless_init(struct ssb_device *dev) | |||
4585 | spin_lock_init(&wl->shm_lock); | 4601 | spin_lock_init(&wl->shm_lock); |
4586 | mutex_init(&wl->mutex); | 4602 | mutex_init(&wl->mutex); |
4587 | INIT_LIST_HEAD(&wl->devlist); | 4603 | INIT_LIST_HEAD(&wl->devlist); |
4588 | INIT_WORK(&wl->qos_update_work, b43_qos_update_work); | ||
4589 | INIT_WORK(&wl->beacon_update_trigger, b43_beacon_update_trigger_work); | 4604 | INIT_WORK(&wl->beacon_update_trigger, b43_beacon_update_trigger_work); |
4590 | INIT_WORK(&wl->txpower_adjust_work, b43_phy_txpower_adjust_work); | 4605 | INIT_WORK(&wl->txpower_adjust_work, b43_phy_txpower_adjust_work); |
4591 | 4606 | ||
diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c index e8c012c9abb0..232181f6333c 100644 --- a/drivers/net/wireless/b43/phy_g.c +++ b/drivers/net/wireless/b43/phy_g.c | |||
@@ -386,7 +386,6 @@ static void b43_set_original_gains(struct b43_wldev *dev) | |||
386 | void b43_nrssi_hw_write(struct b43_wldev *dev, u16 offset, s16 val) | 386 | void b43_nrssi_hw_write(struct b43_wldev *dev, u16 offset, s16 val) |
387 | { | 387 | { |
388 | b43_phy_write(dev, B43_PHY_NRSSILT_CTRL, offset); | 388 | b43_phy_write(dev, B43_PHY_NRSSILT_CTRL, offset); |
389 | mmiowb(); | ||
390 | b43_phy_write(dev, B43_PHY_NRSSILT_DATA, (u16) val); | 389 | b43_phy_write(dev, B43_PHY_NRSSILT_DATA, (u16) val); |
391 | } | 390 | } |
392 | 391 | ||
diff --git a/drivers/net/wireless/b43legacy/phy.c b/drivers/net/wireless/b43legacy/phy.c index 768cccb9b1ba..bed67a54250c 100644 --- a/drivers/net/wireless/b43legacy/phy.c +++ b/drivers/net/wireless/b43legacy/phy.c | |||
@@ -595,12 +595,14 @@ static void b43legacy_phy_initb5(struct b43legacy_wldev *dev) | |||
595 | 0x0035) & 0xFFC0) | 0x0064); | 595 | 0x0035) & 0xFFC0) | 0x0064); |
596 | b43legacy_phy_write(dev, 0x005D, (b43legacy_phy_read(dev, | 596 | b43legacy_phy_write(dev, 0x005D, (b43legacy_phy_read(dev, |
597 | 0x005D) & 0xFF80) | 0x000A); | 597 | 0x005D) & 0xFF80) | 0x000A); |
598 | b43legacy_phy_write(dev, 0x5B, 0x0000); | ||
599 | b43legacy_phy_write(dev, 0x5C, 0x0000); | ||
598 | } | 600 | } |
599 | 601 | ||
600 | if (dev->bad_frames_preempt) | 602 | if (dev->bad_frames_preempt) |
601 | b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD, | 603 | b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD, |
602 | b43legacy_phy_read(dev, | 604 | b43legacy_phy_read(dev, |
603 | B43legacy_PHY_RADIO_BITFIELD) | (1 << 11)); | 605 | B43legacy_PHY_RADIO_BITFIELD) | (1 << 12)); |
604 | 606 | ||
605 | if (phy->analog == 1) { | 607 | if (phy->analog == 1) { |
606 | b43legacy_phy_write(dev, 0x0026, 0xCE00); | 608 | b43legacy_phy_write(dev, 0x0026, 0xCE00); |
@@ -753,7 +755,7 @@ static void b43legacy_phy_initb6(struct b43legacy_wldev *dev) | |||
753 | b43legacy_radio_write16(dev, 0x0050, 0x0020); | 755 | b43legacy_radio_write16(dev, 0x0050, 0x0020); |
754 | } | 756 | } |
755 | if (phy->radio_rev <= 2) { | 757 | if (phy->radio_rev <= 2) { |
756 | b43legacy_radio_write16(dev, 0x007C, 0x0020); | 758 | b43legacy_radio_write16(dev, 0x0050, 0x0020); |
757 | b43legacy_radio_write16(dev, 0x005A, 0x0070); | 759 | b43legacy_radio_write16(dev, 0x005A, 0x0070); |
758 | b43legacy_radio_write16(dev, 0x005B, 0x007B); | 760 | b43legacy_radio_write16(dev, 0x005B, 0x007B); |
759 | b43legacy_radio_write16(dev, 0x005C, 0x00B0); | 761 | b43legacy_radio_write16(dev, 0x005C, 0x00B0); |
@@ -771,7 +773,7 @@ static void b43legacy_phy_initb6(struct b43legacy_wldev *dev) | |||
771 | b43legacy_phy_write(dev, 0x002A, 0x8AC0); | 773 | b43legacy_phy_write(dev, 0x002A, 0x8AC0); |
772 | b43legacy_phy_write(dev, 0x0038, 0x0668); | 774 | b43legacy_phy_write(dev, 0x0038, 0x0668); |
773 | b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF); | 775 | b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF); |
774 | if (phy->radio_rev <= 5) | 776 | if (phy->radio_rev == 4 || phy->radio_rev == 5) |
775 | b43legacy_phy_write(dev, 0x005D, (b43legacy_phy_read(dev, | 777 | b43legacy_phy_write(dev, 0x005D, (b43legacy_phy_read(dev, |
776 | 0x005D) & 0xFF80) | 0x0003); | 778 | 0x005D) & 0xFF80) | 0x0003); |
777 | if (phy->radio_rev <= 2) | 779 | if (phy->radio_rev <= 2) |
@@ -1010,7 +1012,7 @@ static void b43legacy_phy_initg(struct b43legacy_wldev *dev) | |||
1010 | b43legacy_phy_initb5(dev); | 1012 | b43legacy_phy_initb5(dev); |
1011 | else | 1013 | else |
1012 | b43legacy_phy_initb6(dev); | 1014 | b43legacy_phy_initb6(dev); |
1013 | if (phy->rev >= 2 || phy->gmode) | 1015 | if (phy->rev >= 2 && phy->gmode) |
1014 | b43legacy_phy_inita(dev); | 1016 | b43legacy_phy_inita(dev); |
1015 | 1017 | ||
1016 | if (phy->rev >= 2) { | 1018 | if (phy->rev >= 2) { |
@@ -1025,18 +1027,22 @@ static void b43legacy_phy_initg(struct b43legacy_wldev *dev) | |||
1025 | b43legacy_phy_write(dev, 0x0811, 0x0400); | 1027 | b43legacy_phy_write(dev, 0x0811, 0x0400); |
1026 | b43legacy_phy_write(dev, 0x0015, 0x00C0); | 1028 | b43legacy_phy_write(dev, 0x0015, 0x00C0); |
1027 | } | 1029 | } |
1028 | if (phy->rev >= 2 || phy->gmode) { | 1030 | if (phy->gmode) { |
1029 | tmp = b43legacy_phy_read(dev, 0x0400) & 0xFF; | 1031 | tmp = b43legacy_phy_read(dev, 0x0400) & 0xFF; |
1030 | if (tmp == 3 || tmp == 5) { | 1032 | if (tmp == 3) { |
1033 | b43legacy_phy_write(dev, 0x04C2, 0x1816); | ||
1034 | b43legacy_phy_write(dev, 0x04C3, 0x8606); | ||
1035 | } | ||
1036 | if (tmp == 4 || tmp == 5) { | ||
1031 | b43legacy_phy_write(dev, 0x04C2, 0x1816); | 1037 | b43legacy_phy_write(dev, 0x04C2, 0x1816); |
1032 | b43legacy_phy_write(dev, 0x04C3, 0x8006); | 1038 | b43legacy_phy_write(dev, 0x04C3, 0x8006); |
1033 | if (tmp == 5) | 1039 | b43legacy_phy_write(dev, 0x04CC, |
1034 | b43legacy_phy_write(dev, 0x04CC, | 1040 | (b43legacy_phy_read(dev, |
1035 | (b43legacy_phy_read(dev, | 1041 | 0x04CC) & 0x00FF) | |
1036 | 0x04CC) & 0x00FF) | | 1042 | 0x1F00); |
1037 | 0x1F00); | ||
1038 | } | 1043 | } |
1039 | b43legacy_phy_write(dev, 0x047E, 0x0078); | 1044 | if (phy->rev >= 2) |
1045 | b43legacy_phy_write(dev, 0x047E, 0x0078); | ||
1040 | } | 1046 | } |
1041 | if (phy->radio_rev == 8) { | 1047 | if (phy->radio_rev == 8) { |
1042 | b43legacy_phy_write(dev, 0x0801, b43legacy_phy_read(dev, 0x0801) | 1048 | b43legacy_phy_write(dev, 0x0801, b43legacy_phy_read(dev, 0x0801) |
@@ -1078,7 +1084,7 @@ static void b43legacy_phy_initg(struct b43legacy_wldev *dev) | |||
1078 | else | 1084 | else |
1079 | b43legacy_phy_write(dev, 0x002F, 0x0202); | 1085 | b43legacy_phy_write(dev, 0x002F, 0x0202); |
1080 | } | 1086 | } |
1081 | if (phy->gmode || phy->rev >= 2) { | 1087 | if (phy->gmode) { |
1082 | b43legacy_phy_lo_adjust(dev, 0); | 1088 | b43legacy_phy_lo_adjust(dev, 0); |
1083 | b43legacy_phy_write(dev, 0x080F, 0x8078); | 1089 | b43legacy_phy_write(dev, 0x080F, 0x8078); |
1084 | } | 1090 | } |
diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c index c5ca72aa59e7..6835064758fb 100644 --- a/drivers/net/wireless/b43legacy/xmit.c +++ b/drivers/net/wireless/b43legacy/xmit.c | |||
@@ -624,7 +624,7 @@ void b43legacy_handle_hwtxstatus(struct b43legacy_wldev *dev, | |||
624 | tmp = hw->count; | 624 | tmp = hw->count; |
625 | status.frame_count = (tmp >> 4); | 625 | status.frame_count = (tmp >> 4); |
626 | status.rts_count = (tmp & 0x0F); | 626 | status.rts_count = (tmp & 0x0F); |
627 | tmp = hw->flags; | 627 | tmp = hw->flags << 1; |
628 | status.supp_reason = ((tmp & 0x1C) >> 2); | 628 | status.supp_reason = ((tmp & 0x1C) >> 2); |
629 | status.pm_indicated = !!(tmp & 0x80); | 629 | status.pm_indicated = !!(tmp & 0x80); |
630 | status.intermediate = !!(tmp & 0x40); | 630 | status.intermediate = !!(tmp & 0x40); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 1377c8190ecb..3d100e898249 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c | |||
@@ -681,19 +681,7 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, | |||
681 | priv->last_rx_noise = rx_status.noise; | 681 | priv->last_rx_noise = rx_status.noise; |
682 | } | 682 | } |
683 | 683 | ||
684 | if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) { | 684 | iwl3945_pass_packet_to_mac80211(priv, rxb, &rx_status); |
685 | iwl3945_pass_packet_to_mac80211(priv, rxb, &rx_status); | ||
686 | return; | ||
687 | } | ||
688 | |||
689 | switch (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FTYPE) { | ||
690 | case IEEE80211_FTYPE_MGMT: | ||
691 | case IEEE80211_FTYPE_DATA: | ||
692 | /* fall through */ | ||
693 | default: | ||
694 | iwl3945_pass_packet_to_mac80211(priv, rxb, &rx_status); | ||
695 | break; | ||
696 | } | ||
697 | } | 685 | } |
698 | 686 | ||
699 | int iwl3945_hw_txq_attach_buf_to_tfd(struct iwl3945_priv *priv, void *ptr, | 687 | int iwl3945_hw_txq_attach_buf_to_tfd(struct iwl3945_priv *priv, void *ptr, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index d9c4fdbf7f77..9838de5f4369 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c | |||
@@ -1607,8 +1607,8 @@ static int iwl4965_send_rxon_assoc(struct iwl_priv *priv) | |||
1607 | return ret; | 1607 | return ret; |
1608 | } | 1608 | } |
1609 | 1609 | ||
1610 | 1610 | #ifdef IEEE80211_CONF_CHANNEL_SWITCH | |
1611 | int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) | 1611 | static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) |
1612 | { | 1612 | { |
1613 | int rc; | 1613 | int rc; |
1614 | u8 band = 0; | 1614 | u8 band = 0; |
@@ -1648,6 +1648,7 @@ int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) | |||
1648 | rc = iwl_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd); | 1648 | rc = iwl_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd); |
1649 | return rc; | 1649 | return rc; |
1650 | } | 1650 | } |
1651 | #endif | ||
1651 | 1652 | ||
1652 | static int iwl4965_shared_mem_rx_idx(struct iwl_priv *priv) | 1653 | static int iwl4965_shared_mem_rx_idx(struct iwl_priv *priv) |
1653 | { | 1654 | { |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 98f2c843b99e..c293e5b6cbb5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c | |||
@@ -436,7 +436,7 @@ static int rs_collect_tx_data(struct iwl_rate_scale_data *windows, | |||
436 | /* Shift bitmap by one frame (throw away oldest history), | 436 | /* Shift bitmap by one frame (throw away oldest history), |
437 | * OR in "1", and increment "success" if this | 437 | * OR in "1", and increment "success" if this |
438 | * frame was successful. */ | 438 | * frame was successful. */ |
439 | window->data <<= 1;; | 439 | window->data <<= 1; |
440 | if (successes > 0) { | 440 | if (successes > 0) { |
441 | window->success_counter++; | 441 | window->success_counter++; |
442 | window->data |= 0x1; | 442 | window->data |= 0x1; |
@@ -1128,6 +1128,7 @@ static s32 rs_get_best_rate(struct iwl_priv *priv, | |||
1128 | 1128 | ||
1129 | /* Higher rate not available, use the original */ | 1129 | /* Higher rate not available, use the original */ |
1130 | } else { | 1130 | } else { |
1131 | new_rate = rate; | ||
1131 | break; | 1132 | break; |
1132 | } | 1133 | } |
1133 | } | 1134 | } |
@@ -1153,8 +1154,8 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, | |||
1153 | !sta->ht_info.ht_supported) | 1154 | !sta->ht_info.ht_supported) |
1154 | return -1; | 1155 | return -1; |
1155 | 1156 | ||
1156 | if (((sta->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS) >> 2) | 1157 | if (((sta->ht_info.cap & IEEE80211_HT_CAP_SM_PS) >> 2) |
1157 | == IWL_MIMO_PS_STATIC) | 1158 | == WLAN_HT_CAP_SM_PS_STATIC) |
1158 | return -1; | 1159 | return -1; |
1159 | 1160 | ||
1160 | /* Need both Tx chains/antennas to support MIMO */ | 1161 | /* Need both Tx chains/antennas to support MIMO */ |
@@ -1281,15 +1282,23 @@ static int rs_move_legacy_other(struct iwl_priv *priv, | |||
1281 | (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); | 1282 | (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); |
1282 | u8 start_action = tbl->action; | 1283 | u8 start_action = tbl->action; |
1283 | u8 valid_tx_ant = priv->hw_params.valid_tx_ant; | 1284 | u8 valid_tx_ant = priv->hw_params.valid_tx_ant; |
1285 | u8 tx_chains_num = priv->hw_params.tx_chains_num; | ||
1284 | int ret = 0; | 1286 | int ret = 0; |
1285 | 1287 | ||
1286 | for (; ;) { | 1288 | for (; ;) { |
1287 | switch (tbl->action) { | 1289 | switch (tbl->action) { |
1288 | case IWL_LEGACY_SWITCH_ANTENNA: | 1290 | case IWL_LEGACY_SWITCH_ANTENNA1: |
1291 | case IWL_LEGACY_SWITCH_ANTENNA2: | ||
1289 | IWL_DEBUG_RATE("LQ: Legacy toggle Antenna\n"); | 1292 | IWL_DEBUG_RATE("LQ: Legacy toggle Antenna\n"); |
1290 | 1293 | ||
1291 | lq_sta->action_counter++; | 1294 | lq_sta->action_counter++; |
1292 | 1295 | ||
1296 | if ((tbl->action == IWL_LEGACY_SWITCH_ANTENNA1 && | ||
1297 | tx_chains_num <= 1) || | ||
1298 | (tbl->action == IWL_LEGACY_SWITCH_ANTENNA2 && | ||
1299 | tx_chains_num <= 2)) | ||
1300 | break; | ||
1301 | |||
1293 | /* Don't change antenna if success has been great */ | 1302 | /* Don't change antenna if success has been great */ |
1294 | if (window->success_ratio >= IWL_RS_GOOD_RATIO) | 1303 | if (window->success_ratio >= IWL_RS_GOOD_RATIO) |
1295 | break; | 1304 | break; |
@@ -1299,7 +1308,7 @@ static int rs_move_legacy_other(struct iwl_priv *priv, | |||
1299 | 1308 | ||
1300 | if (rs_toggle_antenna(valid_tx_ant, | 1309 | if (rs_toggle_antenna(valid_tx_ant, |
1301 | &search_tbl->current_rate, search_tbl)) { | 1310 | &search_tbl->current_rate, search_tbl)) { |
1302 | lq_sta->search_better_tbl = 1; | 1311 | rs_set_expected_tpt_table(lq_sta, search_tbl); |
1303 | goto out; | 1312 | goto out; |
1304 | } | 1313 | } |
1305 | break; | 1314 | break; |
@@ -1312,43 +1321,54 @@ static int rs_move_legacy_other(struct iwl_priv *priv, | |||
1312 | ret = rs_switch_to_siso(priv, lq_sta, conf, sta, | 1321 | ret = rs_switch_to_siso(priv, lq_sta, conf, sta, |
1313 | search_tbl, index); | 1322 | search_tbl, index); |
1314 | if (!ret) { | 1323 | if (!ret) { |
1315 | lq_sta->search_better_tbl = 1; | ||
1316 | lq_sta->action_counter = 0; | 1324 | lq_sta->action_counter = 0; |
1317 | goto out; | 1325 | goto out; |
1318 | } | 1326 | } |
1319 | 1327 | ||
1320 | break; | 1328 | break; |
1321 | case IWL_LEGACY_SWITCH_MIMO2: | 1329 | case IWL_LEGACY_SWITCH_MIMO2_AB: |
1330 | case IWL_LEGACY_SWITCH_MIMO2_AC: | ||
1331 | case IWL_LEGACY_SWITCH_MIMO2_BC: | ||
1322 | IWL_DEBUG_RATE("LQ: Legacy switch to MIMO2\n"); | 1332 | IWL_DEBUG_RATE("LQ: Legacy switch to MIMO2\n"); |
1323 | 1333 | ||
1324 | /* Set up search table to try MIMO */ | 1334 | /* Set up search table to try MIMO */ |
1325 | memcpy(search_tbl, tbl, sz); | 1335 | memcpy(search_tbl, tbl, sz); |
1326 | search_tbl->is_SGI = 0; | 1336 | search_tbl->is_SGI = 0; |
1327 | search_tbl->ant_type = ANT_AB;/*FIXME:RS*/ | 1337 | |
1328 | /*FIXME:RS:need to check ant validity*/ | 1338 | if (tbl->action == IWL_LEGACY_SWITCH_MIMO2_AB) |
1339 | search_tbl->ant_type = ANT_AB; | ||
1340 | else if (tbl->action == IWL_LEGACY_SWITCH_MIMO2_AC) | ||
1341 | search_tbl->ant_type = ANT_AC; | ||
1342 | else | ||
1343 | search_tbl->ant_type = ANT_BC; | ||
1344 | |||
1345 | if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type)) | ||
1346 | break; | ||
1347 | |||
1329 | ret = rs_switch_to_mimo2(priv, lq_sta, conf, sta, | 1348 | ret = rs_switch_to_mimo2(priv, lq_sta, conf, sta, |
1330 | search_tbl, index); | 1349 | search_tbl, index); |
1331 | if (!ret) { | 1350 | if (!ret) { |
1332 | lq_sta->search_better_tbl = 1; | ||
1333 | lq_sta->action_counter = 0; | 1351 | lq_sta->action_counter = 0; |
1334 | goto out; | 1352 | goto out; |
1335 | } | 1353 | } |
1336 | break; | 1354 | break; |
1337 | } | 1355 | } |
1338 | tbl->action++; | 1356 | tbl->action++; |
1339 | if (tbl->action > IWL_LEGACY_SWITCH_MIMO2) | 1357 | if (tbl->action > IWL_LEGACY_SWITCH_MIMO2_BC) |
1340 | tbl->action = IWL_LEGACY_SWITCH_ANTENNA; | 1358 | tbl->action = IWL_LEGACY_SWITCH_ANTENNA1; |
1341 | 1359 | ||
1342 | if (tbl->action == start_action) | 1360 | if (tbl->action == start_action) |
1343 | break; | 1361 | break; |
1344 | 1362 | ||
1345 | } | 1363 | } |
1364 | search_tbl->lq_type = LQ_NONE; | ||
1346 | return 0; | 1365 | return 0; |
1347 | 1366 | ||
1348 | out: | 1367 | out: |
1368 | lq_sta->search_better_tbl = 1; | ||
1349 | tbl->action++; | 1369 | tbl->action++; |
1350 | if (tbl->action > IWL_LEGACY_SWITCH_MIMO2) | 1370 | if (tbl->action > IWL_LEGACY_SWITCH_MIMO2_BC) |
1351 | tbl->action = IWL_LEGACY_SWITCH_ANTENNA; | 1371 | tbl->action = IWL_LEGACY_SWITCH_ANTENNA1; |
1352 | return 0; | 1372 | return 0; |
1353 | 1373 | ||
1354 | } | 1374 | } |
@@ -1370,34 +1390,51 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, | |||
1370 | (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); | 1390 | (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); |
1371 | u8 start_action = tbl->action; | 1391 | u8 start_action = tbl->action; |
1372 | u8 valid_tx_ant = priv->hw_params.valid_tx_ant; | 1392 | u8 valid_tx_ant = priv->hw_params.valid_tx_ant; |
1393 | u8 tx_chains_num = priv->hw_params.tx_chains_num; | ||
1373 | int ret; | 1394 | int ret; |
1374 | 1395 | ||
1375 | for (;;) { | 1396 | for (;;) { |
1376 | lq_sta->action_counter++; | 1397 | lq_sta->action_counter++; |
1377 | switch (tbl->action) { | 1398 | switch (tbl->action) { |
1378 | case IWL_SISO_SWITCH_ANTENNA: | 1399 | case IWL_SISO_SWITCH_ANTENNA1: |
1400 | case IWL_SISO_SWITCH_ANTENNA2: | ||
1379 | IWL_DEBUG_RATE("LQ: SISO toggle Antenna\n"); | 1401 | IWL_DEBUG_RATE("LQ: SISO toggle Antenna\n"); |
1402 | |||
1403 | if ((tbl->action == IWL_SISO_SWITCH_ANTENNA1 && | ||
1404 | tx_chains_num <= 1) || | ||
1405 | (tbl->action == IWL_SISO_SWITCH_ANTENNA2 && | ||
1406 | tx_chains_num <= 2)) | ||
1407 | break; | ||
1408 | |||
1380 | if (window->success_ratio >= IWL_RS_GOOD_RATIO) | 1409 | if (window->success_ratio >= IWL_RS_GOOD_RATIO) |
1381 | break; | 1410 | break; |
1382 | 1411 | ||
1383 | memcpy(search_tbl, tbl, sz); | 1412 | memcpy(search_tbl, tbl, sz); |
1384 | if (rs_toggle_antenna(valid_tx_ant, | 1413 | if (rs_toggle_antenna(valid_tx_ant, |
1385 | &search_tbl->current_rate, search_tbl)) { | 1414 | &search_tbl->current_rate, search_tbl)) |
1386 | lq_sta->search_better_tbl = 1; | ||
1387 | goto out; | 1415 | goto out; |
1388 | } | ||
1389 | break; | 1416 | break; |
1390 | case IWL_SISO_SWITCH_MIMO2: | 1417 | case IWL_SISO_SWITCH_MIMO2_AB: |
1418 | case IWL_SISO_SWITCH_MIMO2_AC: | ||
1419 | case IWL_SISO_SWITCH_MIMO2_BC: | ||
1391 | IWL_DEBUG_RATE("LQ: SISO switch to MIMO2\n"); | 1420 | IWL_DEBUG_RATE("LQ: SISO switch to MIMO2\n"); |
1392 | memcpy(search_tbl, tbl, sz); | 1421 | memcpy(search_tbl, tbl, sz); |
1393 | search_tbl->is_SGI = 0; | 1422 | search_tbl->is_SGI = 0; |
1394 | search_tbl->ant_type = ANT_AB; /*FIXME:RS*/ | 1423 | |
1424 | if (tbl->action == IWL_SISO_SWITCH_MIMO2_AB) | ||
1425 | search_tbl->ant_type = ANT_AB; | ||
1426 | else if (tbl->action == IWL_SISO_SWITCH_MIMO2_AC) | ||
1427 | search_tbl->ant_type = ANT_AC; | ||
1428 | else | ||
1429 | search_tbl->ant_type = ANT_BC; | ||
1430 | |||
1431 | if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type)) | ||
1432 | break; | ||
1433 | |||
1395 | ret = rs_switch_to_mimo2(priv, lq_sta, conf, sta, | 1434 | ret = rs_switch_to_mimo2(priv, lq_sta, conf, sta, |
1396 | search_tbl, index); | 1435 | search_tbl, index); |
1397 | if (!ret) { | 1436 | if (!ret) |
1398 | lq_sta->search_better_tbl = 1; | ||
1399 | goto out; | 1437 | goto out; |
1400 | } | ||
1401 | break; | 1438 | break; |
1402 | case IWL_SISO_SWITCH_GI: | 1439 | case IWL_SISO_SWITCH_GI: |
1403 | if (!tbl->is_fat && | 1440 | if (!tbl->is_fat && |
@@ -1427,22 +1464,23 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, | |||
1427 | } | 1464 | } |
1428 | search_tbl->current_rate = rate_n_flags_from_tbl( | 1465 | search_tbl->current_rate = rate_n_flags_from_tbl( |
1429 | search_tbl, index, is_green); | 1466 | search_tbl, index, is_green); |
1430 | lq_sta->search_better_tbl = 1; | ||
1431 | goto out; | 1467 | goto out; |
1432 | } | 1468 | } |
1433 | tbl->action++; | 1469 | tbl->action++; |
1434 | if (tbl->action > IWL_SISO_SWITCH_GI) | 1470 | if (tbl->action > IWL_SISO_SWITCH_GI) |
1435 | tbl->action = IWL_SISO_SWITCH_ANTENNA; | 1471 | tbl->action = IWL_SISO_SWITCH_ANTENNA1; |
1436 | 1472 | ||
1437 | if (tbl->action == start_action) | 1473 | if (tbl->action == start_action) |
1438 | break; | 1474 | break; |
1439 | } | 1475 | } |
1476 | search_tbl->lq_type = LQ_NONE; | ||
1440 | return 0; | 1477 | return 0; |
1441 | 1478 | ||
1442 | out: | 1479 | out: |
1480 | lq_sta->search_better_tbl = 1; | ||
1443 | tbl->action++; | 1481 | tbl->action++; |
1444 | if (tbl->action > IWL_SISO_SWITCH_GI) | 1482 | if (tbl->action > IWL_SISO_SWITCH_GI) |
1445 | tbl->action = IWL_SISO_SWITCH_ANTENNA; | 1483 | tbl->action = IWL_SISO_SWITCH_ANTENNA1; |
1446 | return 0; | 1484 | return 0; |
1447 | } | 1485 | } |
1448 | 1486 | ||
@@ -1458,37 +1496,58 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv, | |||
1458 | struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); | 1496 | struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); |
1459 | struct iwl_scale_tbl_info *search_tbl = | 1497 | struct iwl_scale_tbl_info *search_tbl = |
1460 | &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); | 1498 | &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); |
1499 | struct iwl_rate_scale_data *window = &(tbl->win[index]); | ||
1461 | u32 sz = (sizeof(struct iwl_scale_tbl_info) - | 1500 | u32 sz = (sizeof(struct iwl_scale_tbl_info) - |
1462 | (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); | 1501 | (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); |
1463 | u8 start_action = tbl->action; | 1502 | u8 start_action = tbl->action; |
1464 | /*u8 valid_tx_ant = priv->hw_params.valid_tx_ant;*/ | 1503 | u8 valid_tx_ant = priv->hw_params.valid_tx_ant; |
1504 | u8 tx_chains_num = priv->hw_params.tx_chains_num; | ||
1465 | int ret; | 1505 | int ret; |
1466 | 1506 | ||
1467 | for (;;) { | 1507 | for (;;) { |
1468 | lq_sta->action_counter++; | 1508 | lq_sta->action_counter++; |
1469 | switch (tbl->action) { | 1509 | switch (tbl->action) { |
1470 | case IWL_MIMO_SWITCH_ANTENNA_A: | 1510 | case IWL_MIMO2_SWITCH_ANTENNA1: |
1471 | case IWL_MIMO_SWITCH_ANTENNA_B: | 1511 | case IWL_MIMO2_SWITCH_ANTENNA2: |
1512 | IWL_DEBUG_RATE("LQ: MIMO toggle Antennas\n"); | ||
1513 | |||
1514 | if (tx_chains_num <= 2) | ||
1515 | break; | ||
1516 | |||
1517 | if (window->success_ratio >= IWL_RS_GOOD_RATIO) | ||
1518 | break; | ||
1519 | |||
1520 | memcpy(search_tbl, tbl, sz); | ||
1521 | if (rs_toggle_antenna(valid_tx_ant, | ||
1522 | &search_tbl->current_rate, search_tbl)) | ||
1523 | goto out; | ||
1524 | break; | ||
1525 | case IWL_MIMO2_SWITCH_SISO_A: | ||
1526 | case IWL_MIMO2_SWITCH_SISO_B: | ||
1527 | case IWL_MIMO2_SWITCH_SISO_C: | ||
1472 | IWL_DEBUG_RATE("LQ: MIMO2 switch to SISO\n"); | 1528 | IWL_DEBUG_RATE("LQ: MIMO2 switch to SISO\n"); |
1473 | 1529 | ||
1474 | /* Set up new search table for SISO */ | 1530 | /* Set up new search table for SISO */ |
1475 | memcpy(search_tbl, tbl, sz); | 1531 | memcpy(search_tbl, tbl, sz); |
1476 | 1532 | ||
1477 | /*FIXME:RS:need to check ant validity + C*/ | 1533 | if (tbl->action == IWL_MIMO2_SWITCH_SISO_A) |
1478 | if (tbl->action == IWL_MIMO_SWITCH_ANTENNA_A) | ||
1479 | search_tbl->ant_type = ANT_A; | 1534 | search_tbl->ant_type = ANT_A; |
1480 | else | 1535 | else if (tbl->action == IWL_MIMO2_SWITCH_SISO_B) |
1481 | search_tbl->ant_type = ANT_B; | 1536 | search_tbl->ant_type = ANT_B; |
1537 | else | ||
1538 | search_tbl->ant_type = ANT_C; | ||
1539 | |||
1540 | if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type)) | ||
1541 | break; | ||
1482 | 1542 | ||
1483 | ret = rs_switch_to_siso(priv, lq_sta, conf, sta, | 1543 | ret = rs_switch_to_siso(priv, lq_sta, conf, sta, |
1484 | search_tbl, index); | 1544 | search_tbl, index); |
1485 | if (!ret) { | 1545 | if (!ret) |
1486 | lq_sta->search_better_tbl = 1; | ||
1487 | goto out; | 1546 | goto out; |
1488 | } | 1547 | |
1489 | break; | 1548 | break; |
1490 | 1549 | ||
1491 | case IWL_MIMO_SWITCH_GI: | 1550 | case IWL_MIMO2_SWITCH_GI: |
1492 | if (!tbl->is_fat && | 1551 | if (!tbl->is_fat && |
1493 | !(priv->current_ht_config.sgf & | 1552 | !(priv->current_ht_config.sgf & |
1494 | HT_SHORT_GI_20MHZ)) | 1553 | HT_SHORT_GI_20MHZ)) |
@@ -1517,23 +1576,23 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv, | |||
1517 | } | 1576 | } |
1518 | search_tbl->current_rate = rate_n_flags_from_tbl( | 1577 | search_tbl->current_rate = rate_n_flags_from_tbl( |
1519 | search_tbl, index, is_green); | 1578 | search_tbl, index, is_green); |
1520 | lq_sta->search_better_tbl = 1; | ||
1521 | goto out; | 1579 | goto out; |
1522 | 1580 | ||
1523 | } | 1581 | } |
1524 | tbl->action++; | 1582 | tbl->action++; |
1525 | if (tbl->action > IWL_MIMO_SWITCH_GI) | 1583 | if (tbl->action > IWL_MIMO2_SWITCH_GI) |
1526 | tbl->action = IWL_MIMO_SWITCH_ANTENNA_A; | 1584 | tbl->action = IWL_MIMO2_SWITCH_ANTENNA1; |
1527 | 1585 | ||
1528 | if (tbl->action == start_action) | 1586 | if (tbl->action == start_action) |
1529 | break; | 1587 | break; |
1530 | } | 1588 | } |
1531 | 1589 | search_tbl->lq_type = LQ_NONE; | |
1532 | return 0; | 1590 | return 0; |
1533 | out: | 1591 | out: |
1592 | lq_sta->search_better_tbl = 1; | ||
1534 | tbl->action++; | 1593 | tbl->action++; |
1535 | if (tbl->action > IWL_MIMO_SWITCH_GI) | 1594 | if (tbl->action > IWL_MIMO2_SWITCH_GI) |
1536 | tbl->action = IWL_MIMO_SWITCH_ANTENNA_A; | 1595 | tbl->action = IWL_MIMO2_SWITCH_ANTENNA1; |
1537 | return 0; | 1596 | return 0; |
1538 | 1597 | ||
1539 | } | 1598 | } |
@@ -1748,19 +1807,13 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, | |||
1748 | rs_stay_in_table(lq_sta); | 1807 | rs_stay_in_table(lq_sta); |
1749 | 1808 | ||
1750 | goto out; | 1809 | goto out; |
1810 | } | ||
1751 | 1811 | ||
1752 | /* Else we have enough samples; calculate estimate of | 1812 | /* Else we have enough samples; calculate estimate of |
1753 | * actual average throughput */ | 1813 | * actual average throughput */ |
1754 | } else { | 1814 | |
1755 | /*FIXME:RS remove this else if we don't get this error*/ | 1815 | BUG_ON(window->average_tpt != ((window->success_ratio * |
1756 | if (window->average_tpt != ((window->success_ratio * | 1816 | tbl->expected_tpt[index] + 64) / 128)); |
1757 | tbl->expected_tpt[index] + 64) / 128)) { | ||
1758 | IWL_ERROR("expected_tpt should have been calculated" | ||
1759 | " by now\n"); | ||
1760 | window->average_tpt = ((window->success_ratio * | ||
1761 | tbl->expected_tpt[index] + 64) / 128); | ||
1762 | } | ||
1763 | } | ||
1764 | 1817 | ||
1765 | /* If we are searching for better modulation mode, check success. */ | 1818 | /* If we are searching for better modulation mode, check success. */ |
1766 | if (lq_sta->search_better_tbl) { | 1819 | if (lq_sta->search_better_tbl) { |
@@ -1770,7 +1823,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, | |||
1770 | * continuing to use the setup that we've been trying. */ | 1823 | * continuing to use the setup that we've been trying. */ |
1771 | if (window->average_tpt > lq_sta->last_tpt) { | 1824 | if (window->average_tpt > lq_sta->last_tpt) { |
1772 | 1825 | ||
1773 | IWL_DEBUG_RATE("LQ: SWITCHING TO CURRENT TABLE " | 1826 | IWL_DEBUG_RATE("LQ: SWITCHING TO NEW TABLE " |
1774 | "suc=%d cur-tpt=%d old-tpt=%d\n", | 1827 | "suc=%d cur-tpt=%d old-tpt=%d\n", |
1775 | window->success_ratio, | 1828 | window->success_ratio, |
1776 | window->average_tpt, | 1829 | window->average_tpt, |
@@ -2183,7 +2236,7 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, | |||
2183 | for (i = 0; i < IWL_RATE_COUNT; i++) | 2236 | for (i = 0; i < IWL_RATE_COUNT; i++) |
2184 | rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]); | 2237 | rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]); |
2185 | 2238 | ||
2186 | IWL_DEBUG_RATE("LQ: *** rate scale global init ***\n"); | 2239 | IWL_DEBUG_RATE("LQ: *** rate scale station global init ***\n"); |
2187 | /* TODO: what is a good starting rate for STA? About middle? Maybe not | 2240 | /* TODO: what is a good starting rate for STA? About middle? Maybe not |
2188 | * the lowest or the highest rate.. Could consider using RSSI from | 2241 | * the lowest or the highest rate.. Could consider using RSSI from |
2189 | * previous packets? Need to have IEEE 802.1X auth succeed immediately | 2242 | * previous packets? Need to have IEEE 802.1X auth succeed immediately |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h index 84d4d1e33755..d148d73635eb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h | |||
@@ -206,21 +206,28 @@ enum { | |||
206 | #define IWL_RATE_DECREASE_TH 1920 /* 15% */ | 206 | #define IWL_RATE_DECREASE_TH 1920 /* 15% */ |
207 | 207 | ||
208 | /* possible actions when in legacy mode */ | 208 | /* possible actions when in legacy mode */ |
209 | #define IWL_LEGACY_SWITCH_ANTENNA 0 | 209 | #define IWL_LEGACY_SWITCH_ANTENNA1 0 |
210 | #define IWL_LEGACY_SWITCH_SISO 1 | 210 | #define IWL_LEGACY_SWITCH_ANTENNA2 1 |
211 | #define IWL_LEGACY_SWITCH_MIMO2 2 | 211 | #define IWL_LEGACY_SWITCH_SISO 2 |
212 | #define IWL_LEGACY_SWITCH_MIMO2_AB 3 | ||
213 | #define IWL_LEGACY_SWITCH_MIMO2_AC 4 | ||
214 | #define IWL_LEGACY_SWITCH_MIMO2_BC 5 | ||
212 | 215 | ||
213 | /* possible actions when in siso mode */ | 216 | /* possible actions when in siso mode */ |
214 | #define IWL_SISO_SWITCH_ANTENNA 0 | 217 | #define IWL_SISO_SWITCH_ANTENNA1 0 |
215 | #define IWL_SISO_SWITCH_MIMO2 1 | 218 | #define IWL_SISO_SWITCH_ANTENNA2 1 |
216 | #define IWL_SISO_SWITCH_GI 2 | 219 | #define IWL_SISO_SWITCH_MIMO2_AB 2 |
220 | #define IWL_SISO_SWITCH_MIMO2_AC 3 | ||
221 | #define IWL_SISO_SWITCH_MIMO2_BC 4 | ||
222 | #define IWL_SISO_SWITCH_GI 5 | ||
217 | 223 | ||
218 | /* possible actions when in mimo mode */ | 224 | /* possible actions when in mimo mode */ |
219 | #define IWL_MIMO_SWITCH_ANTENNA_A 0 | 225 | #define IWL_MIMO2_SWITCH_ANTENNA1 0 |
220 | #define IWL_MIMO_SWITCH_ANTENNA_B 1 | 226 | #define IWL_MIMO2_SWITCH_ANTENNA2 1 |
221 | #define IWL_MIMO_SWITCH_GI 2 | 227 | #define IWL_MIMO2_SWITCH_SISO_A 2 |
222 | 228 | #define IWL_MIMO2_SWITCH_SISO_B 3 | |
223 | /*FIXME:RS:separate MIMO2/3 transitions*/ | 229 | #define IWL_MIMO2_SWITCH_SISO_C 4 |
230 | #define IWL_MIMO2_SWITCH_GI 5 | ||
224 | 231 | ||
225 | /*FIXME:RS:add posible acctions for MIMO3*/ | 232 | /*FIXME:RS:add posible acctions for MIMO3*/ |
226 | 233 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 1547122e66fa..31ea28858896 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c | |||
@@ -485,7 +485,7 @@ static u8 iwl4965_rate_get_lowest_plcp(struct iwl_priv *priv) | |||
485 | return IWL_RATE_6M_PLCP; | 485 | return IWL_RATE_6M_PLCP; |
486 | } | 486 | } |
487 | 487 | ||
488 | unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, | 488 | static unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, |
489 | struct iwl_frame *frame, u8 rate) | 489 | struct iwl_frame *frame, u8 rate) |
490 | { | 490 | { |
491 | struct iwl_tx_beacon_cmd *tx_beacon_cmd; | 491 | struct iwl_tx_beacon_cmd *tx_beacon_cmd; |
@@ -564,8 +564,6 @@ static void iwl4965_ht_conf(struct iwl_priv *priv, | |||
564 | if (!iwl_conf->is_ht) | 564 | if (!iwl_conf->is_ht) |
565 | return; | 565 | return; |
566 | 566 | ||
567 | priv->ps_mode = (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2); | ||
568 | |||
569 | if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20) | 567 | if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20) |
570 | iwl_conf->sgf |= HT_SHORT_GI_20MHZ; | 568 | iwl_conf->sgf |= HT_SHORT_GI_20MHZ; |
571 | if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40) | 569 | if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40) |
@@ -586,6 +584,8 @@ static void iwl4965_ht_conf(struct iwl_priv *priv, | |||
586 | iwl_conf->supported_chan_width = 0; | 584 | iwl_conf->supported_chan_width = 0; |
587 | } | 585 | } |
588 | 586 | ||
587 | iwl_conf->sm_ps = (u8)((ht_conf->cap & IEEE80211_HT_CAP_SM_PS) >> 2); | ||
588 | |||
589 | memcpy(iwl_conf->supp_mcs_set, ht_conf->supp_mcs_set, 16); | 589 | memcpy(iwl_conf->supp_mcs_set, ht_conf->supp_mcs_set, 16); |
590 | 590 | ||
591 | iwl_conf->control_channel = ht_bss_conf->primary_channel; | 591 | iwl_conf->control_channel = ht_bss_conf->primary_channel; |
@@ -2558,7 +2558,11 @@ static void iwl4965_post_associate(struct iwl_priv *priv) | |||
2558 | iwl_activate_qos(priv, 0); | 2558 | iwl_activate_qos(priv, 0); |
2559 | spin_unlock_irqrestore(&priv->lock, flags); | 2559 | spin_unlock_irqrestore(&priv->lock, flags); |
2560 | 2560 | ||
2561 | iwl_power_enable_management(priv); | 2561 | /* the chain noise calibration will enabled PM upon completion |
2562 | * If chain noise has already been run, then we need to enable | ||
2563 | * power management here */ | ||
2564 | if (priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE) | ||
2565 | iwl_power_enable_management(priv); | ||
2562 | 2566 | ||
2563 | /* Enable Rx differential gain and sensitivity calibrations */ | 2567 | /* Enable Rx differential gain and sensitivity calibrations */ |
2564 | iwl_chain_noise_reset(priv); | 2568 | iwl_chain_noise_reset(priv); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c index 35fb4a4f737d..72fbf47229db 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-calib.c | |||
@@ -808,13 +808,11 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, | |||
808 | } | 808 | } |
809 | } | 809 | } |
810 | 810 | ||
811 | /* Save for use within RXON, TX, SCAN commands, etc. */ | ||
812 | priv->chain_noise_data.active_chains = active_chains; | ||
811 | IWL_DEBUG_CALIB("active_chains (bitwise) = 0x%x\n", | 813 | IWL_DEBUG_CALIB("active_chains (bitwise) = 0x%x\n", |
812 | active_chains); | 814 | active_chains); |
813 | 815 | ||
814 | /* Save for use within RXON, TX, SCAN commands, etc. */ | ||
815 | /*priv->valid_antenna = active_chains;*/ | ||
816 | /*FIXME: should be reflected in RX chains in RXON */ | ||
817 | |||
818 | /* Analyze noise for rx balance */ | 816 | /* Analyze noise for rx balance */ |
819 | average_noise[0] = ((data->chain_noise_a)/CAL_NUM_OF_BEACONS); | 817 | average_noise[0] = ((data->chain_noise_a)/CAL_NUM_OF_BEACONS); |
820 | average_noise[1] = ((data->chain_noise_b)/CAL_NUM_OF_BEACONS); | 818 | average_noise[1] = ((data->chain_noise_b)/CAL_NUM_OF_BEACONS); |
@@ -839,6 +837,15 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, | |||
839 | 837 | ||
840 | priv->cfg->ops->utils->gain_computation(priv, average_noise, | 838 | priv->cfg->ops->utils->gain_computation(priv, average_noise, |
841 | min_average_noise_antenna_i, min_average_noise); | 839 | min_average_noise_antenna_i, min_average_noise); |
840 | |||
841 | /* Some power changes may have been made during the calibration. | ||
842 | * Update and commit the RXON | ||
843 | */ | ||
844 | if (priv->cfg->ops->lib->update_chain_flags) | ||
845 | priv->cfg->ops->lib->update_chain_flags(priv); | ||
846 | |||
847 | data->state = IWL_CHAIN_NOISE_DONE; | ||
848 | iwl_power_enable_management(priv); | ||
842 | } | 849 | } |
843 | EXPORT_SYMBOL(iwl_chain_noise_calibration); | 850 | EXPORT_SYMBOL(iwl_chain_noise_calibration); |
844 | 851 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index a0b86af25c83..36d08b0eec43 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c | |||
@@ -399,8 +399,8 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, | |||
399 | 399 | ||
400 | ht_info->cap |= (u16)IEEE80211_HT_CAP_GRN_FLD; | 400 | ht_info->cap |= (u16)IEEE80211_HT_CAP_GRN_FLD; |
401 | ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_20; | 401 | ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_20; |
402 | ht_info->cap |= (u16)(IEEE80211_HT_CAP_MIMO_PS & | 402 | ht_info->cap |= (u16)(IEEE80211_HT_CAP_SM_PS & |
403 | (IWL_MIMO_PS_NONE << 2)); | 403 | (WLAN_HT_CAP_SM_PS_DISABLED << 2)); |
404 | 404 | ||
405 | max_bit_rate = MAX_BIT_RATE_20_MHZ; | 405 | max_bit_rate = MAX_BIT_RATE_20_MHZ; |
406 | if (priv->hw_params.fat_channel & BIT(band)) { | 406 | if (priv->hw_params.fat_channel & BIT(band)) { |
@@ -709,7 +709,8 @@ static int iwl_get_active_rx_chain_count(struct iwl_priv *priv) | |||
709 | bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status); | 709 | bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status); |
710 | 710 | ||
711 | /* # of Rx chains to use when expecting MIMO. */ | 711 | /* # of Rx chains to use when expecting MIMO. */ |
712 | if (is_single || (!is_cam && (priv->ps_mode == IWL_MIMO_PS_STATIC))) | 712 | if (is_single || (!is_cam && (priv->current_ht_config.sm_ps == |
713 | WLAN_HT_CAP_SM_PS_STATIC))) | ||
713 | return 2; | 714 | return 2; |
714 | else | 715 | else |
715 | return 3; | 716 | return 3; |
@@ -720,17 +721,18 @@ static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt) | |||
720 | int idle_cnt; | 721 | int idle_cnt; |
721 | bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status); | 722 | bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status); |
722 | /* # Rx chains when idling and maybe trying to save power */ | 723 | /* # Rx chains when idling and maybe trying to save power */ |
723 | switch (priv->ps_mode) { | 724 | switch (priv->current_ht_config.sm_ps) { |
724 | case IWL_MIMO_PS_STATIC: | 725 | case WLAN_HT_CAP_SM_PS_STATIC: |
725 | case IWL_MIMO_PS_DYNAMIC: | 726 | case WLAN_HT_CAP_SM_PS_DYNAMIC: |
726 | idle_cnt = (is_cam) ? 2 : 1; | 727 | idle_cnt = (is_cam) ? 2 : 1; |
727 | break; | 728 | break; |
728 | case IWL_MIMO_PS_NONE: | 729 | case WLAN_HT_CAP_SM_PS_DISABLED: |
729 | idle_cnt = (is_cam) ? active_cnt : 1; | 730 | idle_cnt = (is_cam) ? active_cnt : 1; |
730 | break; | 731 | break; |
731 | case IWL_MIMO_PS_INVALID: | 732 | case WLAN_HT_CAP_SM_PS_INVALID: |
732 | default: | 733 | default: |
733 | IWL_ERROR("invalide mimo ps mode %d\n", priv->ps_mode); | 734 | IWL_ERROR("invalide mimo ps mode %d\n", |
735 | priv->current_ht_config.sm_ps); | ||
734 | WARN_ON(1); | 736 | WARN_ON(1); |
735 | idle_cnt = -1; | 737 | idle_cnt = -1; |
736 | break; | 738 | break; |
@@ -738,6 +740,17 @@ static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt) | |||
738 | return idle_cnt; | 740 | return idle_cnt; |
739 | } | 741 | } |
740 | 742 | ||
743 | /* up to 4 chains */ | ||
744 | static u8 iwl_count_chain_bitmap(u32 chain_bitmap) | ||
745 | { | ||
746 | u8 res; | ||
747 | res = (chain_bitmap & BIT(0)) >> 0; | ||
748 | res += (chain_bitmap & BIT(1)) >> 1; | ||
749 | res += (chain_bitmap & BIT(2)) >> 2; | ||
750 | res += (chain_bitmap & BIT(4)) >> 4; | ||
751 | return res; | ||
752 | } | ||
753 | |||
741 | /** | 754 | /** |
742 | * iwl_set_rxon_chain - Set up Rx chain usage in "staging" RXON image | 755 | * iwl_set_rxon_chain - Set up Rx chain usage in "staging" RXON image |
743 | * | 756 | * |
@@ -748,25 +761,35 @@ void iwl_set_rxon_chain(struct iwl_priv *priv) | |||
748 | { | 761 | { |
749 | bool is_single = is_single_rx_stream(priv); | 762 | bool is_single = is_single_rx_stream(priv); |
750 | bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status); | 763 | bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status); |
751 | u8 idle_rx_cnt, active_rx_cnt; | 764 | u8 idle_rx_cnt, active_rx_cnt, valid_rx_cnt; |
765 | u32 active_chains; | ||
752 | u16 rx_chain; | 766 | u16 rx_chain; |
753 | 767 | ||
754 | /* Tell uCode which antennas are actually connected. | 768 | /* Tell uCode which antennas are actually connected. |
755 | * Before first association, we assume all antennas are connected. | 769 | * Before first association, we assume all antennas are connected. |
756 | * Just after first association, iwl_chain_noise_calibration() | 770 | * Just after first association, iwl_chain_noise_calibration() |
757 | * checks which antennas actually *are* connected. */ | 771 | * checks which antennas actually *are* connected. */ |
758 | rx_chain = priv->hw_params.valid_rx_ant << RXON_RX_CHAIN_VALID_POS; | 772 | if (priv->chain_noise_data.active_chains) |
773 | active_chains = priv->chain_noise_data.active_chains; | ||
774 | else | ||
775 | active_chains = priv->hw_params.valid_rx_ant; | ||
776 | |||
777 | rx_chain = active_chains << RXON_RX_CHAIN_VALID_POS; | ||
759 | 778 | ||
760 | /* How many receivers should we use? */ | 779 | /* How many receivers should we use? */ |
761 | active_rx_cnt = iwl_get_active_rx_chain_count(priv); | 780 | active_rx_cnt = iwl_get_active_rx_chain_count(priv); |
762 | idle_rx_cnt = iwl_get_idle_rx_chain_count(priv, active_rx_cnt); | 781 | idle_rx_cnt = iwl_get_idle_rx_chain_count(priv, active_rx_cnt); |
763 | 782 | ||
764 | /* correct rx chain count accoridng hw settings */ | ||
765 | if (priv->hw_params.rx_chains_num < active_rx_cnt) | ||
766 | active_rx_cnt = priv->hw_params.rx_chains_num; | ||
767 | 783 | ||
768 | if (priv->hw_params.rx_chains_num < idle_rx_cnt) | 784 | /* correct rx chain count according hw settings |
769 | idle_rx_cnt = priv->hw_params.rx_chains_num; | 785 | * and chain noise calibration |
786 | */ | ||
787 | valid_rx_cnt = iwl_count_chain_bitmap(active_chains); | ||
788 | if (valid_rx_cnt < active_rx_cnt) | ||
789 | active_rx_cnt = valid_rx_cnt; | ||
790 | |||
791 | if (valid_rx_cnt < idle_rx_cnt) | ||
792 | idle_rx_cnt = valid_rx_cnt; | ||
770 | 793 | ||
771 | rx_chain |= active_rx_cnt << RXON_RX_CHAIN_MIMO_CNT_POS; | 794 | rx_chain |= active_rx_cnt << RXON_RX_CHAIN_MIMO_CNT_POS; |
772 | rx_chain |= idle_rx_cnt << RXON_RX_CHAIN_CNT_POS; | 795 | rx_chain |= idle_rx_cnt << RXON_RX_CHAIN_CNT_POS; |
@@ -778,7 +801,7 @@ void iwl_set_rxon_chain(struct iwl_priv *priv) | |||
778 | else | 801 | else |
779 | priv->staging_rxon.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK; | 802 | priv->staging_rxon.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK; |
780 | 803 | ||
781 | IWL_DEBUG_ASSOC("rx_chain=0x%Xi active=%d idle=%d\n", | 804 | IWL_DEBUG_ASSOC("rx_chain=0x%X active=%d idle=%d\n", |
782 | priv->staging_rxon.rx_chain, | 805 | priv->staging_rxon.rx_chain, |
783 | active_rx_cnt, idle_rx_cnt); | 806 | active_rx_cnt, idle_rx_cnt); |
784 | 807 | ||
@@ -912,7 +935,7 @@ int iwl_init_drv(struct iwl_priv *priv) | |||
912 | priv->iw_mode = IEEE80211_IF_TYPE_STA; | 935 | priv->iw_mode = IEEE80211_IF_TYPE_STA; |
913 | 936 | ||
914 | priv->use_ant_b_for_management_frame = 1; /* start with ant B */ | 937 | priv->use_ant_b_for_management_frame = 1; /* start with ant B */ |
915 | priv->ps_mode = IWL_MIMO_PS_NONE; | 938 | priv->current_ht_config.sm_ps = WLAN_HT_CAP_SM_PS_DISABLED; |
916 | 939 | ||
917 | /* Choose which receivers/antennas to use */ | 940 | /* Choose which receivers/antennas to use */ |
918 | iwl_set_rxon_chain(priv); | 941 | iwl_set_rxon_chain(priv); |
@@ -1135,7 +1158,6 @@ int iwl_verify_ucode(struct iwl_priv *priv) | |||
1135 | } | 1158 | } |
1136 | EXPORT_SYMBOL(iwl_verify_ucode); | 1159 | EXPORT_SYMBOL(iwl_verify_ucode); |
1137 | 1160 | ||
1138 | |||
1139 | static const char *desc_lookup(int i) | 1161 | static const char *desc_lookup(int i) |
1140 | { | 1162 | { |
1141 | switch (i) { | 1163 | switch (i) { |
@@ -1216,9 +1238,9 @@ EXPORT_SYMBOL(iwl_dump_nic_error_log); | |||
1216 | /** | 1238 | /** |
1217 | * iwl_print_event_log - Dump error event log to syslog | 1239 | * iwl_print_event_log - Dump error event log to syslog |
1218 | * | 1240 | * |
1219 | * NOTE: Must be called with iwl4965_grab_nic_access() already obtained! | 1241 | * NOTE: Must be called with iwl_grab_nic_access() already obtained! |
1220 | */ | 1242 | */ |
1221 | void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, | 1243 | static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, |
1222 | u32 num_events, u32 mode) | 1244 | u32 num_events, u32 mode) |
1223 | { | 1245 | { |
1224 | u32 i; | 1246 | u32 i; |
@@ -1259,8 +1281,6 @@ void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, | |||
1259 | } | 1281 | } |
1260 | } | 1282 | } |
1261 | } | 1283 | } |
1262 | EXPORT_SYMBOL(iwl_print_event_log); | ||
1263 | |||
1264 | 1284 | ||
1265 | void iwl_dump_nic_event_log(struct iwl_priv *priv) | 1285 | void iwl_dump_nic_event_log(struct iwl_priv *priv) |
1266 | { | 1286 | { |
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index b5db050b22d1..55a4b584ce07 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h | |||
@@ -184,7 +184,6 @@ struct iwl_cfg { | |||
184 | struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg, | 184 | struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg, |
185 | struct ieee80211_ops *hw_ops); | 185 | struct ieee80211_ops *hw_ops); |
186 | void iwl_hw_detect(struct iwl_priv *priv); | 186 | void iwl_hw_detect(struct iwl_priv *priv); |
187 | |||
188 | void iwl_clear_stations_table(struct iwl_priv *priv); | 187 | void iwl_clear_stations_table(struct iwl_priv *priv); |
189 | void iwl_reset_qos(struct iwl_priv *priv); | 188 | void iwl_reset_qos(struct iwl_priv *priv); |
190 | void iwl_set_rxon_chain(struct iwl_priv *priv); | 189 | void iwl_set_rxon_chain(struct iwl_priv *priv); |
@@ -215,7 +214,6 @@ void iwl_rx_replenish(struct iwl_priv *priv); | |||
215 | int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq); | 214 | int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq); |
216 | int iwl_rx_agg_start(struct iwl_priv *priv, const u8 *addr, int tid, u16 ssn); | 215 | int iwl_rx_agg_start(struct iwl_priv *priv, const u8 *addr, int tid, u16 ssn); |
217 | int iwl_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid); | 216 | int iwl_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid); |
218 | /* FIXME: remove when TX is moved to iwl core */ | ||
219 | int iwl_rx_queue_restock(struct iwl_priv *priv); | 217 | int iwl_rx_queue_restock(struct iwl_priv *priv); |
220 | int iwl_rx_queue_space(const struct iwl_rx_queue *q); | 218 | int iwl_rx_queue_space(const struct iwl_rx_queue *q); |
221 | void iwl_rx_allocate(struct iwl_priv *priv); | 219 | void iwl_rx_allocate(struct iwl_priv *priv); |
@@ -234,11 +232,7 @@ void iwl_rx_statistics(struct iwl_priv *priv, | |||
234 | ******************************************************/ | 232 | ******************************************************/ |
235 | int iwl_txq_ctx_reset(struct iwl_priv *priv); | 233 | int iwl_txq_ctx_reset(struct iwl_priv *priv); |
236 | int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb); | 234 | int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb); |
237 | /* FIXME: remove when free Tx is fully merged into iwlcore */ | ||
238 | int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq); | ||
239 | void iwl_hw_txq_ctx_free(struct iwl_priv *priv); | 235 | void iwl_hw_txq_ctx_free(struct iwl_priv *priv); |
240 | int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *tfd, | ||
241 | dma_addr_t addr, u16 len); | ||
242 | int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq); | 236 | int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq); |
243 | int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn); | 237 | int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn); |
244 | int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid); | 238 | int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid); |
@@ -253,6 +247,7 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force); | |||
253 | * RF -Kill - here and not in iwl-rfkill.h to be available when | 247 | * RF -Kill - here and not in iwl-rfkill.h to be available when |
254 | * RF-kill subsystem is not compiled. | 248 | * RF-kill subsystem is not compiled. |
255 | ****************************************************/ | 249 | ****************************************************/ |
250 | void iwl_rf_kill(struct iwl_priv *priv); | ||
256 | void iwl_radio_kill_sw_disable_radio(struct iwl_priv *priv); | 251 | void iwl_radio_kill_sw_disable_radio(struct iwl_priv *priv); |
257 | int iwl_radio_kill_sw_enable_radio(struct iwl_priv *priv); | 252 | int iwl_radio_kill_sw_enable_radio(struct iwl_priv *priv); |
258 | 253 | ||
@@ -283,7 +278,6 @@ static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags) | |||
283 | void iwl_init_scan_params(struct iwl_priv *priv); | 278 | void iwl_init_scan_params(struct iwl_priv *priv); |
284 | int iwl_scan_cancel(struct iwl_priv *priv); | 279 | int iwl_scan_cancel(struct iwl_priv *priv); |
285 | int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms); | 280 | int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms); |
286 | const char *iwl_escape_essid(const char *essid, u8 essid_len); | ||
287 | int iwl_scan_initiate(struct iwl_priv *priv); | 281 | int iwl_scan_initiate(struct iwl_priv *priv); |
288 | void iwl_setup_rx_scan_handlers(struct iwl_priv *priv); | 282 | void iwl_setup_rx_scan_handlers(struct iwl_priv *priv); |
289 | void iwl_setup_scan_deferred_work(struct iwl_priv *priv); | 283 | void iwl_setup_scan_deferred_work(struct iwl_priv *priv); |
@@ -316,8 +310,6 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd); | |||
316 | /***************************************************** | 310 | /***************************************************** |
317 | * Error Handling Debugging | 311 | * Error Handling Debugging |
318 | ******************************************************/ | 312 | ******************************************************/ |
319 | void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, | ||
320 | u32 num_events, u32 mode); | ||
321 | void iwl_dump_nic_error_log(struct iwl_priv *priv); | 313 | void iwl_dump_nic_error_log(struct iwl_priv *priv); |
322 | void iwl_dump_nic_event_log(struct iwl_priv *priv); | 314 | void iwl_dump_nic_event_log(struct iwl_priv *priv); |
323 | 315 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 640ceea913c7..1823687e5820 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h | |||
@@ -406,6 +406,7 @@ struct iwl_ht_info { | |||
406 | /* self configuration data */ | 406 | /* self configuration data */ |
407 | u8 is_ht; | 407 | u8 is_ht; |
408 | u8 supported_chan_width; | 408 | u8 supported_chan_width; |
409 | u8 sm_ps; | ||
409 | u8 is_green_field; | 410 | u8 is_green_field; |
410 | u8 sgf; /* HT_SHORT_GI_* short guard interval */ | 411 | u8 sgf; /* HT_SHORT_GI_* short guard interval */ |
411 | u8 max_amsdu_size; | 412 | u8 max_amsdu_size; |
@@ -564,50 +565,31 @@ struct iwl_hw_params { | |||
564 | #define IWL_RX_STATS(x) (&x->u.rx_frame.stats) | 565 | #define IWL_RX_STATS(x) (&x->u.rx_frame.stats) |
565 | #define IWL_RX_DATA(x) (IWL_RX_HDR(x)->payload) | 566 | #define IWL_RX_DATA(x) (IWL_RX_HDR(x)->payload) |
566 | 567 | ||
567 | |||
568 | /****************************************************************************** | ||
569 | * | ||
570 | * Functions implemented in iwl-base.c which are forward declared here | ||
571 | * for use by iwl-*.c | ||
572 | * | ||
573 | *****************************************************************************/ | ||
574 | struct iwl_addsta_cmd; | ||
575 | extern int iwl_send_add_sta(struct iwl_priv *priv, | ||
576 | struct iwl_addsta_cmd *sta, u8 flags); | ||
577 | u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap, | ||
578 | u8 flags, struct ieee80211_ht_info *ht_info); | ||
579 | extern unsigned int iwl4965_fill_beacon_frame(struct iwl_priv *priv, | ||
580 | struct ieee80211_hdr *hdr, | ||
581 | const u8 *dest, int left); | ||
582 | extern void iwl4965_update_chain_flags(struct iwl_priv *priv); | ||
583 | int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src); | ||
584 | extern int iwl4965_set_power(struct iwl_priv *priv, void *cmd); | ||
585 | |||
586 | extern const u8 iwl_bcast_addr[ETH_ALEN]; | ||
587 | |||
588 | /****************************************************************************** | 568 | /****************************************************************************** |
589 | * | 569 | * |
590 | * Functions implemented in iwl-[34]*.c which are forward declared here | 570 | * Functions implemented in core module which are forward declared here |
591 | * for use by iwl-base.c | 571 | * for use by iwl-[4-5].c |
592 | * | 572 | * |
593 | * NOTE: The implementation of these functions are hardware specific | 573 | * NOTE: The implementation of these functions are not hardware specific |
594 | * which is why they are in the hardware specific files (vs. iwl-base.c) | 574 | * which is why they are in the core module files. |
595 | * | 575 | * |
596 | * Naming convention -- | 576 | * Naming convention -- |
597 | * iwl4965_ <-- Its part of iwlwifi (should be changed to iwl4965_) | 577 | * iwl_ <-- Is part of iwlwifi |
598 | * iwl4965_hw_ <-- Hardware specific (implemented in iwl-XXXX.c by all HW) | ||
599 | * iwlXXXX_ <-- Hardware specific (implemented in iwl-XXXX.c for XXXX) | 578 | * iwlXXXX_ <-- Hardware specific (implemented in iwl-XXXX.c for XXXX) |
600 | * iwl4965_bg_ <-- Called from work queue context | 579 | * iwl4965_bg_ <-- Called from work queue context |
601 | * iwl4965_mac_ <-- mac80211 callback | 580 | * iwl4965_mac_ <-- mac80211 callback |
602 | * | 581 | * |
603 | ****************************************************************************/ | 582 | ****************************************************************************/ |
583 | struct iwl_addsta_cmd; | ||
584 | extern int iwl_send_add_sta(struct iwl_priv *priv, | ||
585 | struct iwl_addsta_cmd *sta, u8 flags); | ||
586 | extern u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, | ||
587 | int is_ap, u8 flags, struct ieee80211_ht_info *ht_info); | ||
588 | extern void iwl4965_update_chain_flags(struct iwl_priv *priv); | ||
589 | extern int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src); | ||
590 | extern const u8 iwl_bcast_addr[ETH_ALEN]; | ||
604 | extern int iwl_rxq_stop(struct iwl_priv *priv); | 591 | extern int iwl_rxq_stop(struct iwl_priv *priv); |
605 | extern void iwl_txq_ctx_stop(struct iwl_priv *priv); | 592 | extern void iwl_txq_ctx_stop(struct iwl_priv *priv); |
606 | extern unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, | ||
607 | struct iwl_frame *frame, u8 rate); | ||
608 | extern void iwl4965_disable_events(struct iwl_priv *priv); | ||
609 | |||
610 | extern int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel); | ||
611 | extern int iwl_queue_space(const struct iwl_queue *q); | 593 | extern int iwl_queue_space(const struct iwl_queue *q); |
612 | static inline int iwl_queue_used(const struct iwl_queue *q, int i) | 594 | static inline int iwl_queue_used(const struct iwl_queue *q, int i) |
613 | { | 595 | { |
@@ -644,11 +626,6 @@ struct iwl_kw { | |||
644 | #define IWL_CHANNEL_WIDTH_20MHZ 0 | 626 | #define IWL_CHANNEL_WIDTH_20MHZ 0 |
645 | #define IWL_CHANNEL_WIDTH_40MHZ 1 | 627 | #define IWL_CHANNEL_WIDTH_40MHZ 1 |
646 | 628 | ||
647 | #define IWL_MIMO_PS_STATIC 0 | ||
648 | #define IWL_MIMO_PS_NONE 3 | ||
649 | #define IWL_MIMO_PS_DYNAMIC 1 | ||
650 | #define IWL_MIMO_PS_INVALID 2 | ||
651 | |||
652 | #define IWL_OPERATION_MODE_AUTO 0 | 629 | #define IWL_OPERATION_MODE_AUTO 0 |
653 | #define IWL_OPERATION_MODE_HT_ONLY 1 | 630 | #define IWL_OPERATION_MODE_HT_ONLY 1 |
654 | #define IWL_OPERATION_MODE_MIXED 2 | 631 | #define IWL_OPERATION_MODE_MIXED 2 |
@@ -703,8 +680,9 @@ enum iwl4965_false_alarm_state { | |||
703 | 680 | ||
704 | enum iwl4965_chain_noise_state { | 681 | enum iwl4965_chain_noise_state { |
705 | IWL_CHAIN_NOISE_ALIVE = 0, /* must be 0 */ | 682 | IWL_CHAIN_NOISE_ALIVE = 0, /* must be 0 */ |
706 | IWL_CHAIN_NOISE_ACCUMULATE = 1, | 683 | IWL_CHAIN_NOISE_ACCUMULATE, |
707 | IWL_CHAIN_NOISE_CALIBRATED = 2, | 684 | IWL_CHAIN_NOISE_CALIBRATED, |
685 | IWL_CHAIN_NOISE_DONE, | ||
708 | }; | 686 | }; |
709 | 687 | ||
710 | enum iwl4965_calib_enabled_state { | 688 | enum iwl4965_calib_enabled_state { |
@@ -762,17 +740,18 @@ struct iwl_sensitivity_data { | |||
762 | 740 | ||
763 | /* Chain noise (differential Rx gain) calib data */ | 741 | /* Chain noise (differential Rx gain) calib data */ |
764 | struct iwl_chain_noise_data { | 742 | struct iwl_chain_noise_data { |
765 | u8 state; | 743 | u32 active_chains; |
766 | u16 beacon_count; | ||
767 | u32 chain_noise_a; | 744 | u32 chain_noise_a; |
768 | u32 chain_noise_b; | 745 | u32 chain_noise_b; |
769 | u32 chain_noise_c; | 746 | u32 chain_noise_c; |
770 | u32 chain_signal_a; | 747 | u32 chain_signal_a; |
771 | u32 chain_signal_b; | 748 | u32 chain_signal_b; |
772 | u32 chain_signal_c; | 749 | u32 chain_signal_c; |
750 | u16 beacon_count; | ||
773 | u8 disconn_array[NUM_RX_CHAINS]; | 751 | u8 disconn_array[NUM_RX_CHAINS]; |
774 | u8 delta_gain_code[NUM_RX_CHAINS]; | 752 | u8 delta_gain_code[NUM_RX_CHAINS]; |
775 | u8 radio_write; | 753 | u8 radio_write; |
754 | u8 state; | ||
776 | }; | 755 | }; |
777 | 756 | ||
778 | #define EEPROM_SEM_TIMEOUT 10 /* milliseconds */ | 757 | #define EEPROM_SEM_TIMEOUT 10 /* milliseconds */ |
@@ -995,7 +974,6 @@ struct iwl_priv { | |||
995 | * hardware */ | 974 | * hardware */ |
996 | u16 assoc_id; | 975 | u16 assoc_id; |
997 | u16 assoc_capability; | 976 | u16 assoc_capability; |
998 | u8 ps_mode; | ||
999 | 977 | ||
1000 | struct iwl_qos_info qos_data; | 978 | struct iwl_qos_info qos_data; |
1001 | 979 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 16f834d0c486..55ec31ec9e15 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c | |||
@@ -250,17 +250,26 @@ static int iwl_update_power_command(struct iwl_priv *priv, | |||
250 | 250 | ||
251 | 251 | ||
252 | /* | 252 | /* |
253 | * calucaute the final power mode index | 253 | * compute the final power mode index |
254 | */ | 254 | */ |
255 | int iwl_power_update_mode(struct iwl_priv *priv, u8 refresh) | 255 | int iwl_power_update_mode(struct iwl_priv *priv, bool force) |
256 | { | 256 | { |
257 | struct iwl_power_mgr *setting = &(priv->power_data); | 257 | struct iwl_power_mgr *setting = &(priv->power_data); |
258 | int ret = 0; | 258 | int ret = 0; |
259 | u16 uninitialized_var(final_mode); | 259 | u16 uninitialized_var(final_mode); |
260 | 260 | ||
261 | /* If on battery, set to 3, | 261 | /* Don't update the RX chain when chain noise calibration is running */ |
262 | * if plugged into AC power, set to CAM ("continuously aware mode"), | 262 | if (priv->chain_noise_data.state != IWL_CHAIN_NOISE_DONE && |
263 | * else user level */ | 263 | priv->chain_noise_data.state != IWL_CHAIN_NOISE_ALIVE) { |
264 | IWL_DEBUG_POWER("Cannot update the power, chain noise " | ||
265 | "calibration running: %d\n", | ||
266 | priv->chain_noise_data.state); | ||
267 | return -EAGAIN; | ||
268 | } | ||
269 | |||
270 | /* If on battery, set to 3, | ||
271 | * if plugged into AC power, set to CAM ("continuously aware mode"), | ||
272 | * else user level */ | ||
264 | 273 | ||
265 | switch (setting->system_power_setting) { | 274 | switch (setting->system_power_setting) { |
266 | case IWL_POWER_SYS_AUTO: | 275 | case IWL_POWER_SYS_AUTO: |
@@ -285,7 +294,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, u8 refresh) | |||
285 | final_mode = IWL_POWER_MODE_CAM; | 294 | final_mode = IWL_POWER_MODE_CAM; |
286 | 295 | ||
287 | if (!iwl_is_rfkill(priv) && !setting->power_disabled && | 296 | if (!iwl_is_rfkill(priv) && !setting->power_disabled && |
288 | ((setting->power_mode != final_mode) || refresh)) { | 297 | ((setting->power_mode != final_mode) || force)) { |
289 | struct iwl_powertable_cmd cmd; | 298 | struct iwl_powertable_cmd cmd; |
290 | 299 | ||
291 | if (final_mode != IWL_POWER_MODE_CAM) | 300 | if (final_mode != IWL_POWER_MODE_CAM) |
@@ -359,35 +368,26 @@ EXPORT_SYMBOL(iwl_power_enable_management); | |||
359 | /* set user_power_setting */ | 368 | /* set user_power_setting */ |
360 | int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode) | 369 | int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode) |
361 | { | 370 | { |
362 | int ret = 0; | ||
363 | |||
364 | if (mode > IWL_POWER_LIMIT) | 371 | if (mode > IWL_POWER_LIMIT) |
365 | return -EINVAL; | 372 | return -EINVAL; |
366 | 373 | ||
367 | priv->power_data.user_power_setting = mode; | 374 | priv->power_data.user_power_setting = mode; |
368 | 375 | ||
369 | ret = iwl_power_update_mode(priv, 0); | 376 | return iwl_power_update_mode(priv, 0); |
370 | |||
371 | return ret; | ||
372 | } | 377 | } |
373 | EXPORT_SYMBOL(iwl_power_set_user_mode); | 378 | EXPORT_SYMBOL(iwl_power_set_user_mode); |
374 | 379 | ||
375 | |||
376 | /* set system_power_setting. This should be set by over all | 380 | /* set system_power_setting. This should be set by over all |
377 | * PM application. | 381 | * PM application. |
378 | */ | 382 | */ |
379 | int iwl_power_set_system_mode(struct iwl_priv *priv, u16 mode) | 383 | int iwl_power_set_system_mode(struct iwl_priv *priv, u16 mode) |
380 | { | 384 | { |
381 | int ret = 0; | ||
382 | |||
383 | if (mode > IWL_POWER_LIMIT) | 385 | if (mode > IWL_POWER_LIMIT) |
384 | return -EINVAL; | 386 | return -EINVAL; |
385 | 387 | ||
386 | priv->power_data.system_power_setting = mode; | 388 | priv->power_data.system_power_setting = mode; |
387 | 389 | ||
388 | ret = iwl_power_update_mode(priv, 0); | 390 | return iwl_power_update_mode(priv, 0); |
389 | |||
390 | return ret; | ||
391 | } | 391 | } |
392 | EXPORT_SYMBOL(iwl_power_set_system_mode); | 392 | EXPORT_SYMBOL(iwl_power_set_system_mode); |
393 | 393 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h index aa99f3647def..df484a90ae64 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.h +++ b/drivers/net/wireless/iwlwifi/iwl-power.h | |||
@@ -72,7 +72,7 @@ struct iwl_power_mgr { | |||
72 | /* final power level that used to calculate final power command */ | 72 | /* final power level that used to calculate final power command */ |
73 | u8 power_mode; | 73 | u8 power_mode; |
74 | u8 user_power_setting; /* set by user through mac80211 or sysfs */ | 74 | u8 user_power_setting; /* set by user through mac80211 or sysfs */ |
75 | u8 system_power_setting; /* set by kernel syatem tools */ | 75 | u8 system_power_setting; /* set by kernel system tools */ |
76 | u8 critical_power_setting; /* set if driver over heated */ | 76 | u8 critical_power_setting; /* set if driver over heated */ |
77 | u8 is_battery_active; /* DC/AC power */ | 77 | u8 is_battery_active; /* DC/AC power */ |
78 | u8 power_disabled; /* flag to disable using power saving level */ | 78 | u8 power_disabled; /* flag to disable using power saving level */ |
@@ -80,7 +80,7 @@ struct iwl_power_mgr { | |||
80 | 80 | ||
81 | void iwl_setup_power_deferred_work(struct iwl_priv *priv); | 81 | void iwl_setup_power_deferred_work(struct iwl_priv *priv); |
82 | void iwl_power_cancel_timeout(struct iwl_priv *priv); | 82 | void iwl_power_cancel_timeout(struct iwl_priv *priv); |
83 | int iwl_power_update_mode(struct iwl_priv *priv, u8 refresh); | 83 | int iwl_power_update_mode(struct iwl_priv *priv, bool force); |
84 | int iwl_power_disable_management(struct iwl_priv *priv, u32 ms); | 84 | int iwl_power_disable_management(struct iwl_priv *priv, u32 ms); |
85 | int iwl_power_enable_management(struct iwl_priv *priv); | 85 | int iwl_power_enable_management(struct iwl_priv *priv); |
86 | int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode); | 86 | int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 6c8ac3a87d54..d026aaf62335 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c | |||
@@ -88,7 +88,7 @@ static int iwl_is_empty_essid(const char *essid, int essid_len) | |||
88 | 88 | ||
89 | 89 | ||
90 | 90 | ||
91 | const char *iwl_escape_essid(const char *essid, u8 essid_len) | 91 | static const char *iwl_escape_essid(const char *essid, u8 essid_len) |
92 | { | 92 | { |
93 | static char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; | 93 | static char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; |
94 | const char *s = essid; | 94 | const char *s = essid; |
@@ -111,7 +111,6 @@ const char *iwl_escape_essid(const char *essid, u8 essid_len) | |||
111 | *d = '\0'; | 111 | *d = '\0'; |
112 | return escaped; | 112 | return escaped; |
113 | } | 113 | } |
114 | EXPORT_SYMBOL(iwl_escape_essid); | ||
115 | 114 | ||
116 | /** | 115 | /** |
117 | * iwl_scan_cancel - Cancel any currently executing HW scan | 116 | * iwl_scan_cancel - Cancel any currently executing HW scan |
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 5b7b05c8773f..a72569f1acb5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c | |||
@@ -191,20 +191,20 @@ static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index, | |||
191 | if (!sta_ht_inf || !sta_ht_inf->ht_supported) | 191 | if (!sta_ht_inf || !sta_ht_inf->ht_supported) |
192 | goto done; | 192 | goto done; |
193 | 193 | ||
194 | mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2; | 194 | mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_SM_PS) >> 2; |
195 | 195 | ||
196 | sta_flags = priv->stations[index].sta.station_flags; | 196 | sta_flags = priv->stations[index].sta.station_flags; |
197 | 197 | ||
198 | sta_flags &= ~(STA_FLG_RTS_MIMO_PROT_MSK | STA_FLG_MIMO_DIS_MSK); | 198 | sta_flags &= ~(STA_FLG_RTS_MIMO_PROT_MSK | STA_FLG_MIMO_DIS_MSK); |
199 | 199 | ||
200 | switch (mimo_ps_mode) { | 200 | switch (mimo_ps_mode) { |
201 | case WLAN_HT_CAP_MIMO_PS_STATIC: | 201 | case WLAN_HT_CAP_SM_PS_STATIC: |
202 | sta_flags |= STA_FLG_MIMO_DIS_MSK; | 202 | sta_flags |= STA_FLG_MIMO_DIS_MSK; |
203 | break; | 203 | break; |
204 | case WLAN_HT_CAP_MIMO_PS_DYNAMIC: | 204 | case WLAN_HT_CAP_SM_PS_DYNAMIC: |
205 | sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK; | 205 | sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK; |
206 | break; | 206 | break; |
207 | case WLAN_HT_CAP_MIMO_PS_DISABLED: | 207 | case WLAN_HT_CAP_SM_PS_DISABLED: |
208 | break; | 208 | break; |
209 | default: | 209 | default: |
210 | IWL_WARNING("Invalid MIMO PS mode %d\n", mimo_ps_mode); | 210 | IWL_WARNING("Invalid MIMO PS mode %d\n", mimo_ps_mode); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 9d485aadef96..9d5bcf46cbe9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c | |||
@@ -63,7 +63,7 @@ static const u16 default_tid_to_tx_fifo[] = { | |||
63 | * Does NOT advance any TFD circular buffer read/write indexes | 63 | * Does NOT advance any TFD circular buffer read/write indexes |
64 | * Does NOT free the TFD itself (which is within circular buffer) | 64 | * Does NOT free the TFD itself (which is within circular buffer) |
65 | */ | 65 | */ |
66 | int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) | 66 | static int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) |
67 | { | 67 | { |
68 | struct iwl_tfd_frame *bd_tmp = (struct iwl_tfd_frame *)&txq->bd[0]; | 68 | struct iwl_tfd_frame *bd_tmp = (struct iwl_tfd_frame *)&txq->bd[0]; |
69 | struct iwl_tfd_frame *bd = &bd_tmp[txq->q.read_ptr]; | 69 | struct iwl_tfd_frame *bd = &bd_tmp[txq->q.read_ptr]; |
@@ -115,10 +115,8 @@ int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) | |||
115 | } | 115 | } |
116 | return 0; | 116 | return 0; |
117 | } | 117 | } |
118 | EXPORT_SYMBOL(iwl_hw_txq_free_tfd); | ||
119 | 118 | ||
120 | 119 | static int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr, | |
121 | int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr, | ||
122 | dma_addr_t addr, u16 len) | 120 | dma_addr_t addr, u16 len) |
123 | { | 121 | { |
124 | int index, is_odd; | 122 | int index, is_odd; |
@@ -151,7 +149,6 @@ int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr, | |||
151 | 149 | ||
152 | return 0; | 150 | return 0; |
153 | } | 151 | } |
154 | EXPORT_SYMBOL(iwl_hw_txq_attach_buf_to_tfd); | ||
155 | 152 | ||
156 | /** | 153 | /** |
157 | * iwl_txq_update_write_ptr - Send new write index to hardware | 154 | * iwl_txq_update_write_ptr - Send new write index to hardware |
@@ -478,7 +475,6 @@ void iwl_hw_txq_ctx_free(struct iwl_priv *priv) | |||
478 | } | 475 | } |
479 | EXPORT_SYMBOL(iwl_hw_txq_ctx_free); | 476 | EXPORT_SYMBOL(iwl_hw_txq_ctx_free); |
480 | 477 | ||
481 | |||
482 | /** | 478 | /** |
483 | * iwl_txq_ctx_reset - Reset TX queue context | 479 | * iwl_txq_ctx_reset - Reset TX queue context |
484 | * Destroys all DMA structures and initialise them again | 480 | * Destroys all DMA structures and initialise them again |
@@ -545,6 +541,7 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv) | |||
545 | error_kw: | 541 | error_kw: |
546 | return ret; | 542 | return ret; |
547 | } | 543 | } |
544 | |||
548 | /** | 545 | /** |
549 | * iwl_txq_ctx_stop - Stop all Tx DMA channels, free Tx queue memory | 546 | * iwl_txq_ctx_stop - Stop all Tx DMA channels, free Tx queue memory |
550 | */ | 547 | */ |
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 802547e79671..5fef05f3cd00 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c | |||
@@ -1971,6 +1971,70 @@ void lbs_ps_confirm_sleep(struct lbs_private *priv) | |||
1971 | } | 1971 | } |
1972 | 1972 | ||
1973 | 1973 | ||
1974 | /** | ||
1975 | * @brief Configures the transmission power control functionality. | ||
1976 | * | ||
1977 | * @param priv A pointer to struct lbs_private structure | ||
1978 | * @param enable Transmission power control enable | ||
1979 | * @param p0 Power level when link quality is good (dBm). | ||
1980 | * @param p1 Power level when link quality is fair (dBm). | ||
1981 | * @param p2 Power level when link quality is poor (dBm). | ||
1982 | * @param usesnr Use Signal to Noise Ratio in TPC | ||
1983 | * | ||
1984 | * @return 0 on success | ||
1985 | */ | ||
1986 | int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1, | ||
1987 | int8_t p2, int usesnr) | ||
1988 | { | ||
1989 | struct cmd_ds_802_11_tpc_cfg cmd; | ||
1990 | int ret; | ||
1991 | |||
1992 | memset(&cmd, 0, sizeof(cmd)); | ||
1993 | cmd.hdr.size = cpu_to_le16(sizeof(cmd)); | ||
1994 | cmd.action = cpu_to_le16(CMD_ACT_SET); | ||
1995 | cmd.enable = !!enable; | ||
1996 | cmd.usesnr = !!enable; | ||
1997 | cmd.P0 = p0; | ||
1998 | cmd.P1 = p1; | ||
1999 | cmd.P2 = p2; | ||
2000 | |||
2001 | ret = lbs_cmd_with_response(priv, CMD_802_11_TPC_CFG, &cmd); | ||
2002 | |||
2003 | return ret; | ||
2004 | } | ||
2005 | |||
2006 | /** | ||
2007 | * @brief Configures the power adaptation settings. | ||
2008 | * | ||
2009 | * @param priv A pointer to struct lbs_private structure | ||
2010 | * @param enable Power adaptation enable | ||
2011 | * @param p0 Power level for 1, 2, 5.5 and 11 Mbps (dBm). | ||
2012 | * @param p1 Power level for 6, 9, 12, 18, 22, 24 and 36 Mbps (dBm). | ||
2013 | * @param p2 Power level for 48 and 54 Mbps (dBm). | ||
2014 | * | ||
2015 | * @return 0 on Success | ||
2016 | */ | ||
2017 | |||
2018 | int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0, | ||
2019 | int8_t p1, int8_t p2) | ||
2020 | { | ||
2021 | struct cmd_ds_802_11_pa_cfg cmd; | ||
2022 | int ret; | ||
2023 | |||
2024 | memset(&cmd, 0, sizeof(cmd)); | ||
2025 | cmd.hdr.size = cpu_to_le16(sizeof(cmd)); | ||
2026 | cmd.action = cpu_to_le16(CMD_ACT_SET); | ||
2027 | cmd.enable = !!enable; | ||
2028 | cmd.P0 = p0; | ||
2029 | cmd.P1 = p1; | ||
2030 | cmd.P2 = p2; | ||
2031 | |||
2032 | ret = lbs_cmd_with_response(priv, CMD_802_11_PA_CFG , &cmd); | ||
2033 | |||
2034 | return ret; | ||
2035 | } | ||
2036 | |||
2037 | |||
1974 | static struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv, | 2038 | static struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv, |
1975 | uint16_t command, struct cmd_header *in_cmd, int in_cmd_size, | 2039 | uint16_t command, struct cmd_header *in_cmd, int in_cmd_size, |
1976 | int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *), | 2040 | int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *), |
diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h index 11ac996e895e..336a181d857a 100644 --- a/drivers/net/wireless/libertas/cmd.h +++ b/drivers/net/wireless/libertas/cmd.h | |||
@@ -26,6 +26,12 @@ int __lbs_cmd(struct lbs_private *priv, uint16_t command, | |||
26 | int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *), | 26 | int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *), |
27 | unsigned long callback_arg); | 27 | unsigned long callback_arg); |
28 | 28 | ||
29 | int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0, | ||
30 | int8_t p1, int8_t p2); | ||
31 | |||
32 | int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1, | ||
33 | int8_t p2, int usesnr); | ||
34 | |||
29 | int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra, | 35 | int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra, |
30 | struct cmd_header *resp); | 36 | struct cmd_header *resp); |
31 | 37 | ||
diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index 4b2428ac2223..c89d7a1041a8 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h | |||
@@ -189,6 +189,15 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in | |||
189 | #define MRVDRV_CMD_UPLD_RDY 0x0008 | 189 | #define MRVDRV_CMD_UPLD_RDY 0x0008 |
190 | #define MRVDRV_CARDEVENT 0x0010 | 190 | #define MRVDRV_CARDEVENT 0x0010 |
191 | 191 | ||
192 | |||
193 | /* Automatic TX control default levels */ | ||
194 | #define POW_ADAPT_DEFAULT_P0 13 | ||
195 | #define POW_ADAPT_DEFAULT_P1 15 | ||
196 | #define POW_ADAPT_DEFAULT_P2 18 | ||
197 | #define TPC_DEFAULT_P0 5 | ||
198 | #define TPC_DEFAULT_P1 10 | ||
199 | #define TPC_DEFAULT_P2 13 | ||
200 | |||
192 | /** TxPD status */ | 201 | /** TxPD status */ |
193 | 202 | ||
194 | /* Station firmware use TxPD status field to report final Tx transmit | 203 | /* Station firmware use TxPD status field to report final Tx transmit |
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index da618fc997ce..a916bb9bd5da 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h | |||
@@ -83,6 +83,7 @@ | |||
83 | #define CMD_802_11_INACTIVITY_TIMEOUT 0x0067 | 83 | #define CMD_802_11_INACTIVITY_TIMEOUT 0x0067 |
84 | #define CMD_802_11_SLEEP_PERIOD 0x0068 | 84 | #define CMD_802_11_SLEEP_PERIOD 0x0068 |
85 | #define CMD_802_11_TPC_CFG 0x0072 | 85 | #define CMD_802_11_TPC_CFG 0x0072 |
86 | #define CMD_802_11_PA_CFG 0x0073 | ||
86 | #define CMD_802_11_FW_WAKE_METHOD 0x0074 | 87 | #define CMD_802_11_FW_WAKE_METHOD 0x0074 |
87 | #define CMD_802_11_SUBSCRIBE_EVENT 0x0075 | 88 | #define CMD_802_11_SUBSCRIBE_EVENT 0x0075 |
88 | #define CMD_802_11_RATE_ADAPT_RATESET 0x0076 | 89 | #define CMD_802_11_RATE_ADAPT_RATESET 0x0076 |
diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index d27c276b2191..630b79967560 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h | |||
@@ -607,14 +607,28 @@ struct cmd_ds_802_11_eeprom_access { | |||
607 | } __attribute__ ((packed)); | 607 | } __attribute__ ((packed)); |
608 | 608 | ||
609 | struct cmd_ds_802_11_tpc_cfg { | 609 | struct cmd_ds_802_11_tpc_cfg { |
610 | struct cmd_header hdr; | ||
611 | |||
610 | __le16 action; | 612 | __le16 action; |
611 | u8 enable; | 613 | uint8_t enable; |
612 | s8 P0; | 614 | int8_t P0; |
613 | s8 P1; | 615 | int8_t P1; |
614 | s8 P2; | 616 | int8_t P2; |
615 | u8 usesnr; | 617 | uint8_t usesnr; |
616 | } __attribute__ ((packed)); | 618 | } __attribute__ ((packed)); |
617 | 619 | ||
620 | |||
621 | struct cmd_ds_802_11_pa_cfg { | ||
622 | struct cmd_header hdr; | ||
623 | |||
624 | __le16 action; | ||
625 | uint8_t enable; | ||
626 | int8_t P0; | ||
627 | int8_t P1; | ||
628 | int8_t P2; | ||
629 | } __attribute__ ((packed)); | ||
630 | |||
631 | |||
618 | struct cmd_ds_802_11_led_ctrl { | 632 | struct cmd_ds_802_11_led_ctrl { |
619 | __le16 action; | 633 | __le16 action; |
620 | __le16 numled; | 634 | __le16 numled; |
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 2436634b6b7e..73dc8c72402a 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c | |||
@@ -1205,7 +1205,13 @@ void lbs_remove_card(struct lbs_private *priv) | |||
1205 | cancel_delayed_work_sync(&priv->scan_work); | 1205 | cancel_delayed_work_sync(&priv->scan_work); |
1206 | cancel_delayed_work_sync(&priv->assoc_work); | 1206 | cancel_delayed_work_sync(&priv->assoc_work); |
1207 | cancel_work_sync(&priv->mcast_work); | 1207 | cancel_work_sync(&priv->mcast_work); |
1208 | |||
1209 | /* worker thread destruction blocks on the in-flight command which | ||
1210 | * should have been cleared already in lbs_stop_card(). | ||
1211 | */ | ||
1212 | lbs_deb_main("destroying worker thread\n"); | ||
1208 | destroy_workqueue(priv->work_thread); | 1213 | destroy_workqueue(priv->work_thread); |
1214 | lbs_deb_main("done destroying worker thread\n"); | ||
1209 | 1215 | ||
1210 | if (priv->psmode == LBS802_11POWERMODEMAX_PSP) { | 1216 | if (priv->psmode == LBS802_11POWERMODEMAX_PSP) { |
1211 | priv->psmode = LBS802_11POWERMODECAM; | 1217 | priv->psmode = LBS802_11POWERMODECAM; |
@@ -1323,14 +1329,26 @@ void lbs_stop_card(struct lbs_private *priv) | |||
1323 | device_remove_file(&dev->dev, &dev_attr_lbs_rtap); | 1329 | device_remove_file(&dev->dev, &dev_attr_lbs_rtap); |
1324 | } | 1330 | } |
1325 | 1331 | ||
1326 | /* Flush pending command nodes */ | 1332 | /* Delete the timeout of the currently processing command */ |
1327 | del_timer_sync(&priv->command_timer); | 1333 | del_timer_sync(&priv->command_timer); |
1334 | |||
1335 | /* Flush pending command nodes */ | ||
1328 | spin_lock_irqsave(&priv->driver_lock, flags); | 1336 | spin_lock_irqsave(&priv->driver_lock, flags); |
1337 | lbs_deb_main("clearing pending commands\n"); | ||
1329 | list_for_each_entry(cmdnode, &priv->cmdpendingq, list) { | 1338 | list_for_each_entry(cmdnode, &priv->cmdpendingq, list) { |
1330 | cmdnode->result = -ENOENT; | 1339 | cmdnode->result = -ENOENT; |
1331 | cmdnode->cmdwaitqwoken = 1; | 1340 | cmdnode->cmdwaitqwoken = 1; |
1332 | wake_up_interruptible(&cmdnode->cmdwait_q); | 1341 | wake_up_interruptible(&cmdnode->cmdwait_q); |
1333 | } | 1342 | } |
1343 | |||
1344 | /* Flush the command the card is currently processing */ | ||
1345 | if (priv->cur_cmd) { | ||
1346 | lbs_deb_main("clearing current command\n"); | ||
1347 | priv->cur_cmd->result = -ENOENT; | ||
1348 | priv->cur_cmd->cmdwaitqwoken = 1; | ||
1349 | wake_up_interruptible(&priv->cur_cmd->cmdwait_q); | ||
1350 | } | ||
1351 | lbs_deb_main("done clearing commands\n"); | ||
1334 | spin_unlock_irqrestore(&priv->driver_lock, flags); | 1352 | spin_unlock_irqrestore(&priv->driver_lock, flags); |
1335 | 1353 | ||
1336 | unregister_netdev(dev); | 1354 | unregister_netdev(dev); |
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 426f1fe3bb42..e8cadad2c863 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c | |||
@@ -1820,7 +1820,21 @@ static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info, | |||
1820 | } | 1820 | } |
1821 | 1821 | ||
1822 | if (vwrq->fixed == 0) { | 1822 | if (vwrq->fixed == 0) { |
1823 | /* Auto power control */ | 1823 | /* User requests automatic tx power control, however there are |
1824 | * many auto tx settings. For now use firmware defaults until | ||
1825 | * we come up with a good way to expose these to the user. */ | ||
1826 | if (priv->fwrelease < 0x09000000) { | ||
1827 | ret = lbs_set_power_adapt_cfg(priv, 1, | ||
1828 | POW_ADAPT_DEFAULT_P0, | ||
1829 | POW_ADAPT_DEFAULT_P1, | ||
1830 | POW_ADAPT_DEFAULT_P2); | ||
1831 | if (ret) | ||
1832 | goto out; | ||
1833 | } | ||
1834 | ret = lbs_set_tpc_cfg(priv, 0, TPC_DEFAULT_P0, TPC_DEFAULT_P1, | ||
1835 | TPC_DEFAULT_P2, 1); | ||
1836 | if (ret) | ||
1837 | goto out; | ||
1824 | dbm = priv->txpower_max; | 1838 | dbm = priv->txpower_max; |
1825 | } else { | 1839 | } else { |
1826 | /* Userspace check in iwrange if it should use dBm or mW, | 1840 | /* Userspace check in iwrange if it should use dBm or mW, |
@@ -1830,7 +1844,8 @@ static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info, | |||
1830 | goto out; | 1844 | goto out; |
1831 | } | 1845 | } |
1832 | 1846 | ||
1833 | /* Validate requested power level against firmware allowed levels */ | 1847 | /* Validate requested power level against firmware allowed |
1848 | * levels */ | ||
1834 | if (priv->txpower_min && (dbm < priv->txpower_min)) { | 1849 | if (priv->txpower_min && (dbm < priv->txpower_min)) { |
1835 | ret = -EINVAL; | 1850 | ret = -EINVAL; |
1836 | goto out; | 1851 | goto out; |
@@ -1840,6 +1855,18 @@ static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info, | |||
1840 | ret = -EINVAL; | 1855 | ret = -EINVAL; |
1841 | goto out; | 1856 | goto out; |
1842 | } | 1857 | } |
1858 | if (priv->fwrelease < 0x09000000) { | ||
1859 | ret = lbs_set_power_adapt_cfg(priv, 0, | ||
1860 | POW_ADAPT_DEFAULT_P0, | ||
1861 | POW_ADAPT_DEFAULT_P1, | ||
1862 | POW_ADAPT_DEFAULT_P2); | ||
1863 | if (ret) | ||
1864 | goto out; | ||
1865 | } | ||
1866 | ret = lbs_set_tpc_cfg(priv, 0, TPC_DEFAULT_P0, TPC_DEFAULT_P1, | ||
1867 | TPC_DEFAULT_P2, 1); | ||
1868 | if (ret) | ||
1869 | goto out; | ||
1843 | } | 1870 | } |
1844 | 1871 | ||
1845 | /* If the radio was off, turn it on */ | 1872 | /* If the radio was off, turn it on */ |
diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 98d4f8e7d84d..1d0704fe146f 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h | |||
@@ -80,6 +80,7 @@ struct p54_common { | |||
80 | struct pda_channel_output_limit *output_limit; | 80 | struct pda_channel_output_limit *output_limit; |
81 | unsigned int output_limit_len; | 81 | unsigned int output_limit_len; |
82 | struct pda_pa_curve_data *curve_data; | 82 | struct pda_pa_curve_data *curve_data; |
83 | unsigned int filter_flags; | ||
83 | u16 rxhw; | 84 | u16 rxhw; |
84 | u8 version; | 85 | u8 version; |
85 | u8 rx_antenna; | 86 | u8 rx_antenna; |
@@ -87,7 +88,15 @@ struct p54_common { | |||
87 | void *cached_vdcf; | 88 | void *cached_vdcf; |
88 | unsigned int fw_var; | 89 | unsigned int fw_var; |
89 | unsigned int fw_interface; | 90 | unsigned int fw_interface; |
91 | unsigned int output_power; | ||
92 | u32 tsf_low32; | ||
93 | u32 tsf_high32; | ||
90 | struct ieee80211_tx_queue_stats tx_stats[8]; | 94 | struct ieee80211_tx_queue_stats tx_stats[8]; |
95 | struct ieee80211_low_level_stats stats; | ||
96 | struct timer_list stats_timer; | ||
97 | struct completion stats_comp; | ||
98 | void *cached_stats; | ||
99 | int noise; | ||
91 | void *eeprom; | 100 | void *eeprom; |
92 | struct completion eeprom_comp; | 101 | struct completion eeprom_comp; |
93 | }; | 102 | }; |
diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index f96f7c7e6af5..da51786254dc 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c | |||
@@ -27,7 +27,7 @@ MODULE_DESCRIPTION("Softmac Prism54 common code"); | |||
27 | MODULE_LICENSE("GPL"); | 27 | MODULE_LICENSE("GPL"); |
28 | MODULE_ALIAS("prism54common"); | 28 | MODULE_ALIAS("prism54common"); |
29 | 29 | ||
30 | static struct ieee80211_rate p54_rates[] = { | 30 | static struct ieee80211_rate p54_bgrates[] = { |
31 | { .bitrate = 10, .hw_value = 0, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, | 31 | { .bitrate = 10, .hw_value = 0, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, |
32 | { .bitrate = 20, .hw_value = 1, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, | 32 | { .bitrate = 20, .hw_value = 1, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, |
33 | { .bitrate = 55, .hw_value = 2, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, | 33 | { .bitrate = 55, .hw_value = 2, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, |
@@ -42,7 +42,7 @@ static struct ieee80211_rate p54_rates[] = { | |||
42 | { .bitrate = 540, .hw_value = 11, }, | 42 | { .bitrate = 540, .hw_value = 11, }, |
43 | }; | 43 | }; |
44 | 44 | ||
45 | static struct ieee80211_channel p54_channels[] = { | 45 | static struct ieee80211_channel p54_bgchannels[] = { |
46 | { .center_freq = 2412, .hw_value = 1, }, | 46 | { .center_freq = 2412, .hw_value = 1, }, |
47 | { .center_freq = 2417, .hw_value = 2, }, | 47 | { .center_freq = 2417, .hw_value = 2, }, |
48 | { .center_freq = 2422, .hw_value = 3, }, | 48 | { .center_freq = 2422, .hw_value = 3, }, |
@@ -60,10 +60,66 @@ static struct ieee80211_channel p54_channels[] = { | |||
60 | }; | 60 | }; |
61 | 61 | ||
62 | static struct ieee80211_supported_band band_2GHz = { | 62 | static struct ieee80211_supported_band band_2GHz = { |
63 | .channels = p54_channels, | 63 | .channels = p54_bgchannels, |
64 | .n_channels = ARRAY_SIZE(p54_channels), | 64 | .n_channels = ARRAY_SIZE(p54_bgchannels), |
65 | .bitrates = p54_rates, | 65 | .bitrates = p54_bgrates, |
66 | .n_bitrates = ARRAY_SIZE(p54_rates), | 66 | .n_bitrates = ARRAY_SIZE(p54_bgrates), |
67 | }; | ||
68 | |||
69 | static struct ieee80211_rate p54_arates[] = { | ||
70 | { .bitrate = 60, .hw_value = 4, }, | ||
71 | { .bitrate = 90, .hw_value = 5, }, | ||
72 | { .bitrate = 120, .hw_value = 6, }, | ||
73 | { .bitrate = 180, .hw_value = 7, }, | ||
74 | { .bitrate = 240, .hw_value = 8, }, | ||
75 | { .bitrate = 360, .hw_value = 9, }, | ||
76 | { .bitrate = 480, .hw_value = 10, }, | ||
77 | { .bitrate = 540, .hw_value = 11, }, | ||
78 | }; | ||
79 | |||
80 | static struct ieee80211_channel p54_achannels[] = { | ||
81 | { .center_freq = 4920 }, | ||
82 | { .center_freq = 4940 }, | ||
83 | { .center_freq = 4960 }, | ||
84 | { .center_freq = 4980 }, | ||
85 | { .center_freq = 5040 }, | ||
86 | { .center_freq = 5060 }, | ||
87 | { .center_freq = 5080 }, | ||
88 | { .center_freq = 5170 }, | ||
89 | { .center_freq = 5180 }, | ||
90 | { .center_freq = 5190 }, | ||
91 | { .center_freq = 5200 }, | ||
92 | { .center_freq = 5210 }, | ||
93 | { .center_freq = 5220 }, | ||
94 | { .center_freq = 5230 }, | ||
95 | { .center_freq = 5240 }, | ||
96 | { .center_freq = 5260 }, | ||
97 | { .center_freq = 5280 }, | ||
98 | { .center_freq = 5300 }, | ||
99 | { .center_freq = 5320 }, | ||
100 | { .center_freq = 5500 }, | ||
101 | { .center_freq = 5520 }, | ||
102 | { .center_freq = 5540 }, | ||
103 | { .center_freq = 5560 }, | ||
104 | { .center_freq = 5580 }, | ||
105 | { .center_freq = 5600 }, | ||
106 | { .center_freq = 5620 }, | ||
107 | { .center_freq = 5640 }, | ||
108 | { .center_freq = 5660 }, | ||
109 | { .center_freq = 5680 }, | ||
110 | { .center_freq = 5700 }, | ||
111 | { .center_freq = 5745 }, | ||
112 | { .center_freq = 5765 }, | ||
113 | { .center_freq = 5785 }, | ||
114 | { .center_freq = 5805 }, | ||
115 | { .center_freq = 5825 }, | ||
116 | }; | ||
117 | |||
118 | static struct ieee80211_supported_band band_5GHz = { | ||
119 | .channels = p54_achannels, | ||
120 | .n_channels = ARRAY_SIZE(p54_achannels), | ||
121 | .bitrates = p54_arates, | ||
122 | .n_bitrates = ARRAY_SIZE(p54_arates), | ||
67 | }; | 123 | }; |
68 | 124 | ||
69 | int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) | 125 | int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) |
@@ -252,6 +308,7 @@ static int p54_convert_rev1(struct ieee80211_hw *dev, | |||
252 | 308 | ||
253 | const char* p54_rf_chips[] = { "NULL", "Indigo?", "Duette", | 309 | const char* p54_rf_chips[] = { "NULL", "Indigo?", "Duette", |
254 | "Frisbee", "Xbow", "Longbow" }; | 310 | "Frisbee", "Xbow", "Longbow" }; |
311 | static int p54_init_xbow_synth(struct ieee80211_hw *dev); | ||
255 | 312 | ||
256 | int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) | 313 | int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) |
257 | { | 314 | { |
@@ -371,20 +428,20 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) | |||
371 | } | 428 | } |
372 | 429 | ||
373 | switch (priv->rxhw) { | 430 | switch (priv->rxhw) { |
374 | case 4: /* XBow */ | 431 | case 4: /* XBow */ |
375 | case 1: /* Indigo? */ | 432 | p54_init_xbow_synth(dev); |
376 | case 2: /* Duette */ | 433 | case 1: /* Indigo? */ |
377 | /* TODO: 5GHz initialization goes here */ | 434 | case 2: /* Duette */ |
378 | 435 | dev->wiphy->bands[IEEE80211_BAND_5GHZ] = &band_5GHz; | |
379 | case 3: /* Frisbee */ | 436 | case 3: /* Frisbee */ |
380 | case 5: /* Longbow */ | 437 | case 5: /* Longbow */ |
381 | dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz; | 438 | dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz; |
382 | break; | 439 | break; |
383 | default: | 440 | default: |
384 | printk(KERN_ERR "%s: unsupported RF-Chip\n", | 441 | printk(KERN_ERR "%s: unsupported RF-Chip\n", |
385 | wiphy_name(dev->wiphy)); | 442 | wiphy_name(dev->wiphy)); |
386 | err = -EINVAL; | 443 | err = -EINVAL; |
387 | goto err; | 444 | goto err; |
388 | } | 445 | } |
389 | 446 | ||
390 | if (!is_valid_ether_addr(dev->wiphy->perm_addr)) { | 447 | if (!is_valid_ether_addr(dev->wiphy->perm_addr)) { |
@@ -424,21 +481,43 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) | |||
424 | } | 481 | } |
425 | EXPORT_SYMBOL_GPL(p54_parse_eeprom); | 482 | EXPORT_SYMBOL_GPL(p54_parse_eeprom); |
426 | 483 | ||
484 | static int p54_rssi_to_dbm(struct ieee80211_hw *dev, int rssi) | ||
485 | { | ||
486 | /* TODO: get the rssi_add & rssi_mul data from the eeprom */ | ||
487 | return ((rssi * 0x83) / 64 - 400) / 4; | ||
488 | } | ||
489 | |||
427 | static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) | 490 | static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) |
428 | { | 491 | { |
492 | struct p54_common *priv = dev->priv; | ||
429 | struct p54_rx_hdr *hdr = (struct p54_rx_hdr *) skb->data; | 493 | struct p54_rx_hdr *hdr = (struct p54_rx_hdr *) skb->data; |
430 | struct ieee80211_rx_status rx_status = {0}; | 494 | struct ieee80211_rx_status rx_status = {0}; |
431 | u16 freq = le16_to_cpu(hdr->freq); | 495 | u16 freq = le16_to_cpu(hdr->freq); |
432 | size_t header_len = sizeof(*hdr); | 496 | size_t header_len = sizeof(*hdr); |
497 | u32 tsf32; | ||
433 | 498 | ||
434 | rx_status.signal = hdr->rssi; | 499 | if (!(hdr->magic & cpu_to_le16(0x0001))) { |
500 | if (priv->filter_flags & FIF_FCSFAIL) | ||
501 | rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; | ||
502 | else | ||
503 | return 0; | ||
504 | } | ||
505 | |||
506 | rx_status.signal = p54_rssi_to_dbm(dev, hdr->rssi); | ||
507 | rx_status.noise = priv->noise; | ||
435 | /* XX correct? */ | 508 | /* XX correct? */ |
436 | rx_status.qual = (100 * hdr->rssi) / 127; | 509 | rx_status.qual = (100 * hdr->rssi) / 127; |
437 | rx_status.rate_idx = hdr->rate & 0xf; | 510 | rx_status.rate_idx = hdr->rate & 0xf; |
438 | rx_status.freq = freq; | 511 | rx_status.freq = freq; |
439 | rx_status.band = IEEE80211_BAND_2GHZ; | 512 | rx_status.band = IEEE80211_BAND_2GHZ; |
440 | rx_status.antenna = hdr->antenna; | 513 | rx_status.antenna = hdr->antenna; |
441 | rx_status.mactime = le64_to_cpu(hdr->timestamp); | 514 | |
515 | tsf32 = le32_to_cpu(hdr->tsf32); | ||
516 | if (tsf32 < priv->tsf_low32) | ||
517 | priv->tsf_high32++; | ||
518 | rx_status.mactime = ((u64)priv->tsf_high32) << 32 | tsf32; | ||
519 | priv->tsf_low32 = tsf32; | ||
520 | |||
442 | rx_status.flag |= RX_FLAG_TSFT; | 521 | rx_status.flag |= RX_FLAG_TSFT; |
443 | 522 | ||
444 | if (hdr->magic & cpu_to_le16(0x4000)) | 523 | if (hdr->magic & cpu_to_le16(0x4000)) |
@@ -511,7 +590,8 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) | |||
511 | info->status.excessive_retries = 1; | 590 | info->status.excessive_retries = 1; |
512 | } | 591 | } |
513 | info->status.retry_count = payload->retries - 1; | 592 | info->status.retry_count = payload->retries - 1; |
514 | info->status.ack_signal = le16_to_cpu(payload->ack_rssi); | 593 | info->status.ack_signal = p54_rssi_to_dbm(dev, |
594 | le16_to_cpu(payload->ack_rssi)); | ||
515 | skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data)); | 595 | skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data)); |
516 | ieee80211_tx_status_irqsafe(dev, entry); | 596 | ieee80211_tx_status_irqsafe(dev, entry); |
517 | goto out; | 597 | goto out; |
@@ -542,6 +622,27 @@ static void p54_rx_eeprom_readback(struct ieee80211_hw *dev, | |||
542 | complete(&priv->eeprom_comp); | 622 | complete(&priv->eeprom_comp); |
543 | } | 623 | } |
544 | 624 | ||
625 | static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb) | ||
626 | { | ||
627 | struct p54_common *priv = dev->priv; | ||
628 | struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data; | ||
629 | struct p54_statistics *stats = (struct p54_statistics *) hdr->data; | ||
630 | u32 tsf32 = le32_to_cpu(stats->tsf32); | ||
631 | |||
632 | if (tsf32 < priv->tsf_low32) | ||
633 | priv->tsf_high32++; | ||
634 | priv->tsf_low32 = tsf32; | ||
635 | |||
636 | priv->stats.dot11RTSFailureCount = le32_to_cpu(stats->rts_fail); | ||
637 | priv->stats.dot11RTSSuccessCount = le32_to_cpu(stats->rts_success); | ||
638 | priv->stats.dot11FCSErrorCount = le32_to_cpu(stats->rx_bad_fcs); | ||
639 | |||
640 | priv->noise = p54_rssi_to_dbm(dev, le32_to_cpu(stats->noise)); | ||
641 | complete(&priv->stats_comp); | ||
642 | |||
643 | mod_timer(&priv->stats_timer, jiffies + 5 * HZ); | ||
644 | } | ||
645 | |||
545 | static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb) | 646 | static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb) |
546 | { | 647 | { |
547 | struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data; | 648 | struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data; |
@@ -552,6 +653,9 @@ static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb) | |||
552 | break; | 653 | break; |
553 | case P54_CONTROL_TYPE_BBP: | 654 | case P54_CONTROL_TYPE_BBP: |
554 | break; | 655 | break; |
656 | case P54_CONTROL_TYPE_STAT_READBACK: | ||
657 | p54_rx_stats(dev, skb); | ||
658 | break; | ||
555 | case P54_CONTROL_TYPE_EEPROM_READBACK: | 659 | case P54_CONTROL_TYPE_EEPROM_READBACK: |
556 | p54_rx_eeprom_readback(dev, skb); | 660 | p54_rx_eeprom_readback(dev, skb); |
557 | break; | 661 | break; |
@@ -753,7 +857,7 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) | |||
753 | txhdr->hw_queue = skb_get_queue_mapping(skb) + 4; | 857 | txhdr->hw_queue = skb_get_queue_mapping(skb) + 4; |
754 | txhdr->tx_antenna = (info->antenna_sel_tx == 0) ? | 858 | txhdr->tx_antenna = (info->antenna_sel_tx == 0) ? |
755 | 2 : info->antenna_sel_tx - 1; | 859 | 2 : info->antenna_sel_tx - 1; |
756 | txhdr->output_power = 0x7f; // HW Maximum | 860 | txhdr->output_power = priv->output_power; |
757 | txhdr->cts_rate = (info->flags & IEEE80211_TX_CTL_NO_ACK) ? | 861 | txhdr->cts_rate = (info->flags & IEEE80211_TX_CTL_NO_ACK) ? |
758 | 0 : cts_rate; | 862 | 0 : cts_rate; |
759 | if (padding) | 863 | if (padding) |
@@ -1021,12 +1125,25 @@ static int p54_start(struct ieee80211_hw *dev) | |||
1021 | return -ENOMEM; | 1125 | return -ENOMEM; |
1022 | } | 1126 | } |
1023 | 1127 | ||
1128 | if (!priv->cached_stats) { | ||
1129 | priv->cached_stats = kzalloc(sizeof(struct p54_statistics) + | ||
1130 | priv->tx_hdr_len + sizeof(struct p54_control_hdr), | ||
1131 | GFP_KERNEL); | ||
1132 | |||
1133 | if (!priv->cached_stats) { | ||
1134 | kfree(priv->cached_vdcf); | ||
1135 | priv->cached_vdcf = NULL; | ||
1136 | return -ENOMEM; | ||
1137 | } | ||
1138 | } | ||
1139 | |||
1024 | err = priv->open(dev); | 1140 | err = priv->open(dev); |
1025 | if (!err) | 1141 | if (!err) |
1026 | priv->mode = IEEE80211_IF_TYPE_MNTR; | 1142 | priv->mode = IEEE80211_IF_TYPE_MNTR; |
1027 | 1143 | ||
1028 | p54_init_vdcf(dev); | 1144 | p54_init_vdcf(dev); |
1029 | 1145 | ||
1146 | mod_timer(&priv->stats_timer, jiffies + HZ); | ||
1030 | return err; | 1147 | return err; |
1031 | } | 1148 | } |
1032 | 1149 | ||
@@ -1034,9 +1151,12 @@ static void p54_stop(struct ieee80211_hw *dev) | |||
1034 | { | 1151 | { |
1035 | struct p54_common *priv = dev->priv; | 1152 | struct p54_common *priv = dev->priv; |
1036 | struct sk_buff *skb; | 1153 | struct sk_buff *skb; |
1154 | |||
1155 | del_timer(&priv->stats_timer); | ||
1037 | while ((skb = skb_dequeue(&priv->tx_queue))) | 1156 | while ((skb = skb_dequeue(&priv->tx_queue))) |
1038 | kfree_skb(skb); | 1157 | kfree_skb(skb); |
1039 | priv->stop(dev); | 1158 | priv->stop(dev); |
1159 | priv->tsf_high32 = priv->tsf_low32 = 0; | ||
1040 | priv->mode = IEEE80211_IF_TYPE_INVALID; | 1160 | priv->mode = IEEE80211_IF_TYPE_INVALID; |
1041 | } | 1161 | } |
1042 | 1162 | ||
@@ -1091,6 +1211,7 @@ static int p54_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) | |||
1091 | mutex_lock(&priv->conf_mutex); | 1211 | mutex_lock(&priv->conf_mutex); |
1092 | priv->rx_antenna = (conf->antenna_sel_rx == 0) ? | 1212 | priv->rx_antenna = (conf->antenna_sel_rx == 0) ? |
1093 | 2 : conf->antenna_sel_tx - 1; | 1213 | 2 : conf->antenna_sel_tx - 1; |
1214 | priv->output_power = conf->power_level << 2; | ||
1094 | ret = p54_set_freq(dev, cpu_to_le16(conf->channel->center_freq)); | 1215 | ret = p54_set_freq(dev, cpu_to_le16(conf->channel->center_freq)); |
1095 | p54_set_vdcf(dev); | 1216 | p54_set_vdcf(dev); |
1096 | mutex_unlock(&priv->conf_mutex); | 1217 | mutex_unlock(&priv->conf_mutex); |
@@ -1118,13 +1239,26 @@ static void p54_configure_filter(struct ieee80211_hw *dev, | |||
1118 | { | 1239 | { |
1119 | struct p54_common *priv = dev->priv; | 1240 | struct p54_common *priv = dev->priv; |
1120 | 1241 | ||
1121 | *total_flags &= FIF_BCN_PRBRESP_PROMISC; | 1242 | *total_flags &= FIF_BCN_PRBRESP_PROMISC | |
1243 | FIF_PROMISC_IN_BSS | | ||
1244 | FIF_FCSFAIL; | ||
1245 | |||
1246 | priv->filter_flags = *total_flags; | ||
1122 | 1247 | ||
1123 | if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { | 1248 | if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { |
1124 | if (*total_flags & FIF_BCN_PRBRESP_PROMISC) | 1249 | if (*total_flags & FIF_BCN_PRBRESP_PROMISC) |
1125 | p54_set_filter(dev, 0, NULL); | 1250 | p54_set_filter(dev, priv->filter_type, NULL); |
1126 | else | 1251 | else |
1127 | p54_set_filter(dev, 0, priv->bssid); | 1252 | p54_set_filter(dev, priv->filter_type, priv->bssid); |
1253 | } | ||
1254 | |||
1255 | if (changed_flags & FIF_PROMISC_IN_BSS) { | ||
1256 | if (*total_flags & FIF_PROMISC_IN_BSS) | ||
1257 | p54_set_filter(dev, priv->filter_type | | ||
1258 | cpu_to_le16(0x8), NULL); | ||
1259 | else | ||
1260 | p54_set_filter(dev, priv->filter_type & | ||
1261 | ~cpu_to_le16(0x8), priv->bssid); | ||
1128 | } | 1262 | } |
1129 | } | 1263 | } |
1130 | 1264 | ||
@@ -1148,10 +1282,67 @@ static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue, | |||
1148 | return 0; | 1282 | return 0; |
1149 | } | 1283 | } |
1150 | 1284 | ||
1285 | static int p54_init_xbow_synth(struct ieee80211_hw *dev) | ||
1286 | { | ||
1287 | struct p54_common *priv = dev->priv; | ||
1288 | struct p54_control_hdr *hdr; | ||
1289 | struct p54_tx_control_xbow_synth *xbow; | ||
1290 | |||
1291 | hdr = kzalloc(sizeof(*hdr) + sizeof(*xbow) + | ||
1292 | priv->tx_hdr_len, GFP_KERNEL); | ||
1293 | if (!hdr) | ||
1294 | return -ENOMEM; | ||
1295 | |||
1296 | hdr = (void *)hdr + priv->tx_hdr_len; | ||
1297 | hdr->magic1 = cpu_to_le16(0x8001); | ||
1298 | hdr->len = cpu_to_le16(sizeof(*xbow)); | ||
1299 | hdr->type = cpu_to_le16(P54_CONTROL_TYPE_XBOW_SYNTH_CFG); | ||
1300 | p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*xbow)); | ||
1301 | |||
1302 | xbow = (struct p54_tx_control_xbow_synth *) hdr->data; | ||
1303 | xbow->magic1 = cpu_to_le16(0x1); | ||
1304 | xbow->magic2 = cpu_to_le16(0x2); | ||
1305 | xbow->freq = cpu_to_le16(5390); | ||
1306 | |||
1307 | priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*xbow), 1); | ||
1308 | |||
1309 | return 0; | ||
1310 | } | ||
1311 | |||
1312 | static void p54_statistics_timer(unsigned long data) | ||
1313 | { | ||
1314 | struct ieee80211_hw *dev = (struct ieee80211_hw *) data; | ||
1315 | struct p54_common *priv = dev->priv; | ||
1316 | struct p54_control_hdr *hdr; | ||
1317 | struct p54_statistics *stats; | ||
1318 | |||
1319 | BUG_ON(!priv->cached_stats); | ||
1320 | |||
1321 | hdr = (void *)priv->cached_stats + priv->tx_hdr_len; | ||
1322 | hdr->magic1 = cpu_to_le16(0x8000); | ||
1323 | hdr->len = cpu_to_le16(sizeof(*stats)); | ||
1324 | hdr->type = cpu_to_le16(P54_CONTROL_TYPE_STAT_READBACK); | ||
1325 | p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*stats)); | ||
1326 | |||
1327 | priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*stats), 0); | ||
1328 | } | ||
1329 | |||
1151 | static int p54_get_stats(struct ieee80211_hw *dev, | 1330 | static int p54_get_stats(struct ieee80211_hw *dev, |
1152 | struct ieee80211_low_level_stats *stats) | 1331 | struct ieee80211_low_level_stats *stats) |
1153 | { | 1332 | { |
1154 | /* TODO */ | 1333 | struct p54_common *priv = dev->priv; |
1334 | |||
1335 | del_timer(&priv->stats_timer); | ||
1336 | p54_statistics_timer((unsigned long)dev); | ||
1337 | |||
1338 | if (!wait_for_completion_interruptible_timeout(&priv->stats_comp, HZ)) { | ||
1339 | printk(KERN_ERR "%s: device does not respond!\n", | ||
1340 | wiphy_name(dev->wiphy)); | ||
1341 | return -EBUSY; | ||
1342 | } | ||
1343 | |||
1344 | memcpy(stats, &priv->stats, sizeof(*stats)); | ||
1345 | |||
1155 | return 0; | 1346 | return 0; |
1156 | } | 1347 | } |
1157 | 1348 | ||
@@ -1193,12 +1384,12 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) | |||
1193 | skb_queue_head_init(&priv->tx_queue); | 1384 | skb_queue_head_init(&priv->tx_queue); |
1194 | dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | /* not sure */ | 1385 | dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | /* not sure */ |
1195 | IEEE80211_HW_RX_INCLUDES_FCS | | 1386 | IEEE80211_HW_RX_INCLUDES_FCS | |
1196 | IEEE80211_HW_SIGNAL_UNSPEC; | 1387 | IEEE80211_HW_SIGNAL_DBM | |
1388 | IEEE80211_HW_NOISE_DBM; | ||
1197 | 1389 | ||
1198 | dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); | 1390 | dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); |
1199 | 1391 | ||
1200 | dev->channel_change_time = 1000; /* TODO: find actual value */ | 1392 | dev->channel_change_time = 1000; /* TODO: find actual value */ |
1201 | dev->max_signal = 127; | ||
1202 | 1393 | ||
1203 | priv->tx_stats[0].limit = 1; | 1394 | priv->tx_stats[0].limit = 1; |
1204 | priv->tx_stats[1].limit = 1; | 1395 | priv->tx_stats[1].limit = 1; |
@@ -1206,11 +1397,15 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) | |||
1206 | priv->tx_stats[3].limit = 1; | 1397 | priv->tx_stats[3].limit = 1; |
1207 | priv->tx_stats[4].limit = 5; | 1398 | priv->tx_stats[4].limit = 5; |
1208 | dev->queues = 1; | 1399 | dev->queues = 1; |
1400 | priv->noise = -94; | ||
1209 | dev->extra_tx_headroom = sizeof(struct p54_control_hdr) + 4 + | 1401 | dev->extra_tx_headroom = sizeof(struct p54_control_hdr) + 4 + |
1210 | sizeof(struct p54_tx_control_allocdata); | 1402 | sizeof(struct p54_tx_control_allocdata); |
1211 | 1403 | ||
1212 | mutex_init(&priv->conf_mutex); | 1404 | mutex_init(&priv->conf_mutex); |
1213 | init_completion(&priv->eeprom_comp); | 1405 | init_completion(&priv->eeprom_comp); |
1406 | init_completion(&priv->stats_comp); | ||
1407 | setup_timer(&priv->stats_timer, p54_statistics_timer, | ||
1408 | (unsigned long)dev); | ||
1214 | 1409 | ||
1215 | return dev; | 1410 | return dev; |
1216 | } | 1411 | } |
@@ -1219,6 +1414,7 @@ EXPORT_SYMBOL_GPL(p54_init_common); | |||
1219 | void p54_free_common(struct ieee80211_hw *dev) | 1414 | void p54_free_common(struct ieee80211_hw *dev) |
1220 | { | 1415 | { |
1221 | struct p54_common *priv = dev->priv; | 1416 | struct p54_common *priv = dev->priv; |
1417 | kfree(priv->cached_stats); | ||
1222 | kfree(priv->iq_autocal); | 1418 | kfree(priv->iq_autocal); |
1223 | kfree(priv->output_limit); | 1419 | kfree(priv->output_limit); |
1224 | kfree(priv->curve_data); | 1420 | kfree(priv->curve_data); |
diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h index 73a9a2c923dd..4da736c789ac 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h | |||
@@ -185,7 +185,8 @@ struct p54_rx_hdr { | |||
185 | u8 rssi; | 185 | u8 rssi; |
186 | u8 quality; | 186 | u8 quality; |
187 | u16 unknown2; | 187 | u16 unknown2; |
188 | __le64 timestamp; | 188 | __le32 tsf32; |
189 | __le32 unalloc0; | ||
189 | u8 align[0]; | 190 | u8 align[0]; |
190 | } __attribute__ ((packed)); | 191 | } __attribute__ ((packed)); |
191 | 192 | ||
@@ -300,4 +301,24 @@ struct p54_tx_control_vdcf { | |||
300 | __le16 frameburst; | 301 | __le16 frameburst; |
301 | } __attribute__ ((packed)); | 302 | } __attribute__ ((packed)); |
302 | 303 | ||
304 | struct p54_statistics { | ||
305 | __le32 rx_success; | ||
306 | __le32 rx_bad_fcs; | ||
307 | __le32 rx_abort; | ||
308 | __le32 rx_abort_phy; | ||
309 | __le32 rts_success; | ||
310 | __le32 rts_fail; | ||
311 | __le32 tsf32; | ||
312 | __le32 airtime; | ||
313 | __le32 noise; | ||
314 | __le32 unkn[10]; /* CCE / CCA / RADAR */ | ||
315 | } __attribute__ ((packed)); | ||
316 | |||
317 | struct p54_tx_control_xbow_synth { | ||
318 | __le16 magic1; | ||
319 | __le16 magic2; | ||
320 | __le16 freq; | ||
321 | u32 padding[5]; | ||
322 | } __attribute__ ((packed)); | ||
323 | |||
303 | #endif /* P54COMMON_H */ | 324 | #endif /* P54COMMON_H */ |
diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index 11f590d63aff..b686dc45483e 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig | |||
@@ -40,11 +40,15 @@ config RT2X00_LIB_CRYPTO | |||
40 | config RT2X00_LIB_RFKILL | 40 | config RT2X00_LIB_RFKILL |
41 | boolean | 41 | boolean |
42 | depends on RT2X00_LIB | 42 | depends on RT2X00_LIB |
43 | select RFKILL | 43 | depends on RFKILL |
44 | default y | ||
44 | 45 | ||
45 | config RT2X00_LIB_LEDS | 46 | config RT2X00_LIB_LEDS |
46 | boolean | 47 | boolean |
47 | depends on RT2X00_LIB && NEW_LEDS | 48 | depends on RT2X00_LIB |
49 | depends on NEW_LEDS | ||
50 | depends on LEDS_CLASS | ||
51 | default y | ||
48 | 52 | ||
49 | config RT2400PCI | 53 | config RT2400PCI |
50 | tristate "Ralink rt2400 (PCI/PCMCIA) support" | 54 | tristate "Ralink rt2400 (PCI/PCMCIA) support" |
@@ -57,23 +61,6 @@ config RT2400PCI | |||
57 | 61 | ||
58 | When compiled as a module, this driver will be called "rt2400pci.ko". | 62 | When compiled as a module, this driver will be called "rt2400pci.ko". |
59 | 63 | ||
60 | config RT2400PCI_RFKILL | ||
61 | bool "Ralink rt2400 rfkill support" | ||
62 | depends on RT2400PCI | ||
63 | select RT2X00_LIB_RFKILL | ||
64 | ---help--- | ||
65 | This adds support for integrated rt2400 hardware that features a | ||
66 | hardware button to control the radio state. | ||
67 | This feature depends on the RF switch subsystem rfkill. | ||
68 | |||
69 | config RT2400PCI_LEDS | ||
70 | bool "Ralink rt2400 leds support" | ||
71 | depends on RT2400PCI && NEW_LEDS | ||
72 | select LEDS_CLASS | ||
73 | select RT2X00_LIB_LEDS | ||
74 | ---help--- | ||
75 | This adds support for led triggers provided my mac80211. | ||
76 | |||
77 | config RT2500PCI | 64 | config RT2500PCI |
78 | tristate "Ralink rt2500 (PCI/PCMCIA) support" | 65 | tristate "Ralink rt2500 (PCI/PCMCIA) support" |
79 | depends on PCI | 66 | depends on PCI |
@@ -85,23 +72,6 @@ config RT2500PCI | |||
85 | 72 | ||
86 | When compiled as a module, this driver will be called "rt2500pci.ko". | 73 | When compiled as a module, this driver will be called "rt2500pci.ko". |
87 | 74 | ||
88 | config RT2500PCI_RFKILL | ||
89 | bool "Ralink rt2500 rfkill support" | ||
90 | depends on RT2500PCI | ||
91 | select RT2X00_LIB_RFKILL | ||
92 | ---help--- | ||
93 | This adds support for integrated rt2500 hardware that features a | ||
94 | hardware button to control the radio state. | ||
95 | This feature depends on the RF switch subsystem rfkill. | ||
96 | |||
97 | config RT2500PCI_LEDS | ||
98 | bool "Ralink rt2500 leds support" | ||
99 | depends on RT2500PCI && NEW_LEDS | ||
100 | select LEDS_CLASS | ||
101 | select RT2X00_LIB_LEDS | ||
102 | ---help--- | ||
103 | This adds support for led triggers provided my mac80211. | ||
104 | |||
105 | config RT61PCI | 75 | config RT61PCI |
106 | tristate "Ralink rt2501/rt61 (PCI/PCMCIA) support" | 76 | tristate "Ralink rt2501/rt61 (PCI/PCMCIA) support" |
107 | depends on PCI | 77 | depends on PCI |
@@ -116,23 +86,6 @@ config RT61PCI | |||
116 | 86 | ||
117 | When compiled as a module, this driver will be called "rt61pci.ko". | 87 | When compiled as a module, this driver will be called "rt61pci.ko". |
118 | 88 | ||
119 | config RT61PCI_RFKILL | ||
120 | bool "Ralink rt2501/rt61 rfkill support" | ||
121 | depends on RT61PCI | ||
122 | select RT2X00_LIB_RFKILL | ||
123 | ---help--- | ||
124 | This adds support for integrated rt61 hardware that features a | ||
125 | hardware button to control the radio state. | ||
126 | This feature depends on the RF switch subsystem rfkill. | ||
127 | |||
128 | config RT61PCI_LEDS | ||
129 | bool "Ralink rt2501/rt61 leds support" | ||
130 | depends on RT61PCI && NEW_LEDS | ||
131 | select LEDS_CLASS | ||
132 | select RT2X00_LIB_LEDS | ||
133 | ---help--- | ||
134 | This adds support for led triggers provided my mac80211. | ||
135 | |||
136 | config RT2500USB | 89 | config RT2500USB |
137 | tristate "Ralink rt2500 (USB) support" | 90 | tristate "Ralink rt2500 (USB) support" |
138 | depends on USB | 91 | depends on USB |
@@ -143,14 +96,6 @@ config RT2500USB | |||
143 | 96 | ||
144 | When compiled as a module, this driver will be called "rt2500usb.ko". | 97 | When compiled as a module, this driver will be called "rt2500usb.ko". |
145 | 98 | ||
146 | config RT2500USB_LEDS | ||
147 | bool "Ralink rt2500 leds support" | ||
148 | depends on RT2500USB && NEW_LEDS | ||
149 | select LEDS_CLASS | ||
150 | select RT2X00_LIB_LEDS | ||
151 | ---help--- | ||
152 | This adds support for led triggers provided my mac80211. | ||
153 | |||
154 | config RT73USB | 99 | config RT73USB |
155 | tristate "Ralink rt2501/rt73 (USB) support" | 100 | tristate "Ralink rt2501/rt73 (USB) support" |
156 | depends on USB | 101 | depends on USB |
@@ -164,14 +109,6 @@ config RT73USB | |||
164 | 109 | ||
165 | When compiled as a module, this driver will be called "rt73usb.ko". | 110 | When compiled as a module, this driver will be called "rt73usb.ko". |
166 | 111 | ||
167 | config RT73USB_LEDS | ||
168 | bool "Ralink rt2501/rt73 leds support" | ||
169 | depends on RT73USB && NEW_LEDS | ||
170 | select LEDS_CLASS | ||
171 | select RT2X00_LIB_LEDS | ||
172 | ---help--- | ||
173 | This adds support for led triggers provided my mac80211. | ||
174 | |||
175 | config RT2X00_LIB_DEBUGFS | 112 | config RT2X00_LIB_DEBUGFS |
176 | bool "Ralink debugfs support" | 113 | bool "Ralink debugfs support" |
177 | depends on RT2X00_LIB && MAC80211_DEBUGFS | 114 | depends on RT2X00_LIB && MAC80211_DEBUGFS |
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 18b703c3fc2c..08cb9eec16a6 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c | |||
@@ -231,7 +231,7 @@ static const struct rt2x00debug rt2400pci_rt2x00debug = { | |||
231 | }; | 231 | }; |
232 | #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ | 232 | #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ |
233 | 233 | ||
234 | #ifdef CONFIG_RT2400PCI_RFKILL | 234 | #ifdef CONFIG_RT2X00_LIB_RFKILL |
235 | static int rt2400pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) | 235 | static int rt2400pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) |
236 | { | 236 | { |
237 | u32 reg; | 237 | u32 reg; |
@@ -241,9 +241,9 @@ static int rt2400pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) | |||
241 | } | 241 | } |
242 | #else | 242 | #else |
243 | #define rt2400pci_rfkill_poll NULL | 243 | #define rt2400pci_rfkill_poll NULL |
244 | #endif /* CONFIG_RT2400PCI_RFKILL */ | 244 | #endif /* CONFIG_RT2X00_LIB_RFKILL */ |
245 | 245 | ||
246 | #ifdef CONFIG_RT2400PCI_LEDS | 246 | #ifdef CONFIG_RT2X00_LIB_LEDS |
247 | static void rt2400pci_brightness_set(struct led_classdev *led_cdev, | 247 | static void rt2400pci_brightness_set(struct led_classdev *led_cdev, |
248 | enum led_brightness brightness) | 248 | enum led_brightness brightness) |
249 | { | 249 | { |
@@ -288,7 +288,7 @@ static void rt2400pci_init_led(struct rt2x00_dev *rt2x00dev, | |||
288 | led->led_dev.blink_set = rt2400pci_blink_set; | 288 | led->led_dev.blink_set = rt2400pci_blink_set; |
289 | led->flags = LED_INITIALIZED; | 289 | led->flags = LED_INITIALIZED; |
290 | } | 290 | } |
291 | #endif /* CONFIG_RT2400PCI_LEDS */ | 291 | #endif /* CONFIG_RT2X00_LIB_LEDS */ |
292 | 292 | ||
293 | /* | 293 | /* |
294 | * Configuration handlers. | 294 | * Configuration handlers. |
@@ -1374,22 +1374,22 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev) | |||
1374 | /* | 1374 | /* |
1375 | * Store led mode, for correct led behaviour. | 1375 | * Store led mode, for correct led behaviour. |
1376 | */ | 1376 | */ |
1377 | #ifdef CONFIG_RT2400PCI_LEDS | 1377 | #ifdef CONFIG_RT2X00_LIB_LEDS |
1378 | value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE); | 1378 | value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE); |
1379 | 1379 | ||
1380 | rt2400pci_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO); | 1380 | rt2400pci_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO); |
1381 | if (value == LED_MODE_TXRX_ACTIVITY) | 1381 | if (value == LED_MODE_TXRX_ACTIVITY) |
1382 | rt2400pci_init_led(rt2x00dev, &rt2x00dev->led_qual, | 1382 | rt2400pci_init_led(rt2x00dev, &rt2x00dev->led_qual, |
1383 | LED_TYPE_ACTIVITY); | 1383 | LED_TYPE_ACTIVITY); |
1384 | #endif /* CONFIG_RT2400PCI_LEDS */ | 1384 | #endif /* CONFIG_RT2X00_LIB_LEDS */ |
1385 | 1385 | ||
1386 | /* | 1386 | /* |
1387 | * Detect if this device has an hardware controlled radio. | 1387 | * Detect if this device has an hardware controlled radio. |
1388 | */ | 1388 | */ |
1389 | #ifdef CONFIG_RT2400PCI_RFKILL | 1389 | #ifdef CONFIG_RT2X00_LIB_RFKILL |
1390 | if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) | 1390 | if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) |
1391 | __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); | 1391 | __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); |
1392 | #endif /* CONFIG_RT2400PCI_RFKILL */ | 1392 | #endif /* CONFIG_RT2X00_LIB_RFKILL */ |
1393 | 1393 | ||
1394 | /* | 1394 | /* |
1395 | * Check if the BBP tuning should be enabled. | 1395 | * Check if the BBP tuning should be enabled. |
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 2a96a011f2ad..ef42cc04a2d7 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c | |||
@@ -231,7 +231,7 @@ static const struct rt2x00debug rt2500pci_rt2x00debug = { | |||
231 | }; | 231 | }; |
232 | #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ | 232 | #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ |
233 | 233 | ||
234 | #ifdef CONFIG_RT2500PCI_RFKILL | 234 | #ifdef CONFIG_RT2X00_LIB_RFKILL |
235 | static int rt2500pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) | 235 | static int rt2500pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) |
236 | { | 236 | { |
237 | u32 reg; | 237 | u32 reg; |
@@ -241,9 +241,9 @@ static int rt2500pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) | |||
241 | } | 241 | } |
242 | #else | 242 | #else |
243 | #define rt2500pci_rfkill_poll NULL | 243 | #define rt2500pci_rfkill_poll NULL |
244 | #endif /* CONFIG_RT2500PCI_RFKILL */ | 244 | #endif /* CONFIG_RT2X00_LIB_RFKILL */ |
245 | 245 | ||
246 | #ifdef CONFIG_RT2500PCI_LEDS | 246 | #ifdef CONFIG_RT2X00_LIB_LEDS |
247 | static void rt2500pci_brightness_set(struct led_classdev *led_cdev, | 247 | static void rt2500pci_brightness_set(struct led_classdev *led_cdev, |
248 | enum led_brightness brightness) | 248 | enum led_brightness brightness) |
249 | { | 249 | { |
@@ -288,7 +288,7 @@ static void rt2500pci_init_led(struct rt2x00_dev *rt2x00dev, | |||
288 | led->led_dev.blink_set = rt2500pci_blink_set; | 288 | led->led_dev.blink_set = rt2500pci_blink_set; |
289 | led->flags = LED_INITIALIZED; | 289 | led->flags = LED_INITIALIZED; |
290 | } | 290 | } |
291 | #endif /* CONFIG_RT2500PCI_LEDS */ | 291 | #endif /* CONFIG_RT2X00_LIB_LEDS */ |
292 | 292 | ||
293 | /* | 293 | /* |
294 | * Configuration handlers. | 294 | * Configuration handlers. |
@@ -1533,22 +1533,22 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev) | |||
1533 | /* | 1533 | /* |
1534 | * Store led mode, for correct led behaviour. | 1534 | * Store led mode, for correct led behaviour. |
1535 | */ | 1535 | */ |
1536 | #ifdef CONFIG_RT2500PCI_LEDS | 1536 | #ifdef CONFIG_RT2X00_LIB_LEDS |
1537 | value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE); | 1537 | value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE); |
1538 | 1538 | ||
1539 | rt2500pci_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO); | 1539 | rt2500pci_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO); |
1540 | if (value == LED_MODE_TXRX_ACTIVITY) | 1540 | if (value == LED_MODE_TXRX_ACTIVITY) |
1541 | rt2500pci_init_led(rt2x00dev, &rt2x00dev->led_qual, | 1541 | rt2500pci_init_led(rt2x00dev, &rt2x00dev->led_qual, |
1542 | LED_TYPE_ACTIVITY); | 1542 | LED_TYPE_ACTIVITY); |
1543 | #endif /* CONFIG_RT2500PCI_LEDS */ | 1543 | #endif /* CONFIG_RT2X00_LIB_LEDS */ |
1544 | 1544 | ||
1545 | /* | 1545 | /* |
1546 | * Detect if this device has an hardware controlled radio. | 1546 | * Detect if this device has an hardware controlled radio. |
1547 | */ | 1547 | */ |
1548 | #ifdef CONFIG_RT2500PCI_RFKILL | 1548 | #ifdef CONFIG_RT2X00_LIB_RFKILL |
1549 | if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) | 1549 | if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) |
1550 | __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); | 1550 | __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); |
1551 | #endif /* CONFIG_RT2500PCI_RFKILL */ | 1551 | #endif /* CONFIG_RT2X00_LIB_RFKILL */ |
1552 | 1552 | ||
1553 | /* | 1553 | /* |
1554 | * Check if the BBP tuning should be enabled. | 1554 | * Check if the BBP tuning should be enabled. |
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 0e008b606f70..cb5f2d01a9c3 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c | |||
@@ -288,7 +288,7 @@ static const struct rt2x00debug rt2500usb_rt2x00debug = { | |||
288 | }; | 288 | }; |
289 | #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ | 289 | #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ |
290 | 290 | ||
291 | #ifdef CONFIG_RT2500USB_LEDS | 291 | #ifdef CONFIG_RT2X00_LIB_LEDS |
292 | static void rt2500usb_brightness_set(struct led_classdev *led_cdev, | 292 | static void rt2500usb_brightness_set(struct led_classdev *led_cdev, |
293 | enum led_brightness brightness) | 293 | enum led_brightness brightness) |
294 | { | 294 | { |
@@ -333,7 +333,7 @@ static void rt2500usb_init_led(struct rt2x00_dev *rt2x00dev, | |||
333 | led->led_dev.blink_set = rt2500usb_blink_set; | 333 | led->led_dev.blink_set = rt2500usb_blink_set; |
334 | led->flags = LED_INITIALIZED; | 334 | led->flags = LED_INITIALIZED; |
335 | } | 335 | } |
336 | #endif /* CONFIG_RT2500USB_LEDS */ | 336 | #endif /* CONFIG_RT2X00_LIB_LEDS */ |
337 | 337 | ||
338 | /* | 338 | /* |
339 | * Configuration handlers. | 339 | * Configuration handlers. |
@@ -1133,7 +1133,6 @@ static void rt2500usb_write_beacon(struct queue_entry *entry) | |||
1133 | int pipe = usb_sndbulkpipe(usb_dev, 1); | 1133 | int pipe = usb_sndbulkpipe(usb_dev, 1); |
1134 | int length; | 1134 | int length; |
1135 | u16 reg; | 1135 | u16 reg; |
1136 | u32 word, len; | ||
1137 | 1136 | ||
1138 | /* | 1137 | /* |
1139 | * Add the descriptor in front of the skb. | 1138 | * Add the descriptor in front of the skb. |
@@ -1143,17 +1142,6 @@ static void rt2500usb_write_beacon(struct queue_entry *entry) | |||
1143 | skbdesc->desc = entry->skb->data; | 1142 | skbdesc->desc = entry->skb->data; |
1144 | 1143 | ||
1145 | /* | 1144 | /* |
1146 | * Adjust the beacon databyte count. The current number is | ||
1147 | * calculated before this function gets called, but falsely | ||
1148 | * assumes that the descriptor was already present in the SKB. | ||
1149 | */ | ||
1150 | rt2x00_desc_read(skbdesc->desc, 0, &word); | ||
1151 | len = rt2x00_get_field32(word, TXD_W0_DATABYTE_COUNT); | ||
1152 | len += skbdesc->desc_len; | ||
1153 | rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, len); | ||
1154 | rt2x00_desc_write(skbdesc->desc, 0, word); | ||
1155 | |||
1156 | /* | ||
1157 | * Disable beaconing while we are reloading the beacon data, | 1145 | * Disable beaconing while we are reloading the beacon data, |
1158 | * otherwise we might be sending out invalid data. | 1146 | * otherwise we might be sending out invalid data. |
1159 | */ | 1147 | */ |
@@ -1485,14 +1473,14 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev) | |||
1485 | /* | 1473 | /* |
1486 | * Store led mode, for correct led behaviour. | 1474 | * Store led mode, for correct led behaviour. |
1487 | */ | 1475 | */ |
1488 | #ifdef CONFIG_RT2500USB_LEDS | 1476 | #ifdef CONFIG_RT2X00_LIB_LEDS |
1489 | value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE); | 1477 | value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE); |
1490 | 1478 | ||
1491 | rt2500usb_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO); | 1479 | rt2500usb_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO); |
1492 | if (value == LED_MODE_TXRX_ACTIVITY) | 1480 | if (value == LED_MODE_TXRX_ACTIVITY) |
1493 | rt2500usb_init_led(rt2x00dev, &rt2x00dev->led_qual, | 1481 | rt2500usb_init_led(rt2x00dev, &rt2x00dev->led_qual, |
1494 | LED_TYPE_ACTIVITY); | 1482 | LED_TYPE_ACTIVITY); |
1495 | #endif /* CONFIG_RT2500USB_LEDS */ | 1483 | #endif /* CONFIG_RT2X00_LIB_LEDS */ |
1496 | 1484 | ||
1497 | /* | 1485 | /* |
1498 | * Check if the BBP tuning should be disabled. | 1486 | * Check if the BBP tuning should be disabled. |
diff --git a/drivers/net/wireless/rt2x00/rt2x00rfkill.c b/drivers/net/wireless/rt2x00/rt2x00rfkill.c index 8a2fefb365b7..55eff58f1889 100644 --- a/drivers/net/wireless/rt2x00/rt2x00rfkill.c +++ b/drivers/net/wireless/rt2x00/rt2x00rfkill.c | |||
@@ -45,16 +45,15 @@ static int rt2x00rfkill_toggle_radio(void *data, enum rfkill_state state) | |||
45 | return 0; | 45 | return 0; |
46 | 46 | ||
47 | if (state == RFKILL_STATE_UNBLOCKED) { | 47 | if (state == RFKILL_STATE_UNBLOCKED) { |
48 | INFO(rt2x00dev, "Hardware button pressed, enabling radio.\n"); | 48 | INFO(rt2x00dev, "RFKILL event: enabling radio.\n"); |
49 | clear_bit(DEVICE_STATE_DISABLED_RADIO_HW, &rt2x00dev->flags); | 49 | clear_bit(DEVICE_STATE_DISABLED_RADIO_HW, &rt2x00dev->flags); |
50 | retval = rt2x00lib_enable_radio(rt2x00dev); | 50 | retval = rt2x00lib_enable_radio(rt2x00dev); |
51 | } else if (state == RFKILL_STATE_SOFT_BLOCKED) { | 51 | } else if (state == RFKILL_STATE_SOFT_BLOCKED) { |
52 | INFO(rt2x00dev, "Hardware button pressed, disabling radio.\n"); | 52 | INFO(rt2x00dev, "RFKILL event: disabling radio.\n"); |
53 | set_bit(DEVICE_STATE_DISABLED_RADIO_HW, &rt2x00dev->flags); | 53 | set_bit(DEVICE_STATE_DISABLED_RADIO_HW, &rt2x00dev->flags); |
54 | rt2x00lib_disable_radio(rt2x00dev); | 54 | rt2x00lib_disable_radio(rt2x00dev); |
55 | } else { | 55 | } else { |
56 | WARNING(rt2x00dev, "Received unexpected rfkill state %d.\n", | 56 | WARNING(rt2x00dev, "RFKILL event: unknown state %d.\n", state); |
57 | state); | ||
58 | } | 57 | } |
59 | 58 | ||
60 | return retval; | 59 | return retval; |
@@ -64,7 +63,12 @@ static int rt2x00rfkill_get_state(void *data, enum rfkill_state *state) | |||
64 | { | 63 | { |
65 | struct rt2x00_dev *rt2x00dev = data; | 64 | struct rt2x00_dev *rt2x00dev = data; |
66 | 65 | ||
67 | *state = rt2x00dev->rfkill->state; | 66 | /* |
67 | * rfkill_poll reports 1 when the key has been pressed and the | ||
68 | * radio should be blocked. | ||
69 | */ | ||
70 | *state = rt2x00dev->ops->lib->rfkill_poll(rt2x00dev) ? | ||
71 | RFKILL_STATE_SOFT_BLOCKED : RFKILL_STATE_UNBLOCKED; | ||
68 | 72 | ||
69 | return 0; | 73 | return 0; |
70 | } | 74 | } |
@@ -73,19 +77,18 @@ static void rt2x00rfkill_poll(struct work_struct *work) | |||
73 | { | 77 | { |
74 | struct rt2x00_dev *rt2x00dev = | 78 | struct rt2x00_dev *rt2x00dev = |
75 | container_of(work, struct rt2x00_dev, rfkill_work.work); | 79 | container_of(work, struct rt2x00_dev, rfkill_work.work); |
76 | int state; | 80 | enum rfkill_state state; |
77 | 81 | ||
78 | if (!test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state)) | 82 | if (!test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state) || |
83 | !test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) | ||
79 | return; | 84 | return; |
80 | 85 | ||
81 | /* | 86 | /* |
82 | * rfkill_poll reports 1 when the key has been pressed and the | 87 | * Poll latest state and report it to rfkill who should sort |
83 | * radio should be blocked. | 88 | * out if the state should be toggled or not. |
84 | */ | 89 | */ |
85 | state = !rt2x00dev->ops->lib->rfkill_poll(rt2x00dev) ? | 90 | if (!rt2x00rfkill_get_state(rt2x00dev, &state)) |
86 | RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; | 91 | rfkill_force_state(rt2x00dev->rfkill, state); |
87 | |||
88 | rfkill_force_state(rt2x00dev->rfkill, state); | ||
89 | 92 | ||
90 | queue_delayed_work(rt2x00dev->hw->workqueue, | 93 | queue_delayed_work(rt2x00dev->hw->workqueue, |
91 | &rt2x00dev->rfkill_work, RFKILL_POLL_INTERVAL); | 94 | &rt2x00dev->rfkill_work, RFKILL_POLL_INTERVAL); |
@@ -93,8 +96,8 @@ static void rt2x00rfkill_poll(struct work_struct *work) | |||
93 | 96 | ||
94 | void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev) | 97 | void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev) |
95 | { | 98 | { |
96 | if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags) || | 99 | if (!test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state) || |
97 | !test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state)) | 100 | test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state)) |
98 | return; | 101 | return; |
99 | 102 | ||
100 | if (rfkill_register(rt2x00dev->rfkill)) { | 103 | if (rfkill_register(rt2x00dev->rfkill)) { |
@@ -114,7 +117,7 @@ void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev) | |||
114 | 117 | ||
115 | void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev) | 118 | void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev) |
116 | { | 119 | { |
117 | if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags) || | 120 | if (!test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state) || |
118 | !test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state)) | 121 | !test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state)) |
119 | return; | 122 | return; |
120 | 123 | ||
@@ -127,21 +130,25 @@ void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev) | |||
127 | 130 | ||
128 | void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev) | 131 | void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev) |
129 | { | 132 | { |
130 | if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) | 133 | struct device *dev = wiphy_dev(rt2x00dev->hw->wiphy); |
134 | |||
135 | if (test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state)) | ||
131 | return; | 136 | return; |
132 | 137 | ||
133 | rt2x00dev->rfkill = | 138 | rt2x00dev->rfkill = rfkill_allocate(dev, RFKILL_TYPE_WLAN); |
134 | rfkill_allocate(wiphy_dev(rt2x00dev->hw->wiphy), RFKILL_TYPE_WLAN); | ||
135 | if (!rt2x00dev->rfkill) { | 139 | if (!rt2x00dev->rfkill) { |
136 | ERROR(rt2x00dev, "Failed to allocate rfkill handler.\n"); | 140 | ERROR(rt2x00dev, "Failed to allocate rfkill handler.\n"); |
137 | return; | 141 | return; |
138 | } | 142 | } |
139 | 143 | ||
144 | __set_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state); | ||
145 | |||
140 | rt2x00dev->rfkill->name = rt2x00dev->ops->name; | 146 | rt2x00dev->rfkill->name = rt2x00dev->ops->name; |
141 | rt2x00dev->rfkill->data = rt2x00dev; | 147 | rt2x00dev->rfkill->data = rt2x00dev; |
142 | rt2x00dev->rfkill->state = -1; | 148 | rt2x00dev->rfkill->state = -1; |
143 | rt2x00dev->rfkill->toggle_radio = rt2x00rfkill_toggle_radio; | 149 | rt2x00dev->rfkill->toggle_radio = rt2x00rfkill_toggle_radio; |
144 | rt2x00dev->rfkill->get_state = rt2x00rfkill_get_state; | 150 | if (test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) |
151 | rt2x00dev->rfkill->get_state = rt2x00rfkill_get_state; | ||
145 | 152 | ||
146 | INIT_DELAYED_WORK(&rt2x00dev->rfkill_work, rt2x00rfkill_poll); | 153 | INIT_DELAYED_WORK(&rt2x00dev->rfkill_work, rt2x00rfkill_poll); |
147 | 154 | ||
@@ -150,8 +157,7 @@ void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev) | |||
150 | 157 | ||
151 | void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev) | 158 | void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev) |
152 | { | 159 | { |
153 | if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags) || | 160 | if (!test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->flags)) |
154 | !test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state)) | ||
155 | return; | 161 | return; |
156 | 162 | ||
157 | cancel_delayed_work_sync(&rt2x00dev->rfkill_work); | 163 | cancel_delayed_work_sync(&rt2x00dev->rfkill_work); |
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index d740f560ccd0..2c36b91ff4c7 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c | |||
@@ -163,7 +163,7 @@ rf_write: | |||
163 | rt2x00_rf_write(rt2x00dev, word, value); | 163 | rt2x00_rf_write(rt2x00dev, word, value); |
164 | } | 164 | } |
165 | 165 | ||
166 | #ifdef CONFIG_RT61PCI_LEDS | 166 | #ifdef CONFIG_RT2X00_LIB_LEDS |
167 | /* | 167 | /* |
168 | * This function is only called from rt61pci_led_brightness() | 168 | * This function is only called from rt61pci_led_brightness() |
169 | * make gcc happy by placing this function inside the | 169 | * make gcc happy by placing this function inside the |
@@ -195,7 +195,7 @@ static void rt61pci_mcu_request(struct rt2x00_dev *rt2x00dev, | |||
195 | rt2x00_set_field32(®, HOST_CMD_CSR_INTERRUPT_MCU, 1); | 195 | rt2x00_set_field32(®, HOST_CMD_CSR_INTERRUPT_MCU, 1); |
196 | rt2x00pci_register_write(rt2x00dev, HOST_CMD_CSR, reg); | 196 | rt2x00pci_register_write(rt2x00dev, HOST_CMD_CSR, reg); |
197 | } | 197 | } |
198 | #endif /* CONFIG_RT61PCI_LEDS */ | 198 | #endif /* CONFIG_RT2X00_LIB_LEDS */ |
199 | 199 | ||
200 | static void rt61pci_eepromregister_read(struct eeprom_93cx6 *eeprom) | 200 | static void rt61pci_eepromregister_read(struct eeprom_93cx6 *eeprom) |
201 | { | 201 | { |
@@ -271,7 +271,7 @@ static const struct rt2x00debug rt61pci_rt2x00debug = { | |||
271 | }; | 271 | }; |
272 | #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ | 272 | #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ |
273 | 273 | ||
274 | #ifdef CONFIG_RT61PCI_RFKILL | 274 | #ifdef CONFIG_RT2X00_LIB_RFKILL |
275 | static int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) | 275 | static int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) |
276 | { | 276 | { |
277 | u32 reg; | 277 | u32 reg; |
@@ -281,9 +281,9 @@ static int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) | |||
281 | } | 281 | } |
282 | #else | 282 | #else |
283 | #define rt61pci_rfkill_poll NULL | 283 | #define rt61pci_rfkill_poll NULL |
284 | #endif /* CONFIG_RT61PCI_RFKILL */ | 284 | #endif /* CONFIG_RT2X00_LIB_RFKILL */ |
285 | 285 | ||
286 | #ifdef CONFIG_RT61PCI_LEDS | 286 | #ifdef CONFIG_RT2X00_LIB_LEDS |
287 | static void rt61pci_brightness_set(struct led_classdev *led_cdev, | 287 | static void rt61pci_brightness_set(struct led_classdev *led_cdev, |
288 | enum led_brightness brightness) | 288 | enum led_brightness brightness) |
289 | { | 289 | { |
@@ -348,7 +348,7 @@ static void rt61pci_init_led(struct rt2x00_dev *rt2x00dev, | |||
348 | led->led_dev.blink_set = rt61pci_blink_set; | 348 | led->led_dev.blink_set = rt61pci_blink_set; |
349 | led->flags = LED_INITIALIZED; | 349 | led->flags = LED_INITIALIZED; |
350 | } | 350 | } |
351 | #endif /* CONFIG_RT61PCI_LEDS */ | 351 | #endif /* CONFIG_RT2X00_LIB_LEDS */ |
352 | 352 | ||
353 | /* | 353 | /* |
354 | * Configuration handlers. | 354 | * Configuration handlers. |
@@ -2313,10 +2313,10 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) | |||
2313 | /* | 2313 | /* |
2314 | * Detect if this device has an hardware controlled radio. | 2314 | * Detect if this device has an hardware controlled radio. |
2315 | */ | 2315 | */ |
2316 | #ifdef CONFIG_RT61PCI_RFKILL | 2316 | #ifdef CONFIG_RT2X00_LIB_RFKILL |
2317 | if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) | 2317 | if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) |
2318 | __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); | 2318 | __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); |
2319 | #endif /* CONFIG_RT61PCI_RFKILL */ | 2319 | #endif /* CONFIG_RT2X00_LIB_RFKILL */ |
2320 | 2320 | ||
2321 | /* | 2321 | /* |
2322 | * Read frequency offset and RF programming sequence. | 2322 | * Read frequency offset and RF programming sequence. |
@@ -2374,7 +2374,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) | |||
2374 | * If the eeprom value is invalid, | 2374 | * If the eeprom value is invalid, |
2375 | * switch to default led mode. | 2375 | * switch to default led mode. |
2376 | */ | 2376 | */ |
2377 | #ifdef CONFIG_RT61PCI_LEDS | 2377 | #ifdef CONFIG_RT2X00_LIB_LEDS |
2378 | rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &eeprom); | 2378 | rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &eeprom); |
2379 | value = rt2x00_get_field16(eeprom, EEPROM_LED_LED_MODE); | 2379 | value = rt2x00_get_field16(eeprom, EEPROM_LED_LED_MODE); |
2380 | 2380 | ||
@@ -2408,7 +2408,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) | |||
2408 | rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_READY_A, | 2408 | rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_READY_A, |
2409 | rt2x00_get_field16(eeprom, | 2409 | rt2x00_get_field16(eeprom, |
2410 | EEPROM_LED_POLARITY_RDY_A)); | 2410 | EEPROM_LED_POLARITY_RDY_A)); |
2411 | #endif /* CONFIG_RT61PCI_LEDS */ | 2411 | #endif /* CONFIG_RT2X00_LIB_LEDS */ |
2412 | 2412 | ||
2413 | return 0; | 2413 | return 0; |
2414 | } | 2414 | } |
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index e698ae0efbce..27dde3e34603 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c | |||
@@ -292,7 +292,7 @@ static const struct rt2x00debug rt73usb_rt2x00debug = { | |||
292 | }; | 292 | }; |
293 | #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ | 293 | #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ |
294 | 294 | ||
295 | #ifdef CONFIG_RT73USB_LEDS | 295 | #ifdef CONFIG_RT2X00_LIB_LEDS |
296 | static void rt73usb_brightness_set(struct led_classdev *led_cdev, | 296 | static void rt73usb_brightness_set(struct led_classdev *led_cdev, |
297 | enum led_brightness brightness) | 297 | enum led_brightness brightness) |
298 | { | 298 | { |
@@ -359,7 +359,7 @@ static void rt73usb_init_led(struct rt2x00_dev *rt2x00dev, | |||
359 | led->led_dev.blink_set = rt73usb_blink_set; | 359 | led->led_dev.blink_set = rt73usb_blink_set; |
360 | led->flags = LED_INITIALIZED; | 360 | led->flags = LED_INITIALIZED; |
361 | } | 361 | } |
362 | #endif /* CONFIG_RT73USB_LEDS */ | 362 | #endif /* CONFIG_RT2X00_LIB_LEDS */ |
363 | 363 | ||
364 | /* | 364 | /* |
365 | * Configuration handlers. | 365 | * Configuration handlers. |
@@ -1572,7 +1572,6 @@ static void rt73usb_write_beacon(struct queue_entry *entry) | |||
1572 | struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); | 1572 | struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); |
1573 | unsigned int beacon_base; | 1573 | unsigned int beacon_base; |
1574 | u32 reg; | 1574 | u32 reg; |
1575 | u32 word, len; | ||
1576 | 1575 | ||
1577 | /* | 1576 | /* |
1578 | * Add the descriptor in front of the skb. | 1577 | * Add the descriptor in front of the skb. |
@@ -1582,17 +1581,6 @@ static void rt73usb_write_beacon(struct queue_entry *entry) | |||
1582 | skbdesc->desc = entry->skb->data; | 1581 | skbdesc->desc = entry->skb->data; |
1583 | 1582 | ||
1584 | /* | 1583 | /* |
1585 | * Adjust the beacon databyte count. The current number is | ||
1586 | * calculated before this function gets called, but falsely | ||
1587 | * assumes that the descriptor was already present in the SKB. | ||
1588 | */ | ||
1589 | rt2x00_desc_read(skbdesc->desc, 0, &word); | ||
1590 | len = rt2x00_get_field32(word, TXD_W0_DATABYTE_COUNT); | ||
1591 | len += skbdesc->desc_len; | ||
1592 | rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, len); | ||
1593 | rt2x00_desc_write(skbdesc->desc, 0, word); | ||
1594 | |||
1595 | /* | ||
1596 | * Disable beaconing while we are reloading the beacon data, | 1584 | * Disable beaconing while we are reloading the beacon data, |
1597 | * otherwise we might be sending out invalid data. | 1585 | * otherwise we might be sending out invalid data. |
1598 | */ | 1586 | */ |
@@ -1944,7 +1932,7 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev) | |||
1944 | /* | 1932 | /* |
1945 | * Store led settings, for correct led behaviour. | 1933 | * Store led settings, for correct led behaviour. |
1946 | */ | 1934 | */ |
1947 | #ifdef CONFIG_RT73USB_LEDS | 1935 | #ifdef CONFIG_RT2X00_LIB_LEDS |
1948 | rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &eeprom); | 1936 | rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &eeprom); |
1949 | 1937 | ||
1950 | rt73usb_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO); | 1938 | rt73usb_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO); |
@@ -1977,7 +1965,7 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev) | |||
1977 | rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_READY_A, | 1965 | rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_READY_A, |
1978 | rt2x00_get_field16(eeprom, | 1966 | rt2x00_get_field16(eeprom, |
1979 | EEPROM_LED_POLARITY_RDY_A)); | 1967 | EEPROM_LED_POLARITY_RDY_A)); |
1980 | #endif /* CONFIG_RT73USB_LEDS */ | 1968 | #endif /* CONFIG_RT2X00_LIB_LEDS */ |
1981 | 1969 | ||
1982 | return 0; | 1970 | return 0; |
1983 | } | 1971 | } |
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index be456450cd2e..abc1abc63bf0 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h | |||
@@ -643,6 +643,9 @@ struct ieee80211_mgmt { | |||
643 | } u; | 643 | } u; |
644 | } __attribute__ ((packed)); | 644 | } __attribute__ ((packed)); |
645 | 645 | ||
646 | /* mgmt header + 1 byte category code */ | ||
647 | #define IEEE80211_MIN_ACTION_SIZE offsetof(struct ieee80211_mgmt, u.action.u) | ||
648 | |||
646 | 649 | ||
647 | /* Control frames */ | 650 | /* Control frames */ |
648 | struct ieee80211_rts { | 651 | struct ieee80211_rts { |
@@ -708,7 +711,7 @@ struct ieee80211_ht_addt_info { | |||
708 | 711 | ||
709 | /* 802.11n HT capabilities masks */ | 712 | /* 802.11n HT capabilities masks */ |
710 | #define IEEE80211_HT_CAP_SUP_WIDTH 0x0002 | 713 | #define IEEE80211_HT_CAP_SUP_WIDTH 0x0002 |
711 | #define IEEE80211_HT_CAP_MIMO_PS 0x000C | 714 | #define IEEE80211_HT_CAP_SM_PS 0x000C |
712 | #define IEEE80211_HT_CAP_GRN_FLD 0x0010 | 715 | #define IEEE80211_HT_CAP_GRN_FLD 0x0010 |
713 | #define IEEE80211_HT_CAP_SGI_20 0x0020 | 716 | #define IEEE80211_HT_CAP_SGI_20 0x0020 |
714 | #define IEEE80211_HT_CAP_SGI_40 0x0040 | 717 | #define IEEE80211_HT_CAP_SGI_40 0x0040 |
@@ -737,11 +740,26 @@ struct ieee80211_ht_addt_info { | |||
737 | #define IEEE80211_HT_IE_NON_GF_STA_PRSNT 0x0004 | 740 | #define IEEE80211_HT_IE_NON_GF_STA_PRSNT 0x0004 |
738 | #define IEEE80211_HT_IE_NON_HT_STA_PRSNT 0x0010 | 741 | #define IEEE80211_HT_IE_NON_HT_STA_PRSNT 0x0010 |
739 | 742 | ||
740 | /* MIMO Power Save Modes */ | 743 | /* block-ack parameters */ |
741 | #define WLAN_HT_CAP_MIMO_PS_STATIC 0 | 744 | #define IEEE80211_ADDBA_PARAM_POLICY_MASK 0x0002 |
742 | #define WLAN_HT_CAP_MIMO_PS_DYNAMIC 1 | 745 | #define IEEE80211_ADDBA_PARAM_TID_MASK 0x003C |
743 | #define WLAN_HT_CAP_MIMO_PS_INVALID 2 | 746 | #define IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK 0xFFA0 |
744 | #define WLAN_HT_CAP_MIMO_PS_DISABLED 3 | 747 | #define IEEE80211_DELBA_PARAM_TID_MASK 0xF000 |
748 | #define IEEE80211_DELBA_PARAM_INITIATOR_MASK 0x0800 | ||
749 | |||
750 | /* | ||
751 | * A-PMDU buffer sizes | ||
752 | * According to IEEE802.11n spec size varies from 8K to 64K (in powers of 2) | ||
753 | */ | ||
754 | #define IEEE80211_MIN_AMPDU_BUF 0x8 | ||
755 | #define IEEE80211_MAX_AMPDU_BUF 0x40 | ||
756 | |||
757 | |||
758 | /* Spatial Multiplexing Power Save Modes */ | ||
759 | #define WLAN_HT_CAP_SM_PS_STATIC 0 | ||
760 | #define WLAN_HT_CAP_SM_PS_DYNAMIC 1 | ||
761 | #define WLAN_HT_CAP_SM_PS_INVALID 2 | ||
762 | #define WLAN_HT_CAP_SM_PS_DISABLED 3 | ||
745 | 763 | ||
746 | /* Authentication algorithms */ | 764 | /* Authentication algorithms */ |
747 | #define WLAN_AUTH_OPEN 0 | 765 | #define WLAN_AUTH_OPEN 0 |
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 7c399a9c11da..fb9e62211c34 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -1142,7 +1142,7 @@ enum ieee80211_ampdu_mlme_action { | |||
1142 | * of assocaited station or AP. | 1142 | * of assocaited station or AP. |
1143 | * | 1143 | * |
1144 | * @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max), | 1144 | * @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max), |
1145 | * bursting) for a hardware TX queue. Must be atomic. | 1145 | * bursting) for a hardware TX queue. |
1146 | * | 1146 | * |
1147 | * @get_tx_stats: Get statistics of the current TX queue status. This is used | 1147 | * @get_tx_stats: Get statistics of the current TX queue status. This is used |
1148 | * to get number of currently queued packets (queue length), maximum queue | 1148 | * to get number of currently queued packets (queue length), maximum queue |
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index a169b0201d61..2dc8f2bff27b 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile | |||
@@ -7,6 +7,8 @@ mac80211-y := \ | |||
7 | sta_info.o \ | 7 | sta_info.o \ |
8 | wep.o \ | 8 | wep.o \ |
9 | wpa.o \ | 9 | wpa.o \ |
10 | scan.o \ | ||
11 | ht.o \ | ||
10 | mlme.o \ | 12 | mlme.o \ |
11 | iface.o \ | 13 | iface.o \ |
12 | rate.o \ | 14 | rate.o \ |
@@ -15,6 +17,7 @@ mac80211-y := \ | |||
15 | aes_ccm.o \ | 17 | aes_ccm.o \ |
16 | cfg.o \ | 18 | cfg.o \ |
17 | rx.o \ | 19 | rx.o \ |
20 | spectmgmt.o \ | ||
18 | tx.o \ | 21 | tx.o \ |
19 | key.o \ | 22 | key.o \ |
20 | util.o \ | 23 | util.o \ |
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c new file mode 100644 index 000000000000..4dc35c9dabc7 --- /dev/null +++ b/net/mac80211/ht.c | |||
@@ -0,0 +1,992 @@ | |||
1 | /* | ||
2 | * HT handling | ||
3 | * | ||
4 | * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi> | ||
5 | * Copyright 2002-2005, Instant802 Networks, Inc. | ||
6 | * Copyright 2005-2006, Devicescape Software, Inc. | ||
7 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> | ||
8 | * Copyright 2007, Michael Wu <flamingice@sourmilk.net> | ||
9 | * Copyright 2007-2008, Intel Corporation | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License version 2 as | ||
13 | * published by the Free Software Foundation. | ||
14 | */ | ||
15 | |||
16 | #include <linux/ieee80211.h> | ||
17 | #include <net/wireless.h> | ||
18 | #include <net/mac80211.h> | ||
19 | #include "ieee80211_i.h" | ||
20 | #include "sta_info.h" | ||
21 | #include "wme.h" | ||
22 | |||
23 | int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie, | ||
24 | struct ieee80211_ht_info *ht_info) | ||
25 | { | ||
26 | |||
27 | if (ht_info == NULL) | ||
28 | return -EINVAL; | ||
29 | |||
30 | memset(ht_info, 0, sizeof(*ht_info)); | ||
31 | |||
32 | if (ht_cap_ie) { | ||
33 | u8 ampdu_info = ht_cap_ie->ampdu_params_info; | ||
34 | |||
35 | ht_info->ht_supported = 1; | ||
36 | ht_info->cap = le16_to_cpu(ht_cap_ie->cap_info); | ||
37 | ht_info->ampdu_factor = | ||
38 | ampdu_info & IEEE80211_HT_CAP_AMPDU_FACTOR; | ||
39 | ht_info->ampdu_density = | ||
40 | (ampdu_info & IEEE80211_HT_CAP_AMPDU_DENSITY) >> 2; | ||
41 | memcpy(ht_info->supp_mcs_set, ht_cap_ie->supp_mcs_set, 16); | ||
42 | } else | ||
43 | ht_info->ht_supported = 0; | ||
44 | |||
45 | return 0; | ||
46 | } | ||
47 | |||
48 | int ieee80211_ht_addt_info_ie_to_ht_bss_info( | ||
49 | struct ieee80211_ht_addt_info *ht_add_info_ie, | ||
50 | struct ieee80211_ht_bss_info *bss_info) | ||
51 | { | ||
52 | if (bss_info == NULL) | ||
53 | return -EINVAL; | ||
54 | |||
55 | memset(bss_info, 0, sizeof(*bss_info)); | ||
56 | |||
57 | if (ht_add_info_ie) { | ||
58 | u16 op_mode; | ||
59 | op_mode = le16_to_cpu(ht_add_info_ie->operation_mode); | ||
60 | |||
61 | bss_info->primary_channel = ht_add_info_ie->control_chan; | ||
62 | bss_info->bss_cap = ht_add_info_ie->ht_param; | ||
63 | bss_info->bss_op_mode = (u8)(op_mode & 0xff); | ||
64 | } | ||
65 | |||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata, | ||
70 | const u8 *da, u16 tid, | ||
71 | u8 dialog_token, u16 start_seq_num, | ||
72 | u16 agg_size, u16 timeout) | ||
73 | { | ||
74 | struct ieee80211_local *local = sdata->local; | ||
75 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
76 | struct sk_buff *skb; | ||
77 | struct ieee80211_mgmt *mgmt; | ||
78 | u16 capab; | ||
79 | |||
80 | skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom); | ||
81 | |||
82 | if (!skb) { | ||
83 | printk(KERN_ERR "%s: failed to allocate buffer " | ||
84 | "for addba request frame\n", sdata->dev->name); | ||
85 | return; | ||
86 | } | ||
87 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
88 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | ||
89 | memset(mgmt, 0, 24); | ||
90 | memcpy(mgmt->da, da, ETH_ALEN); | ||
91 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
92 | if (sdata->vif.type == IEEE80211_IF_TYPE_AP) | ||
93 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); | ||
94 | else | ||
95 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | ||
96 | |||
97 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
98 | IEEE80211_STYPE_ACTION); | ||
99 | |||
100 | skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_req)); | ||
101 | |||
102 | mgmt->u.action.category = WLAN_CATEGORY_BACK; | ||
103 | mgmt->u.action.u.addba_req.action_code = WLAN_ACTION_ADDBA_REQ; | ||
104 | |||
105 | mgmt->u.action.u.addba_req.dialog_token = dialog_token; | ||
106 | capab = (u16)(1 << 1); /* bit 1 aggregation policy */ | ||
107 | capab |= (u16)(tid << 2); /* bit 5:2 TID number */ | ||
108 | capab |= (u16)(agg_size << 6); /* bit 15:6 max size of aggergation */ | ||
109 | |||
110 | mgmt->u.action.u.addba_req.capab = cpu_to_le16(capab); | ||
111 | |||
112 | mgmt->u.action.u.addba_req.timeout = cpu_to_le16(timeout); | ||
113 | mgmt->u.action.u.addba_req.start_seq_num = | ||
114 | cpu_to_le16(start_seq_num << 4); | ||
115 | |||
116 | ieee80211_tx_skb(sdata, skb, 0); | ||
117 | } | ||
118 | |||
119 | static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *da, u16 tid, | ||
120 | u8 dialog_token, u16 status, u16 policy, | ||
121 | u16 buf_size, u16 timeout) | ||
122 | { | ||
123 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
124 | struct ieee80211_local *local = sdata->local; | ||
125 | struct sk_buff *skb; | ||
126 | struct ieee80211_mgmt *mgmt; | ||
127 | u16 capab; | ||
128 | |||
129 | skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom); | ||
130 | |||
131 | if (!skb) { | ||
132 | printk(KERN_DEBUG "%s: failed to allocate buffer " | ||
133 | "for addba resp frame\n", sdata->dev->name); | ||
134 | return; | ||
135 | } | ||
136 | |||
137 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
138 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | ||
139 | memset(mgmt, 0, 24); | ||
140 | memcpy(mgmt->da, da, ETH_ALEN); | ||
141 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
142 | if (sdata->vif.type == IEEE80211_IF_TYPE_AP) | ||
143 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); | ||
144 | else | ||
145 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | ||
146 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
147 | IEEE80211_STYPE_ACTION); | ||
148 | |||
149 | skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_resp)); | ||
150 | mgmt->u.action.category = WLAN_CATEGORY_BACK; | ||
151 | mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP; | ||
152 | mgmt->u.action.u.addba_resp.dialog_token = dialog_token; | ||
153 | |||
154 | capab = (u16)(policy << 1); /* bit 1 aggregation policy */ | ||
155 | capab |= (u16)(tid << 2); /* bit 5:2 TID number */ | ||
156 | capab |= (u16)(buf_size << 6); /* bit 15:6 max size of aggregation */ | ||
157 | |||
158 | mgmt->u.action.u.addba_resp.capab = cpu_to_le16(capab); | ||
159 | mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout); | ||
160 | mgmt->u.action.u.addba_resp.status = cpu_to_le16(status); | ||
161 | |||
162 | ieee80211_tx_skb(sdata, skb, 0); | ||
163 | } | ||
164 | |||
165 | static void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, | ||
166 | const u8 *da, u16 tid, | ||
167 | u16 initiator, u16 reason_code) | ||
168 | { | ||
169 | struct ieee80211_local *local = sdata->local; | ||
170 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
171 | struct sk_buff *skb; | ||
172 | struct ieee80211_mgmt *mgmt; | ||
173 | u16 params; | ||
174 | |||
175 | skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom); | ||
176 | |||
177 | if (!skb) { | ||
178 | printk(KERN_ERR "%s: failed to allocate buffer " | ||
179 | "for delba frame\n", sdata->dev->name); | ||
180 | return; | ||
181 | } | ||
182 | |||
183 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
184 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | ||
185 | memset(mgmt, 0, 24); | ||
186 | memcpy(mgmt->da, da, ETH_ALEN); | ||
187 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
188 | if (sdata->vif.type == IEEE80211_IF_TYPE_AP) | ||
189 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); | ||
190 | else | ||
191 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | ||
192 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
193 | IEEE80211_STYPE_ACTION); | ||
194 | |||
195 | skb_put(skb, 1 + sizeof(mgmt->u.action.u.delba)); | ||
196 | |||
197 | mgmt->u.action.category = WLAN_CATEGORY_BACK; | ||
198 | mgmt->u.action.u.delba.action_code = WLAN_ACTION_DELBA; | ||
199 | params = (u16)(initiator << 11); /* bit 11 initiator */ | ||
200 | params |= (u16)(tid << 12); /* bit 15:12 TID number */ | ||
201 | |||
202 | mgmt->u.action.u.delba.params = cpu_to_le16(params); | ||
203 | mgmt->u.action.u.delba.reason_code = cpu_to_le16(reason_code); | ||
204 | |||
205 | ieee80211_tx_skb(sdata, skb, 0); | ||
206 | } | ||
207 | |||
208 | void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn) | ||
209 | { | ||
210 | struct ieee80211_local *local = sdata->local; | ||
211 | struct sk_buff *skb; | ||
212 | struct ieee80211_bar *bar; | ||
213 | u16 bar_control = 0; | ||
214 | |||
215 | skb = dev_alloc_skb(sizeof(*bar) + local->hw.extra_tx_headroom); | ||
216 | if (!skb) { | ||
217 | printk(KERN_ERR "%s: failed to allocate buffer for " | ||
218 | "bar frame\n", sdata->dev->name); | ||
219 | return; | ||
220 | } | ||
221 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
222 | bar = (struct ieee80211_bar *)skb_put(skb, sizeof(*bar)); | ||
223 | memset(bar, 0, sizeof(*bar)); | ||
224 | bar->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | | ||
225 | IEEE80211_STYPE_BACK_REQ); | ||
226 | memcpy(bar->ra, ra, ETH_ALEN); | ||
227 | memcpy(bar->ta, sdata->dev->dev_addr, ETH_ALEN); | ||
228 | bar_control |= (u16)IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL; | ||
229 | bar_control |= (u16)IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA; | ||
230 | bar_control |= (u16)(tid << 12); | ||
231 | bar->control = cpu_to_le16(bar_control); | ||
232 | bar->start_seq_num = cpu_to_le16(ssn); | ||
233 | |||
234 | ieee80211_tx_skb(sdata, skb, 0); | ||
235 | } | ||
236 | |||
237 | void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, | ||
238 | u16 initiator, u16 reason) | ||
239 | { | ||
240 | struct ieee80211_local *local = sdata->local; | ||
241 | struct ieee80211_hw *hw = &local->hw; | ||
242 | struct sta_info *sta; | ||
243 | int ret, i; | ||
244 | DECLARE_MAC_BUF(mac); | ||
245 | |||
246 | rcu_read_lock(); | ||
247 | |||
248 | sta = sta_info_get(local, ra); | ||
249 | if (!sta) { | ||
250 | rcu_read_unlock(); | ||
251 | return; | ||
252 | } | ||
253 | |||
254 | /* check if TID is in operational state */ | ||
255 | spin_lock_bh(&sta->lock); | ||
256 | if (sta->ampdu_mlme.tid_state_rx[tid] | ||
257 | != HT_AGG_STATE_OPERATIONAL) { | ||
258 | spin_unlock_bh(&sta->lock); | ||
259 | rcu_read_unlock(); | ||
260 | return; | ||
261 | } | ||
262 | sta->ampdu_mlme.tid_state_rx[tid] = | ||
263 | HT_AGG_STATE_REQ_STOP_BA_MSK | | ||
264 | (initiator << HT_AGG_STATE_INITIATOR_SHIFT); | ||
265 | spin_unlock_bh(&sta->lock); | ||
266 | |||
267 | /* stop HW Rx aggregation. ampdu_action existence | ||
268 | * already verified in session init so we add the BUG_ON */ | ||
269 | BUG_ON(!local->ops->ampdu_action); | ||
270 | |||
271 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
272 | printk(KERN_DEBUG "Rx BA session stop requested for %s tid %u\n", | ||
273 | print_mac(mac, ra), tid); | ||
274 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
275 | |||
276 | ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_STOP, | ||
277 | ra, tid, NULL); | ||
278 | if (ret) | ||
279 | printk(KERN_DEBUG "HW problem - can not stop rx " | ||
280 | "aggregation for tid %d\n", tid); | ||
281 | |||
282 | /* shutdown timer has not expired */ | ||
283 | if (initiator != WLAN_BACK_TIMER) | ||
284 | del_timer_sync(&sta->ampdu_mlme.tid_rx[tid]->session_timer); | ||
285 | |||
286 | /* check if this is a self generated aggregation halt */ | ||
287 | if (initiator == WLAN_BACK_RECIPIENT || initiator == WLAN_BACK_TIMER) | ||
288 | ieee80211_send_delba(sdata, ra, tid, 0, reason); | ||
289 | |||
290 | /* free the reordering buffer */ | ||
291 | for (i = 0; i < sta->ampdu_mlme.tid_rx[tid]->buf_size; i++) { | ||
292 | if (sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]) { | ||
293 | /* release the reordered frames */ | ||
294 | dev_kfree_skb(sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]); | ||
295 | sta->ampdu_mlme.tid_rx[tid]->stored_mpdu_num--; | ||
296 | sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i] = NULL; | ||
297 | } | ||
298 | } | ||
299 | /* free resources */ | ||
300 | kfree(sta->ampdu_mlme.tid_rx[tid]->reorder_buf); | ||
301 | kfree(sta->ampdu_mlme.tid_rx[tid]); | ||
302 | sta->ampdu_mlme.tid_rx[tid] = NULL; | ||
303 | sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_IDLE; | ||
304 | |||
305 | rcu_read_unlock(); | ||
306 | } | ||
307 | |||
308 | |||
309 | /* | ||
310 | * After sending add Block Ack request we activated a timer until | ||
311 | * add Block Ack response will arrive from the recipient. | ||
312 | * If this timer expires sta_addba_resp_timer_expired will be executed. | ||
313 | */ | ||
314 | static void sta_addba_resp_timer_expired(unsigned long data) | ||
315 | { | ||
316 | /* not an elegant detour, but there is no choice as the timer passes | ||
317 | * only one argument, and both sta_info and TID are needed, so init | ||
318 | * flow in sta_info_create gives the TID as data, while the timer_to_id | ||
319 | * array gives the sta through container_of */ | ||
320 | u16 tid = *(u8 *)data; | ||
321 | struct sta_info *temp_sta = container_of((void *)data, | ||
322 | struct sta_info, timer_to_tid[tid]); | ||
323 | |||
324 | struct ieee80211_local *local = temp_sta->local; | ||
325 | struct ieee80211_hw *hw = &local->hw; | ||
326 | struct sta_info *sta; | ||
327 | u8 *state; | ||
328 | |||
329 | rcu_read_lock(); | ||
330 | |||
331 | sta = sta_info_get(local, temp_sta->addr); | ||
332 | if (!sta) { | ||
333 | rcu_read_unlock(); | ||
334 | return; | ||
335 | } | ||
336 | |||
337 | state = &sta->ampdu_mlme.tid_state_tx[tid]; | ||
338 | /* check if the TID waits for addBA response */ | ||
339 | spin_lock_bh(&sta->lock); | ||
340 | if (!(*state & HT_ADDBA_REQUESTED_MSK)) { | ||
341 | spin_unlock_bh(&sta->lock); | ||
342 | *state = HT_AGG_STATE_IDLE; | ||
343 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
344 | printk(KERN_DEBUG "timer expired on tid %d but we are not " | ||
345 | "expecting addBA response there", tid); | ||
346 | #endif | ||
347 | goto timer_expired_exit; | ||
348 | } | ||
349 | |||
350 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
351 | printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid); | ||
352 | #endif | ||
353 | |||
354 | /* go through the state check in stop_BA_session */ | ||
355 | *state = HT_AGG_STATE_OPERATIONAL; | ||
356 | spin_unlock_bh(&sta->lock); | ||
357 | ieee80211_stop_tx_ba_session(hw, temp_sta->addr, tid, | ||
358 | WLAN_BACK_INITIATOR); | ||
359 | |||
360 | timer_expired_exit: | ||
361 | rcu_read_unlock(); | ||
362 | } | ||
363 | |||
364 | void ieee80211_sta_tear_down_BA_sessions(struct ieee80211_sub_if_data *sdata, u8 *addr) | ||
365 | { | ||
366 | struct ieee80211_local *local = sdata->local; | ||
367 | int i; | ||
368 | |||
369 | for (i = 0; i < STA_TID_NUM; i++) { | ||
370 | ieee80211_stop_tx_ba_session(&local->hw, addr, i, | ||
371 | WLAN_BACK_INITIATOR); | ||
372 | ieee80211_sta_stop_rx_ba_session(sdata, addr, i, | ||
373 | WLAN_BACK_RECIPIENT, | ||
374 | WLAN_REASON_QSTA_LEAVE_QBSS); | ||
375 | } | ||
376 | } | ||
377 | |||
378 | int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | ||
379 | { | ||
380 | struct ieee80211_local *local = hw_to_local(hw); | ||
381 | struct sta_info *sta; | ||
382 | struct ieee80211_sub_if_data *sdata; | ||
383 | u16 start_seq_num; | ||
384 | u8 *state; | ||
385 | int ret; | ||
386 | DECLARE_MAC_BUF(mac); | ||
387 | |||
388 | if (tid >= STA_TID_NUM) | ||
389 | return -EINVAL; | ||
390 | |||
391 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
392 | printk(KERN_DEBUG "Open BA session requested for %s tid %u\n", | ||
393 | print_mac(mac, ra), tid); | ||
394 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
395 | |||
396 | rcu_read_lock(); | ||
397 | |||
398 | sta = sta_info_get(local, ra); | ||
399 | if (!sta) { | ||
400 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
401 | printk(KERN_DEBUG "Could not find the station\n"); | ||
402 | #endif | ||
403 | ret = -ENOENT; | ||
404 | goto exit; | ||
405 | } | ||
406 | |||
407 | spin_lock_bh(&sta->lock); | ||
408 | |||
409 | /* we have tried too many times, receiver does not want A-MPDU */ | ||
410 | if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) { | ||
411 | ret = -EBUSY; | ||
412 | goto err_unlock_sta; | ||
413 | } | ||
414 | |||
415 | state = &sta->ampdu_mlme.tid_state_tx[tid]; | ||
416 | /* check if the TID is not in aggregation flow already */ | ||
417 | if (*state != HT_AGG_STATE_IDLE) { | ||
418 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
419 | printk(KERN_DEBUG "BA request denied - session is not " | ||
420 | "idle on tid %u\n", tid); | ||
421 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
422 | ret = -EAGAIN; | ||
423 | goto err_unlock_sta; | ||
424 | } | ||
425 | |||
426 | /* prepare A-MPDU MLME for Tx aggregation */ | ||
427 | sta->ampdu_mlme.tid_tx[tid] = | ||
428 | kmalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC); | ||
429 | if (!sta->ampdu_mlme.tid_tx[tid]) { | ||
430 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
431 | if (net_ratelimit()) | ||
432 | printk(KERN_ERR "allocate tx mlme to tid %d failed\n", | ||
433 | tid); | ||
434 | #endif | ||
435 | ret = -ENOMEM; | ||
436 | goto err_unlock_sta; | ||
437 | } | ||
438 | /* Tx timer */ | ||
439 | sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function = | ||
440 | sta_addba_resp_timer_expired; | ||
441 | sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.data = | ||
442 | (unsigned long)&sta->timer_to_tid[tid]; | ||
443 | init_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); | ||
444 | |||
445 | /* create a new queue for this aggregation */ | ||
446 | ret = ieee80211_ht_agg_queue_add(local, sta, tid); | ||
447 | |||
448 | /* case no queue is available to aggregation | ||
449 | * don't switch to aggregation */ | ||
450 | if (ret) { | ||
451 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
452 | printk(KERN_DEBUG "BA request denied - queue unavailable for" | ||
453 | " tid %d\n", tid); | ||
454 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
455 | goto err_unlock_queue; | ||
456 | } | ||
457 | sdata = sta->sdata; | ||
458 | |||
459 | /* Ok, the Addba frame hasn't been sent yet, but if the driver calls the | ||
460 | * call back right away, it must see that the flow has begun */ | ||
461 | *state |= HT_ADDBA_REQUESTED_MSK; | ||
462 | |||
463 | /* This is slightly racy because the queue isn't stopped */ | ||
464 | start_seq_num = sta->tid_seq[tid]; | ||
465 | |||
466 | if (local->ops->ampdu_action) | ||
467 | ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_START, | ||
468 | ra, tid, &start_seq_num); | ||
469 | |||
470 | if (ret) { | ||
471 | /* No need to requeue the packets in the agg queue, since we | ||
472 | * held the tx lock: no packet could be enqueued to the newly | ||
473 | * allocated queue */ | ||
474 | ieee80211_ht_agg_queue_remove(local, sta, tid, 0); | ||
475 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
476 | printk(KERN_DEBUG "BA request denied - HW unavailable for" | ||
477 | " tid %d\n", tid); | ||
478 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
479 | *state = HT_AGG_STATE_IDLE; | ||
480 | goto err_unlock_queue; | ||
481 | } | ||
482 | |||
483 | /* Will put all the packets in the new SW queue */ | ||
484 | ieee80211_requeue(local, ieee802_1d_to_ac[tid]); | ||
485 | spin_unlock_bh(&sta->lock); | ||
486 | |||
487 | /* send an addBA request */ | ||
488 | sta->ampdu_mlme.dialog_token_allocator++; | ||
489 | sta->ampdu_mlme.tid_tx[tid]->dialog_token = | ||
490 | sta->ampdu_mlme.dialog_token_allocator; | ||
491 | sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num; | ||
492 | |||
493 | |||
494 | ieee80211_send_addba_request(sta->sdata, ra, tid, | ||
495 | sta->ampdu_mlme.tid_tx[tid]->dialog_token, | ||
496 | sta->ampdu_mlme.tid_tx[tid]->ssn, | ||
497 | 0x40, 5000); | ||
498 | /* activate the timer for the recipient's addBA response */ | ||
499 | sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires = | ||
500 | jiffies + ADDBA_RESP_INTERVAL; | ||
501 | add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); | ||
502 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
503 | printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid); | ||
504 | #endif | ||
505 | goto exit; | ||
506 | |||
507 | err_unlock_queue: | ||
508 | kfree(sta->ampdu_mlme.tid_tx[tid]); | ||
509 | sta->ampdu_mlme.tid_tx[tid] = NULL; | ||
510 | ret = -EBUSY; | ||
511 | err_unlock_sta: | ||
512 | spin_unlock_bh(&sta->lock); | ||
513 | exit: | ||
514 | rcu_read_unlock(); | ||
515 | return ret; | ||
516 | } | ||
517 | EXPORT_SYMBOL(ieee80211_start_tx_ba_session); | ||
518 | |||
519 | int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, | ||
520 | u8 *ra, u16 tid, | ||
521 | enum ieee80211_back_parties initiator) | ||
522 | { | ||
523 | struct ieee80211_local *local = hw_to_local(hw); | ||
524 | struct sta_info *sta; | ||
525 | u8 *state; | ||
526 | int ret = 0; | ||
527 | DECLARE_MAC_BUF(mac); | ||
528 | |||
529 | if (tid >= STA_TID_NUM) | ||
530 | return -EINVAL; | ||
531 | |||
532 | rcu_read_lock(); | ||
533 | sta = sta_info_get(local, ra); | ||
534 | if (!sta) { | ||
535 | rcu_read_unlock(); | ||
536 | return -ENOENT; | ||
537 | } | ||
538 | |||
539 | /* check if the TID is in aggregation */ | ||
540 | state = &sta->ampdu_mlme.tid_state_tx[tid]; | ||
541 | spin_lock_bh(&sta->lock); | ||
542 | |||
543 | if (*state != HT_AGG_STATE_OPERATIONAL) { | ||
544 | ret = -ENOENT; | ||
545 | goto stop_BA_exit; | ||
546 | } | ||
547 | |||
548 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
549 | printk(KERN_DEBUG "Tx BA session stop requested for %s tid %u\n", | ||
550 | print_mac(mac, ra), tid); | ||
551 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
552 | |||
553 | ieee80211_stop_queue(hw, sta->tid_to_tx_q[tid]); | ||
554 | |||
555 | *state = HT_AGG_STATE_REQ_STOP_BA_MSK | | ||
556 | (initiator << HT_AGG_STATE_INITIATOR_SHIFT); | ||
557 | |||
558 | if (local->ops->ampdu_action) | ||
559 | ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_STOP, | ||
560 | ra, tid, NULL); | ||
561 | |||
562 | /* case HW denied going back to legacy */ | ||
563 | if (ret) { | ||
564 | WARN_ON(ret != -EBUSY); | ||
565 | *state = HT_AGG_STATE_OPERATIONAL; | ||
566 | ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); | ||
567 | goto stop_BA_exit; | ||
568 | } | ||
569 | |||
570 | stop_BA_exit: | ||
571 | spin_unlock_bh(&sta->lock); | ||
572 | rcu_read_unlock(); | ||
573 | return ret; | ||
574 | } | ||
575 | EXPORT_SYMBOL(ieee80211_stop_tx_ba_session); | ||
576 | |||
577 | void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) | ||
578 | { | ||
579 | struct ieee80211_local *local = hw_to_local(hw); | ||
580 | struct sta_info *sta; | ||
581 | u8 *state; | ||
582 | DECLARE_MAC_BUF(mac); | ||
583 | |||
584 | if (tid >= STA_TID_NUM) { | ||
585 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
586 | printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n", | ||
587 | tid, STA_TID_NUM); | ||
588 | #endif | ||
589 | return; | ||
590 | } | ||
591 | |||
592 | rcu_read_lock(); | ||
593 | sta = sta_info_get(local, ra); | ||
594 | if (!sta) { | ||
595 | rcu_read_unlock(); | ||
596 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
597 | printk(KERN_DEBUG "Could not find station: %s\n", | ||
598 | print_mac(mac, ra)); | ||
599 | #endif | ||
600 | return; | ||
601 | } | ||
602 | |||
603 | state = &sta->ampdu_mlme.tid_state_tx[tid]; | ||
604 | spin_lock_bh(&sta->lock); | ||
605 | |||
606 | if (!(*state & HT_ADDBA_REQUESTED_MSK)) { | ||
607 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
608 | printk(KERN_DEBUG "addBA was not requested yet, state is %d\n", | ||
609 | *state); | ||
610 | #endif | ||
611 | spin_unlock_bh(&sta->lock); | ||
612 | rcu_read_unlock(); | ||
613 | return; | ||
614 | } | ||
615 | |||
616 | WARN_ON_ONCE(*state & HT_ADDBA_DRV_READY_MSK); | ||
617 | |||
618 | *state |= HT_ADDBA_DRV_READY_MSK; | ||
619 | |||
620 | if (*state == HT_AGG_STATE_OPERATIONAL) { | ||
621 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
622 | printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid); | ||
623 | #endif | ||
624 | ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); | ||
625 | } | ||
626 | spin_unlock_bh(&sta->lock); | ||
627 | rcu_read_unlock(); | ||
628 | } | ||
629 | EXPORT_SYMBOL(ieee80211_start_tx_ba_cb); | ||
630 | |||
631 | void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) | ||
632 | { | ||
633 | struct ieee80211_local *local = hw_to_local(hw); | ||
634 | struct sta_info *sta; | ||
635 | u8 *state; | ||
636 | int agg_queue; | ||
637 | DECLARE_MAC_BUF(mac); | ||
638 | |||
639 | if (tid >= STA_TID_NUM) { | ||
640 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
641 | printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n", | ||
642 | tid, STA_TID_NUM); | ||
643 | #endif | ||
644 | return; | ||
645 | } | ||
646 | |||
647 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
648 | printk(KERN_DEBUG "Stopping Tx BA session for %s tid %d\n", | ||
649 | print_mac(mac, ra), tid); | ||
650 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
651 | |||
652 | rcu_read_lock(); | ||
653 | sta = sta_info_get(local, ra); | ||
654 | if (!sta) { | ||
655 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
656 | printk(KERN_DEBUG "Could not find station: %s\n", | ||
657 | print_mac(mac, ra)); | ||
658 | #endif | ||
659 | rcu_read_unlock(); | ||
660 | return; | ||
661 | } | ||
662 | state = &sta->ampdu_mlme.tid_state_tx[tid]; | ||
663 | |||
664 | /* NOTE: no need to use sta->lock in this state check, as | ||
665 | * ieee80211_stop_tx_ba_session will let only one stop call to | ||
666 | * pass through per sta/tid | ||
667 | */ | ||
668 | if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) { | ||
669 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
670 | printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n"); | ||
671 | #endif | ||
672 | rcu_read_unlock(); | ||
673 | return; | ||
674 | } | ||
675 | |||
676 | if (*state & HT_AGG_STATE_INITIATOR_MSK) | ||
677 | ieee80211_send_delba(sta->sdata, ra, tid, | ||
678 | WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE); | ||
679 | |||
680 | agg_queue = sta->tid_to_tx_q[tid]; | ||
681 | |||
682 | ieee80211_ht_agg_queue_remove(local, sta, tid, 1); | ||
683 | |||
684 | /* We just requeued the all the frames that were in the | ||
685 | * removed queue, and since we might miss a softirq we do | ||
686 | * netif_schedule_queue. ieee80211_wake_queue is not used | ||
687 | * here as this queue is not necessarily stopped | ||
688 | */ | ||
689 | netif_schedule_queue(netdev_get_tx_queue(local->mdev, agg_queue)); | ||
690 | spin_lock_bh(&sta->lock); | ||
691 | *state = HT_AGG_STATE_IDLE; | ||
692 | sta->ampdu_mlme.addba_req_num[tid] = 0; | ||
693 | kfree(sta->ampdu_mlme.tid_tx[tid]); | ||
694 | sta->ampdu_mlme.tid_tx[tid] = NULL; | ||
695 | spin_unlock_bh(&sta->lock); | ||
696 | |||
697 | rcu_read_unlock(); | ||
698 | } | ||
699 | EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb); | ||
700 | |||
701 | void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, | ||
702 | const u8 *ra, u16 tid) | ||
703 | { | ||
704 | struct ieee80211_local *local = hw_to_local(hw); | ||
705 | struct ieee80211_ra_tid *ra_tid; | ||
706 | struct sk_buff *skb = dev_alloc_skb(0); | ||
707 | |||
708 | if (unlikely(!skb)) { | ||
709 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
710 | if (net_ratelimit()) | ||
711 | printk(KERN_WARNING "%s: Not enough memory, " | ||
712 | "dropping start BA session", skb->dev->name); | ||
713 | #endif | ||
714 | return; | ||
715 | } | ||
716 | ra_tid = (struct ieee80211_ra_tid *) &skb->cb; | ||
717 | memcpy(&ra_tid->ra, ra, ETH_ALEN); | ||
718 | ra_tid->tid = tid; | ||
719 | |||
720 | skb->pkt_type = IEEE80211_ADDBA_MSG; | ||
721 | skb_queue_tail(&local->skb_queue, skb); | ||
722 | tasklet_schedule(&local->tasklet); | ||
723 | } | ||
724 | EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe); | ||
725 | |||
726 | void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, | ||
727 | const u8 *ra, u16 tid) | ||
728 | { | ||
729 | struct ieee80211_local *local = hw_to_local(hw); | ||
730 | struct ieee80211_ra_tid *ra_tid; | ||
731 | struct sk_buff *skb = dev_alloc_skb(0); | ||
732 | |||
733 | if (unlikely(!skb)) { | ||
734 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
735 | if (net_ratelimit()) | ||
736 | printk(KERN_WARNING "%s: Not enough memory, " | ||
737 | "dropping stop BA session", skb->dev->name); | ||
738 | #endif | ||
739 | return; | ||
740 | } | ||
741 | ra_tid = (struct ieee80211_ra_tid *) &skb->cb; | ||
742 | memcpy(&ra_tid->ra, ra, ETH_ALEN); | ||
743 | ra_tid->tid = tid; | ||
744 | |||
745 | skb->pkt_type = IEEE80211_DELBA_MSG; | ||
746 | skb_queue_tail(&local->skb_queue, skb); | ||
747 | tasklet_schedule(&local->tasklet); | ||
748 | } | ||
749 | EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb_irqsafe); | ||
750 | |||
751 | /* | ||
752 | * After accepting the AddBA Request we activated a timer, | ||
753 | * resetting it after each frame that arrives from the originator. | ||
754 | * if this timer expires ieee80211_sta_stop_rx_ba_session will be executed. | ||
755 | */ | ||
756 | static void sta_rx_agg_session_timer_expired(unsigned long data) | ||
757 | { | ||
758 | /* not an elegant detour, but there is no choice as the timer passes | ||
759 | * only one argument, and various sta_info are needed here, so init | ||
760 | * flow in sta_info_create gives the TID as data, while the timer_to_id | ||
761 | * array gives the sta through container_of */ | ||
762 | u8 *ptid = (u8 *)data; | ||
763 | u8 *timer_to_id = ptid - *ptid; | ||
764 | struct sta_info *sta = container_of(timer_to_id, struct sta_info, | ||
765 | timer_to_tid[0]); | ||
766 | |||
767 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
768 | printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid); | ||
769 | #endif | ||
770 | ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->addr, | ||
771 | (u16)*ptid, WLAN_BACK_TIMER, | ||
772 | WLAN_REASON_QSTA_TIMEOUT); | ||
773 | } | ||
774 | |||
775 | void ieee80211_process_addba_request(struct ieee80211_local *local, | ||
776 | struct sta_info *sta, | ||
777 | struct ieee80211_mgmt *mgmt, | ||
778 | size_t len) | ||
779 | { | ||
780 | struct ieee80211_hw *hw = &local->hw; | ||
781 | struct ieee80211_conf *conf = &hw->conf; | ||
782 | struct tid_ampdu_rx *tid_agg_rx; | ||
783 | u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num, status; | ||
784 | u8 dialog_token; | ||
785 | int ret = -EOPNOTSUPP; | ||
786 | DECLARE_MAC_BUF(mac); | ||
787 | |||
788 | /* extract session parameters from addba request frame */ | ||
789 | dialog_token = mgmt->u.action.u.addba_req.dialog_token; | ||
790 | timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout); | ||
791 | start_seq_num = | ||
792 | le16_to_cpu(mgmt->u.action.u.addba_req.start_seq_num) >> 4; | ||
793 | |||
794 | capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab); | ||
795 | ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1; | ||
796 | tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; | ||
797 | buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6; | ||
798 | |||
799 | status = WLAN_STATUS_REQUEST_DECLINED; | ||
800 | |||
801 | /* sanity check for incoming parameters: | ||
802 | * check if configuration can support the BA policy | ||
803 | * and if buffer size does not exceeds max value */ | ||
804 | if (((ba_policy != 1) | ||
805 | && (!(conf->ht_conf.cap & IEEE80211_HT_CAP_DELAY_BA))) | ||
806 | || (buf_size > IEEE80211_MAX_AMPDU_BUF)) { | ||
807 | status = WLAN_STATUS_INVALID_QOS_PARAM; | ||
808 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
809 | if (net_ratelimit()) | ||
810 | printk(KERN_DEBUG "AddBA Req with bad params from " | ||
811 | "%s on tid %u. policy %d, buffer size %d\n", | ||
812 | print_mac(mac, mgmt->sa), tid, ba_policy, | ||
813 | buf_size); | ||
814 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
815 | goto end_no_lock; | ||
816 | } | ||
817 | /* determine default buffer size */ | ||
818 | if (buf_size == 0) { | ||
819 | struct ieee80211_supported_band *sband; | ||
820 | |||
821 | sband = local->hw.wiphy->bands[conf->channel->band]; | ||
822 | buf_size = IEEE80211_MIN_AMPDU_BUF; | ||
823 | buf_size = buf_size << sband->ht_info.ampdu_factor; | ||
824 | } | ||
825 | |||
826 | |||
827 | /* examine state machine */ | ||
828 | spin_lock_bh(&sta->lock); | ||
829 | |||
830 | if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_IDLE) { | ||
831 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
832 | if (net_ratelimit()) | ||
833 | printk(KERN_DEBUG "unexpected AddBA Req from " | ||
834 | "%s on tid %u\n", | ||
835 | print_mac(mac, mgmt->sa), tid); | ||
836 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
837 | goto end; | ||
838 | } | ||
839 | |||
840 | /* prepare A-MPDU MLME for Rx aggregation */ | ||
841 | sta->ampdu_mlme.tid_rx[tid] = | ||
842 | kmalloc(sizeof(struct tid_ampdu_rx), GFP_ATOMIC); | ||
843 | if (!sta->ampdu_mlme.tid_rx[tid]) { | ||
844 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
845 | if (net_ratelimit()) | ||
846 | printk(KERN_ERR "allocate rx mlme to tid %d failed\n", | ||
847 | tid); | ||
848 | #endif | ||
849 | goto end; | ||
850 | } | ||
851 | /* rx timer */ | ||
852 | sta->ampdu_mlme.tid_rx[tid]->session_timer.function = | ||
853 | sta_rx_agg_session_timer_expired; | ||
854 | sta->ampdu_mlme.tid_rx[tid]->session_timer.data = | ||
855 | (unsigned long)&sta->timer_to_tid[tid]; | ||
856 | init_timer(&sta->ampdu_mlme.tid_rx[tid]->session_timer); | ||
857 | |||
858 | tid_agg_rx = sta->ampdu_mlme.tid_rx[tid]; | ||
859 | |||
860 | /* prepare reordering buffer */ | ||
861 | tid_agg_rx->reorder_buf = | ||
862 | kmalloc(buf_size * sizeof(struct sk_buff *), GFP_ATOMIC); | ||
863 | if (!tid_agg_rx->reorder_buf) { | ||
864 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
865 | if (net_ratelimit()) | ||
866 | printk(KERN_ERR "can not allocate reordering buffer " | ||
867 | "to tid %d\n", tid); | ||
868 | #endif | ||
869 | kfree(sta->ampdu_mlme.tid_rx[tid]); | ||
870 | goto end; | ||
871 | } | ||
872 | memset(tid_agg_rx->reorder_buf, 0, | ||
873 | buf_size * sizeof(struct sk_buff *)); | ||
874 | |||
875 | if (local->ops->ampdu_action) | ||
876 | ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_START, | ||
877 | sta->addr, tid, &start_seq_num); | ||
878 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
879 | printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret); | ||
880 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
881 | |||
882 | if (ret) { | ||
883 | kfree(tid_agg_rx->reorder_buf); | ||
884 | kfree(tid_agg_rx); | ||
885 | sta->ampdu_mlme.tid_rx[tid] = NULL; | ||
886 | goto end; | ||
887 | } | ||
888 | |||
889 | /* change state and send addba resp */ | ||
890 | sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_OPERATIONAL; | ||
891 | tid_agg_rx->dialog_token = dialog_token; | ||
892 | tid_agg_rx->ssn = start_seq_num; | ||
893 | tid_agg_rx->head_seq_num = start_seq_num; | ||
894 | tid_agg_rx->buf_size = buf_size; | ||
895 | tid_agg_rx->timeout = timeout; | ||
896 | tid_agg_rx->stored_mpdu_num = 0; | ||
897 | status = WLAN_STATUS_SUCCESS; | ||
898 | end: | ||
899 | spin_unlock_bh(&sta->lock); | ||
900 | |||
901 | end_no_lock: | ||
902 | ieee80211_send_addba_resp(sta->sdata, sta->addr, tid, | ||
903 | dialog_token, status, 1, buf_size, timeout); | ||
904 | } | ||
905 | |||
906 | void ieee80211_process_addba_resp(struct ieee80211_local *local, | ||
907 | struct sta_info *sta, | ||
908 | struct ieee80211_mgmt *mgmt, | ||
909 | size_t len) | ||
910 | { | ||
911 | struct ieee80211_hw *hw = &local->hw; | ||
912 | u16 capab; | ||
913 | u16 tid; | ||
914 | u8 *state; | ||
915 | |||
916 | capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab); | ||
917 | tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; | ||
918 | |||
919 | state = &sta->ampdu_mlme.tid_state_tx[tid]; | ||
920 | |||
921 | spin_lock_bh(&sta->lock); | ||
922 | |||
923 | if (!(*state & HT_ADDBA_REQUESTED_MSK)) { | ||
924 | spin_unlock_bh(&sta->lock); | ||
925 | return; | ||
926 | } | ||
927 | |||
928 | if (mgmt->u.action.u.addba_resp.dialog_token != | ||
929 | sta->ampdu_mlme.tid_tx[tid]->dialog_token) { | ||
930 | spin_unlock_bh(&sta->lock); | ||
931 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
932 | printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid); | ||
933 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
934 | return; | ||
935 | } | ||
936 | |||
937 | del_timer_sync(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); | ||
938 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
939 | printk(KERN_DEBUG "switched off addBA timer for tid %d \n", tid); | ||
940 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
941 | if (le16_to_cpu(mgmt->u.action.u.addba_resp.status) | ||
942 | == WLAN_STATUS_SUCCESS) { | ||
943 | *state |= HT_ADDBA_RECEIVED_MSK; | ||
944 | sta->ampdu_mlme.addba_req_num[tid] = 0; | ||
945 | |||
946 | if (*state == HT_AGG_STATE_OPERATIONAL) | ||
947 | ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); | ||
948 | |||
949 | spin_unlock_bh(&sta->lock); | ||
950 | } else { | ||
951 | sta->ampdu_mlme.addba_req_num[tid]++; | ||
952 | /* this will allow the state check in stop_BA_session */ | ||
953 | *state = HT_AGG_STATE_OPERATIONAL; | ||
954 | spin_unlock_bh(&sta->lock); | ||
955 | ieee80211_stop_tx_ba_session(hw, sta->addr, tid, | ||
956 | WLAN_BACK_INITIATOR); | ||
957 | } | ||
958 | } | ||
959 | |||
960 | void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, | ||
961 | struct sta_info *sta, | ||
962 | struct ieee80211_mgmt *mgmt, size_t len) | ||
963 | { | ||
964 | struct ieee80211_local *local = sdata->local; | ||
965 | u16 tid, params; | ||
966 | u16 initiator; | ||
967 | DECLARE_MAC_BUF(mac); | ||
968 | |||
969 | params = le16_to_cpu(mgmt->u.action.u.delba.params); | ||
970 | tid = (params & IEEE80211_DELBA_PARAM_TID_MASK) >> 12; | ||
971 | initiator = (params & IEEE80211_DELBA_PARAM_INITIATOR_MASK) >> 11; | ||
972 | |||
973 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
974 | if (net_ratelimit()) | ||
975 | printk(KERN_DEBUG "delba from %s (%s) tid %d reason code %d\n", | ||
976 | print_mac(mac, mgmt->sa), | ||
977 | initiator ? "initiator" : "recipient", tid, | ||
978 | mgmt->u.action.u.delba.reason_code); | ||
979 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
980 | |||
981 | if (initiator == WLAN_BACK_INITIATOR) | ||
982 | ieee80211_sta_stop_rx_ba_session(sdata, sta->addr, tid, | ||
983 | WLAN_BACK_INITIATOR, 0); | ||
984 | else { /* WLAN_BACK_RECIPIENT */ | ||
985 | spin_lock_bh(&sta->lock); | ||
986 | sta->ampdu_mlme.tid_state_tx[tid] = | ||
987 | HT_AGG_STATE_OPERATIONAL; | ||
988 | spin_unlock_bh(&sta->lock); | ||
989 | ieee80211_stop_tx_ba_session(&local->hw, sta->addr, tid, | ||
990 | WLAN_BACK_RECIPIENT); | ||
991 | } | ||
992 | } | ||
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index c68d4df11196..6f334e4c3d66 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -53,6 +53,12 @@ struct ieee80211_local; | |||
53 | * increased memory use (about 2 kB of RAM per entry). */ | 53 | * increased memory use (about 2 kB of RAM per entry). */ |
54 | #define IEEE80211_FRAGMENT_MAX 4 | 54 | #define IEEE80211_FRAGMENT_MAX 4 |
55 | 55 | ||
56 | /* | ||
57 | * Time after which we ignore scan results and no longer report/use | ||
58 | * them in any way. | ||
59 | */ | ||
60 | #define IEEE80211_SCAN_RESULT_EXPIRE (10 * HZ) | ||
61 | |||
56 | struct ieee80211_fragment_entry { | 62 | struct ieee80211_fragment_entry { |
57 | unsigned long first_frag_time; | 63 | unsigned long first_frag_time; |
58 | unsigned int seq; | 64 | unsigned int seq; |
@@ -636,7 +642,7 @@ struct ieee80211_local { | |||
636 | enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state; | 642 | enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state; |
637 | unsigned long last_scan_completed; | 643 | unsigned long last_scan_completed; |
638 | struct delayed_work scan_work; | 644 | struct delayed_work scan_work; |
639 | struct net_device *scan_dev; | 645 | struct ieee80211_sub_if_data *scan_sdata; |
640 | struct ieee80211_channel *oper_channel, *scan_channel; | 646 | struct ieee80211_channel *oper_channel, *scan_channel; |
641 | u8 scan_ssid[IEEE80211_MAX_SSID_LEN]; | 647 | u8 scan_ssid[IEEE80211_MAX_SSID_LEN]; |
642 | size_t scan_ssid_len; | 648 | size_t scan_ssid_len; |
@@ -903,29 +909,31 @@ int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason); | |||
903 | void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, | 909 | void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, |
904 | u32 changed); | 910 | u32 changed); |
905 | u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata); | 911 | u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata); |
906 | int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie, | ||
907 | struct ieee80211_ht_info *ht_info); | ||
908 | int ieee80211_ht_addt_info_ie_to_ht_bss_info( | ||
909 | struct ieee80211_ht_addt_info *ht_add_info_ie, | ||
910 | struct ieee80211_ht_bss_info *bss_info); | ||
911 | void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata, const u8 *da, | ||
912 | u16 tid, u8 dialog_token, u16 start_seq_num, | ||
913 | u16 agg_size, u16 timeout); | ||
914 | void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, const u8 *da, u16 tid, | ||
915 | u16 initiator, u16 reason_code); | ||
916 | void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn); | ||
917 | |||
918 | void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *da, | ||
919 | u16 tid, u16 initiator, u16 reason); | ||
920 | void sta_addba_resp_timer_expired(unsigned long data); | ||
921 | void ieee80211_sta_tear_down_BA_sessions(struct ieee80211_sub_if_data *sdata, u8 *addr); | ||
922 | u64 ieee80211_sta_get_rates(struct ieee80211_local *local, | 912 | u64 ieee80211_sta_get_rates(struct ieee80211_local *local, |
923 | struct ieee802_11_elems *elems, | 913 | struct ieee802_11_elems *elems, |
924 | enum ieee80211_band band); | 914 | enum ieee80211_band band); |
925 | void ieee80211_sta_tx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | 915 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, |
926 | int encrypt); | 916 | u8 *ssid, size_t ssid_len); |
927 | void ieee802_11_parse_elems(u8 *start, size_t len, | 917 | void ieee802_11_parse_elems(u8 *start, size_t len, |
928 | struct ieee802_11_elems *elems); | 918 | struct ieee802_11_elems *elems); |
919 | void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local); | ||
920 | int ieee80211_sta_start_scan(struct ieee80211_sub_if_data *scan_sdata, | ||
921 | u8 *ssid, size_t ssid_len); | ||
922 | struct ieee80211_sta_bss * | ||
923 | ieee80211_bss_info_update(struct ieee80211_local *local, | ||
924 | struct ieee80211_rx_status *rx_status, | ||
925 | struct ieee80211_mgmt *mgmt, | ||
926 | size_t len, | ||
927 | struct ieee802_11_elems *elems, | ||
928 | int freq, bool beacon); | ||
929 | struct ieee80211_sta_bss * | ||
930 | ieee80211_rx_bss_add(struct ieee80211_local *local, u8 *bssid, int freq, | ||
931 | u8 *ssid, u8 ssid_len); | ||
932 | struct ieee80211_sta_bss * | ||
933 | ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq, | ||
934 | u8 *ssid, u8 ssid_len); | ||
935 | void ieee80211_rx_bss_put(struct ieee80211_local *local, | ||
936 | struct ieee80211_sta_bss *bss); | ||
929 | 937 | ||
930 | #ifdef CONFIG_MAC80211_MESH | 938 | #ifdef CONFIG_MAC80211_MESH |
931 | void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata); | 939 | void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata); |
@@ -951,6 +959,34 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev); | |||
951 | int ieee80211_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev); | 959 | int ieee80211_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev); |
952 | int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev); | 960 | int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev); |
953 | 961 | ||
962 | /* HT */ | ||
963 | int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie, | ||
964 | struct ieee80211_ht_info *ht_info); | ||
965 | int ieee80211_ht_addt_info_ie_to_ht_bss_info( | ||
966 | struct ieee80211_ht_addt_info *ht_add_info_ie, | ||
967 | struct ieee80211_ht_bss_info *bss_info); | ||
968 | void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn); | ||
969 | |||
970 | void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *da, | ||
971 | u16 tid, u16 initiator, u16 reason); | ||
972 | void ieee80211_sta_tear_down_BA_sessions(struct ieee80211_sub_if_data *sdata, u8 *addr); | ||
973 | void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, | ||
974 | struct sta_info *sta, | ||
975 | struct ieee80211_mgmt *mgmt, size_t len); | ||
976 | void ieee80211_process_addba_resp(struct ieee80211_local *local, | ||
977 | struct sta_info *sta, | ||
978 | struct ieee80211_mgmt *mgmt, | ||
979 | size_t len); | ||
980 | void ieee80211_process_addba_request(struct ieee80211_local *local, | ||
981 | struct sta_info *sta, | ||
982 | struct ieee80211_mgmt *mgmt, | ||
983 | size_t len); | ||
984 | |||
985 | /* Spectrum management */ | ||
986 | void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, | ||
987 | struct ieee80211_mgmt *mgmt, | ||
988 | size_t len); | ||
989 | |||
954 | /* utility functions/constants */ | 990 | /* utility functions/constants */ |
955 | extern void *mac80211_wiphy_privid; /* for wiphy privid */ | 991 | extern void *mac80211_wiphy_privid; /* for wiphy privid */ |
956 | extern const unsigned char rfc1042_header[6]; | 992 | extern const unsigned char rfc1042_header[6]; |
@@ -961,6 +997,9 @@ int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, | |||
961 | int rate, int erp, int short_preamble); | 997 | int rate, int erp, int short_preamble); |
962 | void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int keyidx, | 998 | void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int keyidx, |
963 | struct ieee80211_hdr *hdr); | 999 | struct ieee80211_hdr *hdr); |
1000 | void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata); | ||
1001 | void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | ||
1002 | int encrypt); | ||
964 | 1003 | ||
965 | #ifdef CONFIG_MAC80211_NOINLINE | 1004 | #ifdef CONFIG_MAC80211_NOINLINE |
966 | #define debug_noinline noinline | 1005 | #define debug_noinline noinline |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 4a623b8e91fd..672cec60a2fb 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -31,11 +31,11 @@ static void ieee80211_teardown_sdata(struct net_device *dev) | |||
31 | int flushed; | 31 | int flushed; |
32 | int i; | 32 | int i; |
33 | 33 | ||
34 | ieee80211_debugfs_remove_netdev(sdata); | ||
35 | |||
36 | /* free extra data */ | 34 | /* free extra data */ |
37 | ieee80211_free_keys(sdata); | 35 | ieee80211_free_keys(sdata); |
38 | 36 | ||
37 | ieee80211_debugfs_remove_netdev(sdata); | ||
38 | |||
39 | for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) | 39 | for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) |
40 | __skb_queue_purge(&sdata->fragments[i].skb_list); | 40 | __skb_queue_purge(&sdata->fragments[i].skb_list); |
41 | sdata->fragment_next = 0; | 41 | sdata->fragment_next = 0; |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 396cfb2d0f46..6a7f4fae18c2 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -399,8 +399,15 @@ static int ieee80211_open(struct net_device *dev) | |||
399 | atomic_inc(&local->iff_promiscs); | 399 | atomic_inc(&local->iff_promiscs); |
400 | 400 | ||
401 | local->open_count++; | 401 | local->open_count++; |
402 | if (need_hw_reconfig) | 402 | if (need_hw_reconfig) { |
403 | ieee80211_hw_config(local); | 403 | ieee80211_hw_config(local); |
404 | /* | ||
405 | * set default queue parameters so drivers don't | ||
406 | * need to initialise the hardware if the hardware | ||
407 | * doesn't start up with sane defaults | ||
408 | */ | ||
409 | ieee80211_set_wmm_default(sdata); | ||
410 | } | ||
404 | 411 | ||
405 | /* | 412 | /* |
406 | * ieee80211_sta_work is disabled while network interface | 413 | * ieee80211_sta_work is disabled while network interface |
@@ -551,7 +558,7 @@ static int ieee80211_stop(struct net_device *dev) | |||
551 | synchronize_rcu(); | 558 | synchronize_rcu(); |
552 | skb_queue_purge(&sdata->u.sta.skb_queue); | 559 | skb_queue_purge(&sdata->u.sta.skb_queue); |
553 | 560 | ||
554 | if (local->scan_dev == sdata->dev) { | 561 | if (local->scan_sdata == sdata) { |
555 | if (!local->ops->hw_scan) { | 562 | if (!local->ops->hw_scan) { |
556 | local->sta_sw_scanning = 0; | 563 | local->sta_sw_scanning = 0; |
557 | cancel_delayed_work(&local->scan_work); | 564 | cancel_delayed_work(&local->scan_work); |
@@ -593,379 +600,6 @@ static int ieee80211_stop(struct net_device *dev) | |||
593 | return 0; | 600 | return 0; |
594 | } | 601 | } |
595 | 602 | ||
596 | int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | ||
597 | { | ||
598 | struct ieee80211_local *local = hw_to_local(hw); | ||
599 | struct sta_info *sta; | ||
600 | struct ieee80211_sub_if_data *sdata; | ||
601 | u16 start_seq_num; | ||
602 | u8 *state; | ||
603 | int ret; | ||
604 | DECLARE_MAC_BUF(mac); | ||
605 | |||
606 | if (tid >= STA_TID_NUM) | ||
607 | return -EINVAL; | ||
608 | |||
609 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
610 | printk(KERN_DEBUG "Open BA session requested for %s tid %u\n", | ||
611 | print_mac(mac, ra), tid); | ||
612 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
613 | |||
614 | rcu_read_lock(); | ||
615 | |||
616 | sta = sta_info_get(local, ra); | ||
617 | if (!sta) { | ||
618 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
619 | printk(KERN_DEBUG "Could not find the station\n"); | ||
620 | #endif | ||
621 | ret = -ENOENT; | ||
622 | goto exit; | ||
623 | } | ||
624 | |||
625 | spin_lock_bh(&sta->lock); | ||
626 | |||
627 | /* we have tried too many times, receiver does not want A-MPDU */ | ||
628 | if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) { | ||
629 | ret = -EBUSY; | ||
630 | goto err_unlock_sta; | ||
631 | } | ||
632 | |||
633 | state = &sta->ampdu_mlme.tid_state_tx[tid]; | ||
634 | /* check if the TID is not in aggregation flow already */ | ||
635 | if (*state != HT_AGG_STATE_IDLE) { | ||
636 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
637 | printk(KERN_DEBUG "BA request denied - session is not " | ||
638 | "idle on tid %u\n", tid); | ||
639 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
640 | ret = -EAGAIN; | ||
641 | goto err_unlock_sta; | ||
642 | } | ||
643 | |||
644 | /* prepare A-MPDU MLME for Tx aggregation */ | ||
645 | sta->ampdu_mlme.tid_tx[tid] = | ||
646 | kmalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC); | ||
647 | if (!sta->ampdu_mlme.tid_tx[tid]) { | ||
648 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
649 | if (net_ratelimit()) | ||
650 | printk(KERN_ERR "allocate tx mlme to tid %d failed\n", | ||
651 | tid); | ||
652 | #endif | ||
653 | ret = -ENOMEM; | ||
654 | goto err_unlock_sta; | ||
655 | } | ||
656 | /* Tx timer */ | ||
657 | sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function = | ||
658 | sta_addba_resp_timer_expired; | ||
659 | sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.data = | ||
660 | (unsigned long)&sta->timer_to_tid[tid]; | ||
661 | init_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); | ||
662 | |||
663 | /* create a new queue for this aggregation */ | ||
664 | ret = ieee80211_ht_agg_queue_add(local, sta, tid); | ||
665 | |||
666 | /* case no queue is available to aggregation | ||
667 | * don't switch to aggregation */ | ||
668 | if (ret) { | ||
669 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
670 | printk(KERN_DEBUG "BA request denied - queue unavailable for" | ||
671 | " tid %d\n", tid); | ||
672 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
673 | goto err_unlock_queue; | ||
674 | } | ||
675 | sdata = sta->sdata; | ||
676 | |||
677 | /* Ok, the Addba frame hasn't been sent yet, but if the driver calls the | ||
678 | * call back right away, it must see that the flow has begun */ | ||
679 | *state |= HT_ADDBA_REQUESTED_MSK; | ||
680 | |||
681 | /* This is slightly racy because the queue isn't stopped */ | ||
682 | start_seq_num = sta->tid_seq[tid]; | ||
683 | |||
684 | if (local->ops->ampdu_action) | ||
685 | ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_START, | ||
686 | ra, tid, &start_seq_num); | ||
687 | |||
688 | if (ret) { | ||
689 | /* No need to requeue the packets in the agg queue, since we | ||
690 | * held the tx lock: no packet could be enqueued to the newly | ||
691 | * allocated queue */ | ||
692 | ieee80211_ht_agg_queue_remove(local, sta, tid, 0); | ||
693 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
694 | printk(KERN_DEBUG "BA request denied - HW unavailable for" | ||
695 | " tid %d\n", tid); | ||
696 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
697 | *state = HT_AGG_STATE_IDLE; | ||
698 | goto err_unlock_queue; | ||
699 | } | ||
700 | |||
701 | /* Will put all the packets in the new SW queue */ | ||
702 | ieee80211_requeue(local, ieee802_1d_to_ac[tid]); | ||
703 | spin_unlock_bh(&sta->lock); | ||
704 | |||
705 | /* send an addBA request */ | ||
706 | sta->ampdu_mlme.dialog_token_allocator++; | ||
707 | sta->ampdu_mlme.tid_tx[tid]->dialog_token = | ||
708 | sta->ampdu_mlme.dialog_token_allocator; | ||
709 | sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num; | ||
710 | |||
711 | |||
712 | ieee80211_send_addba_request(sta->sdata, ra, tid, | ||
713 | sta->ampdu_mlme.tid_tx[tid]->dialog_token, | ||
714 | sta->ampdu_mlme.tid_tx[tid]->ssn, | ||
715 | 0x40, 5000); | ||
716 | /* activate the timer for the recipient's addBA response */ | ||
717 | sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires = | ||
718 | jiffies + ADDBA_RESP_INTERVAL; | ||
719 | add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); | ||
720 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
721 | printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid); | ||
722 | #endif | ||
723 | goto exit; | ||
724 | |||
725 | err_unlock_queue: | ||
726 | kfree(sta->ampdu_mlme.tid_tx[tid]); | ||
727 | sta->ampdu_mlme.tid_tx[tid] = NULL; | ||
728 | ret = -EBUSY; | ||
729 | err_unlock_sta: | ||
730 | spin_unlock_bh(&sta->lock); | ||
731 | exit: | ||
732 | rcu_read_unlock(); | ||
733 | return ret; | ||
734 | } | ||
735 | EXPORT_SYMBOL(ieee80211_start_tx_ba_session); | ||
736 | |||
737 | int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, | ||
738 | u8 *ra, u16 tid, | ||
739 | enum ieee80211_back_parties initiator) | ||
740 | { | ||
741 | struct ieee80211_local *local = hw_to_local(hw); | ||
742 | struct sta_info *sta; | ||
743 | u8 *state; | ||
744 | int ret = 0; | ||
745 | DECLARE_MAC_BUF(mac); | ||
746 | |||
747 | if (tid >= STA_TID_NUM) | ||
748 | return -EINVAL; | ||
749 | |||
750 | rcu_read_lock(); | ||
751 | sta = sta_info_get(local, ra); | ||
752 | if (!sta) { | ||
753 | rcu_read_unlock(); | ||
754 | return -ENOENT; | ||
755 | } | ||
756 | |||
757 | /* check if the TID is in aggregation */ | ||
758 | state = &sta->ampdu_mlme.tid_state_tx[tid]; | ||
759 | spin_lock_bh(&sta->lock); | ||
760 | |||
761 | if (*state != HT_AGG_STATE_OPERATIONAL) { | ||
762 | ret = -ENOENT; | ||
763 | goto stop_BA_exit; | ||
764 | } | ||
765 | |||
766 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
767 | printk(KERN_DEBUG "Tx BA session stop requested for %s tid %u\n", | ||
768 | print_mac(mac, ra), tid); | ||
769 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
770 | |||
771 | ieee80211_stop_queue(hw, sta->tid_to_tx_q[tid]); | ||
772 | |||
773 | *state = HT_AGG_STATE_REQ_STOP_BA_MSK | | ||
774 | (initiator << HT_AGG_STATE_INITIATOR_SHIFT); | ||
775 | |||
776 | if (local->ops->ampdu_action) | ||
777 | ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_STOP, | ||
778 | ra, tid, NULL); | ||
779 | |||
780 | /* case HW denied going back to legacy */ | ||
781 | if (ret) { | ||
782 | WARN_ON(ret != -EBUSY); | ||
783 | *state = HT_AGG_STATE_OPERATIONAL; | ||
784 | ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); | ||
785 | goto stop_BA_exit; | ||
786 | } | ||
787 | |||
788 | stop_BA_exit: | ||
789 | spin_unlock_bh(&sta->lock); | ||
790 | rcu_read_unlock(); | ||
791 | return ret; | ||
792 | } | ||
793 | EXPORT_SYMBOL(ieee80211_stop_tx_ba_session); | ||
794 | |||
795 | void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) | ||
796 | { | ||
797 | struct ieee80211_local *local = hw_to_local(hw); | ||
798 | struct sta_info *sta; | ||
799 | u8 *state; | ||
800 | DECLARE_MAC_BUF(mac); | ||
801 | |||
802 | if (tid >= STA_TID_NUM) { | ||
803 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
804 | printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n", | ||
805 | tid, STA_TID_NUM); | ||
806 | #endif | ||
807 | return; | ||
808 | } | ||
809 | |||
810 | rcu_read_lock(); | ||
811 | sta = sta_info_get(local, ra); | ||
812 | if (!sta) { | ||
813 | rcu_read_unlock(); | ||
814 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
815 | printk(KERN_DEBUG "Could not find station: %s\n", | ||
816 | print_mac(mac, ra)); | ||
817 | #endif | ||
818 | return; | ||
819 | } | ||
820 | |||
821 | state = &sta->ampdu_mlme.tid_state_tx[tid]; | ||
822 | spin_lock_bh(&sta->lock); | ||
823 | |||
824 | if (!(*state & HT_ADDBA_REQUESTED_MSK)) { | ||
825 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
826 | printk(KERN_DEBUG "addBA was not requested yet, state is %d\n", | ||
827 | *state); | ||
828 | #endif | ||
829 | spin_unlock_bh(&sta->lock); | ||
830 | rcu_read_unlock(); | ||
831 | return; | ||
832 | } | ||
833 | |||
834 | WARN_ON_ONCE(*state & HT_ADDBA_DRV_READY_MSK); | ||
835 | |||
836 | *state |= HT_ADDBA_DRV_READY_MSK; | ||
837 | |||
838 | if (*state == HT_AGG_STATE_OPERATIONAL) { | ||
839 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
840 | printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid); | ||
841 | #endif | ||
842 | ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); | ||
843 | } | ||
844 | spin_unlock_bh(&sta->lock); | ||
845 | rcu_read_unlock(); | ||
846 | } | ||
847 | EXPORT_SYMBOL(ieee80211_start_tx_ba_cb); | ||
848 | |||
849 | void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) | ||
850 | { | ||
851 | struct ieee80211_local *local = hw_to_local(hw); | ||
852 | struct sta_info *sta; | ||
853 | u8 *state; | ||
854 | int agg_queue; | ||
855 | DECLARE_MAC_BUF(mac); | ||
856 | |||
857 | if (tid >= STA_TID_NUM) { | ||
858 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
859 | printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n", | ||
860 | tid, STA_TID_NUM); | ||
861 | #endif | ||
862 | return; | ||
863 | } | ||
864 | |||
865 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
866 | printk(KERN_DEBUG "Stopping Tx BA session for %s tid %d\n", | ||
867 | print_mac(mac, ra), tid); | ||
868 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
869 | |||
870 | rcu_read_lock(); | ||
871 | sta = sta_info_get(local, ra); | ||
872 | if (!sta) { | ||
873 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
874 | printk(KERN_DEBUG "Could not find station: %s\n", | ||
875 | print_mac(mac, ra)); | ||
876 | #endif | ||
877 | rcu_read_unlock(); | ||
878 | return; | ||
879 | } | ||
880 | state = &sta->ampdu_mlme.tid_state_tx[tid]; | ||
881 | |||
882 | /* NOTE: no need to use sta->lock in this state check, as | ||
883 | * ieee80211_stop_tx_ba_session will let only one stop call to | ||
884 | * pass through per sta/tid | ||
885 | */ | ||
886 | if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) { | ||
887 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
888 | printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n"); | ||
889 | #endif | ||
890 | rcu_read_unlock(); | ||
891 | return; | ||
892 | } | ||
893 | |||
894 | if (*state & HT_AGG_STATE_INITIATOR_MSK) | ||
895 | ieee80211_send_delba(sta->sdata, ra, tid, | ||
896 | WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE); | ||
897 | |||
898 | agg_queue = sta->tid_to_tx_q[tid]; | ||
899 | |||
900 | ieee80211_ht_agg_queue_remove(local, sta, tid, 1); | ||
901 | |||
902 | /* We just requeued the all the frames that were in the | ||
903 | * removed queue, and since we might miss a softirq we do | ||
904 | * netif_schedule_queue. ieee80211_wake_queue is not used | ||
905 | * here as this queue is not necessarily stopped | ||
906 | */ | ||
907 | netif_schedule_queue(netdev_get_tx_queue(local->mdev, agg_queue)); | ||
908 | spin_lock_bh(&sta->lock); | ||
909 | *state = HT_AGG_STATE_IDLE; | ||
910 | sta->ampdu_mlme.addba_req_num[tid] = 0; | ||
911 | kfree(sta->ampdu_mlme.tid_tx[tid]); | ||
912 | sta->ampdu_mlme.tid_tx[tid] = NULL; | ||
913 | spin_unlock_bh(&sta->lock); | ||
914 | |||
915 | rcu_read_unlock(); | ||
916 | } | ||
917 | EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb); | ||
918 | |||
919 | void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, | ||
920 | const u8 *ra, u16 tid) | ||
921 | { | ||
922 | struct ieee80211_local *local = hw_to_local(hw); | ||
923 | struct ieee80211_ra_tid *ra_tid; | ||
924 | struct sk_buff *skb = dev_alloc_skb(0); | ||
925 | |||
926 | if (unlikely(!skb)) { | ||
927 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
928 | if (net_ratelimit()) | ||
929 | printk(KERN_WARNING "%s: Not enough memory, " | ||
930 | "dropping start BA session", skb->dev->name); | ||
931 | #endif | ||
932 | return; | ||
933 | } | ||
934 | ra_tid = (struct ieee80211_ra_tid *) &skb->cb; | ||
935 | memcpy(&ra_tid->ra, ra, ETH_ALEN); | ||
936 | ra_tid->tid = tid; | ||
937 | |||
938 | skb->pkt_type = IEEE80211_ADDBA_MSG; | ||
939 | skb_queue_tail(&local->skb_queue, skb); | ||
940 | tasklet_schedule(&local->tasklet); | ||
941 | } | ||
942 | EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe); | ||
943 | |||
944 | void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, | ||
945 | const u8 *ra, u16 tid) | ||
946 | { | ||
947 | struct ieee80211_local *local = hw_to_local(hw); | ||
948 | struct ieee80211_ra_tid *ra_tid; | ||
949 | struct sk_buff *skb = dev_alloc_skb(0); | ||
950 | |||
951 | if (unlikely(!skb)) { | ||
952 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
953 | if (net_ratelimit()) | ||
954 | printk(KERN_WARNING "%s: Not enough memory, " | ||
955 | "dropping stop BA session", skb->dev->name); | ||
956 | #endif | ||
957 | return; | ||
958 | } | ||
959 | ra_tid = (struct ieee80211_ra_tid *) &skb->cb; | ||
960 | memcpy(&ra_tid->ra, ra, ETH_ALEN); | ||
961 | ra_tid->tid = tid; | ||
962 | |||
963 | skb->pkt_type = IEEE80211_DELBA_MSG; | ||
964 | skb_queue_tail(&local->skb_queue, skb); | ||
965 | tasklet_schedule(&local->tasklet); | ||
966 | } | ||
967 | EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb_irqsafe); | ||
968 | |||
969 | static void ieee80211_set_multicast_list(struct net_device *dev) | 603 | static void ieee80211_set_multicast_list(struct net_device *dev) |
970 | { | 604 | { |
971 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 605 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
@@ -1140,8 +774,8 @@ u32 ieee80211_handle_ht(struct ieee80211_local *local, int enable_ht, | |||
1140 | ht_conf.ht_supported = 1; | 774 | ht_conf.ht_supported = 1; |
1141 | 775 | ||
1142 | ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap; | 776 | ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap; |
1143 | ht_conf.cap &= ~(IEEE80211_HT_CAP_MIMO_PS); | 777 | ht_conf.cap &= ~(IEEE80211_HT_CAP_SM_PS); |
1144 | ht_conf.cap |= sband->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS; | 778 | ht_conf.cap |= sband->ht_info.cap & IEEE80211_HT_CAP_SM_PS; |
1145 | ht_bss_conf.primary_channel = req_bss_cap->primary_channel; | 779 | ht_bss_conf.primary_channel = req_bss_cap->primary_channel; |
1146 | ht_bss_conf.bss_cap = req_bss_cap->bss_cap; | 780 | ht_bss_conf.bss_cap = req_bss_cap->bss_cap; |
1147 | ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode; | 781 | ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode; |
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index eeb0ce2d5d37..210d6b852406 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c | |||
@@ -149,7 +149,7 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, | |||
149 | pos += ETH_ALEN; | 149 | pos += ETH_ALEN; |
150 | memcpy(pos, &dst_dsn, 4); | 150 | memcpy(pos, &dst_dsn, 4); |
151 | 151 | ||
152 | ieee80211_sta_tx(sdata, skb, 0); | 152 | ieee80211_tx_skb(sdata, skb, 0); |
153 | return 0; | 153 | return 0; |
154 | } | 154 | } |
155 | 155 | ||
@@ -198,7 +198,7 @@ int mesh_path_error_tx(u8 *dst, __le32 dst_dsn, u8 *ra, | |||
198 | pos += ETH_ALEN; | 198 | pos += ETH_ALEN; |
199 | memcpy(pos, &dst_dsn, 4); | 199 | memcpy(pos, &dst_dsn, 4); |
200 | 200 | ||
201 | ieee80211_sta_tx(sdata, skb, 0); | 201 | ieee80211_tx_skb(sdata, skb, 0); |
202 | return 0; | 202 | return 0; |
203 | } | 203 | } |
204 | 204 | ||
@@ -581,6 +581,10 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, | |||
581 | size_t baselen; | 581 | size_t baselen; |
582 | u32 last_hop_metric; | 582 | u32 last_hop_metric; |
583 | 583 | ||
584 | /* need action_code */ | ||
585 | if (len < IEEE80211_MIN_ACTION_SIZE + 1) | ||
586 | return; | ||
587 | |||
584 | baselen = (u8 *) mgmt->u.action.u.mesh_action.variable - (u8 *) mgmt; | 588 | baselen = (u8 *) mgmt->u.action.u.mesh_action.variable - (u8 *) mgmt; |
585 | ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable, | 589 | ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable, |
586 | len - baselen, &elems); | 590 | len - baselen, &elems); |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 7714b0e6e4d7..7356462dee96 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -217,7 +217,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
217 | memcpy(pos, &reason, 2); | 217 | memcpy(pos, &reason, 2); |
218 | } | 218 | } |
219 | 219 | ||
220 | ieee80211_sta_tx(sdata, skb, 0); | 220 | ieee80211_tx_skb(sdata, skb, 0); |
221 | return 0; | 221 | return 0; |
222 | } | 222 | } |
223 | 223 | ||
@@ -421,6 +421,10 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
421 | DECLARE_MAC_BUF(mac); | 421 | DECLARE_MAC_BUF(mac); |
422 | #endif | 422 | #endif |
423 | 423 | ||
424 | /* need action_code, aux */ | ||
425 | if (len < IEEE80211_MIN_ACTION_SIZE + 3) | ||
426 | return; | ||
427 | |||
424 | if (is_multicast_ether_addr(mgmt->da)) { | 428 | if (is_multicast_ether_addr(mgmt->da)) { |
425 | mpl_dbg("Mesh plink: ignore frame from multicast address"); | 429 | mpl_dbg("Mesh plink: ignore frame from multicast address"); |
426 | return; | 430 | return; |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index df12e746b03e..2c06f6965b7d 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -11,11 +11,6 @@ | |||
11 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
12 | */ | 12 | */ |
13 | 13 | ||
14 | /* TODO: | ||
15 | * order BSS list by RSSI(?) ("quality of AP") | ||
16 | * scan result table filtering (by capability (privacy, IBSS/BSS, WPA/RSN IE, | ||
17 | * SSID) | ||
18 | */ | ||
19 | #include <linux/delay.h> | 14 | #include <linux/delay.h> |
20 | #include <linux/if_ether.h> | 15 | #include <linux/if_ether.h> |
21 | #include <linux/skbuff.h> | 16 | #include <linux/skbuff.h> |
@@ -26,9 +21,8 @@ | |||
26 | #include <linux/etherdevice.h> | 21 | #include <linux/etherdevice.h> |
27 | #include <linux/rtnetlink.h> | 22 | #include <linux/rtnetlink.h> |
28 | #include <net/iw_handler.h> | 23 | #include <net/iw_handler.h> |
29 | #include <asm/types.h> | ||
30 | |||
31 | #include <net/mac80211.h> | 24 | #include <net/mac80211.h> |
25 | |||
32 | #include "ieee80211_i.h" | 26 | #include "ieee80211_i.h" |
33 | #include "rate.h" | 27 | #include "rate.h" |
34 | #include "led.h" | 28 | #include "led.h" |
@@ -47,10 +41,6 @@ | |||
47 | #define IEEE80211_SCAN_INTERVAL_SLOW (15 * HZ) | 41 | #define IEEE80211_SCAN_INTERVAL_SLOW (15 * HZ) |
48 | #define IEEE80211_IBSS_JOIN_TIMEOUT (7 * HZ) | 42 | #define IEEE80211_IBSS_JOIN_TIMEOUT (7 * HZ) |
49 | 43 | ||
50 | #define IEEE80211_PROBE_DELAY (HZ / 33) | ||
51 | #define IEEE80211_CHANNEL_TIME (HZ / 33) | ||
52 | #define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 5) | ||
53 | #define IEEE80211_SCAN_RESULT_EXPIRE (10 * HZ) | ||
54 | #define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ) | 44 | #define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ) |
55 | #define IEEE80211_IBSS_INACTIVITY_LIMIT (60 * HZ) | 45 | #define IEEE80211_IBSS_INACTIVITY_LIMIT (60 * HZ) |
56 | #define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ) | 46 | #define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ) |
@@ -58,219 +48,396 @@ | |||
58 | #define IEEE80211_IBSS_MAX_STA_ENTRIES 128 | 48 | #define IEEE80211_IBSS_MAX_STA_ENTRIES 128 |
59 | 49 | ||
60 | 50 | ||
61 | #define ERP_INFO_USE_PROTECTION BIT(1) | 51 | /* utils */ |
52 | static int ecw2cw(int ecw) | ||
53 | { | ||
54 | return (1 << ecw) - 1; | ||
55 | } | ||
62 | 56 | ||
63 | /* mgmt header + 1 byte action code */ | 57 | static u8 *ieee80211_bss_get_ie(struct ieee80211_sta_bss *bss, u8 ie) |
64 | #define IEEE80211_MIN_ACTION_SIZE (24 + 1) | 58 | { |
59 | u8 *end, *pos; | ||
65 | 60 | ||
66 | #define IEEE80211_ADDBA_PARAM_POLICY_MASK 0x0002 | 61 | pos = bss->ies; |
67 | #define IEEE80211_ADDBA_PARAM_TID_MASK 0x003C | 62 | if (pos == NULL) |
68 | #define IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK 0xFFA0 | 63 | return NULL; |
69 | #define IEEE80211_DELBA_PARAM_TID_MASK 0xF000 | 64 | end = pos + bss->ies_len; |
70 | #define IEEE80211_DELBA_PARAM_INITIATOR_MASK 0x0800 | ||
71 | 65 | ||
72 | /* next values represent the buffer size for A-MPDU frame. | 66 | while (pos + 1 < end) { |
73 | * According to IEEE802.11n spec size varies from 8K to 64K (in powers of 2) */ | 67 | if (pos + 2 + pos[1] > end) |
74 | #define IEEE80211_MIN_AMPDU_BUF 0x8 | 68 | break; |
75 | #define IEEE80211_MAX_AMPDU_BUF 0x40 | 69 | if (pos[0] == ie) |
70 | return pos; | ||
71 | pos += 2 + pos[1]; | ||
72 | } | ||
76 | 73 | ||
77 | static void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | 74 | return NULL; |
78 | u8 *ssid, size_t ssid_len); | 75 | } |
79 | static struct ieee80211_sta_bss * | ||
80 | ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq, | ||
81 | u8 *ssid, u8 ssid_len); | ||
82 | static void ieee80211_rx_bss_put(struct ieee80211_local *local, | ||
83 | struct ieee80211_sta_bss *bss); | ||
84 | static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata, | ||
85 | struct ieee80211_if_sta *ifsta); | ||
86 | static int ieee80211_sta_wep_configured(struct ieee80211_sub_if_data *sdata); | ||
87 | static int ieee80211_sta_start_scan(struct ieee80211_sub_if_data *sdata, | ||
88 | u8 *ssid, size_t ssid_len); | ||
89 | static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata, | ||
90 | struct ieee80211_if_sta *ifsta); | ||
91 | static void sta_rx_agg_session_timer_expired(unsigned long data); | ||
92 | 76 | ||
77 | static int ieee80211_compatible_rates(struct ieee80211_sta_bss *bss, | ||
78 | struct ieee80211_supported_band *sband, | ||
79 | u64 *rates) | ||
80 | { | ||
81 | int i, j, count; | ||
82 | *rates = 0; | ||
83 | count = 0; | ||
84 | for (i = 0; i < bss->supp_rates_len; i++) { | ||
85 | int rate = (bss->supp_rates[i] & 0x7F) * 5; | ||
86 | |||
87 | for (j = 0; j < sband->n_bitrates; j++) | ||
88 | if (sband->bitrates[j].bitrate == rate) { | ||
89 | *rates |= BIT(j); | ||
90 | count++; | ||
91 | break; | ||
92 | } | ||
93 | } | ||
93 | 94 | ||
94 | void ieee802_11_parse_elems(u8 *start, size_t len, | 95 | return count; |
95 | struct ieee802_11_elems *elems) | 96 | } |
97 | |||
98 | /* frame sending functions */ | ||
99 | static void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | ||
100 | struct ieee80211_if_sta *ifsta, | ||
101 | int transaction, u8 *extra, size_t extra_len, | ||
102 | int encrypt) | ||
96 | { | 103 | { |
97 | size_t left = len; | 104 | struct ieee80211_local *local = sdata->local; |
98 | u8 *pos = start; | 105 | struct sk_buff *skb; |
106 | struct ieee80211_mgmt *mgmt; | ||
99 | 107 | ||
100 | memset(elems, 0, sizeof(*elems)); | 108 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + |
101 | elems->ie_start = start; | 109 | sizeof(*mgmt) + 6 + extra_len); |
102 | elems->total_len = len; | 110 | if (!skb) { |
111 | printk(KERN_DEBUG "%s: failed to allocate buffer for auth " | ||
112 | "frame\n", sdata->dev->name); | ||
113 | return; | ||
114 | } | ||
115 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
103 | 116 | ||
104 | while (left >= 2) { | 117 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6); |
105 | u8 id, elen; | 118 | memset(mgmt, 0, 24 + 6); |
119 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
120 | IEEE80211_STYPE_AUTH); | ||
121 | if (encrypt) | ||
122 | mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); | ||
123 | memcpy(mgmt->da, ifsta->bssid, ETH_ALEN); | ||
124 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
125 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | ||
126 | mgmt->u.auth.auth_alg = cpu_to_le16(ifsta->auth_alg); | ||
127 | mgmt->u.auth.auth_transaction = cpu_to_le16(transaction); | ||
128 | ifsta->auth_transaction = transaction + 1; | ||
129 | mgmt->u.auth.status_code = cpu_to_le16(0); | ||
130 | if (extra) | ||
131 | memcpy(skb_put(skb, extra_len), extra, extra_len); | ||
106 | 132 | ||
107 | id = *pos++; | 133 | ieee80211_tx_skb(sdata, skb, encrypt); |
108 | elen = *pos++; | 134 | } |
109 | left -= 2; | ||
110 | 135 | ||
111 | if (elen > left) | 136 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, |
112 | return; | 137 | u8 *ssid, size_t ssid_len) |
138 | { | ||
139 | struct ieee80211_local *local = sdata->local; | ||
140 | struct ieee80211_supported_band *sband; | ||
141 | struct sk_buff *skb; | ||
142 | struct ieee80211_mgmt *mgmt; | ||
143 | u8 *pos, *supp_rates, *esupp_rates = NULL; | ||
144 | int i; | ||
113 | 145 | ||
114 | switch (id) { | 146 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200); |
115 | case WLAN_EID_SSID: | 147 | if (!skb) { |
116 | elems->ssid = pos; | 148 | printk(KERN_DEBUG "%s: failed to allocate buffer for probe " |
117 | elems->ssid_len = elen; | 149 | "request\n", sdata->dev->name); |
118 | break; | 150 | return; |
119 | case WLAN_EID_SUPP_RATES: | 151 | } |
120 | elems->supp_rates = pos; | 152 | skb_reserve(skb, local->hw.extra_tx_headroom); |
121 | elems->supp_rates_len = elen; | 153 | |
122 | break; | 154 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); |
123 | case WLAN_EID_FH_PARAMS: | 155 | memset(mgmt, 0, 24); |
124 | elems->fh_params = pos; | 156 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
125 | elems->fh_params_len = elen; | 157 | IEEE80211_STYPE_PROBE_REQ); |
126 | break; | 158 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); |
127 | case WLAN_EID_DS_PARAMS: | 159 | if (dst) { |
128 | elems->ds_params = pos; | 160 | memcpy(mgmt->da, dst, ETH_ALEN); |
129 | elems->ds_params_len = elen; | 161 | memcpy(mgmt->bssid, dst, ETH_ALEN); |
130 | break; | 162 | } else { |
131 | case WLAN_EID_CF_PARAMS: | 163 | memset(mgmt->da, 0xff, ETH_ALEN); |
132 | elems->cf_params = pos; | 164 | memset(mgmt->bssid, 0xff, ETH_ALEN); |
133 | elems->cf_params_len = elen; | 165 | } |
134 | break; | 166 | pos = skb_put(skb, 2 + ssid_len); |
135 | case WLAN_EID_TIM: | 167 | *pos++ = WLAN_EID_SSID; |
136 | elems->tim = pos; | 168 | *pos++ = ssid_len; |
137 | elems->tim_len = elen; | 169 | memcpy(pos, ssid, ssid_len); |
138 | break; | 170 | |
139 | case WLAN_EID_IBSS_PARAMS: | 171 | supp_rates = skb_put(skb, 2); |
140 | elems->ibss_params = pos; | 172 | supp_rates[0] = WLAN_EID_SUPP_RATES; |
141 | elems->ibss_params_len = elen; | 173 | supp_rates[1] = 0; |
142 | break; | 174 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
143 | case WLAN_EID_CHALLENGE: | 175 | |
144 | elems->challenge = pos; | 176 | for (i = 0; i < sband->n_bitrates; i++) { |
145 | elems->challenge_len = elen; | 177 | struct ieee80211_rate *rate = &sband->bitrates[i]; |
146 | break; | 178 | if (esupp_rates) { |
147 | case WLAN_EID_WPA: | 179 | pos = skb_put(skb, 1); |
148 | if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 && | 180 | esupp_rates[1]++; |
149 | pos[2] == 0xf2) { | 181 | } else if (supp_rates[1] == 8) { |
150 | /* Microsoft OUI (00:50:F2) */ | 182 | esupp_rates = skb_put(skb, 3); |
151 | if (pos[3] == 1) { | 183 | esupp_rates[0] = WLAN_EID_EXT_SUPP_RATES; |
152 | /* OUI Type 1 - WPA IE */ | 184 | esupp_rates[1] = 1; |
153 | elems->wpa = pos; | 185 | pos = &esupp_rates[2]; |
154 | elems->wpa_len = elen; | 186 | } else { |
155 | } else if (elen >= 5 && pos[3] == 2) { | 187 | pos = skb_put(skb, 1); |
156 | if (pos[4] == 0) { | 188 | supp_rates[1]++; |
157 | elems->wmm_info = pos; | 189 | } |
158 | elems->wmm_info_len = elen; | 190 | *pos = rate->bitrate / 5; |
159 | } else if (pos[4] == 1) { | 191 | } |
160 | elems->wmm_param = pos; | 192 | |
161 | elems->wmm_param_len = elen; | 193 | ieee80211_tx_skb(sdata, skb, 0); |
162 | } | 194 | } |
163 | } | 195 | |
164 | } | 196 | static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, |
165 | break; | 197 | struct ieee80211_if_sta *ifsta) |
166 | case WLAN_EID_RSN: | 198 | { |
167 | elems->rsn = pos; | 199 | struct ieee80211_local *local = sdata->local; |
168 | elems->rsn_len = elen; | 200 | struct sk_buff *skb; |
169 | break; | 201 | struct ieee80211_mgmt *mgmt; |
170 | case WLAN_EID_ERP_INFO: | 202 | u8 *pos, *ies, *ht_add_ie; |
171 | elems->erp_info = pos; | 203 | int i, len, count, rates_len, supp_rates_len; |
172 | elems->erp_info_len = elen; | 204 | u16 capab; |
173 | break; | 205 | struct ieee80211_sta_bss *bss; |
174 | case WLAN_EID_EXT_SUPP_RATES: | 206 | int wmm = 0; |
175 | elems->ext_supp_rates = pos; | 207 | struct ieee80211_supported_band *sband; |
176 | elems->ext_supp_rates_len = elen; | 208 | u64 rates = 0; |
177 | break; | 209 | |
178 | case WLAN_EID_HT_CAPABILITY: | 210 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + |
179 | elems->ht_cap_elem = pos; | 211 | sizeof(*mgmt) + 200 + ifsta->extra_ie_len + |
180 | elems->ht_cap_elem_len = elen; | 212 | ifsta->ssid_len); |
181 | break; | 213 | if (!skb) { |
182 | case WLAN_EID_HT_EXTRA_INFO: | 214 | printk(KERN_DEBUG "%s: failed to allocate buffer for assoc " |
183 | elems->ht_info_elem = pos; | 215 | "frame\n", sdata->dev->name); |
184 | elems->ht_info_elem_len = elen; | 216 | return; |
185 | break; | 217 | } |
186 | case WLAN_EID_MESH_ID: | 218 | skb_reserve(skb, local->hw.extra_tx_headroom); |
187 | elems->mesh_id = pos; | 219 | |
188 | elems->mesh_id_len = elen; | 220 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
189 | break; | 221 | |
190 | case WLAN_EID_MESH_CONFIG: | 222 | capab = ifsta->capab; |
191 | elems->mesh_config = pos; | 223 | |
192 | elems->mesh_config_len = elen; | 224 | if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) { |
193 | break; | 225 | if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE)) |
194 | case WLAN_EID_PEER_LINK: | 226 | capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME; |
195 | elems->peer_link = pos; | 227 | if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE)) |
196 | elems->peer_link_len = elen; | 228 | capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; |
197 | break; | 229 | } |
198 | case WLAN_EID_PREQ: | 230 | |
199 | elems->preq = pos; | 231 | bss = ieee80211_rx_bss_get(local, ifsta->bssid, |
200 | elems->preq_len = elen; | 232 | local->hw.conf.channel->center_freq, |
201 | break; | 233 | ifsta->ssid, ifsta->ssid_len); |
202 | case WLAN_EID_PREP: | 234 | if (bss) { |
203 | elems->prep = pos; | 235 | if (bss->capability & WLAN_CAPABILITY_PRIVACY) |
204 | elems->prep_len = elen; | 236 | capab |= WLAN_CAPABILITY_PRIVACY; |
205 | break; | 237 | if (bss->wmm_used) |
206 | case WLAN_EID_PERR: | 238 | wmm = 1; |
207 | elems->perr = pos; | 239 | |
208 | elems->perr_len = elen; | 240 | /* get all rates supported by the device and the AP as |
209 | break; | 241 | * some APs don't like getting a superset of their rates |
210 | case WLAN_EID_CHANNEL_SWITCH: | 242 | * in the association request (e.g. D-Link DAP 1353 in |
211 | elems->ch_switch_elem = pos; | 243 | * b-only mode) */ |
212 | elems->ch_switch_elem_len = elen; | 244 | rates_len = ieee80211_compatible_rates(bss, sband, &rates); |
213 | break; | 245 | |
214 | case WLAN_EID_QUIET: | 246 | if ((bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT) && |
215 | if (!elems->quiet_elem) { | 247 | (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)) |
216 | elems->quiet_elem = pos; | 248 | capab |= WLAN_CAPABILITY_SPECTRUM_MGMT; |
217 | elems->quiet_elem_len = elen; | 249 | |
250 | ieee80211_rx_bss_put(local, bss); | ||
251 | } else { | ||
252 | rates = ~0; | ||
253 | rates_len = sband->n_bitrates; | ||
254 | } | ||
255 | |||
256 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | ||
257 | memset(mgmt, 0, 24); | ||
258 | memcpy(mgmt->da, ifsta->bssid, ETH_ALEN); | ||
259 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
260 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | ||
261 | |||
262 | if (ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) { | ||
263 | skb_put(skb, 10); | ||
264 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
265 | IEEE80211_STYPE_REASSOC_REQ); | ||
266 | mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab); | ||
267 | mgmt->u.reassoc_req.listen_interval = | ||
268 | cpu_to_le16(local->hw.conf.listen_interval); | ||
269 | memcpy(mgmt->u.reassoc_req.current_ap, ifsta->prev_bssid, | ||
270 | ETH_ALEN); | ||
271 | } else { | ||
272 | skb_put(skb, 4); | ||
273 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
274 | IEEE80211_STYPE_ASSOC_REQ); | ||
275 | mgmt->u.assoc_req.capab_info = cpu_to_le16(capab); | ||
276 | mgmt->u.reassoc_req.listen_interval = | ||
277 | cpu_to_le16(local->hw.conf.listen_interval); | ||
278 | } | ||
279 | |||
280 | /* SSID */ | ||
281 | ies = pos = skb_put(skb, 2 + ifsta->ssid_len); | ||
282 | *pos++ = WLAN_EID_SSID; | ||
283 | *pos++ = ifsta->ssid_len; | ||
284 | memcpy(pos, ifsta->ssid, ifsta->ssid_len); | ||
285 | |||
286 | /* add all rates which were marked to be used above */ | ||
287 | supp_rates_len = rates_len; | ||
288 | if (supp_rates_len > 8) | ||
289 | supp_rates_len = 8; | ||
290 | |||
291 | len = sband->n_bitrates; | ||
292 | pos = skb_put(skb, supp_rates_len + 2); | ||
293 | *pos++ = WLAN_EID_SUPP_RATES; | ||
294 | *pos++ = supp_rates_len; | ||
295 | |||
296 | count = 0; | ||
297 | for (i = 0; i < sband->n_bitrates; i++) { | ||
298 | if (BIT(i) & rates) { | ||
299 | int rate = sband->bitrates[i].bitrate; | ||
300 | *pos++ = (u8) (rate / 5); | ||
301 | if (++count == 8) | ||
302 | break; | ||
303 | } | ||
304 | } | ||
305 | |||
306 | if (rates_len > count) { | ||
307 | pos = skb_put(skb, rates_len - count + 2); | ||
308 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | ||
309 | *pos++ = rates_len - count; | ||
310 | |||
311 | for (i++; i < sband->n_bitrates; i++) { | ||
312 | if (BIT(i) & rates) { | ||
313 | int rate = sband->bitrates[i].bitrate; | ||
314 | *pos++ = (u8) (rate / 5); | ||
218 | } | 315 | } |
219 | elems->num_of_quiet_elem++; | ||
220 | break; | ||
221 | case WLAN_EID_COUNTRY: | ||
222 | elems->country_elem = pos; | ||
223 | elems->country_elem_len = elen; | ||
224 | break; | ||
225 | case WLAN_EID_PWR_CONSTRAINT: | ||
226 | elems->pwr_constr_elem = pos; | ||
227 | elems->pwr_constr_elem_len = elen; | ||
228 | break; | ||
229 | default: | ||
230 | break; | ||
231 | } | 316 | } |
317 | } | ||
318 | |||
319 | if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) { | ||
320 | /* 1. power capabilities */ | ||
321 | pos = skb_put(skb, 4); | ||
322 | *pos++ = WLAN_EID_PWR_CAPABILITY; | ||
323 | *pos++ = 2; | ||
324 | *pos++ = 0; /* min tx power */ | ||
325 | *pos++ = local->hw.conf.channel->max_power; /* max tx power */ | ||
232 | 326 | ||
233 | left -= elen; | 327 | /* 2. supported channels */ |
234 | pos += elen; | 328 | /* TODO: get this in reg domain format */ |
329 | pos = skb_put(skb, 2 * sband->n_channels + 2); | ||
330 | *pos++ = WLAN_EID_SUPPORTED_CHANNELS; | ||
331 | *pos++ = 2 * sband->n_channels; | ||
332 | for (i = 0; i < sband->n_channels; i++) { | ||
333 | *pos++ = ieee80211_frequency_to_channel( | ||
334 | sband->channels[i].center_freq); | ||
335 | *pos++ = 1; /* one channel in the subband*/ | ||
336 | } | ||
235 | } | 337 | } |
236 | } | ||
237 | 338 | ||
339 | if (ifsta->extra_ie) { | ||
340 | pos = skb_put(skb, ifsta->extra_ie_len); | ||
341 | memcpy(pos, ifsta->extra_ie, ifsta->extra_ie_len); | ||
342 | } | ||
238 | 343 | ||
239 | static u8 * ieee80211_bss_get_ie(struct ieee80211_sta_bss *bss, u8 ie) | 344 | if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) { |
240 | { | 345 | pos = skb_put(skb, 9); |
241 | u8 *end, *pos; | 346 | *pos++ = WLAN_EID_VENDOR_SPECIFIC; |
347 | *pos++ = 7; /* len */ | ||
348 | *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */ | ||
349 | *pos++ = 0x50; | ||
350 | *pos++ = 0xf2; | ||
351 | *pos++ = 2; /* WME */ | ||
352 | *pos++ = 0; /* WME info */ | ||
353 | *pos++ = 1; /* WME ver */ | ||
354 | *pos++ = 0; | ||
355 | } | ||
242 | 356 | ||
243 | pos = bss->ies; | 357 | /* wmm support is a must to HT */ |
244 | if (pos == NULL) | 358 | if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED) && |
245 | return NULL; | 359 | sband->ht_info.ht_supported && |
246 | end = pos + bss->ies_len; | 360 | (ht_add_ie = ieee80211_bss_get_ie(bss, WLAN_EID_HT_EXTRA_INFO))) { |
361 | struct ieee80211_ht_addt_info *ht_add_info = | ||
362 | (struct ieee80211_ht_addt_info *)ht_add_ie; | ||
363 | u16 cap = sband->ht_info.cap; | ||
364 | __le16 tmp; | ||
365 | u32 flags = local->hw.conf.channel->flags; | ||
247 | 366 | ||
248 | while (pos + 1 < end) { | 367 | switch (ht_add_info->ht_param & IEEE80211_HT_IE_CHA_SEC_OFFSET) { |
249 | if (pos + 2 + pos[1] > end) | 368 | case IEEE80211_HT_IE_CHA_SEC_ABOVE: |
369 | if (flags & IEEE80211_CHAN_NO_FAT_ABOVE) { | ||
370 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH; | ||
371 | cap &= ~IEEE80211_HT_CAP_SGI_40; | ||
372 | } | ||
250 | break; | 373 | break; |
251 | if (pos[0] == ie) | 374 | case IEEE80211_HT_IE_CHA_SEC_BELOW: |
252 | return pos; | 375 | if (flags & IEEE80211_CHAN_NO_FAT_BELOW) { |
253 | pos += 2 + pos[1]; | 376 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH; |
377 | cap &= ~IEEE80211_HT_CAP_SGI_40; | ||
378 | } | ||
379 | break; | ||
380 | } | ||
381 | |||
382 | tmp = cpu_to_le16(cap); | ||
383 | pos = skb_put(skb, sizeof(struct ieee80211_ht_cap)+2); | ||
384 | *pos++ = WLAN_EID_HT_CAPABILITY; | ||
385 | *pos++ = sizeof(struct ieee80211_ht_cap); | ||
386 | memset(pos, 0, sizeof(struct ieee80211_ht_cap)); | ||
387 | memcpy(pos, &tmp, sizeof(u16)); | ||
388 | pos += sizeof(u16); | ||
389 | /* TODO: needs a define here for << 2 */ | ||
390 | *pos++ = sband->ht_info.ampdu_factor | | ||
391 | (sband->ht_info.ampdu_density << 2); | ||
392 | memcpy(pos, sband->ht_info.supp_mcs_set, 16); | ||
254 | } | 393 | } |
255 | 394 | ||
256 | return NULL; | 395 | kfree(ifsta->assocreq_ies); |
396 | ifsta->assocreq_ies_len = (skb->data + skb->len) - ies; | ||
397 | ifsta->assocreq_ies = kmalloc(ifsta->assocreq_ies_len, GFP_KERNEL); | ||
398 | if (ifsta->assocreq_ies) | ||
399 | memcpy(ifsta->assocreq_ies, ies, ifsta->assocreq_ies_len); | ||
400 | |||
401 | ieee80211_tx_skb(sdata, skb, 0); | ||
257 | } | 402 | } |
258 | 403 | ||
259 | 404 | ||
260 | static int ecw2cw(int ecw) | 405 | static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, |
406 | u16 stype, u16 reason) | ||
261 | { | 407 | { |
262 | return (1 << ecw) - 1; | 408 | struct ieee80211_local *local = sdata->local; |
263 | } | 409 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; |
410 | struct sk_buff *skb; | ||
411 | struct ieee80211_mgmt *mgmt; | ||
264 | 412 | ||
413 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt)); | ||
414 | if (!skb) { | ||
415 | printk(KERN_DEBUG "%s: failed to allocate buffer for " | ||
416 | "deauth/disassoc frame\n", sdata->dev->name); | ||
417 | return; | ||
418 | } | ||
419 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
265 | 420 | ||
421 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | ||
422 | memset(mgmt, 0, 24); | ||
423 | memcpy(mgmt->da, ifsta->bssid, ETH_ALEN); | ||
424 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
425 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | ||
426 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype); | ||
427 | skb_put(skb, 2); | ||
428 | /* u.deauth.reason_code == u.disassoc.reason_code */ | ||
429 | mgmt->u.deauth.reason_code = cpu_to_le16(reason); | ||
430 | |||
431 | ieee80211_tx_skb(sdata, skb, 0); | ||
432 | } | ||
433 | |||
434 | /* MLME */ | ||
266 | static void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, | 435 | static void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, |
267 | struct ieee80211_sta_bss *bss, | 436 | struct ieee80211_sta_bss *bss) |
268 | int ibss) | ||
269 | { | 437 | { |
270 | struct ieee80211_local *local = sdata->local; | 438 | struct ieee80211_local *local = sdata->local; |
271 | int i, have_higher_than_11mbit = 0; | 439 | int i, have_higher_than_11mbit = 0; |
272 | 440 | ||
273 | |||
274 | /* cf. IEEE 802.11 9.2.12 */ | 441 | /* cf. IEEE 802.11 9.2.12 */ |
275 | for (i = 0; i < bss->supp_rates_len; i++) | 442 | for (i = 0; i < bss->supp_rates_len; i++) |
276 | if ((bss->supp_rates[i] & 0x7f) * 5 > 110) | 443 | if ((bss->supp_rates[i] & 0x7f) * 5 > 110) |
@@ -282,26 +449,7 @@ static void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, | |||
282 | else | 449 | else |
283 | sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; | 450 | sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; |
284 | 451 | ||
285 | 452 | ieee80211_set_wmm_default(sdata); | |
286 | if (local->ops->conf_tx) { | ||
287 | struct ieee80211_tx_queue_params qparam; | ||
288 | |||
289 | memset(&qparam, 0, sizeof(qparam)); | ||
290 | |||
291 | qparam.aifs = 2; | ||
292 | |||
293 | if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && | ||
294 | !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)) | ||
295 | qparam.cw_min = 31; | ||
296 | else | ||
297 | qparam.cw_min = 15; | ||
298 | |||
299 | qparam.cw_max = 1023; | ||
300 | qparam.txop = 0; | ||
301 | |||
302 | for (i = 0; i < local_to_hw(local)->queues; i++) | ||
303 | local->ops->conf_tx(local_to_hw(local), i, &qparam); | ||
304 | } | ||
305 | } | 453 | } |
306 | 454 | ||
307 | static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | 455 | static void ieee80211_sta_wmm_params(struct ieee80211_local *local, |
@@ -451,50 +599,15 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, | |||
451 | return changed; | 599 | return changed; |
452 | } | 600 | } |
453 | 601 | ||
454 | int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie, | 602 | static void ieee80211_sta_send_apinfo(struct ieee80211_sub_if_data *sdata, |
455 | struct ieee80211_ht_info *ht_info) | 603 | struct ieee80211_if_sta *ifsta) |
456 | { | 604 | { |
457 | 605 | union iwreq_data wrqu; | |
458 | if (ht_info == NULL) | 606 | memset(&wrqu, 0, sizeof(wrqu)); |
459 | return -EINVAL; | 607 | if (ifsta->flags & IEEE80211_STA_ASSOCIATED) |
460 | 608 | memcpy(wrqu.ap_addr.sa_data, sdata->u.sta.bssid, ETH_ALEN); | |
461 | memset(ht_info, 0, sizeof(*ht_info)); | 609 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; |
462 | 610 | wireless_send_event(sdata->dev, SIOCGIWAP, &wrqu, NULL); | |
463 | if (ht_cap_ie) { | ||
464 | u8 ampdu_info = ht_cap_ie->ampdu_params_info; | ||
465 | |||
466 | ht_info->ht_supported = 1; | ||
467 | ht_info->cap = le16_to_cpu(ht_cap_ie->cap_info); | ||
468 | ht_info->ampdu_factor = | ||
469 | ampdu_info & IEEE80211_HT_CAP_AMPDU_FACTOR; | ||
470 | ht_info->ampdu_density = | ||
471 | (ampdu_info & IEEE80211_HT_CAP_AMPDU_DENSITY) >> 2; | ||
472 | memcpy(ht_info->supp_mcs_set, ht_cap_ie->supp_mcs_set, 16); | ||
473 | } else | ||
474 | ht_info->ht_supported = 0; | ||
475 | |||
476 | return 0; | ||
477 | } | ||
478 | |||
479 | int ieee80211_ht_addt_info_ie_to_ht_bss_info( | ||
480 | struct ieee80211_ht_addt_info *ht_add_info_ie, | ||
481 | struct ieee80211_ht_bss_info *bss_info) | ||
482 | { | ||
483 | if (bss_info == NULL) | ||
484 | return -EINVAL; | ||
485 | |||
486 | memset(bss_info, 0, sizeof(*bss_info)); | ||
487 | |||
488 | if (ht_add_info_ie) { | ||
489 | u16 op_mode; | ||
490 | op_mode = le16_to_cpu(ht_add_info_ie->operation_mode); | ||
491 | |||
492 | bss_info->primary_channel = ht_add_info_ie->control_chan; | ||
493 | bss_info->bss_cap = ht_add_info_ie->ht_param; | ||
494 | bss_info->bss_op_mode = (u8)(op_mode & 0xff); | ||
495 | } | ||
496 | |||
497 | return 0; | ||
498 | } | 611 | } |
499 | 612 | ||
500 | static void ieee80211_sta_send_associnfo(struct ieee80211_sub_if_data *sdata, | 613 | static void ieee80211_sta_send_associnfo(struct ieee80211_sub_if_data *sdata, |
@@ -518,134 +631,54 @@ static void ieee80211_sta_send_associnfo(struct ieee80211_sub_if_data *sdata, | |||
518 | 631 | ||
519 | 632 | ||
520 | static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | 633 | static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, |
521 | struct ieee80211_if_sta *ifsta, | 634 | struct ieee80211_if_sta *ifsta) |
522 | bool assoc) | ||
523 | { | 635 | { |
524 | struct ieee80211_local *local = sdata->local; | 636 | struct ieee80211_local *local = sdata->local; |
525 | struct ieee80211_conf *conf = &local_to_hw(local)->conf; | 637 | struct ieee80211_conf *conf = &local_to_hw(local)->conf; |
526 | union iwreq_data wrqu; | ||
527 | u32 changed = BSS_CHANGED_ASSOC; | 638 | u32 changed = BSS_CHANGED_ASSOC; |
528 | 639 | ||
529 | if (assoc) { | 640 | struct ieee80211_sta_bss *bss; |
530 | struct ieee80211_sta_bss *bss; | ||
531 | |||
532 | ifsta->flags |= IEEE80211_STA_ASSOCIATED; | ||
533 | |||
534 | if (sdata->vif.type != IEEE80211_IF_TYPE_STA) | ||
535 | return; | ||
536 | |||
537 | bss = ieee80211_rx_bss_get(local, ifsta->bssid, | ||
538 | conf->channel->center_freq, | ||
539 | ifsta->ssid, ifsta->ssid_len); | ||
540 | if (bss) { | ||
541 | /* set timing information */ | ||
542 | sdata->bss_conf.beacon_int = bss->beacon_int; | ||
543 | sdata->bss_conf.timestamp = bss->timestamp; | ||
544 | sdata->bss_conf.dtim_period = bss->dtim_period; | ||
545 | |||
546 | changed |= ieee80211_handle_bss_capability(sdata, bss); | ||
547 | 641 | ||
548 | ieee80211_rx_bss_put(local, bss); | 642 | ifsta->flags |= IEEE80211_STA_ASSOCIATED; |
549 | } | ||
550 | 643 | ||
551 | if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) { | 644 | if (sdata->vif.type != IEEE80211_IF_TYPE_STA) |
552 | changed |= BSS_CHANGED_HT; | 645 | return; |
553 | sdata->bss_conf.assoc_ht = 1; | ||
554 | sdata->bss_conf.ht_conf = &conf->ht_conf; | ||
555 | sdata->bss_conf.ht_bss_conf = &conf->ht_bss_conf; | ||
556 | } | ||
557 | 646 | ||
558 | ifsta->flags |= IEEE80211_STA_PREV_BSSID_SET; | 647 | bss = ieee80211_rx_bss_get(local, ifsta->bssid, |
559 | memcpy(ifsta->prev_bssid, sdata->u.sta.bssid, ETH_ALEN); | 648 | conf->channel->center_freq, |
560 | memcpy(wrqu.ap_addr.sa_data, sdata->u.sta.bssid, ETH_ALEN); | 649 | ifsta->ssid, ifsta->ssid_len); |
561 | ieee80211_sta_send_associnfo(sdata, ifsta); | 650 | if (bss) { |
562 | } else { | 651 | /* set timing information */ |
563 | netif_carrier_off(sdata->dev); | 652 | sdata->bss_conf.beacon_int = bss->beacon_int; |
564 | ieee80211_sta_tear_down_BA_sessions(sdata, ifsta->bssid); | 653 | sdata->bss_conf.timestamp = bss->timestamp; |
565 | ifsta->flags &= ~IEEE80211_STA_ASSOCIATED; | 654 | sdata->bss_conf.dtim_period = bss->dtim_period; |
566 | changed |= ieee80211_reset_erp_info(sdata); | ||
567 | 655 | ||
568 | sdata->bss_conf.assoc_ht = 0; | 656 | changed |= ieee80211_handle_bss_capability(sdata, bss); |
569 | sdata->bss_conf.ht_conf = NULL; | ||
570 | sdata->bss_conf.ht_bss_conf = NULL; | ||
571 | 657 | ||
572 | memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); | 658 | ieee80211_rx_bss_put(local, bss); |
573 | } | 659 | } |
574 | ifsta->last_probe = jiffies; | ||
575 | ieee80211_led_assoc(local, assoc); | ||
576 | |||
577 | sdata->bss_conf.assoc = assoc; | ||
578 | ieee80211_bss_info_change_notify(sdata, changed); | ||
579 | |||
580 | if (assoc) | ||
581 | netif_carrier_on(sdata->dev); | ||
582 | |||
583 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | ||
584 | wireless_send_event(sdata->dev, SIOCGIWAP, &wrqu, NULL); | ||
585 | } | ||
586 | 660 | ||
587 | static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | 661 | if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) { |
588 | struct ieee80211_if_sta *ifsta, int deauth) | 662 | changed |= BSS_CHANGED_HT; |
589 | { | 663 | sdata->bss_conf.assoc_ht = 1; |
590 | if (deauth) { | 664 | sdata->bss_conf.ht_conf = &conf->ht_conf; |
591 | ifsta->direct_probe_tries = 0; | 665 | sdata->bss_conf.ht_bss_conf = &conf->ht_bss_conf; |
592 | ifsta->auth_tries = 0; | ||
593 | } | 666 | } |
594 | ifsta->assoc_scan_tries = 0; | ||
595 | ifsta->assoc_tries = 0; | ||
596 | ieee80211_set_associated(sdata, ifsta, 0); | ||
597 | } | ||
598 | |||
599 | void ieee80211_sta_tx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | ||
600 | int encrypt) | ||
601 | { | ||
602 | skb->dev = sdata->local->mdev; | ||
603 | skb_set_mac_header(skb, 0); | ||
604 | skb_set_network_header(skb, 0); | ||
605 | skb_set_transport_header(skb, 0); | ||
606 | 667 | ||
607 | skb->iif = sdata->dev->ifindex; | 668 | ifsta->flags |= IEEE80211_STA_PREV_BSSID_SET; |
608 | skb->do_not_encrypt = !encrypt; | 669 | memcpy(ifsta->prev_bssid, sdata->u.sta.bssid, ETH_ALEN); |
670 | ieee80211_sta_send_associnfo(sdata, ifsta); | ||
609 | 671 | ||
610 | dev_queue_xmit(skb); | 672 | ifsta->last_probe = jiffies; |
611 | } | 673 | ieee80211_led_assoc(local, 1); |
612 | |||
613 | |||
614 | static void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | ||
615 | struct ieee80211_if_sta *ifsta, | ||
616 | int transaction, u8 *extra, size_t extra_len, | ||
617 | int encrypt) | ||
618 | { | ||
619 | struct ieee80211_local *local = sdata->local; | ||
620 | struct sk_buff *skb; | ||
621 | struct ieee80211_mgmt *mgmt; | ||
622 | 674 | ||
623 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | 675 | sdata->bss_conf.assoc = 1; |
624 | sizeof(*mgmt) + 6 + extra_len); | 676 | ieee80211_bss_info_change_notify(sdata, changed); |
625 | if (!skb) { | ||
626 | printk(KERN_DEBUG "%s: failed to allocate buffer for auth " | ||
627 | "frame\n", sdata->dev->name); | ||
628 | return; | ||
629 | } | ||
630 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
631 | 677 | ||
632 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6); | 678 | netif_tx_start_all_queues(sdata->dev); |
633 | memset(mgmt, 0, 24 + 6); | 679 | netif_carrier_on(sdata->dev); |
634 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
635 | IEEE80211_STYPE_AUTH); | ||
636 | if (encrypt) | ||
637 | mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); | ||
638 | memcpy(mgmt->da, ifsta->bssid, ETH_ALEN); | ||
639 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
640 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | ||
641 | mgmt->u.auth.auth_alg = cpu_to_le16(ifsta->auth_alg); | ||
642 | mgmt->u.auth.auth_transaction = cpu_to_le16(transaction); | ||
643 | ifsta->auth_transaction = transaction + 1; | ||
644 | mgmt->u.auth.status_code = cpu_to_le16(0); | ||
645 | if (extra) | ||
646 | memcpy(skb_put(skb, extra_len), extra, extra_len); | ||
647 | 680 | ||
648 | ieee80211_sta_tx(sdata, skb, encrypt); | 681 | ieee80211_sta_send_apinfo(sdata, ifsta); |
649 | } | 682 | } |
650 | 683 | ||
651 | static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata, | 684 | static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata, |
@@ -702,294 +735,76 @@ static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata, | |||
702 | mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT); | 735 | mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT); |
703 | } | 736 | } |
704 | 737 | ||
705 | static int ieee80211_compatible_rates(struct ieee80211_sta_bss *bss, | 738 | static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, |
706 | struct ieee80211_supported_band *sband, | 739 | struct ieee80211_if_sta *ifsta, bool deauth, |
707 | u64 *rates) | 740 | bool self_disconnected, u16 reason) |
708 | { | ||
709 | int i, j, count; | ||
710 | *rates = 0; | ||
711 | count = 0; | ||
712 | for (i = 0; i < bss->supp_rates_len; i++) { | ||
713 | int rate = (bss->supp_rates[i] & 0x7F) * 5; | ||
714 | |||
715 | for (j = 0; j < sband->n_bitrates; j++) | ||
716 | if (sband->bitrates[j].bitrate == rate) { | ||
717 | *rates |= BIT(j); | ||
718 | count++; | ||
719 | break; | ||
720 | } | ||
721 | } | ||
722 | |||
723 | return count; | ||
724 | } | ||
725 | |||
726 | static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | ||
727 | struct ieee80211_if_sta *ifsta) | ||
728 | { | 741 | { |
729 | struct ieee80211_local *local = sdata->local; | 742 | struct ieee80211_local *local = sdata->local; |
730 | struct sk_buff *skb; | 743 | struct sta_info *sta; |
731 | struct ieee80211_mgmt *mgmt; | 744 | u32 changed = BSS_CHANGED_ASSOC; |
732 | u8 *pos, *ies, *ht_add_ie; | ||
733 | int i, len, count, rates_len, supp_rates_len; | ||
734 | u16 capab; | ||
735 | struct ieee80211_sta_bss *bss; | ||
736 | int wmm = 0; | ||
737 | struct ieee80211_supported_band *sband; | ||
738 | u64 rates = 0; | ||
739 | |||
740 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | ||
741 | sizeof(*mgmt) + 200 + ifsta->extra_ie_len + | ||
742 | ifsta->ssid_len); | ||
743 | if (!skb) { | ||
744 | printk(KERN_DEBUG "%s: failed to allocate buffer for assoc " | ||
745 | "frame\n", sdata->dev->name); | ||
746 | return; | ||
747 | } | ||
748 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
749 | |||
750 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
751 | |||
752 | capab = ifsta->capab; | ||
753 | |||
754 | if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) { | ||
755 | if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE)) | ||
756 | capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME; | ||
757 | if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE)) | ||
758 | capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; | ||
759 | } | ||
760 | |||
761 | bss = ieee80211_rx_bss_get(local, ifsta->bssid, | ||
762 | local->hw.conf.channel->center_freq, | ||
763 | ifsta->ssid, ifsta->ssid_len); | ||
764 | if (bss) { | ||
765 | if (bss->capability & WLAN_CAPABILITY_PRIVACY) | ||
766 | capab |= WLAN_CAPABILITY_PRIVACY; | ||
767 | if (bss->wmm_used) | ||
768 | wmm = 1; | ||
769 | |||
770 | /* get all rates supported by the device and the AP as | ||
771 | * some APs don't like getting a superset of their rates | ||
772 | * in the association request (e.g. D-Link DAP 1353 in | ||
773 | * b-only mode) */ | ||
774 | rates_len = ieee80211_compatible_rates(bss, sband, &rates); | ||
775 | |||
776 | if ((bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT) && | ||
777 | (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)) | ||
778 | capab |= WLAN_CAPABILITY_SPECTRUM_MGMT; | ||
779 | |||
780 | ieee80211_rx_bss_put(local, bss); | ||
781 | } else { | ||
782 | rates = ~0; | ||
783 | rates_len = sband->n_bitrates; | ||
784 | } | ||
785 | |||
786 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | ||
787 | memset(mgmt, 0, 24); | ||
788 | memcpy(mgmt->da, ifsta->bssid, ETH_ALEN); | ||
789 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
790 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | ||
791 | |||
792 | if (ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) { | ||
793 | skb_put(skb, 10); | ||
794 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
795 | IEEE80211_STYPE_REASSOC_REQ); | ||
796 | mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab); | ||
797 | mgmt->u.reassoc_req.listen_interval = | ||
798 | cpu_to_le16(local->hw.conf.listen_interval); | ||
799 | memcpy(mgmt->u.reassoc_req.current_ap, ifsta->prev_bssid, | ||
800 | ETH_ALEN); | ||
801 | } else { | ||
802 | skb_put(skb, 4); | ||
803 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
804 | IEEE80211_STYPE_ASSOC_REQ); | ||
805 | mgmt->u.assoc_req.capab_info = cpu_to_le16(capab); | ||
806 | mgmt->u.reassoc_req.listen_interval = | ||
807 | cpu_to_le16(local->hw.conf.listen_interval); | ||
808 | } | ||
809 | |||
810 | /* SSID */ | ||
811 | ies = pos = skb_put(skb, 2 + ifsta->ssid_len); | ||
812 | *pos++ = WLAN_EID_SSID; | ||
813 | *pos++ = ifsta->ssid_len; | ||
814 | memcpy(pos, ifsta->ssid, ifsta->ssid_len); | ||
815 | |||
816 | /* add all rates which were marked to be used above */ | ||
817 | supp_rates_len = rates_len; | ||
818 | if (supp_rates_len > 8) | ||
819 | supp_rates_len = 8; | ||
820 | 745 | ||
821 | len = sband->n_bitrates; | 746 | rcu_read_lock(); |
822 | pos = skb_put(skb, supp_rates_len + 2); | ||
823 | *pos++ = WLAN_EID_SUPP_RATES; | ||
824 | *pos++ = supp_rates_len; | ||
825 | 747 | ||
826 | count = 0; | 748 | sta = sta_info_get(local, ifsta->bssid); |
827 | for (i = 0; i < sband->n_bitrates; i++) { | 749 | if (!sta) { |
828 | if (BIT(i) & rates) { | 750 | rcu_read_unlock(); |
829 | int rate = sband->bitrates[i].bitrate; | 751 | return; |
830 | *pos++ = (u8) (rate / 5); | ||
831 | if (++count == 8) | ||
832 | break; | ||
833 | } | ||
834 | } | 752 | } |
835 | 753 | ||
836 | if (rates_len > count) { | 754 | if (deauth) { |
837 | pos = skb_put(skb, rates_len - count + 2); | 755 | ifsta->direct_probe_tries = 0; |
838 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | 756 | ifsta->auth_tries = 0; |
839 | *pos++ = rates_len - count; | ||
840 | |||
841 | for (i++; i < sband->n_bitrates; i++) { | ||
842 | if (BIT(i) & rates) { | ||
843 | int rate = sband->bitrates[i].bitrate; | ||
844 | *pos++ = (u8) (rate / 5); | ||
845 | } | ||
846 | } | ||
847 | } | 757 | } |
758 | ifsta->assoc_scan_tries = 0; | ||
759 | ifsta->assoc_tries = 0; | ||
848 | 760 | ||
849 | if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) { | 761 | netif_tx_stop_all_queues(sdata->dev); |
850 | /* 1. power capabilities */ | 762 | netif_carrier_off(sdata->dev); |
851 | pos = skb_put(skb, 4); | ||
852 | *pos++ = WLAN_EID_PWR_CAPABILITY; | ||
853 | *pos++ = 2; | ||
854 | *pos++ = 0; /* min tx power */ | ||
855 | *pos++ = local->hw.conf.channel->max_power; /* max tx power */ | ||
856 | |||
857 | /* 2. supported channels */ | ||
858 | /* TODO: get this in reg domain format */ | ||
859 | pos = skb_put(skb, 2 * sband->n_channels + 2); | ||
860 | *pos++ = WLAN_EID_SUPPORTED_CHANNELS; | ||
861 | *pos++ = 2 * sband->n_channels; | ||
862 | for (i = 0; i < sband->n_channels; i++) { | ||
863 | *pos++ = ieee80211_frequency_to_channel( | ||
864 | sband->channels[i].center_freq); | ||
865 | *pos++ = 1; /* one channel in the subband*/ | ||
866 | } | ||
867 | } | ||
868 | 763 | ||
869 | if (ifsta->extra_ie) { | 764 | ieee80211_sta_tear_down_BA_sessions(sdata, sta->addr); |
870 | pos = skb_put(skb, ifsta->extra_ie_len); | ||
871 | memcpy(pos, ifsta->extra_ie, ifsta->extra_ie_len); | ||
872 | } | ||
873 | 765 | ||
874 | if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) { | 766 | if (self_disconnected) { |
875 | pos = skb_put(skb, 9); | 767 | if (deauth) |
876 | *pos++ = WLAN_EID_VENDOR_SPECIFIC; | 768 | ieee80211_send_deauth_disassoc(sdata, |
877 | *pos++ = 7; /* len */ | 769 | IEEE80211_STYPE_DEAUTH, reason); |
878 | *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */ | 770 | else |
879 | *pos++ = 0x50; | 771 | ieee80211_send_deauth_disassoc(sdata, |
880 | *pos++ = 0xf2; | 772 | IEEE80211_STYPE_DISASSOC, reason); |
881 | *pos++ = 2; /* WME */ | ||
882 | *pos++ = 0; /* WME info */ | ||
883 | *pos++ = 1; /* WME ver */ | ||
884 | *pos++ = 0; | ||
885 | } | 773 | } |
886 | 774 | ||
887 | /* wmm support is a must to HT */ | 775 | ifsta->flags &= ~IEEE80211_STA_ASSOCIATED; |
888 | if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED) && | 776 | changed |= ieee80211_reset_erp_info(sdata); |
889 | sband->ht_info.ht_supported && | ||
890 | (ht_add_ie = ieee80211_bss_get_ie(bss, WLAN_EID_HT_EXTRA_INFO))) { | ||
891 | struct ieee80211_ht_addt_info *ht_add_info = | ||
892 | (struct ieee80211_ht_addt_info *)ht_add_ie; | ||
893 | u16 cap = sband->ht_info.cap; | ||
894 | __le16 tmp; | ||
895 | u32 flags = local->hw.conf.channel->flags; | ||
896 | |||
897 | switch (ht_add_info->ht_param & IEEE80211_HT_IE_CHA_SEC_OFFSET) { | ||
898 | case IEEE80211_HT_IE_CHA_SEC_ABOVE: | ||
899 | if (flags & IEEE80211_CHAN_NO_FAT_ABOVE) { | ||
900 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH; | ||
901 | cap &= ~IEEE80211_HT_CAP_SGI_40; | ||
902 | } | ||
903 | break; | ||
904 | case IEEE80211_HT_IE_CHA_SEC_BELOW: | ||
905 | if (flags & IEEE80211_CHAN_NO_FAT_BELOW) { | ||
906 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH; | ||
907 | cap &= ~IEEE80211_HT_CAP_SGI_40; | ||
908 | } | ||
909 | break; | ||
910 | } | ||
911 | 777 | ||
912 | tmp = cpu_to_le16(cap); | 778 | if (sdata->bss_conf.assoc_ht) |
913 | pos = skb_put(skb, sizeof(struct ieee80211_ht_cap)+2); | 779 | changed |= BSS_CHANGED_HT; |
914 | *pos++ = WLAN_EID_HT_CAPABILITY; | ||
915 | *pos++ = sizeof(struct ieee80211_ht_cap); | ||
916 | memset(pos, 0, sizeof(struct ieee80211_ht_cap)); | ||
917 | memcpy(pos, &tmp, sizeof(u16)); | ||
918 | pos += sizeof(u16); | ||
919 | /* TODO: needs a define here for << 2 */ | ||
920 | *pos++ = sband->ht_info.ampdu_factor | | ||
921 | (sband->ht_info.ampdu_density << 2); | ||
922 | memcpy(pos, sband->ht_info.supp_mcs_set, 16); | ||
923 | } | ||
924 | 780 | ||
925 | kfree(ifsta->assocreq_ies); | 781 | sdata->bss_conf.assoc_ht = 0; |
926 | ifsta->assocreq_ies_len = (skb->data + skb->len) - ies; | 782 | sdata->bss_conf.ht_conf = NULL; |
927 | ifsta->assocreq_ies = kmalloc(ifsta->assocreq_ies_len, GFP_KERNEL); | 783 | sdata->bss_conf.ht_bss_conf = NULL; |
928 | if (ifsta->assocreq_ies) | ||
929 | memcpy(ifsta->assocreq_ies, ies, ifsta->assocreq_ies_len); | ||
930 | 784 | ||
931 | ieee80211_sta_tx(sdata, skb, 0); | 785 | ieee80211_led_assoc(local, 0); |
932 | } | 786 | sdata->bss_conf.assoc = 0; |
933 | 787 | ||
788 | ieee80211_sta_send_apinfo(sdata, ifsta); | ||
934 | 789 | ||
935 | static void ieee80211_send_deauth(struct ieee80211_sub_if_data *sdata, | 790 | if (self_disconnected) |
936 | struct ieee80211_if_sta *ifsta, u16 reason) | 791 | ifsta->state = IEEE80211_STA_MLME_DISABLED; |
937 | { | ||
938 | struct ieee80211_local *local = sdata->local; | ||
939 | struct sk_buff *skb; | ||
940 | struct ieee80211_mgmt *mgmt; | ||
941 | 792 | ||
942 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt)); | 793 | sta_info_unlink(&sta); |
943 | if (!skb) { | ||
944 | printk(KERN_DEBUG "%s: failed to allocate buffer for deauth " | ||
945 | "frame\n", sdata->dev->name); | ||
946 | return; | ||
947 | } | ||
948 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
949 | 794 | ||
950 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | 795 | rcu_read_unlock(); |
951 | memset(mgmt, 0, 24); | ||
952 | memcpy(mgmt->da, ifsta->bssid, ETH_ALEN); | ||
953 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
954 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | ||
955 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
956 | IEEE80211_STYPE_DEAUTH); | ||
957 | skb_put(skb, 2); | ||
958 | mgmt->u.deauth.reason_code = cpu_to_le16(reason); | ||
959 | 796 | ||
960 | ieee80211_sta_tx(sdata, skb, 0); | 797 | sta_info_destroy(sta); |
961 | } | 798 | } |
962 | 799 | ||
963 | 800 | static int ieee80211_sta_wep_configured(struct ieee80211_sub_if_data *sdata) | |
964 | static void ieee80211_send_disassoc(struct ieee80211_sub_if_data *sdata, | ||
965 | struct ieee80211_if_sta *ifsta, u16 reason) | ||
966 | { | 801 | { |
967 | struct ieee80211_local *local = sdata->local; | 802 | if (!sdata || !sdata->default_key || |
968 | struct sk_buff *skb; | 803 | sdata->default_key->conf.alg != ALG_WEP) |
969 | struct ieee80211_mgmt *mgmt; | 804 | return 0; |
970 | 805 | return 1; | |
971 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt)); | ||
972 | if (!skb) { | ||
973 | printk(KERN_DEBUG "%s: failed to allocate buffer for disassoc " | ||
974 | "frame\n", sdata->dev->name); | ||
975 | return; | ||
976 | } | ||
977 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
978 | |||
979 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | ||
980 | memset(mgmt, 0, 24); | ||
981 | memcpy(mgmt->da, ifsta->bssid, ETH_ALEN); | ||
982 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
983 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | ||
984 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
985 | IEEE80211_STYPE_DISASSOC); | ||
986 | skb_put(skb, 2); | ||
987 | mgmt->u.disassoc.reason_code = cpu_to_le16(reason); | ||
988 | |||
989 | ieee80211_sta_tx(sdata, skb, 0); | ||
990 | } | 806 | } |
991 | 807 | ||
992 | |||
993 | static int ieee80211_privacy_mismatch(struct ieee80211_sub_if_data *sdata, | 808 | static int ieee80211_privacy_mismatch(struct ieee80211_sub_if_data *sdata, |
994 | struct ieee80211_if_sta *ifsta) | 809 | struct ieee80211_if_sta *ifsta) |
995 | { | 810 | { |
@@ -1020,7 +835,6 @@ static int ieee80211_privacy_mismatch(struct ieee80211_sub_if_data *sdata, | |||
1020 | return 1; | 835 | return 1; |
1021 | } | 836 | } |
1022 | 837 | ||
1023 | |||
1024 | static void ieee80211_associate(struct ieee80211_sub_if_data *sdata, | 838 | static void ieee80211_associate(struct ieee80211_sub_if_data *sdata, |
1025 | struct ieee80211_if_sta *ifsta) | 839 | struct ieee80211_if_sta *ifsta) |
1026 | { | 840 | { |
@@ -1083,7 +897,6 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata, | |||
1083 | "range\n", | 897 | "range\n", |
1084 | sdata->dev->name, print_mac(mac, ifsta->bssid)); | 898 | sdata->dev->name, print_mac(mac, ifsta->bssid)); |
1085 | disassoc = 1; | 899 | disassoc = 1; |
1086 | sta_info_unlink(&sta); | ||
1087 | } else | 900 | } else |
1088 | ieee80211_send_probe_req(sdata, ifsta->bssid, | 901 | ieee80211_send_probe_req(sdata, ifsta->bssid, |
1089 | local->scan_ssid, | 902 | local->scan_ssid, |
@@ -1103,86 +916,12 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata, | |||
1103 | 916 | ||
1104 | rcu_read_unlock(); | 917 | rcu_read_unlock(); |
1105 | 918 | ||
1106 | if (disassoc && sta) | 919 | if (disassoc) |
1107 | sta_info_destroy(sta); | 920 | ieee80211_set_disassoc(sdata, ifsta, true, true, |
1108 | 921 | WLAN_REASON_PREV_AUTH_NOT_VALID); | |
1109 | if (disassoc) { | 922 | else |
1110 | ifsta->state = IEEE80211_STA_MLME_DISABLED; | ||
1111 | ieee80211_set_associated(sdata, ifsta, 0); | ||
1112 | } else { | ||
1113 | mod_timer(&ifsta->timer, jiffies + | 923 | mod_timer(&ifsta->timer, jiffies + |
1114 | IEEE80211_MONITORING_INTERVAL); | 924 | IEEE80211_MONITORING_INTERVAL); |
1115 | } | ||
1116 | } | ||
1117 | |||
1118 | |||
1119 | static void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | ||
1120 | u8 *ssid, size_t ssid_len) | ||
1121 | { | ||
1122 | struct ieee80211_local *local = sdata->local; | ||
1123 | struct ieee80211_supported_band *sband; | ||
1124 | struct sk_buff *skb; | ||
1125 | struct ieee80211_mgmt *mgmt; | ||
1126 | u8 *pos, *supp_rates, *esupp_rates = NULL; | ||
1127 | int i; | ||
1128 | |||
1129 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200); | ||
1130 | if (!skb) { | ||
1131 | printk(KERN_DEBUG "%s: failed to allocate buffer for probe " | ||
1132 | "request\n", sdata->dev->name); | ||
1133 | return; | ||
1134 | } | ||
1135 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
1136 | |||
1137 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | ||
1138 | memset(mgmt, 0, 24); | ||
1139 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
1140 | IEEE80211_STYPE_PROBE_REQ); | ||
1141 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
1142 | if (dst) { | ||
1143 | memcpy(mgmt->da, dst, ETH_ALEN); | ||
1144 | memcpy(mgmt->bssid, dst, ETH_ALEN); | ||
1145 | } else { | ||
1146 | memset(mgmt->da, 0xff, ETH_ALEN); | ||
1147 | memset(mgmt->bssid, 0xff, ETH_ALEN); | ||
1148 | } | ||
1149 | pos = skb_put(skb, 2 + ssid_len); | ||
1150 | *pos++ = WLAN_EID_SSID; | ||
1151 | *pos++ = ssid_len; | ||
1152 | memcpy(pos, ssid, ssid_len); | ||
1153 | |||
1154 | supp_rates = skb_put(skb, 2); | ||
1155 | supp_rates[0] = WLAN_EID_SUPP_RATES; | ||
1156 | supp_rates[1] = 0; | ||
1157 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
1158 | |||
1159 | for (i = 0; i < sband->n_bitrates; i++) { | ||
1160 | struct ieee80211_rate *rate = &sband->bitrates[i]; | ||
1161 | if (esupp_rates) { | ||
1162 | pos = skb_put(skb, 1); | ||
1163 | esupp_rates[1]++; | ||
1164 | } else if (supp_rates[1] == 8) { | ||
1165 | esupp_rates = skb_put(skb, 3); | ||
1166 | esupp_rates[0] = WLAN_EID_EXT_SUPP_RATES; | ||
1167 | esupp_rates[1] = 1; | ||
1168 | pos = &esupp_rates[2]; | ||
1169 | } else { | ||
1170 | pos = skb_put(skb, 1); | ||
1171 | supp_rates[1]++; | ||
1172 | } | ||
1173 | *pos = rate->bitrate / 5; | ||
1174 | } | ||
1175 | |||
1176 | ieee80211_sta_tx(sdata, skb, 0); | ||
1177 | } | ||
1178 | |||
1179 | |||
1180 | static int ieee80211_sta_wep_configured(struct ieee80211_sub_if_data *sdata) | ||
1181 | { | ||
1182 | if (!sdata || !sdata->default_key || | ||
1183 | sdata->default_key->conf.alg != ALG_WEP) | ||
1184 | return 0; | ||
1185 | return 1; | ||
1186 | } | 925 | } |
1187 | 926 | ||
1188 | 927 | ||
@@ -1211,652 +950,6 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, | |||
1211 | elems.challenge_len + 2, 1); | 950 | elems.challenge_len + 2, 1); |
1212 | } | 951 | } |
1213 | 952 | ||
1214 | static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *da, u16 tid, | ||
1215 | u8 dialog_token, u16 status, u16 policy, | ||
1216 | u16 buf_size, u16 timeout) | ||
1217 | { | ||
1218 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
1219 | struct ieee80211_local *local = sdata->local; | ||
1220 | struct sk_buff *skb; | ||
1221 | struct ieee80211_mgmt *mgmt; | ||
1222 | u16 capab; | ||
1223 | |||
1224 | skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom); | ||
1225 | |||
1226 | if (!skb) { | ||
1227 | printk(KERN_DEBUG "%s: failed to allocate buffer " | ||
1228 | "for addba resp frame\n", sdata->dev->name); | ||
1229 | return; | ||
1230 | } | ||
1231 | |||
1232 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
1233 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | ||
1234 | memset(mgmt, 0, 24); | ||
1235 | memcpy(mgmt->da, da, ETH_ALEN); | ||
1236 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
1237 | if (sdata->vif.type == IEEE80211_IF_TYPE_AP) | ||
1238 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); | ||
1239 | else | ||
1240 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | ||
1241 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
1242 | IEEE80211_STYPE_ACTION); | ||
1243 | |||
1244 | skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_resp)); | ||
1245 | mgmt->u.action.category = WLAN_CATEGORY_BACK; | ||
1246 | mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP; | ||
1247 | mgmt->u.action.u.addba_resp.dialog_token = dialog_token; | ||
1248 | |||
1249 | capab = (u16)(policy << 1); /* bit 1 aggregation policy */ | ||
1250 | capab |= (u16)(tid << 2); /* bit 5:2 TID number */ | ||
1251 | capab |= (u16)(buf_size << 6); /* bit 15:6 max size of aggregation */ | ||
1252 | |||
1253 | mgmt->u.action.u.addba_resp.capab = cpu_to_le16(capab); | ||
1254 | mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout); | ||
1255 | mgmt->u.action.u.addba_resp.status = cpu_to_le16(status); | ||
1256 | |||
1257 | ieee80211_sta_tx(sdata, skb, 0); | ||
1258 | |||
1259 | return; | ||
1260 | } | ||
1261 | |||
1262 | void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata, const u8 *da, | ||
1263 | u16 tid, u8 dialog_token, u16 start_seq_num, | ||
1264 | u16 agg_size, u16 timeout) | ||
1265 | { | ||
1266 | struct ieee80211_local *local = sdata->local; | ||
1267 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
1268 | struct sk_buff *skb; | ||
1269 | struct ieee80211_mgmt *mgmt; | ||
1270 | u16 capab; | ||
1271 | |||
1272 | skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom); | ||
1273 | |||
1274 | if (!skb) { | ||
1275 | printk(KERN_ERR "%s: failed to allocate buffer " | ||
1276 | "for addba request frame\n", sdata->dev->name); | ||
1277 | return; | ||
1278 | } | ||
1279 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
1280 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | ||
1281 | memset(mgmt, 0, 24); | ||
1282 | memcpy(mgmt->da, da, ETH_ALEN); | ||
1283 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
1284 | if (sdata->vif.type == IEEE80211_IF_TYPE_AP) | ||
1285 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); | ||
1286 | else | ||
1287 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | ||
1288 | |||
1289 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
1290 | IEEE80211_STYPE_ACTION); | ||
1291 | |||
1292 | skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_req)); | ||
1293 | |||
1294 | mgmt->u.action.category = WLAN_CATEGORY_BACK; | ||
1295 | mgmt->u.action.u.addba_req.action_code = WLAN_ACTION_ADDBA_REQ; | ||
1296 | |||
1297 | mgmt->u.action.u.addba_req.dialog_token = dialog_token; | ||
1298 | capab = (u16)(1 << 1); /* bit 1 aggregation policy */ | ||
1299 | capab |= (u16)(tid << 2); /* bit 5:2 TID number */ | ||
1300 | capab |= (u16)(agg_size << 6); /* bit 15:6 max size of aggergation */ | ||
1301 | |||
1302 | mgmt->u.action.u.addba_req.capab = cpu_to_le16(capab); | ||
1303 | |||
1304 | mgmt->u.action.u.addba_req.timeout = cpu_to_le16(timeout); | ||
1305 | mgmt->u.action.u.addba_req.start_seq_num = | ||
1306 | cpu_to_le16(start_seq_num << 4); | ||
1307 | |||
1308 | ieee80211_sta_tx(sdata, skb, 0); | ||
1309 | } | ||
1310 | |||
1311 | static void ieee80211_sta_process_addba_request(struct ieee80211_local *local, | ||
1312 | struct ieee80211_mgmt *mgmt, | ||
1313 | size_t len) | ||
1314 | { | ||
1315 | struct ieee80211_hw *hw = &local->hw; | ||
1316 | struct ieee80211_conf *conf = &hw->conf; | ||
1317 | struct sta_info *sta; | ||
1318 | struct tid_ampdu_rx *tid_agg_rx; | ||
1319 | u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num, status; | ||
1320 | u8 dialog_token; | ||
1321 | int ret = -EOPNOTSUPP; | ||
1322 | DECLARE_MAC_BUF(mac); | ||
1323 | |||
1324 | rcu_read_lock(); | ||
1325 | |||
1326 | sta = sta_info_get(local, mgmt->sa); | ||
1327 | if (!sta) { | ||
1328 | rcu_read_unlock(); | ||
1329 | return; | ||
1330 | } | ||
1331 | |||
1332 | /* extract session parameters from addba request frame */ | ||
1333 | dialog_token = mgmt->u.action.u.addba_req.dialog_token; | ||
1334 | timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout); | ||
1335 | start_seq_num = | ||
1336 | le16_to_cpu(mgmt->u.action.u.addba_req.start_seq_num) >> 4; | ||
1337 | |||
1338 | capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab); | ||
1339 | ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1; | ||
1340 | tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; | ||
1341 | buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6; | ||
1342 | |||
1343 | status = WLAN_STATUS_REQUEST_DECLINED; | ||
1344 | |||
1345 | /* sanity check for incoming parameters: | ||
1346 | * check if configuration can support the BA policy | ||
1347 | * and if buffer size does not exceeds max value */ | ||
1348 | if (((ba_policy != 1) | ||
1349 | && (!(conf->ht_conf.cap & IEEE80211_HT_CAP_DELAY_BA))) | ||
1350 | || (buf_size > IEEE80211_MAX_AMPDU_BUF)) { | ||
1351 | status = WLAN_STATUS_INVALID_QOS_PARAM; | ||
1352 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
1353 | if (net_ratelimit()) | ||
1354 | printk(KERN_DEBUG "AddBA Req with bad params from " | ||
1355 | "%s on tid %u. policy %d, buffer size %d\n", | ||
1356 | print_mac(mac, mgmt->sa), tid, ba_policy, | ||
1357 | buf_size); | ||
1358 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
1359 | goto end_no_lock; | ||
1360 | } | ||
1361 | /* determine default buffer size */ | ||
1362 | if (buf_size == 0) { | ||
1363 | struct ieee80211_supported_band *sband; | ||
1364 | |||
1365 | sband = local->hw.wiphy->bands[conf->channel->band]; | ||
1366 | buf_size = IEEE80211_MIN_AMPDU_BUF; | ||
1367 | buf_size = buf_size << sband->ht_info.ampdu_factor; | ||
1368 | } | ||
1369 | |||
1370 | |||
1371 | /* examine state machine */ | ||
1372 | spin_lock_bh(&sta->lock); | ||
1373 | |||
1374 | if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_IDLE) { | ||
1375 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
1376 | if (net_ratelimit()) | ||
1377 | printk(KERN_DEBUG "unexpected AddBA Req from " | ||
1378 | "%s on tid %u\n", | ||
1379 | print_mac(mac, mgmt->sa), tid); | ||
1380 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
1381 | goto end; | ||
1382 | } | ||
1383 | |||
1384 | /* prepare A-MPDU MLME for Rx aggregation */ | ||
1385 | sta->ampdu_mlme.tid_rx[tid] = | ||
1386 | kmalloc(sizeof(struct tid_ampdu_rx), GFP_ATOMIC); | ||
1387 | if (!sta->ampdu_mlme.tid_rx[tid]) { | ||
1388 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
1389 | if (net_ratelimit()) | ||
1390 | printk(KERN_ERR "allocate rx mlme to tid %d failed\n", | ||
1391 | tid); | ||
1392 | #endif | ||
1393 | goto end; | ||
1394 | } | ||
1395 | /* rx timer */ | ||
1396 | sta->ampdu_mlme.tid_rx[tid]->session_timer.function = | ||
1397 | sta_rx_agg_session_timer_expired; | ||
1398 | sta->ampdu_mlme.tid_rx[tid]->session_timer.data = | ||
1399 | (unsigned long)&sta->timer_to_tid[tid]; | ||
1400 | init_timer(&sta->ampdu_mlme.tid_rx[tid]->session_timer); | ||
1401 | |||
1402 | tid_agg_rx = sta->ampdu_mlme.tid_rx[tid]; | ||
1403 | |||
1404 | /* prepare reordering buffer */ | ||
1405 | tid_agg_rx->reorder_buf = | ||
1406 | kmalloc(buf_size * sizeof(struct sk_buff *), GFP_ATOMIC); | ||
1407 | if (!tid_agg_rx->reorder_buf) { | ||
1408 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
1409 | if (net_ratelimit()) | ||
1410 | printk(KERN_ERR "can not allocate reordering buffer " | ||
1411 | "to tid %d\n", tid); | ||
1412 | #endif | ||
1413 | kfree(sta->ampdu_mlme.tid_rx[tid]); | ||
1414 | goto end; | ||
1415 | } | ||
1416 | memset(tid_agg_rx->reorder_buf, 0, | ||
1417 | buf_size * sizeof(struct sk_buff *)); | ||
1418 | |||
1419 | if (local->ops->ampdu_action) | ||
1420 | ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_START, | ||
1421 | sta->addr, tid, &start_seq_num); | ||
1422 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
1423 | printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret); | ||
1424 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
1425 | |||
1426 | if (ret) { | ||
1427 | kfree(tid_agg_rx->reorder_buf); | ||
1428 | kfree(tid_agg_rx); | ||
1429 | sta->ampdu_mlme.tid_rx[tid] = NULL; | ||
1430 | goto end; | ||
1431 | } | ||
1432 | |||
1433 | /* change state and send addba resp */ | ||
1434 | sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_OPERATIONAL; | ||
1435 | tid_agg_rx->dialog_token = dialog_token; | ||
1436 | tid_agg_rx->ssn = start_seq_num; | ||
1437 | tid_agg_rx->head_seq_num = start_seq_num; | ||
1438 | tid_agg_rx->buf_size = buf_size; | ||
1439 | tid_agg_rx->timeout = timeout; | ||
1440 | tid_agg_rx->stored_mpdu_num = 0; | ||
1441 | status = WLAN_STATUS_SUCCESS; | ||
1442 | end: | ||
1443 | spin_unlock_bh(&sta->lock); | ||
1444 | |||
1445 | end_no_lock: | ||
1446 | ieee80211_send_addba_resp(sta->sdata, sta->addr, tid, | ||
1447 | dialog_token, status, 1, buf_size, timeout); | ||
1448 | rcu_read_unlock(); | ||
1449 | } | ||
1450 | |||
1451 | static void ieee80211_sta_process_addba_resp(struct ieee80211_local *local, | ||
1452 | struct ieee80211_mgmt *mgmt, | ||
1453 | size_t len) | ||
1454 | { | ||
1455 | struct ieee80211_hw *hw = &local->hw; | ||
1456 | struct sta_info *sta; | ||
1457 | u16 capab; | ||
1458 | u16 tid; | ||
1459 | u8 *state; | ||
1460 | |||
1461 | rcu_read_lock(); | ||
1462 | |||
1463 | sta = sta_info_get(local, mgmt->sa); | ||
1464 | if (!sta) { | ||
1465 | rcu_read_unlock(); | ||
1466 | return; | ||
1467 | } | ||
1468 | |||
1469 | capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab); | ||
1470 | tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; | ||
1471 | |||
1472 | state = &sta->ampdu_mlme.tid_state_tx[tid]; | ||
1473 | |||
1474 | spin_lock_bh(&sta->lock); | ||
1475 | |||
1476 | if (!(*state & HT_ADDBA_REQUESTED_MSK)) { | ||
1477 | spin_unlock_bh(&sta->lock); | ||
1478 | goto addba_resp_exit; | ||
1479 | } | ||
1480 | |||
1481 | if (mgmt->u.action.u.addba_resp.dialog_token != | ||
1482 | sta->ampdu_mlme.tid_tx[tid]->dialog_token) { | ||
1483 | spin_unlock_bh(&sta->lock); | ||
1484 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
1485 | printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid); | ||
1486 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
1487 | goto addba_resp_exit; | ||
1488 | } | ||
1489 | |||
1490 | del_timer_sync(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); | ||
1491 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
1492 | printk(KERN_DEBUG "switched off addBA timer for tid %d \n", tid); | ||
1493 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
1494 | if (le16_to_cpu(mgmt->u.action.u.addba_resp.status) | ||
1495 | == WLAN_STATUS_SUCCESS) { | ||
1496 | *state |= HT_ADDBA_RECEIVED_MSK; | ||
1497 | sta->ampdu_mlme.addba_req_num[tid] = 0; | ||
1498 | |||
1499 | if (*state == HT_AGG_STATE_OPERATIONAL) | ||
1500 | ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); | ||
1501 | |||
1502 | spin_unlock_bh(&sta->lock); | ||
1503 | } else { | ||
1504 | sta->ampdu_mlme.addba_req_num[tid]++; | ||
1505 | /* this will allow the state check in stop_BA_session */ | ||
1506 | *state = HT_AGG_STATE_OPERATIONAL; | ||
1507 | spin_unlock_bh(&sta->lock); | ||
1508 | ieee80211_stop_tx_ba_session(hw, sta->addr, tid, | ||
1509 | WLAN_BACK_INITIATOR); | ||
1510 | } | ||
1511 | |||
1512 | addba_resp_exit: | ||
1513 | rcu_read_unlock(); | ||
1514 | } | ||
1515 | |||
1516 | void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, const u8 *da, u16 tid, | ||
1517 | u16 initiator, u16 reason_code) | ||
1518 | { | ||
1519 | struct ieee80211_local *local = sdata->local; | ||
1520 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
1521 | struct sk_buff *skb; | ||
1522 | struct ieee80211_mgmt *mgmt; | ||
1523 | u16 params; | ||
1524 | |||
1525 | skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom); | ||
1526 | |||
1527 | if (!skb) { | ||
1528 | printk(KERN_ERR "%s: failed to allocate buffer " | ||
1529 | "for delba frame\n", sdata->dev->name); | ||
1530 | return; | ||
1531 | } | ||
1532 | |||
1533 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
1534 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | ||
1535 | memset(mgmt, 0, 24); | ||
1536 | memcpy(mgmt->da, da, ETH_ALEN); | ||
1537 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
1538 | if (sdata->vif.type == IEEE80211_IF_TYPE_AP) | ||
1539 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); | ||
1540 | else | ||
1541 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | ||
1542 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
1543 | IEEE80211_STYPE_ACTION); | ||
1544 | |||
1545 | skb_put(skb, 1 + sizeof(mgmt->u.action.u.delba)); | ||
1546 | |||
1547 | mgmt->u.action.category = WLAN_CATEGORY_BACK; | ||
1548 | mgmt->u.action.u.delba.action_code = WLAN_ACTION_DELBA; | ||
1549 | params = (u16)(initiator << 11); /* bit 11 initiator */ | ||
1550 | params |= (u16)(tid << 12); /* bit 15:12 TID number */ | ||
1551 | |||
1552 | mgmt->u.action.u.delba.params = cpu_to_le16(params); | ||
1553 | mgmt->u.action.u.delba.reason_code = cpu_to_le16(reason_code); | ||
1554 | |||
1555 | ieee80211_sta_tx(sdata, skb, 0); | ||
1556 | } | ||
1557 | |||
1558 | void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn) | ||
1559 | { | ||
1560 | struct ieee80211_local *local = sdata->local; | ||
1561 | struct sk_buff *skb; | ||
1562 | struct ieee80211_bar *bar; | ||
1563 | u16 bar_control = 0; | ||
1564 | |||
1565 | skb = dev_alloc_skb(sizeof(*bar) + local->hw.extra_tx_headroom); | ||
1566 | if (!skb) { | ||
1567 | printk(KERN_ERR "%s: failed to allocate buffer for " | ||
1568 | "bar frame\n", sdata->dev->name); | ||
1569 | return; | ||
1570 | } | ||
1571 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
1572 | bar = (struct ieee80211_bar *)skb_put(skb, sizeof(*bar)); | ||
1573 | memset(bar, 0, sizeof(*bar)); | ||
1574 | bar->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | | ||
1575 | IEEE80211_STYPE_BACK_REQ); | ||
1576 | memcpy(bar->ra, ra, ETH_ALEN); | ||
1577 | memcpy(bar->ta, sdata->dev->dev_addr, ETH_ALEN); | ||
1578 | bar_control |= (u16)IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL; | ||
1579 | bar_control |= (u16)IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA; | ||
1580 | bar_control |= (u16)(tid << 12); | ||
1581 | bar->control = cpu_to_le16(bar_control); | ||
1582 | bar->start_seq_num = cpu_to_le16(ssn); | ||
1583 | |||
1584 | ieee80211_sta_tx(sdata, skb, 0); | ||
1585 | } | ||
1586 | |||
1587 | void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, | ||
1588 | u16 initiator, u16 reason) | ||
1589 | { | ||
1590 | struct ieee80211_local *local = sdata->local; | ||
1591 | struct ieee80211_hw *hw = &local->hw; | ||
1592 | struct sta_info *sta; | ||
1593 | int ret, i; | ||
1594 | DECLARE_MAC_BUF(mac); | ||
1595 | |||
1596 | rcu_read_lock(); | ||
1597 | |||
1598 | sta = sta_info_get(local, ra); | ||
1599 | if (!sta) { | ||
1600 | rcu_read_unlock(); | ||
1601 | return; | ||
1602 | } | ||
1603 | |||
1604 | /* check if TID is in operational state */ | ||
1605 | spin_lock_bh(&sta->lock); | ||
1606 | if (sta->ampdu_mlme.tid_state_rx[tid] | ||
1607 | != HT_AGG_STATE_OPERATIONAL) { | ||
1608 | spin_unlock_bh(&sta->lock); | ||
1609 | rcu_read_unlock(); | ||
1610 | return; | ||
1611 | } | ||
1612 | sta->ampdu_mlme.tid_state_rx[tid] = | ||
1613 | HT_AGG_STATE_REQ_STOP_BA_MSK | | ||
1614 | (initiator << HT_AGG_STATE_INITIATOR_SHIFT); | ||
1615 | spin_unlock_bh(&sta->lock); | ||
1616 | |||
1617 | /* stop HW Rx aggregation. ampdu_action existence | ||
1618 | * already verified in session init so we add the BUG_ON */ | ||
1619 | BUG_ON(!local->ops->ampdu_action); | ||
1620 | |||
1621 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
1622 | printk(KERN_DEBUG "Rx BA session stop requested for %s tid %u\n", | ||
1623 | print_mac(mac, ra), tid); | ||
1624 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
1625 | |||
1626 | ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_STOP, | ||
1627 | ra, tid, NULL); | ||
1628 | if (ret) | ||
1629 | printk(KERN_DEBUG "HW problem - can not stop rx " | ||
1630 | "aggregation for tid %d\n", tid); | ||
1631 | |||
1632 | /* shutdown timer has not expired */ | ||
1633 | if (initiator != WLAN_BACK_TIMER) | ||
1634 | del_timer_sync(&sta->ampdu_mlme.tid_rx[tid]->session_timer); | ||
1635 | |||
1636 | /* check if this is a self generated aggregation halt */ | ||
1637 | if (initiator == WLAN_BACK_RECIPIENT || initiator == WLAN_BACK_TIMER) | ||
1638 | ieee80211_send_delba(sdata, ra, tid, 0, reason); | ||
1639 | |||
1640 | /* free the reordering buffer */ | ||
1641 | for (i = 0; i < sta->ampdu_mlme.tid_rx[tid]->buf_size; i++) { | ||
1642 | if (sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]) { | ||
1643 | /* release the reordered frames */ | ||
1644 | dev_kfree_skb(sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]); | ||
1645 | sta->ampdu_mlme.tid_rx[tid]->stored_mpdu_num--; | ||
1646 | sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i] = NULL; | ||
1647 | } | ||
1648 | } | ||
1649 | /* free resources */ | ||
1650 | kfree(sta->ampdu_mlme.tid_rx[tid]->reorder_buf); | ||
1651 | kfree(sta->ampdu_mlme.tid_rx[tid]); | ||
1652 | sta->ampdu_mlme.tid_rx[tid] = NULL; | ||
1653 | sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_IDLE; | ||
1654 | |||
1655 | rcu_read_unlock(); | ||
1656 | } | ||
1657 | |||
1658 | |||
1659 | static void ieee80211_sta_process_delba(struct ieee80211_sub_if_data *sdata, | ||
1660 | struct ieee80211_mgmt *mgmt, size_t len) | ||
1661 | { | ||
1662 | struct ieee80211_local *local = sdata->local; | ||
1663 | struct sta_info *sta; | ||
1664 | u16 tid, params; | ||
1665 | u16 initiator; | ||
1666 | DECLARE_MAC_BUF(mac); | ||
1667 | |||
1668 | rcu_read_lock(); | ||
1669 | |||
1670 | sta = sta_info_get(local, mgmt->sa); | ||
1671 | if (!sta) { | ||
1672 | rcu_read_unlock(); | ||
1673 | return; | ||
1674 | } | ||
1675 | |||
1676 | params = le16_to_cpu(mgmt->u.action.u.delba.params); | ||
1677 | tid = (params & IEEE80211_DELBA_PARAM_TID_MASK) >> 12; | ||
1678 | initiator = (params & IEEE80211_DELBA_PARAM_INITIATOR_MASK) >> 11; | ||
1679 | |||
1680 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
1681 | if (net_ratelimit()) | ||
1682 | printk(KERN_DEBUG "delba from %s (%s) tid %d reason code %d\n", | ||
1683 | print_mac(mac, mgmt->sa), | ||
1684 | initiator ? "initiator" : "recipient", tid, | ||
1685 | mgmt->u.action.u.delba.reason_code); | ||
1686 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
1687 | |||
1688 | if (initiator == WLAN_BACK_INITIATOR) | ||
1689 | ieee80211_sta_stop_rx_ba_session(sdata, sta->addr, tid, | ||
1690 | WLAN_BACK_INITIATOR, 0); | ||
1691 | else { /* WLAN_BACK_RECIPIENT */ | ||
1692 | spin_lock_bh(&sta->lock); | ||
1693 | sta->ampdu_mlme.tid_state_tx[tid] = | ||
1694 | HT_AGG_STATE_OPERATIONAL; | ||
1695 | spin_unlock_bh(&sta->lock); | ||
1696 | ieee80211_stop_tx_ba_session(&local->hw, sta->addr, tid, | ||
1697 | WLAN_BACK_RECIPIENT); | ||
1698 | } | ||
1699 | rcu_read_unlock(); | ||
1700 | } | ||
1701 | |||
1702 | /* | ||
1703 | * After sending add Block Ack request we activated a timer until | ||
1704 | * add Block Ack response will arrive from the recipient. | ||
1705 | * If this timer expires sta_addba_resp_timer_expired will be executed. | ||
1706 | */ | ||
1707 | void sta_addba_resp_timer_expired(unsigned long data) | ||
1708 | { | ||
1709 | /* not an elegant detour, but there is no choice as the timer passes | ||
1710 | * only one argument, and both sta_info and TID are needed, so init | ||
1711 | * flow in sta_info_create gives the TID as data, while the timer_to_id | ||
1712 | * array gives the sta through container_of */ | ||
1713 | u16 tid = *(u8 *)data; | ||
1714 | struct sta_info *temp_sta = container_of((void *)data, | ||
1715 | struct sta_info, timer_to_tid[tid]); | ||
1716 | |||
1717 | struct ieee80211_local *local = temp_sta->local; | ||
1718 | struct ieee80211_hw *hw = &local->hw; | ||
1719 | struct sta_info *sta; | ||
1720 | u8 *state; | ||
1721 | |||
1722 | rcu_read_lock(); | ||
1723 | |||
1724 | sta = sta_info_get(local, temp_sta->addr); | ||
1725 | if (!sta) { | ||
1726 | rcu_read_unlock(); | ||
1727 | return; | ||
1728 | } | ||
1729 | |||
1730 | state = &sta->ampdu_mlme.tid_state_tx[tid]; | ||
1731 | /* check if the TID waits for addBA response */ | ||
1732 | spin_lock_bh(&sta->lock); | ||
1733 | if (!(*state & HT_ADDBA_REQUESTED_MSK)) { | ||
1734 | spin_unlock_bh(&sta->lock); | ||
1735 | *state = HT_AGG_STATE_IDLE; | ||
1736 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
1737 | printk(KERN_DEBUG "timer expired on tid %d but we are not " | ||
1738 | "expecting addBA response there", tid); | ||
1739 | #endif | ||
1740 | goto timer_expired_exit; | ||
1741 | } | ||
1742 | |||
1743 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
1744 | printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid); | ||
1745 | #endif | ||
1746 | |||
1747 | /* go through the state check in stop_BA_session */ | ||
1748 | *state = HT_AGG_STATE_OPERATIONAL; | ||
1749 | spin_unlock_bh(&sta->lock); | ||
1750 | ieee80211_stop_tx_ba_session(hw, temp_sta->addr, tid, | ||
1751 | WLAN_BACK_INITIATOR); | ||
1752 | |||
1753 | timer_expired_exit: | ||
1754 | rcu_read_unlock(); | ||
1755 | } | ||
1756 | |||
1757 | /* | ||
1758 | * After accepting the AddBA Request we activated a timer, | ||
1759 | * resetting it after each frame that arrives from the originator. | ||
1760 | * if this timer expires ieee80211_sta_stop_rx_ba_session will be executed. | ||
1761 | */ | ||
1762 | static void sta_rx_agg_session_timer_expired(unsigned long data) | ||
1763 | { | ||
1764 | /* not an elegant detour, but there is no choice as the timer passes | ||
1765 | * only one argument, and various sta_info are needed here, so init | ||
1766 | * flow in sta_info_create gives the TID as data, while the timer_to_id | ||
1767 | * array gives the sta through container_of */ | ||
1768 | u8 *ptid = (u8 *)data; | ||
1769 | u8 *timer_to_id = ptid - *ptid; | ||
1770 | struct sta_info *sta = container_of(timer_to_id, struct sta_info, | ||
1771 | timer_to_tid[0]); | ||
1772 | |||
1773 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
1774 | printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid); | ||
1775 | #endif | ||
1776 | ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->addr, | ||
1777 | (u16)*ptid, WLAN_BACK_TIMER, | ||
1778 | WLAN_REASON_QSTA_TIMEOUT); | ||
1779 | } | ||
1780 | |||
1781 | void ieee80211_sta_tear_down_BA_sessions(struct ieee80211_sub_if_data *sdata, u8 *addr) | ||
1782 | { | ||
1783 | struct ieee80211_local *local = sdata->local; | ||
1784 | int i; | ||
1785 | |||
1786 | for (i = 0; i < STA_TID_NUM; i++) { | ||
1787 | ieee80211_stop_tx_ba_session(&local->hw, addr, i, | ||
1788 | WLAN_BACK_INITIATOR); | ||
1789 | ieee80211_sta_stop_rx_ba_session(sdata, addr, i, | ||
1790 | WLAN_BACK_RECIPIENT, | ||
1791 | WLAN_REASON_QSTA_LEAVE_QBSS); | ||
1792 | } | ||
1793 | } | ||
1794 | |||
1795 | static void ieee80211_send_refuse_measurement_request(struct ieee80211_sub_if_data *sdata, | ||
1796 | struct ieee80211_msrment_ie *request_ie, | ||
1797 | const u8 *da, const u8 *bssid, | ||
1798 | u8 dialog_token) | ||
1799 | { | ||
1800 | struct ieee80211_local *local = sdata->local; | ||
1801 | struct sk_buff *skb; | ||
1802 | struct ieee80211_mgmt *msr_report; | ||
1803 | |||
1804 | skb = dev_alloc_skb(sizeof(*msr_report) + local->hw.extra_tx_headroom + | ||
1805 | sizeof(struct ieee80211_msrment_ie)); | ||
1806 | |||
1807 | if (!skb) { | ||
1808 | printk(KERN_ERR "%s: failed to allocate buffer for " | ||
1809 | "measurement report frame\n", sdata->dev->name); | ||
1810 | return; | ||
1811 | } | ||
1812 | |||
1813 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
1814 | msr_report = (struct ieee80211_mgmt *)skb_put(skb, 24); | ||
1815 | memset(msr_report, 0, 24); | ||
1816 | memcpy(msr_report->da, da, ETH_ALEN); | ||
1817 | memcpy(msr_report->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
1818 | memcpy(msr_report->bssid, bssid, ETH_ALEN); | ||
1819 | msr_report->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
1820 | IEEE80211_STYPE_ACTION); | ||
1821 | |||
1822 | skb_put(skb, 1 + sizeof(msr_report->u.action.u.measurement)); | ||
1823 | msr_report->u.action.category = WLAN_CATEGORY_SPECTRUM_MGMT; | ||
1824 | msr_report->u.action.u.measurement.action_code = | ||
1825 | WLAN_ACTION_SPCT_MSR_RPRT; | ||
1826 | msr_report->u.action.u.measurement.dialog_token = dialog_token; | ||
1827 | |||
1828 | msr_report->u.action.u.measurement.element_id = WLAN_EID_MEASURE_REPORT; | ||
1829 | msr_report->u.action.u.measurement.length = | ||
1830 | sizeof(struct ieee80211_msrment_ie); | ||
1831 | |||
1832 | memset(&msr_report->u.action.u.measurement.msr_elem, 0, | ||
1833 | sizeof(struct ieee80211_msrment_ie)); | ||
1834 | msr_report->u.action.u.measurement.msr_elem.token = request_ie->token; | ||
1835 | msr_report->u.action.u.measurement.msr_elem.mode |= | ||
1836 | IEEE80211_SPCT_MSR_RPRT_MODE_REFUSED; | ||
1837 | msr_report->u.action.u.measurement.msr_elem.type = request_ie->type; | ||
1838 | |||
1839 | ieee80211_sta_tx(sdata, skb, 0); | ||
1840 | } | ||
1841 | |||
1842 | static void ieee80211_sta_process_measurement_req(struct ieee80211_sub_if_data *sdata, | ||
1843 | struct ieee80211_mgmt *mgmt, | ||
1844 | size_t len) | ||
1845 | { | ||
1846 | /* | ||
1847 | * Ignoring measurement request is spec violation. | ||
1848 | * Mandatory measurements must be reported optional | ||
1849 | * measurements might be refused or reported incapable | ||
1850 | * For now just refuse | ||
1851 | * TODO: Answer basic measurement as unmeasured | ||
1852 | */ | ||
1853 | ieee80211_send_refuse_measurement_request(sdata, | ||
1854 | &mgmt->u.action.u.measurement.msr_elem, | ||
1855 | mgmt->sa, mgmt->bssid, | ||
1856 | mgmt->u.action.u.measurement.dialog_token); | ||
1857 | } | ||
1858 | |||
1859 | |||
1860 | static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | 953 | static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, |
1861 | struct ieee80211_if_sta *ifsta, | 954 | struct ieee80211_if_sta *ifsta, |
1862 | struct ieee80211_mgmt *mgmt, | 955 | struct ieee80211_mgmt *mgmt, |
@@ -1977,7 +1070,7 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, | |||
1977 | IEEE80211_RETRY_AUTH_INTERVAL); | 1070 | IEEE80211_RETRY_AUTH_INTERVAL); |
1978 | } | 1071 | } |
1979 | 1072 | ||
1980 | ieee80211_set_disassoc(sdata, ifsta, 1); | 1073 | ieee80211_set_disassoc(sdata, ifsta, true, false, 0); |
1981 | ifsta->flags &= ~IEEE80211_STA_AUTHENTICATED; | 1074 | ifsta->flags &= ~IEEE80211_STA_AUTHENTICATED; |
1982 | } | 1075 | } |
1983 | 1076 | ||
@@ -2007,7 +1100,7 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, | |||
2007 | IEEE80211_RETRY_AUTH_INTERVAL); | 1100 | IEEE80211_RETRY_AUTH_INTERVAL); |
2008 | } | 1101 | } |
2009 | 1102 | ||
2010 | ieee80211_set_disassoc(sdata, ifsta, 0); | 1103 | ieee80211_set_disassoc(sdata, ifsta, false, false, 0); |
2011 | } | 1104 | } |
2012 | 1105 | ||
2013 | 1106 | ||
@@ -2201,209 +1294,12 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
2201 | * ieee80211_set_associated() will tell the driver */ | 1294 | * ieee80211_set_associated() will tell the driver */ |
2202 | bss_conf->aid = aid; | 1295 | bss_conf->aid = aid; |
2203 | bss_conf->assoc_capability = capab_info; | 1296 | bss_conf->assoc_capability = capab_info; |
2204 | ieee80211_set_associated(sdata, ifsta, 1); | 1297 | ieee80211_set_associated(sdata, ifsta); |
2205 | 1298 | ||
2206 | ieee80211_associated(sdata, ifsta); | 1299 | ieee80211_associated(sdata, ifsta); |
2207 | } | 1300 | } |
2208 | 1301 | ||
2209 | 1302 | ||
2210 | /* Caller must hold local->sta_bss_lock */ | ||
2211 | static void __ieee80211_rx_bss_hash_add(struct ieee80211_local *local, | ||
2212 | struct ieee80211_sta_bss *bss) | ||
2213 | { | ||
2214 | u8 hash_idx; | ||
2215 | |||
2216 | if (bss_mesh_cfg(bss)) | ||
2217 | hash_idx = mesh_id_hash(bss_mesh_id(bss), | ||
2218 | bss_mesh_id_len(bss)); | ||
2219 | else | ||
2220 | hash_idx = STA_HASH(bss->bssid); | ||
2221 | |||
2222 | bss->hnext = local->sta_bss_hash[hash_idx]; | ||
2223 | local->sta_bss_hash[hash_idx] = bss; | ||
2224 | } | ||
2225 | |||
2226 | |||
2227 | /* Caller must hold local->sta_bss_lock */ | ||
2228 | static void __ieee80211_rx_bss_hash_del(struct ieee80211_local *local, | ||
2229 | struct ieee80211_sta_bss *bss) | ||
2230 | { | ||
2231 | struct ieee80211_sta_bss *b, *prev = NULL; | ||
2232 | b = local->sta_bss_hash[STA_HASH(bss->bssid)]; | ||
2233 | while (b) { | ||
2234 | if (b == bss) { | ||
2235 | if (!prev) | ||
2236 | local->sta_bss_hash[STA_HASH(bss->bssid)] = | ||
2237 | bss->hnext; | ||
2238 | else | ||
2239 | prev->hnext = bss->hnext; | ||
2240 | break; | ||
2241 | } | ||
2242 | prev = b; | ||
2243 | b = b->hnext; | ||
2244 | } | ||
2245 | } | ||
2246 | |||
2247 | |||
2248 | static struct ieee80211_sta_bss * | ||
2249 | ieee80211_rx_bss_add(struct ieee80211_sub_if_data *sdata, u8 *bssid, int freq, | ||
2250 | u8 *ssid, u8 ssid_len) | ||
2251 | { | ||
2252 | struct ieee80211_local *local = sdata->local; | ||
2253 | struct ieee80211_sta_bss *bss; | ||
2254 | |||
2255 | bss = kzalloc(sizeof(*bss), GFP_ATOMIC); | ||
2256 | if (!bss) | ||
2257 | return NULL; | ||
2258 | atomic_inc(&bss->users); | ||
2259 | atomic_inc(&bss->users); | ||
2260 | memcpy(bss->bssid, bssid, ETH_ALEN); | ||
2261 | bss->freq = freq; | ||
2262 | if (ssid && ssid_len <= IEEE80211_MAX_SSID_LEN) { | ||
2263 | memcpy(bss->ssid, ssid, ssid_len); | ||
2264 | bss->ssid_len = ssid_len; | ||
2265 | } | ||
2266 | |||
2267 | spin_lock_bh(&local->sta_bss_lock); | ||
2268 | /* TODO: order by RSSI? */ | ||
2269 | list_add_tail(&bss->list, &local->sta_bss_list); | ||
2270 | __ieee80211_rx_bss_hash_add(local, bss); | ||
2271 | spin_unlock_bh(&local->sta_bss_lock); | ||
2272 | return bss; | ||
2273 | } | ||
2274 | |||
2275 | static struct ieee80211_sta_bss * | ||
2276 | ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq, | ||
2277 | u8 *ssid, u8 ssid_len) | ||
2278 | { | ||
2279 | struct ieee80211_sta_bss *bss; | ||
2280 | |||
2281 | spin_lock_bh(&local->sta_bss_lock); | ||
2282 | bss = local->sta_bss_hash[STA_HASH(bssid)]; | ||
2283 | while (bss) { | ||
2284 | if (!bss_mesh_cfg(bss) && | ||
2285 | !memcmp(bss->bssid, bssid, ETH_ALEN) && | ||
2286 | bss->freq == freq && | ||
2287 | bss->ssid_len == ssid_len && | ||
2288 | (ssid_len == 0 || !memcmp(bss->ssid, ssid, ssid_len))) { | ||
2289 | atomic_inc(&bss->users); | ||
2290 | break; | ||
2291 | } | ||
2292 | bss = bss->hnext; | ||
2293 | } | ||
2294 | spin_unlock_bh(&local->sta_bss_lock); | ||
2295 | return bss; | ||
2296 | } | ||
2297 | |||
2298 | #ifdef CONFIG_MAC80211_MESH | ||
2299 | static struct ieee80211_sta_bss * | ||
2300 | ieee80211_rx_mesh_bss_get(struct ieee80211_local *local, u8 *mesh_id, int mesh_id_len, | ||
2301 | u8 *mesh_cfg, int freq) | ||
2302 | { | ||
2303 | struct ieee80211_sta_bss *bss; | ||
2304 | |||
2305 | spin_lock_bh(&local->sta_bss_lock); | ||
2306 | bss = local->sta_bss_hash[mesh_id_hash(mesh_id, mesh_id_len)]; | ||
2307 | while (bss) { | ||
2308 | if (bss_mesh_cfg(bss) && | ||
2309 | !memcmp(bss_mesh_cfg(bss), mesh_cfg, MESH_CFG_CMP_LEN) && | ||
2310 | bss->freq == freq && | ||
2311 | mesh_id_len == bss->mesh_id_len && | ||
2312 | (mesh_id_len == 0 || !memcmp(bss->mesh_id, mesh_id, | ||
2313 | mesh_id_len))) { | ||
2314 | atomic_inc(&bss->users); | ||
2315 | break; | ||
2316 | } | ||
2317 | bss = bss->hnext; | ||
2318 | } | ||
2319 | spin_unlock_bh(&local->sta_bss_lock); | ||
2320 | return bss; | ||
2321 | } | ||
2322 | |||
2323 | static struct ieee80211_sta_bss * | ||
2324 | ieee80211_rx_mesh_bss_add(struct ieee80211_local *local, u8 *mesh_id, int mesh_id_len, | ||
2325 | u8 *mesh_cfg, int mesh_config_len, int freq) | ||
2326 | { | ||
2327 | struct ieee80211_sta_bss *bss; | ||
2328 | |||
2329 | if (mesh_config_len != MESH_CFG_LEN) | ||
2330 | return NULL; | ||
2331 | |||
2332 | bss = kzalloc(sizeof(*bss), GFP_ATOMIC); | ||
2333 | if (!bss) | ||
2334 | return NULL; | ||
2335 | |||
2336 | bss->mesh_cfg = kmalloc(MESH_CFG_CMP_LEN, GFP_ATOMIC); | ||
2337 | if (!bss->mesh_cfg) { | ||
2338 | kfree(bss); | ||
2339 | return NULL; | ||
2340 | } | ||
2341 | |||
2342 | if (mesh_id_len && mesh_id_len <= IEEE80211_MAX_MESH_ID_LEN) { | ||
2343 | bss->mesh_id = kmalloc(mesh_id_len, GFP_ATOMIC); | ||
2344 | if (!bss->mesh_id) { | ||
2345 | kfree(bss->mesh_cfg); | ||
2346 | kfree(bss); | ||
2347 | return NULL; | ||
2348 | } | ||
2349 | memcpy(bss->mesh_id, mesh_id, mesh_id_len); | ||
2350 | } | ||
2351 | |||
2352 | atomic_inc(&bss->users); | ||
2353 | atomic_inc(&bss->users); | ||
2354 | memcpy(bss->mesh_cfg, mesh_cfg, MESH_CFG_CMP_LEN); | ||
2355 | bss->mesh_id_len = mesh_id_len; | ||
2356 | bss->freq = freq; | ||
2357 | spin_lock_bh(&local->sta_bss_lock); | ||
2358 | /* TODO: order by RSSI? */ | ||
2359 | list_add_tail(&bss->list, &local->sta_bss_list); | ||
2360 | __ieee80211_rx_bss_hash_add(local, bss); | ||
2361 | spin_unlock_bh(&local->sta_bss_lock); | ||
2362 | return bss; | ||
2363 | } | ||
2364 | #endif | ||
2365 | |||
2366 | static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss) | ||
2367 | { | ||
2368 | kfree(bss->ies); | ||
2369 | kfree(bss_mesh_id(bss)); | ||
2370 | kfree(bss_mesh_cfg(bss)); | ||
2371 | kfree(bss); | ||
2372 | } | ||
2373 | |||
2374 | |||
2375 | static void ieee80211_rx_bss_put(struct ieee80211_local *local, | ||
2376 | struct ieee80211_sta_bss *bss) | ||
2377 | { | ||
2378 | local_bh_disable(); | ||
2379 | if (!atomic_dec_and_lock(&bss->users, &local->sta_bss_lock)) { | ||
2380 | local_bh_enable(); | ||
2381 | return; | ||
2382 | } | ||
2383 | |||
2384 | __ieee80211_rx_bss_hash_del(local, bss); | ||
2385 | list_del(&bss->list); | ||
2386 | spin_unlock_bh(&local->sta_bss_lock); | ||
2387 | ieee80211_rx_bss_free(bss); | ||
2388 | } | ||
2389 | |||
2390 | |||
2391 | void ieee80211_rx_bss_list_init(struct ieee80211_local *local) | ||
2392 | { | ||
2393 | spin_lock_init(&local->sta_bss_lock); | ||
2394 | INIT_LIST_HEAD(&local->sta_bss_list); | ||
2395 | } | ||
2396 | |||
2397 | |||
2398 | void ieee80211_rx_bss_list_deinit(struct ieee80211_local *local) | ||
2399 | { | ||
2400 | struct ieee80211_sta_bss *bss, *tmp; | ||
2401 | |||
2402 | list_for_each_entry_safe(bss, tmp, &local->sta_bss_list, list) | ||
2403 | ieee80211_rx_bss_put(local, bss); | ||
2404 | } | ||
2405 | |||
2406 | |||
2407 | static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | 1303 | static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, |
2408 | struct ieee80211_if_sta *ifsta, | 1304 | struct ieee80211_if_sta *ifsta, |
2409 | struct ieee80211_sta_bss *bss) | 1305 | struct ieee80211_sta_bss *bss) |
@@ -2508,7 +1404,7 @@ static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
2508 | } | 1404 | } |
2509 | ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates; | 1405 | ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates; |
2510 | 1406 | ||
2511 | ieee80211_sta_def_wmm_params(sdata, bss, 1); | 1407 | ieee80211_sta_def_wmm_params(sdata, bss); |
2512 | 1408 | ||
2513 | ifsta->state = IEEE80211_STA_MLME_IBSS_JOINED; | 1409 | ifsta->state = IEEE80211_STA_MLME_IBSS_JOINED; |
2514 | mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); | 1410 | mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); |
@@ -2588,21 +1484,29 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
2588 | struct ieee80211_mgmt *mgmt, | 1484 | struct ieee80211_mgmt *mgmt, |
2589 | size_t len, | 1485 | size_t len, |
2590 | struct ieee80211_rx_status *rx_status, | 1486 | struct ieee80211_rx_status *rx_status, |
2591 | struct ieee802_11_elems *elems) | 1487 | struct ieee802_11_elems *elems, |
1488 | bool beacon) | ||
2592 | { | 1489 | { |
2593 | struct ieee80211_local *local = sdata->local; | 1490 | struct ieee80211_local *local = sdata->local; |
2594 | int freq, clen; | 1491 | int freq; |
2595 | struct ieee80211_sta_bss *bss; | 1492 | struct ieee80211_sta_bss *bss; |
2596 | struct sta_info *sta; | 1493 | struct sta_info *sta; |
2597 | struct ieee80211_channel *channel; | 1494 | struct ieee80211_channel *channel; |
2598 | u64 beacon_timestamp, rx_timestamp; | 1495 | u64 beacon_timestamp, rx_timestamp; |
2599 | u64 supp_rates = 0; | 1496 | u64 supp_rates = 0; |
2600 | bool beacon = ieee80211_is_beacon(mgmt->frame_control); | ||
2601 | enum ieee80211_band band = rx_status->band; | 1497 | enum ieee80211_band band = rx_status->band; |
2602 | DECLARE_MAC_BUF(mac); | 1498 | DECLARE_MAC_BUF(mac); |
2603 | DECLARE_MAC_BUF(mac2); | 1499 | DECLARE_MAC_BUF(mac2); |
2604 | 1500 | ||
2605 | beacon_timestamp = le64_to_cpu(mgmt->u.beacon.timestamp); | 1501 | if (elems->ds_params && elems->ds_params_len == 1) |
1502 | freq = ieee80211_channel_to_frequency(elems->ds_params[0]); | ||
1503 | else | ||
1504 | freq = rx_status->freq; | ||
1505 | |||
1506 | channel = ieee80211_get_channel(local->hw.wiphy, freq); | ||
1507 | |||
1508 | if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) | ||
1509 | return; | ||
2606 | 1510 | ||
2607 | if (ieee80211_vif_is_mesh(&sdata->vif) && elems->mesh_id && | 1511 | if (ieee80211_vif_is_mesh(&sdata->vif) && elems->mesh_id && |
2608 | elems->mesh_config && mesh_matches_local(elems, sdata)) { | 1512 | elems->mesh_config && mesh_matches_local(elems, sdata)) { |
@@ -2612,13 +1516,12 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
2612 | mesh_peer_accepts_plinks(elems)); | 1516 | mesh_peer_accepts_plinks(elems)); |
2613 | } | 1517 | } |
2614 | 1518 | ||
2615 | rcu_read_lock(); | ||
2616 | |||
2617 | if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems->supp_rates && | 1519 | if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems->supp_rates && |
2618 | memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0) { | 1520 | memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0) { |
2619 | |||
2620 | supp_rates = ieee80211_sta_get_rates(local, elems, band); | 1521 | supp_rates = ieee80211_sta_get_rates(local, elems, band); |
2621 | 1522 | ||
1523 | rcu_read_lock(); | ||
1524 | |||
2622 | sta = sta_info_get(local, mgmt->sa); | 1525 | sta = sta_info_get(local, mgmt->sa); |
2623 | if (sta) { | 1526 | if (sta) { |
2624 | u64 prev_rates; | 1527 | u64 prev_rates; |
@@ -2642,95 +1545,18 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
2642 | ieee80211_ibss_add_sta(sdata, NULL, mgmt->bssid, | 1545 | ieee80211_ibss_add_sta(sdata, NULL, mgmt->bssid, |
2643 | mgmt->sa, supp_rates); | 1546 | mgmt->sa, supp_rates); |
2644 | } | 1547 | } |
2645 | } | ||
2646 | |||
2647 | rcu_read_unlock(); | ||
2648 | |||
2649 | if (elems->ds_params && elems->ds_params_len == 1) | ||
2650 | freq = ieee80211_channel_to_frequency(elems->ds_params[0]); | ||
2651 | else | ||
2652 | freq = rx_status->freq; | ||
2653 | |||
2654 | channel = ieee80211_get_channel(local->hw.wiphy, freq); | ||
2655 | |||
2656 | if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) | ||
2657 | return; | ||
2658 | |||
2659 | #ifdef CONFIG_MAC80211_MESH | ||
2660 | if (elems->mesh_config) | ||
2661 | bss = ieee80211_rx_mesh_bss_get(local, elems->mesh_id, | ||
2662 | elems->mesh_id_len, elems->mesh_config, freq); | ||
2663 | else | ||
2664 | #endif | ||
2665 | bss = ieee80211_rx_bss_get(local, mgmt->bssid, freq, | ||
2666 | elems->ssid, elems->ssid_len); | ||
2667 | if (!bss) { | ||
2668 | #ifdef CONFIG_MAC80211_MESH | ||
2669 | if (elems->mesh_config) | ||
2670 | bss = ieee80211_rx_mesh_bss_add(local, elems->mesh_id, | ||
2671 | elems->mesh_id_len, elems->mesh_config, | ||
2672 | elems->mesh_config_len, freq); | ||
2673 | else | ||
2674 | #endif | ||
2675 | bss = ieee80211_rx_bss_add(sdata, mgmt->bssid, freq, | ||
2676 | elems->ssid, elems->ssid_len); | ||
2677 | if (!bss) | ||
2678 | return; | ||
2679 | } else { | ||
2680 | #if 0 | ||
2681 | /* TODO: order by RSSI? */ | ||
2682 | spin_lock_bh(&local->sta_bss_lock); | ||
2683 | list_move_tail(&bss->list, &local->sta_bss_list); | ||
2684 | spin_unlock_bh(&local->sta_bss_lock); | ||
2685 | #endif | ||
2686 | } | ||
2687 | 1548 | ||
2688 | /* save the ERP value so that it is available at association time */ | 1549 | rcu_read_unlock(); |
2689 | if (elems->erp_info && elems->erp_info_len >= 1) { | ||
2690 | bss->erp_value = elems->erp_info[0]; | ||
2691 | bss->has_erp_value = 1; | ||
2692 | } | ||
2693 | |||
2694 | bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int); | ||
2695 | bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info); | ||
2696 | |||
2697 | if (elems->tim) { | ||
2698 | struct ieee80211_tim_ie *tim_ie = | ||
2699 | (struct ieee80211_tim_ie *)elems->tim; | ||
2700 | bss->dtim_period = tim_ie->dtim_period; | ||
2701 | } | 1550 | } |
2702 | 1551 | ||
2703 | /* set default value for buggy APs */ | 1552 | bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, |
2704 | if (!elems->tim || bss->dtim_period == 0) | 1553 | freq, beacon); |
2705 | bss->dtim_period = 1; | 1554 | if (!bss) |
2706 | 1555 | return; | |
2707 | bss->supp_rates_len = 0; | ||
2708 | if (elems->supp_rates) { | ||
2709 | clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len; | ||
2710 | if (clen > elems->supp_rates_len) | ||
2711 | clen = elems->supp_rates_len; | ||
2712 | memcpy(&bss->supp_rates[bss->supp_rates_len], elems->supp_rates, | ||
2713 | clen); | ||
2714 | bss->supp_rates_len += clen; | ||
2715 | } | ||
2716 | if (elems->ext_supp_rates) { | ||
2717 | clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len; | ||
2718 | if (clen > elems->ext_supp_rates_len) | ||
2719 | clen = elems->ext_supp_rates_len; | ||
2720 | memcpy(&bss->supp_rates[bss->supp_rates_len], | ||
2721 | elems->ext_supp_rates, clen); | ||
2722 | bss->supp_rates_len += clen; | ||
2723 | } | ||
2724 | 1556 | ||
2725 | bss->band = band; | 1557 | /* was just updated in ieee80211_bss_info_update */ |
1558 | beacon_timestamp = bss->timestamp; | ||
2726 | 1559 | ||
2727 | bss->timestamp = beacon_timestamp; | ||
2728 | bss->last_update = jiffies; | ||
2729 | bss->signal = rx_status->signal; | ||
2730 | bss->noise = rx_status->noise; | ||
2731 | bss->qual = rx_status->qual; | ||
2732 | if (!beacon) | ||
2733 | bss->last_probe_resp = jiffies; | ||
2734 | /* | 1560 | /* |
2735 | * In STA mode, the remaining parameters should not be overridden | 1561 | * In STA mode, the remaining parameters should not be overridden |
2736 | * by beacons because they're not necessarily accurate there. | 1562 | * by beacons because they're not necessarily accurate there. |
@@ -2741,21 +1567,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
2741 | return; | 1567 | return; |
2742 | } | 1568 | } |
2743 | 1569 | ||
2744 | if (bss->ies == NULL || bss->ies_len < elems->total_len) { | ||
2745 | kfree(bss->ies); | ||
2746 | bss->ies = kmalloc(elems->total_len, GFP_ATOMIC); | ||
2747 | } | ||
2748 | if (bss->ies) { | ||
2749 | memcpy(bss->ies, elems->ie_start, elems->total_len); | ||
2750 | bss->ies_len = elems->total_len; | ||
2751 | } else | ||
2752 | bss->ies_len = 0; | ||
2753 | |||
2754 | bss->wmm_used = elems->wmm_param || elems->wmm_info; | ||
2755 | |||
2756 | /* check if we need to merge IBSS */ | 1570 | /* check if we need to merge IBSS */ |
2757 | if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && beacon && | 1571 | if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && beacon && |
2758 | !local->sta_sw_scanning && !local->sta_hw_scanning && | ||
2759 | bss->capability & WLAN_CAPABILITY_IBSS && | 1572 | bss->capability & WLAN_CAPABILITY_IBSS && |
2760 | bss->freq == local->oper_channel->center_freq && | 1573 | bss->freq == local->oper_channel->center_freq && |
2761 | elems->ssid_len == sdata->u.sta.ssid_len && | 1574 | elems->ssid_len == sdata->u.sta.ssid_len && |
@@ -2832,7 +1645,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
2832 | ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, | 1645 | ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, |
2833 | &elems); | 1646 | &elems); |
2834 | 1647 | ||
2835 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems); | 1648 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false); |
2836 | 1649 | ||
2837 | /* direct probe may be part of the association flow */ | 1650 | /* direct probe may be part of the association flow */ |
2838 | if (test_and_clear_bit(IEEE80211_STA_REQ_DIRECT_PROBE, | 1651 | if (test_and_clear_bit(IEEE80211_STA_REQ_DIRECT_PROBE, |
@@ -2863,7 +1676,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
2863 | 1676 | ||
2864 | ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems); | 1677 | ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems); |
2865 | 1678 | ||
2866 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems); | 1679 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, true); |
2867 | 1680 | ||
2868 | if (sdata->vif.type != IEEE80211_IF_TYPE_STA) | 1681 | if (sdata->vif.type != IEEE80211_IF_TYPE_STA) |
2869 | return; | 1682 | return; |
@@ -2876,12 +1689,6 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
2876 | ieee80211_sta_wmm_params(local, ifsta, elems.wmm_param, | 1689 | ieee80211_sta_wmm_params(local, ifsta, elems.wmm_param, |
2877 | elems.wmm_param_len); | 1690 | elems.wmm_param_len); |
2878 | 1691 | ||
2879 | /* Do not send changes to driver if we are scanning. This removes | ||
2880 | * requirement that driver's bss_info_changed function needs to be | ||
2881 | * atomic. */ | ||
2882 | if (local->sta_sw_scanning || local->sta_hw_scanning) | ||
2883 | return; | ||
2884 | |||
2885 | if (elems.erp_info && elems.erp_info_len >= 1) | 1692 | if (elems.erp_info && elems.erp_info_len >= 1) |
2886 | changed |= ieee80211_handle_erp_ie(sdata, elems.erp_info[0]); | 1693 | changed |= ieee80211_handle_erp_ie(sdata, elems.erp_info[0]); |
2887 | else { | 1694 | else { |
@@ -2975,7 +1782,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, | |||
2975 | printk(KERN_DEBUG "%s: Sending ProbeResp to %s\n", | 1782 | printk(KERN_DEBUG "%s: Sending ProbeResp to %s\n", |
2976 | sdata->dev->name, print_mac(mac, resp->da)); | 1783 | sdata->dev->name, print_mac(mac, resp->da)); |
2977 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | 1784 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ |
2978 | ieee80211_sta_tx(sdata, skb, 0); | 1785 | ieee80211_tx_skb(sdata, skb, 0); |
2979 | } | 1786 | } |
2980 | 1787 | ||
2981 | static void ieee80211_rx_mgmt_action(struct ieee80211_sub_if_data *sdata, | 1788 | static void ieee80211_rx_mgmt_action(struct ieee80211_sub_if_data *sdata, |
@@ -2984,53 +1791,16 @@ static void ieee80211_rx_mgmt_action(struct ieee80211_sub_if_data *sdata, | |||
2984 | size_t len, | 1791 | size_t len, |
2985 | struct ieee80211_rx_status *rx_status) | 1792 | struct ieee80211_rx_status *rx_status) |
2986 | { | 1793 | { |
2987 | struct ieee80211_local *local = sdata->local; | 1794 | /* currently we only handle mesh interface action frames here */ |
2988 | 1795 | if (!ieee80211_vif_is_mesh(&sdata->vif)) | |
2989 | if (len < IEEE80211_MIN_ACTION_SIZE) | ||
2990 | return; | 1796 | return; |
2991 | 1797 | ||
2992 | switch (mgmt->u.action.category) { | 1798 | switch (mgmt->u.action.category) { |
2993 | case WLAN_CATEGORY_SPECTRUM_MGMT: | ||
2994 | if (local->hw.conf.channel->band != IEEE80211_BAND_5GHZ) | ||
2995 | break; | ||
2996 | switch (mgmt->u.action.u.chan_switch.action_code) { | ||
2997 | case WLAN_ACTION_SPCT_MSR_REQ: | ||
2998 | if (len < (IEEE80211_MIN_ACTION_SIZE + | ||
2999 | sizeof(mgmt->u.action.u.measurement))) | ||
3000 | break; | ||
3001 | ieee80211_sta_process_measurement_req(sdata, mgmt, len); | ||
3002 | break; | ||
3003 | } | ||
3004 | break; | ||
3005 | case WLAN_CATEGORY_BACK: | ||
3006 | switch (mgmt->u.action.u.addba_req.action_code) { | ||
3007 | case WLAN_ACTION_ADDBA_REQ: | ||
3008 | if (len < (IEEE80211_MIN_ACTION_SIZE + | ||
3009 | sizeof(mgmt->u.action.u.addba_req))) | ||
3010 | break; | ||
3011 | ieee80211_sta_process_addba_request(local, mgmt, len); | ||
3012 | break; | ||
3013 | case WLAN_ACTION_ADDBA_RESP: | ||
3014 | if (len < (IEEE80211_MIN_ACTION_SIZE + | ||
3015 | sizeof(mgmt->u.action.u.addba_resp))) | ||
3016 | break; | ||
3017 | ieee80211_sta_process_addba_resp(local, mgmt, len); | ||
3018 | break; | ||
3019 | case WLAN_ACTION_DELBA: | ||
3020 | if (len < (IEEE80211_MIN_ACTION_SIZE + | ||
3021 | sizeof(mgmt->u.action.u.delba))) | ||
3022 | break; | ||
3023 | ieee80211_sta_process_delba(sdata, mgmt, len); | ||
3024 | break; | ||
3025 | } | ||
3026 | break; | ||
3027 | case PLINK_CATEGORY: | 1799 | case PLINK_CATEGORY: |
3028 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 1800 | mesh_rx_plink_frame(sdata, mgmt, len, rx_status); |
3029 | mesh_rx_plink_frame(sdata, mgmt, len, rx_status); | ||
3030 | break; | 1801 | break; |
3031 | case MESH_PATH_SEL_CATEGORY: | 1802 | case MESH_PATH_SEL_CATEGORY: |
3032 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 1803 | mesh_rx_path_sel_frame(sdata, mgmt, len); |
3033 | mesh_rx_path_sel_frame(sdata, mgmt, len); | ||
3034 | break; | 1804 | break; |
3035 | } | 1805 | } |
3036 | } | 1806 | } |
@@ -3120,41 +1890,6 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
3120 | } | 1890 | } |
3121 | 1891 | ||
3122 | 1892 | ||
3123 | ieee80211_rx_result | ||
3124 | ieee80211_sta_rx_scan(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | ||
3125 | struct ieee80211_rx_status *rx_status) | ||
3126 | { | ||
3127 | struct ieee80211_mgmt *mgmt; | ||
3128 | __le16 fc; | ||
3129 | |||
3130 | if (skb->len < 2) | ||
3131 | return RX_DROP_UNUSABLE; | ||
3132 | |||
3133 | mgmt = (struct ieee80211_mgmt *) skb->data; | ||
3134 | fc = mgmt->frame_control; | ||
3135 | |||
3136 | if (ieee80211_is_ctl(fc)) | ||
3137 | return RX_CONTINUE; | ||
3138 | |||
3139 | if (skb->len < 24) | ||
3140 | return RX_DROP_MONITOR; | ||
3141 | |||
3142 | if (ieee80211_is_probe_resp(fc)) { | ||
3143 | ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len, rx_status); | ||
3144 | dev_kfree_skb(skb); | ||
3145 | return RX_QUEUED; | ||
3146 | } | ||
3147 | |||
3148 | if (ieee80211_is_beacon(fc)) { | ||
3149 | ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, rx_status); | ||
3150 | dev_kfree_skb(skb); | ||
3151 | return RX_QUEUED; | ||
3152 | } | ||
3153 | |||
3154 | return RX_CONTINUE; | ||
3155 | } | ||
3156 | |||
3157 | |||
3158 | static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata) | 1893 | static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata) |
3159 | { | 1894 | { |
3160 | struct ieee80211_local *local = sdata->local; | 1895 | struct ieee80211_local *local = sdata->local; |
@@ -3259,95 +1994,6 @@ void ieee80211_sta_timer(unsigned long data) | |||
3259 | queue_work(local->hw.workqueue, &ifsta->work); | 1994 | queue_work(local->hw.workqueue, &ifsta->work); |
3260 | } | 1995 | } |
3261 | 1996 | ||
3262 | void ieee80211_sta_work(struct work_struct *work) | ||
3263 | { | ||
3264 | struct ieee80211_sub_if_data *sdata = | ||
3265 | container_of(work, struct ieee80211_sub_if_data, u.sta.work); | ||
3266 | struct ieee80211_local *local = sdata->local; | ||
3267 | struct ieee80211_if_sta *ifsta; | ||
3268 | struct sk_buff *skb; | ||
3269 | |||
3270 | if (!netif_running(sdata->dev)) | ||
3271 | return; | ||
3272 | |||
3273 | if (local->sta_sw_scanning || local->sta_hw_scanning) | ||
3274 | return; | ||
3275 | |||
3276 | if (WARN_ON(sdata->vif.type != IEEE80211_IF_TYPE_STA && | ||
3277 | sdata->vif.type != IEEE80211_IF_TYPE_IBSS && | ||
3278 | sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)) | ||
3279 | return; | ||
3280 | ifsta = &sdata->u.sta; | ||
3281 | |||
3282 | while ((skb = skb_dequeue(&ifsta->skb_queue))) | ||
3283 | ieee80211_sta_rx_queued_mgmt(sdata, skb); | ||
3284 | |||
3285 | #ifdef CONFIG_MAC80211_MESH | ||
3286 | if (ifsta->preq_queue_len && | ||
3287 | time_after(jiffies, | ||
3288 | ifsta->last_preq + msecs_to_jiffies(ifsta->mshcfg.dot11MeshHWMPpreqMinInterval))) | ||
3289 | mesh_path_start_discovery(sdata); | ||
3290 | #endif | ||
3291 | |||
3292 | if (ifsta->state != IEEE80211_STA_MLME_DIRECT_PROBE && | ||
3293 | ifsta->state != IEEE80211_STA_MLME_AUTHENTICATE && | ||
3294 | ifsta->state != IEEE80211_STA_MLME_ASSOCIATE && | ||
3295 | test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request)) { | ||
3296 | if (ifsta->scan_ssid_len) | ||
3297 | ieee80211_sta_start_scan(sdata, ifsta->scan_ssid, ifsta->scan_ssid_len); | ||
3298 | else | ||
3299 | ieee80211_sta_start_scan(sdata, NULL, 0); | ||
3300 | return; | ||
3301 | } | ||
3302 | |||
3303 | if (test_and_clear_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request)) { | ||
3304 | if (ieee80211_sta_config_auth(sdata, ifsta)) | ||
3305 | return; | ||
3306 | clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request); | ||
3307 | } else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request)) | ||
3308 | return; | ||
3309 | |||
3310 | switch (ifsta->state) { | ||
3311 | case IEEE80211_STA_MLME_DISABLED: | ||
3312 | break; | ||
3313 | case IEEE80211_STA_MLME_DIRECT_PROBE: | ||
3314 | ieee80211_direct_probe(sdata, ifsta); | ||
3315 | break; | ||
3316 | case IEEE80211_STA_MLME_AUTHENTICATE: | ||
3317 | ieee80211_authenticate(sdata, ifsta); | ||
3318 | break; | ||
3319 | case IEEE80211_STA_MLME_ASSOCIATE: | ||
3320 | ieee80211_associate(sdata, ifsta); | ||
3321 | break; | ||
3322 | case IEEE80211_STA_MLME_ASSOCIATED: | ||
3323 | ieee80211_associated(sdata, ifsta); | ||
3324 | break; | ||
3325 | case IEEE80211_STA_MLME_IBSS_SEARCH: | ||
3326 | ieee80211_sta_find_ibss(sdata, ifsta); | ||
3327 | break; | ||
3328 | case IEEE80211_STA_MLME_IBSS_JOINED: | ||
3329 | ieee80211_sta_merge_ibss(sdata, ifsta); | ||
3330 | break; | ||
3331 | #ifdef CONFIG_MAC80211_MESH | ||
3332 | case IEEE80211_STA_MLME_MESH_UP: | ||
3333 | ieee80211_mesh_housekeeping(sdata, ifsta); | ||
3334 | break; | ||
3335 | #endif | ||
3336 | default: | ||
3337 | WARN_ON(1); | ||
3338 | break; | ||
3339 | } | ||
3340 | |||
3341 | if (ieee80211_privacy_mismatch(sdata, ifsta)) { | ||
3342 | printk(KERN_DEBUG "%s: privacy configuration mismatch and " | ||
3343 | "mixed-cell disabled - disassociate\n", sdata->dev->name); | ||
3344 | |||
3345 | ieee80211_send_disassoc(sdata, ifsta, WLAN_REASON_UNSPECIFIED); | ||
3346 | ieee80211_set_disassoc(sdata, ifsta, 0); | ||
3347 | } | ||
3348 | } | ||
3349 | |||
3350 | |||
3351 | static void ieee80211_sta_reset_auth(struct ieee80211_sub_if_data *sdata, | 1997 | static void ieee80211_sta_reset_auth(struct ieee80211_sub_if_data *sdata, |
3352 | struct ieee80211_if_sta *ifsta) | 1998 | struct ieee80211_if_sta *ifsta) |
3353 | { | 1999 | { |
@@ -3375,6 +2021,7 @@ static void ieee80211_sta_reset_auth(struct ieee80211_sub_if_data *sdata, | |||
3375 | ifsta->direct_probe_tries = 0; | 2021 | ifsta->direct_probe_tries = 0; |
3376 | ifsta->auth_tries = 0; | 2022 | ifsta->auth_tries = 0; |
3377 | ifsta->assoc_tries = 0; | 2023 | ifsta->assoc_tries = 0; |
2024 | netif_tx_stop_all_queues(sdata->dev); | ||
3378 | netif_carrier_off(sdata->dev); | 2025 | netif_carrier_off(sdata->dev); |
3379 | } | 2026 | } |
3380 | 2027 | ||
@@ -3388,9 +2035,14 @@ void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata, | |||
3388 | return; | 2035 | return; |
3389 | 2036 | ||
3390 | if ((ifsta->flags & (IEEE80211_STA_BSSID_SET | | 2037 | if ((ifsta->flags & (IEEE80211_STA_BSSID_SET | |
3391 | IEEE80211_STA_AUTO_BSSID_SEL)) && | 2038 | IEEE80211_STA_AUTO_BSSID_SEL)) && |
3392 | (ifsta->flags & (IEEE80211_STA_SSID_SET | | 2039 | (ifsta->flags & (IEEE80211_STA_SSID_SET | |
3393 | IEEE80211_STA_AUTO_SSID_SEL))) { | 2040 | IEEE80211_STA_AUTO_SSID_SEL))) { |
2041 | |||
2042 | if (ifsta->state == IEEE80211_STA_MLME_ASSOCIATED) | ||
2043 | ieee80211_set_disassoc(sdata, ifsta, true, true, | ||
2044 | WLAN_REASON_DEAUTH_LEAVING); | ||
2045 | |||
3394 | set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request); | 2046 | set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request); |
3395 | queue_work(local->hw.workqueue, &ifsta->work); | 2047 | queue_work(local->hw.workqueue, &ifsta->work); |
3396 | } | 2048 | } |
@@ -3426,85 +2078,6 @@ static int ieee80211_sta_match_ssid(struct ieee80211_if_sta *ifsta, | |||
3426 | return 0; | 2078 | return 0; |
3427 | } | 2079 | } |
3428 | 2080 | ||
3429 | static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata, | ||
3430 | struct ieee80211_if_sta *ifsta) | ||
3431 | { | ||
3432 | struct ieee80211_local *local = sdata->local; | ||
3433 | struct ieee80211_sta_bss *bss, *selected = NULL; | ||
3434 | int top_rssi = 0, freq; | ||
3435 | |||
3436 | spin_lock_bh(&local->sta_bss_lock); | ||
3437 | freq = local->oper_channel->center_freq; | ||
3438 | list_for_each_entry(bss, &local->sta_bss_list, list) { | ||
3439 | if (!(bss->capability & WLAN_CAPABILITY_ESS)) | ||
3440 | continue; | ||
3441 | |||
3442 | if ((ifsta->flags & (IEEE80211_STA_AUTO_SSID_SEL | | ||
3443 | IEEE80211_STA_AUTO_BSSID_SEL | | ||
3444 | IEEE80211_STA_AUTO_CHANNEL_SEL)) && | ||
3445 | (!!(bss->capability & WLAN_CAPABILITY_PRIVACY) ^ | ||
3446 | !!sdata->default_key)) | ||
3447 | continue; | ||
3448 | |||
3449 | if (!(ifsta->flags & IEEE80211_STA_AUTO_CHANNEL_SEL) && | ||
3450 | bss->freq != freq) | ||
3451 | continue; | ||
3452 | |||
3453 | if (!(ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL) && | ||
3454 | memcmp(bss->bssid, ifsta->bssid, ETH_ALEN)) | ||
3455 | continue; | ||
3456 | |||
3457 | if (!(ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL) && | ||
3458 | !ieee80211_sta_match_ssid(ifsta, bss->ssid, bss->ssid_len)) | ||
3459 | continue; | ||
3460 | |||
3461 | if (!selected || top_rssi < bss->signal) { | ||
3462 | selected = bss; | ||
3463 | top_rssi = bss->signal; | ||
3464 | } | ||
3465 | } | ||
3466 | if (selected) | ||
3467 | atomic_inc(&selected->users); | ||
3468 | spin_unlock_bh(&local->sta_bss_lock); | ||
3469 | |||
3470 | if (selected) { | ||
3471 | ieee80211_set_freq(sdata, selected->freq); | ||
3472 | if (!(ifsta->flags & IEEE80211_STA_SSID_SET)) | ||
3473 | ieee80211_sta_set_ssid(sdata, selected->ssid, | ||
3474 | selected->ssid_len); | ||
3475 | ieee80211_sta_set_bssid(sdata, selected->bssid); | ||
3476 | ieee80211_sta_def_wmm_params(sdata, selected, 0); | ||
3477 | |||
3478 | /* Send out direct probe if no probe resp was received or | ||
3479 | * the one we have is outdated | ||
3480 | */ | ||
3481 | if (!selected->last_probe_resp || | ||
3482 | time_after(jiffies, selected->last_probe_resp | ||
3483 | + IEEE80211_SCAN_RESULT_EXPIRE)) | ||
3484 | ifsta->state = IEEE80211_STA_MLME_DIRECT_PROBE; | ||
3485 | else | ||
3486 | ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE; | ||
3487 | |||
3488 | ieee80211_rx_bss_put(local, selected); | ||
3489 | ieee80211_sta_reset_auth(sdata, ifsta); | ||
3490 | return 0; | ||
3491 | } else { | ||
3492 | if (ifsta->assoc_scan_tries < IEEE80211_ASSOC_SCANS_MAX_TRIES) { | ||
3493 | ifsta->assoc_scan_tries++; | ||
3494 | if (ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL) | ||
3495 | ieee80211_sta_start_scan(sdata, NULL, 0); | ||
3496 | else | ||
3497 | ieee80211_sta_start_scan(sdata, ifsta->ssid, | ||
3498 | ifsta->ssid_len); | ||
3499 | ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE; | ||
3500 | set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request); | ||
3501 | } else | ||
3502 | ifsta->state = IEEE80211_STA_MLME_DISABLED; | ||
3503 | } | ||
3504 | return -1; | ||
3505 | } | ||
3506 | |||
3507 | |||
3508 | static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata, | 2081 | static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata, |
3509 | struct ieee80211_if_sta *ifsta) | 2082 | struct ieee80211_if_sta *ifsta) |
3510 | { | 2083 | { |
@@ -3533,7 +2106,7 @@ static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata, | |||
3533 | printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %s\n", | 2106 | printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %s\n", |
3534 | sdata->dev->name, print_mac(mac, bssid)); | 2107 | sdata->dev->name, print_mac(mac, bssid)); |
3535 | 2108 | ||
3536 | bss = ieee80211_rx_bss_add(sdata, bssid, | 2109 | bss = ieee80211_rx_bss_add(local, bssid, |
3537 | local->hw.conf.channel->center_freq, | 2110 | local->hw.conf.channel->center_freq, |
3538 | sdata->u.sta.ssid, sdata->u.sta.ssid_len); | 2111 | sdata->u.sta.ssid, sdata->u.sta.ssid_len); |
3539 | if (!bss) | 2112 | if (!bss) |
@@ -3762,544 +2335,6 @@ int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid) | |||
3762 | } | 2335 | } |
3763 | 2336 | ||
3764 | 2337 | ||
3765 | static void ieee80211_send_nullfunc(struct ieee80211_local *local, | ||
3766 | struct ieee80211_sub_if_data *sdata, | ||
3767 | int powersave) | ||
3768 | { | ||
3769 | struct sk_buff *skb; | ||
3770 | struct ieee80211_hdr *nullfunc; | ||
3771 | __le16 fc; | ||
3772 | |||
3773 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24); | ||
3774 | if (!skb) { | ||
3775 | printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc " | ||
3776 | "frame\n", sdata->dev->name); | ||
3777 | return; | ||
3778 | } | ||
3779 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
3780 | |||
3781 | nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24); | ||
3782 | memset(nullfunc, 0, 24); | ||
3783 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | | ||
3784 | IEEE80211_FCTL_TODS); | ||
3785 | if (powersave) | ||
3786 | fc |= cpu_to_le16(IEEE80211_FCTL_PM); | ||
3787 | nullfunc->frame_control = fc; | ||
3788 | memcpy(nullfunc->addr1, sdata->u.sta.bssid, ETH_ALEN); | ||
3789 | memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN); | ||
3790 | memcpy(nullfunc->addr3, sdata->u.sta.bssid, ETH_ALEN); | ||
3791 | |||
3792 | ieee80211_sta_tx(sdata, skb, 0); | ||
3793 | } | ||
3794 | |||
3795 | |||
3796 | static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) | ||
3797 | { | ||
3798 | if (sdata->vif.type == IEEE80211_IF_TYPE_STA || | ||
3799 | ieee80211_vif_is_mesh(&sdata->vif)) | ||
3800 | ieee80211_sta_timer((unsigned long)sdata); | ||
3801 | } | ||
3802 | |||
3803 | void ieee80211_scan_completed(struct ieee80211_hw *hw) | ||
3804 | { | ||
3805 | struct ieee80211_local *local = hw_to_local(hw); | ||
3806 | struct net_device *dev = local->scan_dev; | ||
3807 | struct ieee80211_sub_if_data *sdata; | ||
3808 | union iwreq_data wrqu; | ||
3809 | |||
3810 | local->last_scan_completed = jiffies; | ||
3811 | memset(&wrqu, 0, sizeof(wrqu)); | ||
3812 | wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); | ||
3813 | |||
3814 | if (local->sta_hw_scanning) { | ||
3815 | local->sta_hw_scanning = 0; | ||
3816 | if (ieee80211_hw_config(local)) | ||
3817 | printk(KERN_DEBUG "%s: failed to restore operational " | ||
3818 | "channel after scan\n", dev->name); | ||
3819 | /* Restart STA timer for HW scan case */ | ||
3820 | rcu_read_lock(); | ||
3821 | list_for_each_entry_rcu(sdata, &local->interfaces, list) | ||
3822 | ieee80211_restart_sta_timer(sdata); | ||
3823 | rcu_read_unlock(); | ||
3824 | |||
3825 | goto done; | ||
3826 | } | ||
3827 | |||
3828 | local->sta_sw_scanning = 0; | ||
3829 | if (ieee80211_hw_config(local)) | ||
3830 | printk(KERN_DEBUG "%s: failed to restore operational " | ||
3831 | "channel after scan\n", dev->name); | ||
3832 | |||
3833 | |||
3834 | netif_tx_lock_bh(local->mdev); | ||
3835 | netif_addr_lock(local->mdev); | ||
3836 | local->filter_flags &= ~FIF_BCN_PRBRESP_PROMISC; | ||
3837 | local->ops->configure_filter(local_to_hw(local), | ||
3838 | FIF_BCN_PRBRESP_PROMISC, | ||
3839 | &local->filter_flags, | ||
3840 | local->mdev->mc_count, | ||
3841 | local->mdev->mc_list); | ||
3842 | |||
3843 | netif_addr_unlock(local->mdev); | ||
3844 | netif_tx_unlock_bh(local->mdev); | ||
3845 | |||
3846 | rcu_read_lock(); | ||
3847 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | ||
3848 | /* Tell AP we're back */ | ||
3849 | if (sdata->vif.type == IEEE80211_IF_TYPE_STA && | ||
3850 | sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) | ||
3851 | ieee80211_send_nullfunc(local, sdata, 0); | ||
3852 | |||
3853 | ieee80211_restart_sta_timer(sdata); | ||
3854 | |||
3855 | netif_wake_queue(sdata->dev); | ||
3856 | } | ||
3857 | rcu_read_unlock(); | ||
3858 | |||
3859 | done: | ||
3860 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
3861 | if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS) { | ||
3862 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
3863 | if (!(ifsta->flags & IEEE80211_STA_BSSID_SET) || | ||
3864 | (!(ifsta->state == IEEE80211_STA_MLME_IBSS_JOINED) && | ||
3865 | !ieee80211_sta_active_ibss(sdata))) | ||
3866 | ieee80211_sta_find_ibss(sdata, ifsta); | ||
3867 | } | ||
3868 | } | ||
3869 | EXPORT_SYMBOL(ieee80211_scan_completed); | ||
3870 | |||
3871 | void ieee80211_sta_scan_work(struct work_struct *work) | ||
3872 | { | ||
3873 | struct ieee80211_local *local = | ||
3874 | container_of(work, struct ieee80211_local, scan_work.work); | ||
3875 | struct net_device *dev = local->scan_dev; | ||
3876 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
3877 | struct ieee80211_supported_band *sband; | ||
3878 | struct ieee80211_channel *chan; | ||
3879 | int skip; | ||
3880 | unsigned long next_delay = 0; | ||
3881 | |||
3882 | if (!local->sta_sw_scanning) | ||
3883 | return; | ||
3884 | |||
3885 | switch (local->scan_state) { | ||
3886 | case SCAN_SET_CHANNEL: | ||
3887 | /* | ||
3888 | * Get current scan band. scan_band may be IEEE80211_NUM_BANDS | ||
3889 | * after we successfully scanned the last channel of the last | ||
3890 | * band (and the last band is supported by the hw) | ||
3891 | */ | ||
3892 | if (local->scan_band < IEEE80211_NUM_BANDS) | ||
3893 | sband = local->hw.wiphy->bands[local->scan_band]; | ||
3894 | else | ||
3895 | sband = NULL; | ||
3896 | |||
3897 | /* | ||
3898 | * If we are at an unsupported band and have more bands | ||
3899 | * left to scan, advance to the next supported one. | ||
3900 | */ | ||
3901 | while (!sband && local->scan_band < IEEE80211_NUM_BANDS - 1) { | ||
3902 | local->scan_band++; | ||
3903 | sband = local->hw.wiphy->bands[local->scan_band]; | ||
3904 | local->scan_channel_idx = 0; | ||
3905 | } | ||
3906 | |||
3907 | /* if no more bands/channels left, complete scan */ | ||
3908 | if (!sband || local->scan_channel_idx >= sband->n_channels) { | ||
3909 | ieee80211_scan_completed(local_to_hw(local)); | ||
3910 | return; | ||
3911 | } | ||
3912 | skip = 0; | ||
3913 | chan = &sband->channels[local->scan_channel_idx]; | ||
3914 | |||
3915 | if (chan->flags & IEEE80211_CHAN_DISABLED || | ||
3916 | (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && | ||
3917 | chan->flags & IEEE80211_CHAN_NO_IBSS)) | ||
3918 | skip = 1; | ||
3919 | |||
3920 | if (!skip) { | ||
3921 | local->scan_channel = chan; | ||
3922 | if (ieee80211_hw_config(local)) { | ||
3923 | printk(KERN_DEBUG "%s: failed to set freq to " | ||
3924 | "%d MHz for scan\n", dev->name, | ||
3925 | chan->center_freq); | ||
3926 | skip = 1; | ||
3927 | } | ||
3928 | } | ||
3929 | |||
3930 | /* advance state machine to next channel/band */ | ||
3931 | local->scan_channel_idx++; | ||
3932 | if (local->scan_channel_idx >= sband->n_channels) { | ||
3933 | /* | ||
3934 | * scan_band may end up == IEEE80211_NUM_BANDS, but | ||
3935 | * we'll catch that case above and complete the scan | ||
3936 | * if that is the case. | ||
3937 | */ | ||
3938 | local->scan_band++; | ||
3939 | local->scan_channel_idx = 0; | ||
3940 | } | ||
3941 | |||
3942 | if (skip) | ||
3943 | break; | ||
3944 | |||
3945 | next_delay = IEEE80211_PROBE_DELAY + | ||
3946 | usecs_to_jiffies(local->hw.channel_change_time); | ||
3947 | local->scan_state = SCAN_SEND_PROBE; | ||
3948 | break; | ||
3949 | case SCAN_SEND_PROBE: | ||
3950 | next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; | ||
3951 | local->scan_state = SCAN_SET_CHANNEL; | ||
3952 | |||
3953 | if (local->scan_channel->flags & IEEE80211_CHAN_PASSIVE_SCAN) | ||
3954 | break; | ||
3955 | ieee80211_send_probe_req(sdata, NULL, local->scan_ssid, | ||
3956 | local->scan_ssid_len); | ||
3957 | next_delay = IEEE80211_CHANNEL_TIME; | ||
3958 | break; | ||
3959 | } | ||
3960 | |||
3961 | if (local->sta_sw_scanning) | ||
3962 | queue_delayed_work(local->hw.workqueue, &local->scan_work, | ||
3963 | next_delay); | ||
3964 | } | ||
3965 | |||
3966 | |||
3967 | static int ieee80211_sta_start_scan(struct ieee80211_sub_if_data *scan_sdata, | ||
3968 | u8 *ssid, size_t ssid_len) | ||
3969 | { | ||
3970 | struct ieee80211_local *local = scan_sdata->local; | ||
3971 | struct ieee80211_sub_if_data *sdata; | ||
3972 | |||
3973 | if (ssid_len > IEEE80211_MAX_SSID_LEN) | ||
3974 | return -EINVAL; | ||
3975 | |||
3976 | /* MLME-SCAN.request (page 118) page 144 (11.1.3.1) | ||
3977 | * BSSType: INFRASTRUCTURE, INDEPENDENT, ANY_BSS | ||
3978 | * BSSID: MACAddress | ||
3979 | * SSID | ||
3980 | * ScanType: ACTIVE, PASSIVE | ||
3981 | * ProbeDelay: delay (in microseconds) to be used prior to transmitting | ||
3982 | * a Probe frame during active scanning | ||
3983 | * ChannelList | ||
3984 | * MinChannelTime (>= ProbeDelay), in TU | ||
3985 | * MaxChannelTime: (>= MinChannelTime), in TU | ||
3986 | */ | ||
3987 | |||
3988 | /* MLME-SCAN.confirm | ||
3989 | * BSSDescriptionSet | ||
3990 | * ResultCode: SUCCESS, INVALID_PARAMETERS | ||
3991 | */ | ||
3992 | |||
3993 | if (local->sta_sw_scanning || local->sta_hw_scanning) { | ||
3994 | if (local->scan_dev == scan_sdata->dev) | ||
3995 | return 0; | ||
3996 | return -EBUSY; | ||
3997 | } | ||
3998 | |||
3999 | if (local->ops->hw_scan) { | ||
4000 | int rc = local->ops->hw_scan(local_to_hw(local), | ||
4001 | ssid, ssid_len); | ||
4002 | if (!rc) { | ||
4003 | local->sta_hw_scanning = 1; | ||
4004 | local->scan_dev = scan_sdata->dev; | ||
4005 | } | ||
4006 | return rc; | ||
4007 | } | ||
4008 | |||
4009 | local->sta_sw_scanning = 1; | ||
4010 | |||
4011 | rcu_read_lock(); | ||
4012 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | ||
4013 | netif_stop_queue(sdata->dev); | ||
4014 | if (sdata->vif.type == IEEE80211_IF_TYPE_STA && | ||
4015 | (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED)) | ||
4016 | ieee80211_send_nullfunc(local, sdata, 1); | ||
4017 | } | ||
4018 | rcu_read_unlock(); | ||
4019 | |||
4020 | if (ssid) { | ||
4021 | local->scan_ssid_len = ssid_len; | ||
4022 | memcpy(local->scan_ssid, ssid, ssid_len); | ||
4023 | } else | ||
4024 | local->scan_ssid_len = 0; | ||
4025 | local->scan_state = SCAN_SET_CHANNEL; | ||
4026 | local->scan_channel_idx = 0; | ||
4027 | local->scan_band = IEEE80211_BAND_2GHZ; | ||
4028 | local->scan_dev = scan_sdata->dev; | ||
4029 | |||
4030 | netif_addr_lock_bh(local->mdev); | ||
4031 | local->filter_flags |= FIF_BCN_PRBRESP_PROMISC; | ||
4032 | local->ops->configure_filter(local_to_hw(local), | ||
4033 | FIF_BCN_PRBRESP_PROMISC, | ||
4034 | &local->filter_flags, | ||
4035 | local->mdev->mc_count, | ||
4036 | local->mdev->mc_list); | ||
4037 | netif_addr_unlock_bh(local->mdev); | ||
4038 | |||
4039 | /* TODO: start scan as soon as all nullfunc frames are ACKed */ | ||
4040 | queue_delayed_work(local->hw.workqueue, &local->scan_work, | ||
4041 | IEEE80211_CHANNEL_TIME); | ||
4042 | |||
4043 | return 0; | ||
4044 | } | ||
4045 | |||
4046 | |||
4047 | int ieee80211_sta_req_scan(struct ieee80211_sub_if_data *sdata, u8 *ssid, size_t ssid_len) | ||
4048 | { | ||
4049 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
4050 | struct ieee80211_local *local = sdata->local; | ||
4051 | |||
4052 | if (sdata->vif.type != IEEE80211_IF_TYPE_STA) | ||
4053 | return ieee80211_sta_start_scan(sdata, ssid, ssid_len); | ||
4054 | |||
4055 | if (local->sta_sw_scanning || local->sta_hw_scanning) { | ||
4056 | if (local->scan_dev == sdata->dev) | ||
4057 | return 0; | ||
4058 | return -EBUSY; | ||
4059 | } | ||
4060 | |||
4061 | ifsta->scan_ssid_len = ssid_len; | ||
4062 | if (ssid_len) | ||
4063 | memcpy(ifsta->scan_ssid, ssid, ssid_len); | ||
4064 | set_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request); | ||
4065 | queue_work(local->hw.workqueue, &ifsta->work); | ||
4066 | return 0; | ||
4067 | } | ||
4068 | |||
4069 | |||
4070 | static void ieee80211_sta_add_scan_ies(struct iw_request_info *info, | ||
4071 | struct ieee80211_sta_bss *bss, | ||
4072 | char **current_ev, char *end_buf) | ||
4073 | { | ||
4074 | u8 *pos, *end, *next; | ||
4075 | struct iw_event iwe; | ||
4076 | |||
4077 | if (bss == NULL || bss->ies == NULL) | ||
4078 | return; | ||
4079 | |||
4080 | /* | ||
4081 | * If needed, fragment the IEs buffer (at IE boundaries) into short | ||
4082 | * enough fragments to fit into IW_GENERIC_IE_MAX octet messages. | ||
4083 | */ | ||
4084 | pos = bss->ies; | ||
4085 | end = pos + bss->ies_len; | ||
4086 | |||
4087 | while (end - pos > IW_GENERIC_IE_MAX) { | ||
4088 | next = pos + 2 + pos[1]; | ||
4089 | while (next + 2 + next[1] - pos < IW_GENERIC_IE_MAX) | ||
4090 | next = next + 2 + next[1]; | ||
4091 | |||
4092 | memset(&iwe, 0, sizeof(iwe)); | ||
4093 | iwe.cmd = IWEVGENIE; | ||
4094 | iwe.u.data.length = next - pos; | ||
4095 | *current_ev = iwe_stream_add_point(info, *current_ev, | ||
4096 | end_buf, &iwe, pos); | ||
4097 | |||
4098 | pos = next; | ||
4099 | } | ||
4100 | |||
4101 | if (end > pos) { | ||
4102 | memset(&iwe, 0, sizeof(iwe)); | ||
4103 | iwe.cmd = IWEVGENIE; | ||
4104 | iwe.u.data.length = end - pos; | ||
4105 | *current_ev = iwe_stream_add_point(info, *current_ev, | ||
4106 | end_buf, &iwe, pos); | ||
4107 | } | ||
4108 | } | ||
4109 | |||
4110 | |||
4111 | static char * | ||
4112 | ieee80211_sta_scan_result(struct ieee80211_local *local, | ||
4113 | struct iw_request_info *info, | ||
4114 | struct ieee80211_sta_bss *bss, | ||
4115 | char *current_ev, char *end_buf) | ||
4116 | { | ||
4117 | struct iw_event iwe; | ||
4118 | |||
4119 | if (time_after(jiffies, | ||
4120 | bss->last_update + IEEE80211_SCAN_RESULT_EXPIRE)) | ||
4121 | return current_ev; | ||
4122 | |||
4123 | memset(&iwe, 0, sizeof(iwe)); | ||
4124 | iwe.cmd = SIOCGIWAP; | ||
4125 | iwe.u.ap_addr.sa_family = ARPHRD_ETHER; | ||
4126 | memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN); | ||
4127 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, | ||
4128 | IW_EV_ADDR_LEN); | ||
4129 | |||
4130 | memset(&iwe, 0, sizeof(iwe)); | ||
4131 | iwe.cmd = SIOCGIWESSID; | ||
4132 | if (bss_mesh_cfg(bss)) { | ||
4133 | iwe.u.data.length = bss_mesh_id_len(bss); | ||
4134 | iwe.u.data.flags = 1; | ||
4135 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
4136 | &iwe, bss_mesh_id(bss)); | ||
4137 | } else { | ||
4138 | iwe.u.data.length = bss->ssid_len; | ||
4139 | iwe.u.data.flags = 1; | ||
4140 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
4141 | &iwe, bss->ssid); | ||
4142 | } | ||
4143 | |||
4144 | if (bss->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS) | ||
4145 | || bss_mesh_cfg(bss)) { | ||
4146 | memset(&iwe, 0, sizeof(iwe)); | ||
4147 | iwe.cmd = SIOCGIWMODE; | ||
4148 | if (bss_mesh_cfg(bss)) | ||
4149 | iwe.u.mode = IW_MODE_MESH; | ||
4150 | else if (bss->capability & WLAN_CAPABILITY_ESS) | ||
4151 | iwe.u.mode = IW_MODE_MASTER; | ||
4152 | else | ||
4153 | iwe.u.mode = IW_MODE_ADHOC; | ||
4154 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, | ||
4155 | &iwe, IW_EV_UINT_LEN); | ||
4156 | } | ||
4157 | |||
4158 | memset(&iwe, 0, sizeof(iwe)); | ||
4159 | iwe.cmd = SIOCGIWFREQ; | ||
4160 | iwe.u.freq.m = ieee80211_frequency_to_channel(bss->freq); | ||
4161 | iwe.u.freq.e = 0; | ||
4162 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, | ||
4163 | IW_EV_FREQ_LEN); | ||
4164 | |||
4165 | memset(&iwe, 0, sizeof(iwe)); | ||
4166 | iwe.cmd = SIOCGIWFREQ; | ||
4167 | iwe.u.freq.m = bss->freq; | ||
4168 | iwe.u.freq.e = 6; | ||
4169 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, | ||
4170 | IW_EV_FREQ_LEN); | ||
4171 | memset(&iwe, 0, sizeof(iwe)); | ||
4172 | iwe.cmd = IWEVQUAL; | ||
4173 | iwe.u.qual.qual = bss->qual; | ||
4174 | iwe.u.qual.level = bss->signal; | ||
4175 | iwe.u.qual.noise = bss->noise; | ||
4176 | iwe.u.qual.updated = local->wstats_flags; | ||
4177 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, | ||
4178 | IW_EV_QUAL_LEN); | ||
4179 | |||
4180 | memset(&iwe, 0, sizeof(iwe)); | ||
4181 | iwe.cmd = SIOCGIWENCODE; | ||
4182 | if (bss->capability & WLAN_CAPABILITY_PRIVACY) | ||
4183 | iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; | ||
4184 | else | ||
4185 | iwe.u.data.flags = IW_ENCODE_DISABLED; | ||
4186 | iwe.u.data.length = 0; | ||
4187 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
4188 | &iwe, ""); | ||
4189 | |||
4190 | ieee80211_sta_add_scan_ies(info, bss, ¤t_ev, end_buf); | ||
4191 | |||
4192 | if (bss && bss->supp_rates_len > 0) { | ||
4193 | /* display all supported rates in readable format */ | ||
4194 | char *p = current_ev + iwe_stream_lcp_len(info); | ||
4195 | int i; | ||
4196 | |||
4197 | memset(&iwe, 0, sizeof(iwe)); | ||
4198 | iwe.cmd = SIOCGIWRATE; | ||
4199 | /* Those two flags are ignored... */ | ||
4200 | iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; | ||
4201 | |||
4202 | for (i = 0; i < bss->supp_rates_len; i++) { | ||
4203 | iwe.u.bitrate.value = ((bss->supp_rates[i] & | ||
4204 | 0x7f) * 500000); | ||
4205 | p = iwe_stream_add_value(info, current_ev, p, | ||
4206 | end_buf, &iwe, IW_EV_PARAM_LEN); | ||
4207 | } | ||
4208 | current_ev = p; | ||
4209 | } | ||
4210 | |||
4211 | if (bss) { | ||
4212 | char *buf; | ||
4213 | buf = kmalloc(30, GFP_ATOMIC); | ||
4214 | if (buf) { | ||
4215 | memset(&iwe, 0, sizeof(iwe)); | ||
4216 | iwe.cmd = IWEVCUSTOM; | ||
4217 | sprintf(buf, "tsf=%016llx", (unsigned long long)(bss->timestamp)); | ||
4218 | iwe.u.data.length = strlen(buf); | ||
4219 | current_ev = iwe_stream_add_point(info, current_ev, | ||
4220 | end_buf, | ||
4221 | &iwe, buf); | ||
4222 | memset(&iwe, 0, sizeof(iwe)); | ||
4223 | iwe.cmd = IWEVCUSTOM; | ||
4224 | sprintf(buf, " Last beacon: %dms ago", | ||
4225 | jiffies_to_msecs(jiffies - bss->last_update)); | ||
4226 | iwe.u.data.length = strlen(buf); | ||
4227 | current_ev = iwe_stream_add_point(info, current_ev, | ||
4228 | end_buf, &iwe, buf); | ||
4229 | kfree(buf); | ||
4230 | } | ||
4231 | } | ||
4232 | |||
4233 | if (bss_mesh_cfg(bss)) { | ||
4234 | char *buf; | ||
4235 | u8 *cfg = bss_mesh_cfg(bss); | ||
4236 | buf = kmalloc(50, GFP_ATOMIC); | ||
4237 | if (buf) { | ||
4238 | memset(&iwe, 0, sizeof(iwe)); | ||
4239 | iwe.cmd = IWEVCUSTOM; | ||
4240 | sprintf(buf, "Mesh network (version %d)", cfg[0]); | ||
4241 | iwe.u.data.length = strlen(buf); | ||
4242 | current_ev = iwe_stream_add_point(info, current_ev, | ||
4243 | end_buf, | ||
4244 | &iwe, buf); | ||
4245 | sprintf(buf, "Path Selection Protocol ID: " | ||
4246 | "0x%02X%02X%02X%02X", cfg[1], cfg[2], cfg[3], | ||
4247 | cfg[4]); | ||
4248 | iwe.u.data.length = strlen(buf); | ||
4249 | current_ev = iwe_stream_add_point(info, current_ev, | ||
4250 | end_buf, | ||
4251 | &iwe, buf); | ||
4252 | sprintf(buf, "Path Selection Metric ID: " | ||
4253 | "0x%02X%02X%02X%02X", cfg[5], cfg[6], cfg[7], | ||
4254 | cfg[8]); | ||
4255 | iwe.u.data.length = strlen(buf); | ||
4256 | current_ev = iwe_stream_add_point(info, current_ev, | ||
4257 | end_buf, | ||
4258 | &iwe, buf); | ||
4259 | sprintf(buf, "Congestion Control Mode ID: " | ||
4260 | "0x%02X%02X%02X%02X", cfg[9], cfg[10], | ||
4261 | cfg[11], cfg[12]); | ||
4262 | iwe.u.data.length = strlen(buf); | ||
4263 | current_ev = iwe_stream_add_point(info, current_ev, | ||
4264 | end_buf, | ||
4265 | &iwe, buf); | ||
4266 | sprintf(buf, "Channel Precedence: " | ||
4267 | "0x%02X%02X%02X%02X", cfg[13], cfg[14], | ||
4268 | cfg[15], cfg[16]); | ||
4269 | iwe.u.data.length = strlen(buf); | ||
4270 | current_ev = iwe_stream_add_point(info, current_ev, | ||
4271 | end_buf, | ||
4272 | &iwe, buf); | ||
4273 | kfree(buf); | ||
4274 | } | ||
4275 | } | ||
4276 | |||
4277 | return current_ev; | ||
4278 | } | ||
4279 | |||
4280 | |||
4281 | int ieee80211_sta_scan_results(struct ieee80211_local *local, | ||
4282 | struct iw_request_info *info, | ||
4283 | char *buf, size_t len) | ||
4284 | { | ||
4285 | char *current_ev = buf; | ||
4286 | char *end_buf = buf + len; | ||
4287 | struct ieee80211_sta_bss *bss; | ||
4288 | |||
4289 | spin_lock_bh(&local->sta_bss_lock); | ||
4290 | list_for_each_entry(bss, &local->sta_bss_list, list) { | ||
4291 | if (buf + len - current_ev <= IW_EV_ADDR_LEN) { | ||
4292 | spin_unlock_bh(&local->sta_bss_lock); | ||
4293 | return -E2BIG; | ||
4294 | } | ||
4295 | current_ev = ieee80211_sta_scan_result(local, info, bss, | ||
4296 | current_ev, end_buf); | ||
4297 | } | ||
4298 | spin_unlock_bh(&local->sta_bss_lock); | ||
4299 | return current_ev - buf; | ||
4300 | } | ||
4301 | |||
4302 | |||
4303 | int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, char *ie, size_t len) | 2338 | int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, char *ie, size_t len) |
4304 | { | 2339 | { |
4305 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 2340 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; |
@@ -4367,6 +2402,85 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | |||
4367 | } | 2402 | } |
4368 | 2403 | ||
4369 | 2404 | ||
2405 | static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata, | ||
2406 | struct ieee80211_if_sta *ifsta) | ||
2407 | { | ||
2408 | struct ieee80211_local *local = sdata->local; | ||
2409 | struct ieee80211_sta_bss *bss, *selected = NULL; | ||
2410 | int top_rssi = 0, freq; | ||
2411 | |||
2412 | spin_lock_bh(&local->sta_bss_lock); | ||
2413 | freq = local->oper_channel->center_freq; | ||
2414 | list_for_each_entry(bss, &local->sta_bss_list, list) { | ||
2415 | if (!(bss->capability & WLAN_CAPABILITY_ESS)) | ||
2416 | continue; | ||
2417 | |||
2418 | if ((ifsta->flags & (IEEE80211_STA_AUTO_SSID_SEL | | ||
2419 | IEEE80211_STA_AUTO_BSSID_SEL | | ||
2420 | IEEE80211_STA_AUTO_CHANNEL_SEL)) && | ||
2421 | (!!(bss->capability & WLAN_CAPABILITY_PRIVACY) ^ | ||
2422 | !!sdata->default_key)) | ||
2423 | continue; | ||
2424 | |||
2425 | if (!(ifsta->flags & IEEE80211_STA_AUTO_CHANNEL_SEL) && | ||
2426 | bss->freq != freq) | ||
2427 | continue; | ||
2428 | |||
2429 | if (!(ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL) && | ||
2430 | memcmp(bss->bssid, ifsta->bssid, ETH_ALEN)) | ||
2431 | continue; | ||
2432 | |||
2433 | if (!(ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL) && | ||
2434 | !ieee80211_sta_match_ssid(ifsta, bss->ssid, bss->ssid_len)) | ||
2435 | continue; | ||
2436 | |||
2437 | if (!selected || top_rssi < bss->signal) { | ||
2438 | selected = bss; | ||
2439 | top_rssi = bss->signal; | ||
2440 | } | ||
2441 | } | ||
2442 | if (selected) | ||
2443 | atomic_inc(&selected->users); | ||
2444 | spin_unlock_bh(&local->sta_bss_lock); | ||
2445 | |||
2446 | if (selected) { | ||
2447 | ieee80211_set_freq(sdata, selected->freq); | ||
2448 | if (!(ifsta->flags & IEEE80211_STA_SSID_SET)) | ||
2449 | ieee80211_sta_set_ssid(sdata, selected->ssid, | ||
2450 | selected->ssid_len); | ||
2451 | ieee80211_sta_set_bssid(sdata, selected->bssid); | ||
2452 | ieee80211_sta_def_wmm_params(sdata, selected); | ||
2453 | |||
2454 | /* Send out direct probe if no probe resp was received or | ||
2455 | * the one we have is outdated | ||
2456 | */ | ||
2457 | if (!selected->last_probe_resp || | ||
2458 | time_after(jiffies, selected->last_probe_resp | ||
2459 | + IEEE80211_SCAN_RESULT_EXPIRE)) | ||
2460 | ifsta->state = IEEE80211_STA_MLME_DIRECT_PROBE; | ||
2461 | else | ||
2462 | ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE; | ||
2463 | |||
2464 | ieee80211_rx_bss_put(local, selected); | ||
2465 | ieee80211_sta_reset_auth(sdata, ifsta); | ||
2466 | return 0; | ||
2467 | } else { | ||
2468 | if (ifsta->assoc_scan_tries < IEEE80211_ASSOC_SCANS_MAX_TRIES) { | ||
2469 | ifsta->assoc_scan_tries++; | ||
2470 | if (ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL) | ||
2471 | ieee80211_sta_start_scan(sdata, NULL, 0); | ||
2472 | else | ||
2473 | ieee80211_sta_start_scan(sdata, ifsta->ssid, | ||
2474 | ifsta->ssid_len); | ||
2475 | ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE; | ||
2476 | set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request); | ||
2477 | } else | ||
2478 | ifsta->state = IEEE80211_STA_MLME_DISABLED; | ||
2479 | } | ||
2480 | return -1; | ||
2481 | } | ||
2482 | |||
2483 | |||
4370 | int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason) | 2484 | int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason) |
4371 | { | 2485 | { |
4372 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 2486 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; |
@@ -4378,8 +2492,7 @@ int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason | |||
4378 | sdata->vif.type != IEEE80211_IF_TYPE_IBSS) | 2492 | sdata->vif.type != IEEE80211_IF_TYPE_IBSS) |
4379 | return -EINVAL; | 2493 | return -EINVAL; |
4380 | 2494 | ||
4381 | ieee80211_send_deauth(sdata, ifsta, reason); | 2495 | ieee80211_set_disassoc(sdata, ifsta, true, true, reason); |
4382 | ieee80211_set_disassoc(sdata, ifsta, 1); | ||
4383 | return 0; | 2496 | return 0; |
4384 | } | 2497 | } |
4385 | 2498 | ||
@@ -4397,8 +2510,7 @@ int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason) | |||
4397 | if (!(ifsta->flags & IEEE80211_STA_ASSOCIATED)) | 2510 | if (!(ifsta->flags & IEEE80211_STA_ASSOCIATED)) |
4398 | return -1; | 2511 | return -1; |
4399 | 2512 | ||
4400 | ieee80211_send_disassoc(sdata, ifsta, reason); | 2513 | ieee80211_set_disassoc(sdata, ifsta, false, true, reason); |
4401 | ieee80211_set_disassoc(sdata, ifsta, 0); | ||
4402 | return 0; | 2514 | return 0; |
4403 | } | 2515 | } |
4404 | 2516 | ||
@@ -4422,3 +2534,102 @@ void ieee80211_notify_mac(struct ieee80211_hw *hw, | |||
4422 | } | 2534 | } |
4423 | } | 2535 | } |
4424 | EXPORT_SYMBOL(ieee80211_notify_mac); | 2536 | EXPORT_SYMBOL(ieee80211_notify_mac); |
2537 | |||
2538 | void ieee80211_sta_work(struct work_struct *work) | ||
2539 | { | ||
2540 | struct ieee80211_sub_if_data *sdata = | ||
2541 | container_of(work, struct ieee80211_sub_if_data, u.sta.work); | ||
2542 | struct ieee80211_local *local = sdata->local; | ||
2543 | struct ieee80211_if_sta *ifsta; | ||
2544 | struct sk_buff *skb; | ||
2545 | |||
2546 | if (!netif_running(sdata->dev)) | ||
2547 | return; | ||
2548 | |||
2549 | if (local->sta_sw_scanning || local->sta_hw_scanning) | ||
2550 | return; | ||
2551 | |||
2552 | if (WARN_ON(sdata->vif.type != IEEE80211_IF_TYPE_STA && | ||
2553 | sdata->vif.type != IEEE80211_IF_TYPE_IBSS && | ||
2554 | sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)) | ||
2555 | return; | ||
2556 | ifsta = &sdata->u.sta; | ||
2557 | |||
2558 | while ((skb = skb_dequeue(&ifsta->skb_queue))) | ||
2559 | ieee80211_sta_rx_queued_mgmt(sdata, skb); | ||
2560 | |||
2561 | #ifdef CONFIG_MAC80211_MESH | ||
2562 | if (ifsta->preq_queue_len && | ||
2563 | time_after(jiffies, | ||
2564 | ifsta->last_preq + msecs_to_jiffies(ifsta->mshcfg.dot11MeshHWMPpreqMinInterval))) | ||
2565 | mesh_path_start_discovery(sdata); | ||
2566 | #endif | ||
2567 | |||
2568 | if (ifsta->state != IEEE80211_STA_MLME_DIRECT_PROBE && | ||
2569 | ifsta->state != IEEE80211_STA_MLME_AUTHENTICATE && | ||
2570 | ifsta->state != IEEE80211_STA_MLME_ASSOCIATE && | ||
2571 | test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request)) { | ||
2572 | ieee80211_sta_start_scan(sdata, ifsta->scan_ssid, ifsta->scan_ssid_len); | ||
2573 | return; | ||
2574 | } | ||
2575 | |||
2576 | if (test_and_clear_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request)) { | ||
2577 | if (ieee80211_sta_config_auth(sdata, ifsta)) | ||
2578 | return; | ||
2579 | clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request); | ||
2580 | } else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request)) | ||
2581 | return; | ||
2582 | |||
2583 | switch (ifsta->state) { | ||
2584 | case IEEE80211_STA_MLME_DISABLED: | ||
2585 | break; | ||
2586 | case IEEE80211_STA_MLME_DIRECT_PROBE: | ||
2587 | ieee80211_direct_probe(sdata, ifsta); | ||
2588 | break; | ||
2589 | case IEEE80211_STA_MLME_AUTHENTICATE: | ||
2590 | ieee80211_authenticate(sdata, ifsta); | ||
2591 | break; | ||
2592 | case IEEE80211_STA_MLME_ASSOCIATE: | ||
2593 | ieee80211_associate(sdata, ifsta); | ||
2594 | break; | ||
2595 | case IEEE80211_STA_MLME_ASSOCIATED: | ||
2596 | ieee80211_associated(sdata, ifsta); | ||
2597 | break; | ||
2598 | case IEEE80211_STA_MLME_IBSS_SEARCH: | ||
2599 | ieee80211_sta_find_ibss(sdata, ifsta); | ||
2600 | break; | ||
2601 | case IEEE80211_STA_MLME_IBSS_JOINED: | ||
2602 | ieee80211_sta_merge_ibss(sdata, ifsta); | ||
2603 | break; | ||
2604 | #ifdef CONFIG_MAC80211_MESH | ||
2605 | case IEEE80211_STA_MLME_MESH_UP: | ||
2606 | ieee80211_mesh_housekeeping(sdata, ifsta); | ||
2607 | break; | ||
2608 | #endif | ||
2609 | default: | ||
2610 | WARN_ON(1); | ||
2611 | break; | ||
2612 | } | ||
2613 | |||
2614 | if (ieee80211_privacy_mismatch(sdata, ifsta)) { | ||
2615 | printk(KERN_DEBUG "%s: privacy configuration mismatch and " | ||
2616 | "mixed-cell disabled - disassociate\n", sdata->dev->name); | ||
2617 | |||
2618 | ieee80211_set_disassoc(sdata, ifsta, false, true, | ||
2619 | WLAN_REASON_UNSPECIFIED); | ||
2620 | } | ||
2621 | } | ||
2622 | |||
2623 | void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local) | ||
2624 | { | ||
2625 | struct ieee80211_sub_if_data *sdata = local->scan_sdata; | ||
2626 | struct ieee80211_if_sta *ifsta; | ||
2627 | |||
2628 | if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS) { | ||
2629 | ifsta = &sdata->u.sta; | ||
2630 | if (!(ifsta->flags & IEEE80211_STA_BSSID_SET) || | ||
2631 | (!(ifsta->state == IEEE80211_STA_MLME_IBSS_JOINED) && | ||
2632 | !ieee80211_sta_active_ibss(sdata))) | ||
2633 | ieee80211_sta_find_ibss(sdata, ifsta); | ||
2634 | } | ||
2635 | } | ||
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 7e09b30dd393..d0803797902b 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -1511,22 +1511,95 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx) | |||
1511 | } | 1511 | } |
1512 | 1512 | ||
1513 | static ieee80211_rx_result debug_noinline | 1513 | static ieee80211_rx_result debug_noinline |
1514 | ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | ||
1515 | { | ||
1516 | struct ieee80211_local *local = rx->local; | ||
1517 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); | ||
1518 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; | ||
1519 | int len = rx->skb->len; | ||
1520 | |||
1521 | if (!ieee80211_is_action(mgmt->frame_control)) | ||
1522 | return RX_CONTINUE; | ||
1523 | |||
1524 | if (!rx->sta) | ||
1525 | return RX_DROP_MONITOR; | ||
1526 | |||
1527 | if (!(rx->flags & IEEE80211_RX_RA_MATCH)) | ||
1528 | return RX_DROP_MONITOR; | ||
1529 | |||
1530 | /* all categories we currently handle have action_code */ | ||
1531 | if (len < IEEE80211_MIN_ACTION_SIZE + 1) | ||
1532 | return RX_DROP_MONITOR; | ||
1533 | |||
1534 | /* | ||
1535 | * FIXME: revisit this, I'm sure we should handle most | ||
1536 | * of these frames in other modes as well! | ||
1537 | */ | ||
1538 | if (sdata->vif.type != IEEE80211_IF_TYPE_STA && | ||
1539 | sdata->vif.type != IEEE80211_IF_TYPE_IBSS) | ||
1540 | return RX_DROP_MONITOR; | ||
1541 | |||
1542 | switch (mgmt->u.action.category) { | ||
1543 | case WLAN_CATEGORY_BACK: | ||
1544 | switch (mgmt->u.action.u.addba_req.action_code) { | ||
1545 | case WLAN_ACTION_ADDBA_REQ: | ||
1546 | if (len < (IEEE80211_MIN_ACTION_SIZE + | ||
1547 | sizeof(mgmt->u.action.u.addba_req))) | ||
1548 | return RX_DROP_MONITOR; | ||
1549 | ieee80211_process_addba_request(local, rx->sta, mgmt, len); | ||
1550 | break; | ||
1551 | case WLAN_ACTION_ADDBA_RESP: | ||
1552 | if (len < (IEEE80211_MIN_ACTION_SIZE + | ||
1553 | sizeof(mgmt->u.action.u.addba_resp))) | ||
1554 | return RX_DROP_MONITOR; | ||
1555 | ieee80211_process_addba_resp(local, rx->sta, mgmt, len); | ||
1556 | break; | ||
1557 | case WLAN_ACTION_DELBA: | ||
1558 | if (len < (IEEE80211_MIN_ACTION_SIZE + | ||
1559 | sizeof(mgmt->u.action.u.delba))) | ||
1560 | return RX_DROP_MONITOR; | ||
1561 | ieee80211_process_delba(sdata, rx->sta, mgmt, len); | ||
1562 | break; | ||
1563 | } | ||
1564 | break; | ||
1565 | case WLAN_CATEGORY_SPECTRUM_MGMT: | ||
1566 | if (local->hw.conf.channel->band != IEEE80211_BAND_5GHZ) | ||
1567 | return RX_DROP_MONITOR; | ||
1568 | switch (mgmt->u.action.u.measurement.action_code) { | ||
1569 | case WLAN_ACTION_SPCT_MSR_REQ: | ||
1570 | if (len < (IEEE80211_MIN_ACTION_SIZE + | ||
1571 | sizeof(mgmt->u.action.u.measurement))) | ||
1572 | return RX_DROP_MONITOR; | ||
1573 | ieee80211_process_measurement_req(sdata, mgmt, len); | ||
1574 | break; | ||
1575 | } | ||
1576 | break; | ||
1577 | default: | ||
1578 | return RX_CONTINUE; | ||
1579 | } | ||
1580 | |||
1581 | rx->sta->rx_packets++; | ||
1582 | dev_kfree_skb(rx->skb); | ||
1583 | return RX_QUEUED; | ||
1584 | } | ||
1585 | |||
1586 | static ieee80211_rx_result debug_noinline | ||
1514 | ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) | 1587 | ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) |
1515 | { | 1588 | { |
1516 | struct ieee80211_sub_if_data *sdata; | 1589 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); |
1517 | 1590 | ||
1518 | if (!(rx->flags & IEEE80211_RX_RA_MATCH)) | 1591 | if (!(rx->flags & IEEE80211_RX_RA_MATCH)) |
1519 | return RX_DROP_MONITOR; | 1592 | return RX_DROP_MONITOR; |
1520 | 1593 | ||
1521 | sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); | 1594 | if (sdata->vif.type != IEEE80211_IF_TYPE_STA && |
1522 | if ((sdata->vif.type == IEEE80211_IF_TYPE_STA || | 1595 | sdata->vif.type != IEEE80211_IF_TYPE_IBSS && |
1523 | sdata->vif.type == IEEE80211_IF_TYPE_IBSS || | 1596 | sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) |
1524 | sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) && | 1597 | return RX_DROP_MONITOR; |
1525 | !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)) | 1598 | |
1526 | ieee80211_sta_rx_mgmt(sdata, rx->skb, rx->status); | 1599 | if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) |
1527 | else | ||
1528 | return RX_DROP_MONITOR; | 1600 | return RX_DROP_MONITOR; |
1529 | 1601 | ||
1602 | ieee80211_sta_rx_mgmt(sdata, rx->skb, rx->status); | ||
1530 | return RX_QUEUED; | 1603 | return RX_QUEUED; |
1531 | } | 1604 | } |
1532 | 1605 | ||
@@ -1689,6 +1762,7 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata, | |||
1689 | CALL_RXH(ieee80211_rx_h_mesh_fwding); | 1762 | CALL_RXH(ieee80211_rx_h_mesh_fwding); |
1690 | CALL_RXH(ieee80211_rx_h_data) | 1763 | CALL_RXH(ieee80211_rx_h_data) |
1691 | CALL_RXH(ieee80211_rx_h_ctrl) | 1764 | CALL_RXH(ieee80211_rx_h_ctrl) |
1765 | CALL_RXH(ieee80211_rx_h_action) | ||
1692 | CALL_RXH(ieee80211_rx_h_mgmt) | 1766 | CALL_RXH(ieee80211_rx_h_mgmt) |
1693 | 1767 | ||
1694 | #undef CALL_RXH | 1768 | #undef CALL_RXH |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c new file mode 100644 index 000000000000..010781b806f3 --- /dev/null +++ b/net/mac80211/scan.c | |||
@@ -0,0 +1,933 @@ | |||
1 | /* | ||
2 | * Scanning implementation | ||
3 | * | ||
4 | * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi> | ||
5 | * Copyright 2004, Instant802 Networks, Inc. | ||
6 | * Copyright 2005, Devicescape Software, Inc. | ||
7 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> | ||
8 | * Copyright 2007, Michael Wu <flamingice@sourmilk.net> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | /* TODO: | ||
16 | * order BSS list by RSSI(?) ("quality of AP") | ||
17 | * scan result table filtering (by capability (privacy, IBSS/BSS, WPA/RSN IE, | ||
18 | * SSID) | ||
19 | */ | ||
20 | |||
21 | #include <linux/wireless.h> | ||
22 | #include <linux/if_arp.h> | ||
23 | #include <net/mac80211.h> | ||
24 | #include <net/iw_handler.h> | ||
25 | |||
26 | #include "ieee80211_i.h" | ||
27 | #include "mesh.h" | ||
28 | |||
29 | #define IEEE80211_PROBE_DELAY (HZ / 33) | ||
30 | #define IEEE80211_CHANNEL_TIME (HZ / 33) | ||
31 | #define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 5) | ||
32 | |||
33 | void ieee80211_rx_bss_list_init(struct ieee80211_local *local) | ||
34 | { | ||
35 | spin_lock_init(&local->sta_bss_lock); | ||
36 | INIT_LIST_HEAD(&local->sta_bss_list); | ||
37 | } | ||
38 | |||
39 | void ieee80211_rx_bss_list_deinit(struct ieee80211_local *local) | ||
40 | { | ||
41 | struct ieee80211_sta_bss *bss, *tmp; | ||
42 | |||
43 | list_for_each_entry_safe(bss, tmp, &local->sta_bss_list, list) | ||
44 | ieee80211_rx_bss_put(local, bss); | ||
45 | } | ||
46 | |||
47 | struct ieee80211_sta_bss * | ||
48 | ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq, | ||
49 | u8 *ssid, u8 ssid_len) | ||
50 | { | ||
51 | struct ieee80211_sta_bss *bss; | ||
52 | |||
53 | spin_lock_bh(&local->sta_bss_lock); | ||
54 | bss = local->sta_bss_hash[STA_HASH(bssid)]; | ||
55 | while (bss) { | ||
56 | if (!bss_mesh_cfg(bss) && | ||
57 | !memcmp(bss->bssid, bssid, ETH_ALEN) && | ||
58 | bss->freq == freq && | ||
59 | bss->ssid_len == ssid_len && | ||
60 | (ssid_len == 0 || !memcmp(bss->ssid, ssid, ssid_len))) { | ||
61 | atomic_inc(&bss->users); | ||
62 | break; | ||
63 | } | ||
64 | bss = bss->hnext; | ||
65 | } | ||
66 | spin_unlock_bh(&local->sta_bss_lock); | ||
67 | return bss; | ||
68 | } | ||
69 | |||
70 | /* Caller must hold local->sta_bss_lock */ | ||
71 | static void __ieee80211_rx_bss_hash_add(struct ieee80211_local *local, | ||
72 | struct ieee80211_sta_bss *bss) | ||
73 | { | ||
74 | u8 hash_idx; | ||
75 | |||
76 | if (bss_mesh_cfg(bss)) | ||
77 | hash_idx = mesh_id_hash(bss_mesh_id(bss), | ||
78 | bss_mesh_id_len(bss)); | ||
79 | else | ||
80 | hash_idx = STA_HASH(bss->bssid); | ||
81 | |||
82 | bss->hnext = local->sta_bss_hash[hash_idx]; | ||
83 | local->sta_bss_hash[hash_idx] = bss; | ||
84 | } | ||
85 | |||
86 | /* Caller must hold local->sta_bss_lock */ | ||
87 | static void __ieee80211_rx_bss_hash_del(struct ieee80211_local *local, | ||
88 | struct ieee80211_sta_bss *bss) | ||
89 | { | ||
90 | struct ieee80211_sta_bss *b, *prev = NULL; | ||
91 | b = local->sta_bss_hash[STA_HASH(bss->bssid)]; | ||
92 | while (b) { | ||
93 | if (b == bss) { | ||
94 | if (!prev) | ||
95 | local->sta_bss_hash[STA_HASH(bss->bssid)] = | ||
96 | bss->hnext; | ||
97 | else | ||
98 | prev->hnext = bss->hnext; | ||
99 | break; | ||
100 | } | ||
101 | prev = b; | ||
102 | b = b->hnext; | ||
103 | } | ||
104 | } | ||
105 | |||
106 | struct ieee80211_sta_bss * | ||
107 | ieee80211_rx_bss_add(struct ieee80211_local *local, u8 *bssid, int freq, | ||
108 | u8 *ssid, u8 ssid_len) | ||
109 | { | ||
110 | struct ieee80211_sta_bss *bss; | ||
111 | |||
112 | bss = kzalloc(sizeof(*bss), GFP_ATOMIC); | ||
113 | if (!bss) | ||
114 | return NULL; | ||
115 | atomic_set(&bss->users, 2); | ||
116 | memcpy(bss->bssid, bssid, ETH_ALEN); | ||
117 | bss->freq = freq; | ||
118 | if (ssid && ssid_len <= IEEE80211_MAX_SSID_LEN) { | ||
119 | memcpy(bss->ssid, ssid, ssid_len); | ||
120 | bss->ssid_len = ssid_len; | ||
121 | } | ||
122 | |||
123 | spin_lock_bh(&local->sta_bss_lock); | ||
124 | /* TODO: order by RSSI? */ | ||
125 | list_add_tail(&bss->list, &local->sta_bss_list); | ||
126 | __ieee80211_rx_bss_hash_add(local, bss); | ||
127 | spin_unlock_bh(&local->sta_bss_lock); | ||
128 | return bss; | ||
129 | } | ||
130 | |||
131 | #ifdef CONFIG_MAC80211_MESH | ||
132 | static struct ieee80211_sta_bss * | ||
133 | ieee80211_rx_mesh_bss_get(struct ieee80211_local *local, u8 *mesh_id, int mesh_id_len, | ||
134 | u8 *mesh_cfg, int freq) | ||
135 | { | ||
136 | struct ieee80211_sta_bss *bss; | ||
137 | |||
138 | spin_lock_bh(&local->sta_bss_lock); | ||
139 | bss = local->sta_bss_hash[mesh_id_hash(mesh_id, mesh_id_len)]; | ||
140 | while (bss) { | ||
141 | if (bss_mesh_cfg(bss) && | ||
142 | !memcmp(bss_mesh_cfg(bss), mesh_cfg, MESH_CFG_CMP_LEN) && | ||
143 | bss->freq == freq && | ||
144 | mesh_id_len == bss->mesh_id_len && | ||
145 | (mesh_id_len == 0 || !memcmp(bss->mesh_id, mesh_id, | ||
146 | mesh_id_len))) { | ||
147 | atomic_inc(&bss->users); | ||
148 | break; | ||
149 | } | ||
150 | bss = bss->hnext; | ||
151 | } | ||
152 | spin_unlock_bh(&local->sta_bss_lock); | ||
153 | return bss; | ||
154 | } | ||
155 | |||
156 | static struct ieee80211_sta_bss * | ||
157 | ieee80211_rx_mesh_bss_add(struct ieee80211_local *local, u8 *mesh_id, int mesh_id_len, | ||
158 | u8 *mesh_cfg, int mesh_config_len, int freq) | ||
159 | { | ||
160 | struct ieee80211_sta_bss *bss; | ||
161 | |||
162 | if (mesh_config_len != MESH_CFG_LEN) | ||
163 | return NULL; | ||
164 | |||
165 | bss = kzalloc(sizeof(*bss), GFP_ATOMIC); | ||
166 | if (!bss) | ||
167 | return NULL; | ||
168 | |||
169 | bss->mesh_cfg = kmalloc(MESH_CFG_CMP_LEN, GFP_ATOMIC); | ||
170 | if (!bss->mesh_cfg) { | ||
171 | kfree(bss); | ||
172 | return NULL; | ||
173 | } | ||
174 | |||
175 | if (mesh_id_len && mesh_id_len <= IEEE80211_MAX_MESH_ID_LEN) { | ||
176 | bss->mesh_id = kmalloc(mesh_id_len, GFP_ATOMIC); | ||
177 | if (!bss->mesh_id) { | ||
178 | kfree(bss->mesh_cfg); | ||
179 | kfree(bss); | ||
180 | return NULL; | ||
181 | } | ||
182 | memcpy(bss->mesh_id, mesh_id, mesh_id_len); | ||
183 | } | ||
184 | |||
185 | atomic_set(&bss->users, 2); | ||
186 | memcpy(bss->mesh_cfg, mesh_cfg, MESH_CFG_CMP_LEN); | ||
187 | bss->mesh_id_len = mesh_id_len; | ||
188 | bss->freq = freq; | ||
189 | spin_lock_bh(&local->sta_bss_lock); | ||
190 | /* TODO: order by RSSI? */ | ||
191 | list_add_tail(&bss->list, &local->sta_bss_list); | ||
192 | __ieee80211_rx_bss_hash_add(local, bss); | ||
193 | spin_unlock_bh(&local->sta_bss_lock); | ||
194 | return bss; | ||
195 | } | ||
196 | #endif | ||
197 | |||
198 | static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss) | ||
199 | { | ||
200 | kfree(bss->ies); | ||
201 | kfree(bss_mesh_id(bss)); | ||
202 | kfree(bss_mesh_cfg(bss)); | ||
203 | kfree(bss); | ||
204 | } | ||
205 | |||
206 | void ieee80211_rx_bss_put(struct ieee80211_local *local, | ||
207 | struct ieee80211_sta_bss *bss) | ||
208 | { | ||
209 | local_bh_disable(); | ||
210 | if (!atomic_dec_and_lock(&bss->users, &local->sta_bss_lock)) { | ||
211 | local_bh_enable(); | ||
212 | return; | ||
213 | } | ||
214 | |||
215 | __ieee80211_rx_bss_hash_del(local, bss); | ||
216 | list_del(&bss->list); | ||
217 | spin_unlock_bh(&local->sta_bss_lock); | ||
218 | ieee80211_rx_bss_free(bss); | ||
219 | } | ||
220 | |||
221 | struct ieee80211_sta_bss * | ||
222 | ieee80211_bss_info_update(struct ieee80211_local *local, | ||
223 | struct ieee80211_rx_status *rx_status, | ||
224 | struct ieee80211_mgmt *mgmt, | ||
225 | size_t len, | ||
226 | struct ieee802_11_elems *elems, | ||
227 | int freq, bool beacon) | ||
228 | { | ||
229 | struct ieee80211_sta_bss *bss; | ||
230 | int clen; | ||
231 | |||
232 | #ifdef CONFIG_MAC80211_MESH | ||
233 | if (elems->mesh_config) | ||
234 | bss = ieee80211_rx_mesh_bss_get(local, elems->mesh_id, | ||
235 | elems->mesh_id_len, elems->mesh_config, freq); | ||
236 | else | ||
237 | #endif | ||
238 | bss = ieee80211_rx_bss_get(local, mgmt->bssid, freq, | ||
239 | elems->ssid, elems->ssid_len); | ||
240 | if (!bss) { | ||
241 | #ifdef CONFIG_MAC80211_MESH | ||
242 | if (elems->mesh_config) | ||
243 | bss = ieee80211_rx_mesh_bss_add(local, elems->mesh_id, | ||
244 | elems->mesh_id_len, elems->mesh_config, | ||
245 | elems->mesh_config_len, freq); | ||
246 | else | ||
247 | #endif | ||
248 | bss = ieee80211_rx_bss_add(local, mgmt->bssid, freq, | ||
249 | elems->ssid, elems->ssid_len); | ||
250 | if (!bss) | ||
251 | return NULL; | ||
252 | } else { | ||
253 | #if 0 | ||
254 | /* TODO: order by RSSI? */ | ||
255 | spin_lock_bh(&local->sta_bss_lock); | ||
256 | list_move_tail(&bss->list, &local->sta_bss_list); | ||
257 | spin_unlock_bh(&local->sta_bss_lock); | ||
258 | #endif | ||
259 | } | ||
260 | |||
261 | /* save the ERP value so that it is available at association time */ | ||
262 | if (elems->erp_info && elems->erp_info_len >= 1) { | ||
263 | bss->erp_value = elems->erp_info[0]; | ||
264 | bss->has_erp_value = 1; | ||
265 | } | ||
266 | |||
267 | bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int); | ||
268 | bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info); | ||
269 | |||
270 | if (elems->tim) { | ||
271 | struct ieee80211_tim_ie *tim_ie = | ||
272 | (struct ieee80211_tim_ie *)elems->tim; | ||
273 | bss->dtim_period = tim_ie->dtim_period; | ||
274 | } | ||
275 | |||
276 | /* set default value for buggy APs */ | ||
277 | if (!elems->tim || bss->dtim_period == 0) | ||
278 | bss->dtim_period = 1; | ||
279 | |||
280 | bss->supp_rates_len = 0; | ||
281 | if (elems->supp_rates) { | ||
282 | clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len; | ||
283 | if (clen > elems->supp_rates_len) | ||
284 | clen = elems->supp_rates_len; | ||
285 | memcpy(&bss->supp_rates[bss->supp_rates_len], elems->supp_rates, | ||
286 | clen); | ||
287 | bss->supp_rates_len += clen; | ||
288 | } | ||
289 | if (elems->ext_supp_rates) { | ||
290 | clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len; | ||
291 | if (clen > elems->ext_supp_rates_len) | ||
292 | clen = elems->ext_supp_rates_len; | ||
293 | memcpy(&bss->supp_rates[bss->supp_rates_len], | ||
294 | elems->ext_supp_rates, clen); | ||
295 | bss->supp_rates_len += clen; | ||
296 | } | ||
297 | |||
298 | bss->band = rx_status->band; | ||
299 | |||
300 | bss->timestamp = le64_to_cpu(mgmt->u.beacon.timestamp); | ||
301 | bss->last_update = jiffies; | ||
302 | bss->signal = rx_status->signal; | ||
303 | bss->noise = rx_status->noise; | ||
304 | bss->qual = rx_status->qual; | ||
305 | bss->wmm_used = elems->wmm_param || elems->wmm_info; | ||
306 | |||
307 | if (!beacon) | ||
308 | bss->last_probe_resp = jiffies; | ||
309 | |||
310 | /* | ||
311 | * For probe responses, or if we don't have any information yet, | ||
312 | * use the IEs from the beacon. | ||
313 | */ | ||
314 | if (!bss->ies || !beacon) { | ||
315 | if (bss->ies == NULL || bss->ies_len < elems->total_len) { | ||
316 | kfree(bss->ies); | ||
317 | bss->ies = kmalloc(elems->total_len, GFP_ATOMIC); | ||
318 | } | ||
319 | if (bss->ies) { | ||
320 | memcpy(bss->ies, elems->ie_start, elems->total_len); | ||
321 | bss->ies_len = elems->total_len; | ||
322 | } else | ||
323 | bss->ies_len = 0; | ||
324 | } | ||
325 | |||
326 | return bss; | ||
327 | } | ||
328 | |||
329 | ieee80211_rx_result | ||
330 | ieee80211_sta_rx_scan(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | ||
331 | struct ieee80211_rx_status *rx_status) | ||
332 | { | ||
333 | struct ieee80211_mgmt *mgmt; | ||
334 | struct ieee80211_sta_bss *bss; | ||
335 | u8 *elements; | ||
336 | struct ieee80211_channel *channel; | ||
337 | size_t baselen; | ||
338 | int freq; | ||
339 | __le16 fc; | ||
340 | bool presp, beacon = false; | ||
341 | struct ieee802_11_elems elems; | ||
342 | |||
343 | if (skb->len < 2) | ||
344 | return RX_DROP_UNUSABLE; | ||
345 | |||
346 | mgmt = (struct ieee80211_mgmt *) skb->data; | ||
347 | fc = mgmt->frame_control; | ||
348 | |||
349 | if (ieee80211_is_ctl(fc)) | ||
350 | return RX_CONTINUE; | ||
351 | |||
352 | if (skb->len < 24) | ||
353 | return RX_DROP_MONITOR; | ||
354 | |||
355 | presp = ieee80211_is_probe_resp(fc); | ||
356 | if (presp) { | ||
357 | /* ignore ProbeResp to foreign address */ | ||
358 | if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN)) | ||
359 | return RX_DROP_MONITOR; | ||
360 | |||
361 | presp = true; | ||
362 | elements = mgmt->u.probe_resp.variable; | ||
363 | baselen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); | ||
364 | } else { | ||
365 | beacon = ieee80211_is_beacon(fc); | ||
366 | baselen = offsetof(struct ieee80211_mgmt, u.beacon.variable); | ||
367 | elements = mgmt->u.beacon.variable; | ||
368 | } | ||
369 | |||
370 | if (!presp && !beacon) | ||
371 | return RX_CONTINUE; | ||
372 | |||
373 | if (baselen > skb->len) | ||
374 | return RX_DROP_MONITOR; | ||
375 | |||
376 | ieee802_11_parse_elems(elements, skb->len - baselen, &elems); | ||
377 | |||
378 | if (elems.ds_params && elems.ds_params_len == 1) | ||
379 | freq = ieee80211_channel_to_frequency(elems.ds_params[0]); | ||
380 | else | ||
381 | freq = rx_status->freq; | ||
382 | |||
383 | channel = ieee80211_get_channel(sdata->local->hw.wiphy, freq); | ||
384 | |||
385 | if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) | ||
386 | return RX_DROP_MONITOR; | ||
387 | |||
388 | bss = ieee80211_bss_info_update(sdata->local, rx_status, | ||
389 | mgmt, skb->len, &elems, | ||
390 | freq, beacon); | ||
391 | ieee80211_rx_bss_put(sdata->local, bss); | ||
392 | |||
393 | dev_kfree_skb(skb); | ||
394 | return RX_QUEUED; | ||
395 | } | ||
396 | |||
397 | static void ieee80211_send_nullfunc(struct ieee80211_local *local, | ||
398 | struct ieee80211_sub_if_data *sdata, | ||
399 | int powersave) | ||
400 | { | ||
401 | struct sk_buff *skb; | ||
402 | struct ieee80211_hdr *nullfunc; | ||
403 | __le16 fc; | ||
404 | |||
405 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24); | ||
406 | if (!skb) { | ||
407 | printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc " | ||
408 | "frame\n", sdata->dev->name); | ||
409 | return; | ||
410 | } | ||
411 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
412 | |||
413 | nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24); | ||
414 | memset(nullfunc, 0, 24); | ||
415 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | | ||
416 | IEEE80211_FCTL_TODS); | ||
417 | if (powersave) | ||
418 | fc |= cpu_to_le16(IEEE80211_FCTL_PM); | ||
419 | nullfunc->frame_control = fc; | ||
420 | memcpy(nullfunc->addr1, sdata->u.sta.bssid, ETH_ALEN); | ||
421 | memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN); | ||
422 | memcpy(nullfunc->addr3, sdata->u.sta.bssid, ETH_ALEN); | ||
423 | |||
424 | ieee80211_tx_skb(sdata, skb, 0); | ||
425 | } | ||
426 | |||
427 | static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) | ||
428 | { | ||
429 | if (sdata->vif.type == IEEE80211_IF_TYPE_STA || | ||
430 | ieee80211_vif_is_mesh(&sdata->vif)) | ||
431 | ieee80211_sta_timer((unsigned long)sdata); | ||
432 | } | ||
433 | |||
434 | void ieee80211_scan_completed(struct ieee80211_hw *hw) | ||
435 | { | ||
436 | struct ieee80211_local *local = hw_to_local(hw); | ||
437 | struct ieee80211_sub_if_data *sdata; | ||
438 | union iwreq_data wrqu; | ||
439 | |||
440 | local->last_scan_completed = jiffies; | ||
441 | memset(&wrqu, 0, sizeof(wrqu)); | ||
442 | wireless_send_event(local->scan_sdata->dev, SIOCGIWSCAN, &wrqu, NULL); | ||
443 | |||
444 | if (local->sta_hw_scanning) { | ||
445 | local->sta_hw_scanning = 0; | ||
446 | if (ieee80211_hw_config(local)) | ||
447 | printk(KERN_DEBUG "%s: failed to restore operational " | ||
448 | "channel after scan\n", wiphy_name(local->hw.wiphy)); | ||
449 | /* Restart STA timer for HW scan case */ | ||
450 | rcu_read_lock(); | ||
451 | list_for_each_entry_rcu(sdata, &local->interfaces, list) | ||
452 | ieee80211_restart_sta_timer(sdata); | ||
453 | rcu_read_unlock(); | ||
454 | |||
455 | goto done; | ||
456 | } | ||
457 | |||
458 | local->sta_sw_scanning = 0; | ||
459 | if (ieee80211_hw_config(local)) | ||
460 | printk(KERN_DEBUG "%s: failed to restore operational " | ||
461 | "channel after scan\n", wiphy_name(local->hw.wiphy)); | ||
462 | |||
463 | |||
464 | netif_tx_lock_bh(local->mdev); | ||
465 | netif_addr_lock(local->mdev); | ||
466 | local->filter_flags &= ~FIF_BCN_PRBRESP_PROMISC; | ||
467 | local->ops->configure_filter(local_to_hw(local), | ||
468 | FIF_BCN_PRBRESP_PROMISC, | ||
469 | &local->filter_flags, | ||
470 | local->mdev->mc_count, | ||
471 | local->mdev->mc_list); | ||
472 | |||
473 | netif_addr_unlock(local->mdev); | ||
474 | netif_tx_unlock_bh(local->mdev); | ||
475 | |||
476 | rcu_read_lock(); | ||
477 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | ||
478 | /* Tell AP we're back */ | ||
479 | if (sdata->vif.type == IEEE80211_IF_TYPE_STA) { | ||
480 | if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) { | ||
481 | ieee80211_send_nullfunc(local, sdata, 0); | ||
482 | netif_tx_wake_all_queues(sdata->dev); | ||
483 | } | ||
484 | } else | ||
485 | netif_tx_wake_all_queues(sdata->dev); | ||
486 | |||
487 | ieee80211_restart_sta_timer(sdata); | ||
488 | } | ||
489 | rcu_read_unlock(); | ||
490 | |||
491 | done: | ||
492 | ieee80211_mlme_notify_scan_completed(local); | ||
493 | } | ||
494 | EXPORT_SYMBOL(ieee80211_scan_completed); | ||
495 | |||
496 | |||
497 | void ieee80211_sta_scan_work(struct work_struct *work) | ||
498 | { | ||
499 | struct ieee80211_local *local = | ||
500 | container_of(work, struct ieee80211_local, scan_work.work); | ||
501 | struct ieee80211_sub_if_data *sdata = local->scan_sdata; | ||
502 | struct ieee80211_supported_band *sband; | ||
503 | struct ieee80211_channel *chan; | ||
504 | int skip; | ||
505 | unsigned long next_delay = 0; | ||
506 | |||
507 | if (!local->sta_sw_scanning) | ||
508 | return; | ||
509 | |||
510 | switch (local->scan_state) { | ||
511 | case SCAN_SET_CHANNEL: | ||
512 | /* | ||
513 | * Get current scan band. scan_band may be IEEE80211_NUM_BANDS | ||
514 | * after we successfully scanned the last channel of the last | ||
515 | * band (and the last band is supported by the hw) | ||
516 | */ | ||
517 | if (local->scan_band < IEEE80211_NUM_BANDS) | ||
518 | sband = local->hw.wiphy->bands[local->scan_band]; | ||
519 | else | ||
520 | sband = NULL; | ||
521 | |||
522 | /* | ||
523 | * If we are at an unsupported band and have more bands | ||
524 | * left to scan, advance to the next supported one. | ||
525 | */ | ||
526 | while (!sband && local->scan_band < IEEE80211_NUM_BANDS - 1) { | ||
527 | local->scan_band++; | ||
528 | sband = local->hw.wiphy->bands[local->scan_band]; | ||
529 | local->scan_channel_idx = 0; | ||
530 | } | ||
531 | |||
532 | /* if no more bands/channels left, complete scan */ | ||
533 | if (!sband || local->scan_channel_idx >= sband->n_channels) { | ||
534 | ieee80211_scan_completed(local_to_hw(local)); | ||
535 | return; | ||
536 | } | ||
537 | skip = 0; | ||
538 | chan = &sband->channels[local->scan_channel_idx]; | ||
539 | |||
540 | if (chan->flags & IEEE80211_CHAN_DISABLED || | ||
541 | (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && | ||
542 | chan->flags & IEEE80211_CHAN_NO_IBSS)) | ||
543 | skip = 1; | ||
544 | |||
545 | if (!skip) { | ||
546 | local->scan_channel = chan; | ||
547 | if (ieee80211_hw_config(local)) { | ||
548 | printk(KERN_DEBUG "%s: failed to set freq to " | ||
549 | "%d MHz for scan\n", wiphy_name(local->hw.wiphy), | ||
550 | chan->center_freq); | ||
551 | skip = 1; | ||
552 | } | ||
553 | } | ||
554 | |||
555 | /* advance state machine to next channel/band */ | ||
556 | local->scan_channel_idx++; | ||
557 | if (local->scan_channel_idx >= sband->n_channels) { | ||
558 | /* | ||
559 | * scan_band may end up == IEEE80211_NUM_BANDS, but | ||
560 | * we'll catch that case above and complete the scan | ||
561 | * if that is the case. | ||
562 | */ | ||
563 | local->scan_band++; | ||
564 | local->scan_channel_idx = 0; | ||
565 | } | ||
566 | |||
567 | if (skip) | ||
568 | break; | ||
569 | |||
570 | next_delay = IEEE80211_PROBE_DELAY + | ||
571 | usecs_to_jiffies(local->hw.channel_change_time); | ||
572 | local->scan_state = SCAN_SEND_PROBE; | ||
573 | break; | ||
574 | case SCAN_SEND_PROBE: | ||
575 | next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; | ||
576 | local->scan_state = SCAN_SET_CHANNEL; | ||
577 | |||
578 | if (local->scan_channel->flags & IEEE80211_CHAN_PASSIVE_SCAN) | ||
579 | break; | ||
580 | ieee80211_send_probe_req(sdata, NULL, local->scan_ssid, | ||
581 | local->scan_ssid_len); | ||
582 | next_delay = IEEE80211_CHANNEL_TIME; | ||
583 | break; | ||
584 | } | ||
585 | |||
586 | if (local->sta_sw_scanning) | ||
587 | queue_delayed_work(local->hw.workqueue, &local->scan_work, | ||
588 | next_delay); | ||
589 | } | ||
590 | |||
591 | |||
592 | int ieee80211_sta_start_scan(struct ieee80211_sub_if_data *scan_sdata, | ||
593 | u8 *ssid, size_t ssid_len) | ||
594 | { | ||
595 | struct ieee80211_local *local = scan_sdata->local; | ||
596 | struct ieee80211_sub_if_data *sdata; | ||
597 | |||
598 | if (ssid_len > IEEE80211_MAX_SSID_LEN) | ||
599 | return -EINVAL; | ||
600 | |||
601 | /* MLME-SCAN.request (page 118) page 144 (11.1.3.1) | ||
602 | * BSSType: INFRASTRUCTURE, INDEPENDENT, ANY_BSS | ||
603 | * BSSID: MACAddress | ||
604 | * SSID | ||
605 | * ScanType: ACTIVE, PASSIVE | ||
606 | * ProbeDelay: delay (in microseconds) to be used prior to transmitting | ||
607 | * a Probe frame during active scanning | ||
608 | * ChannelList | ||
609 | * MinChannelTime (>= ProbeDelay), in TU | ||
610 | * MaxChannelTime: (>= MinChannelTime), in TU | ||
611 | */ | ||
612 | |||
613 | /* MLME-SCAN.confirm | ||
614 | * BSSDescriptionSet | ||
615 | * ResultCode: SUCCESS, INVALID_PARAMETERS | ||
616 | */ | ||
617 | |||
618 | if (local->sta_sw_scanning || local->sta_hw_scanning) { | ||
619 | if (local->scan_sdata == scan_sdata) | ||
620 | return 0; | ||
621 | return -EBUSY; | ||
622 | } | ||
623 | |||
624 | if (local->ops->hw_scan) { | ||
625 | int rc = local->ops->hw_scan(local_to_hw(local), | ||
626 | ssid, ssid_len); | ||
627 | if (!rc) { | ||
628 | local->sta_hw_scanning = 1; | ||
629 | local->scan_sdata = scan_sdata; | ||
630 | } | ||
631 | return rc; | ||
632 | } | ||
633 | |||
634 | local->sta_sw_scanning = 1; | ||
635 | |||
636 | rcu_read_lock(); | ||
637 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | ||
638 | if (sdata->vif.type == IEEE80211_IF_TYPE_STA) { | ||
639 | if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) { | ||
640 | netif_tx_stop_all_queues(sdata->dev); | ||
641 | ieee80211_send_nullfunc(local, sdata, 1); | ||
642 | } | ||
643 | } else | ||
644 | netif_tx_stop_all_queues(sdata->dev); | ||
645 | } | ||
646 | rcu_read_unlock(); | ||
647 | |||
648 | if (ssid) { | ||
649 | local->scan_ssid_len = ssid_len; | ||
650 | memcpy(local->scan_ssid, ssid, ssid_len); | ||
651 | } else | ||
652 | local->scan_ssid_len = 0; | ||
653 | local->scan_state = SCAN_SET_CHANNEL; | ||
654 | local->scan_channel_idx = 0; | ||
655 | local->scan_band = IEEE80211_BAND_2GHZ; | ||
656 | local->scan_sdata = scan_sdata; | ||
657 | |||
658 | netif_addr_lock_bh(local->mdev); | ||
659 | local->filter_flags |= FIF_BCN_PRBRESP_PROMISC; | ||
660 | local->ops->configure_filter(local_to_hw(local), | ||
661 | FIF_BCN_PRBRESP_PROMISC, | ||
662 | &local->filter_flags, | ||
663 | local->mdev->mc_count, | ||
664 | local->mdev->mc_list); | ||
665 | netif_addr_unlock_bh(local->mdev); | ||
666 | |||
667 | /* TODO: start scan as soon as all nullfunc frames are ACKed */ | ||
668 | queue_delayed_work(local->hw.workqueue, &local->scan_work, | ||
669 | IEEE80211_CHANNEL_TIME); | ||
670 | |||
671 | return 0; | ||
672 | } | ||
673 | |||
674 | |||
675 | int ieee80211_sta_req_scan(struct ieee80211_sub_if_data *sdata, u8 *ssid, size_t ssid_len) | ||
676 | { | ||
677 | struct ieee80211_local *local = sdata->local; | ||
678 | struct ieee80211_if_sta *ifsta; | ||
679 | |||
680 | if (sdata->vif.type != IEEE80211_IF_TYPE_STA) | ||
681 | return ieee80211_sta_start_scan(sdata, ssid, ssid_len); | ||
682 | |||
683 | /* | ||
684 | * STA has a state machine that might need to defer scanning | ||
685 | * while it's trying to associate/authenticate, therefore we | ||
686 | * queue it up to the state machine in that case. | ||
687 | */ | ||
688 | |||
689 | if (local->sta_sw_scanning || local->sta_hw_scanning) { | ||
690 | if (local->scan_sdata == sdata) | ||
691 | return 0; | ||
692 | return -EBUSY; | ||
693 | } | ||
694 | |||
695 | ifsta = &sdata->u.sta; | ||
696 | |||
697 | ifsta->scan_ssid_len = ssid_len; | ||
698 | if (ssid_len) | ||
699 | memcpy(ifsta->scan_ssid, ssid, ssid_len); | ||
700 | set_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request); | ||
701 | queue_work(local->hw.workqueue, &ifsta->work); | ||
702 | |||
703 | return 0; | ||
704 | } | ||
705 | |||
706 | |||
707 | static void ieee80211_sta_add_scan_ies(struct iw_request_info *info, | ||
708 | struct ieee80211_sta_bss *bss, | ||
709 | char **current_ev, char *end_buf) | ||
710 | { | ||
711 | u8 *pos, *end, *next; | ||
712 | struct iw_event iwe; | ||
713 | |||
714 | if (bss == NULL || bss->ies == NULL) | ||
715 | return; | ||
716 | |||
717 | /* | ||
718 | * If needed, fragment the IEs buffer (at IE boundaries) into short | ||
719 | * enough fragments to fit into IW_GENERIC_IE_MAX octet messages. | ||
720 | */ | ||
721 | pos = bss->ies; | ||
722 | end = pos + bss->ies_len; | ||
723 | |||
724 | while (end - pos > IW_GENERIC_IE_MAX) { | ||
725 | next = pos + 2 + pos[1]; | ||
726 | while (next + 2 + next[1] - pos < IW_GENERIC_IE_MAX) | ||
727 | next = next + 2 + next[1]; | ||
728 | |||
729 | memset(&iwe, 0, sizeof(iwe)); | ||
730 | iwe.cmd = IWEVGENIE; | ||
731 | iwe.u.data.length = next - pos; | ||
732 | *current_ev = iwe_stream_add_point(info, *current_ev, | ||
733 | end_buf, &iwe, pos); | ||
734 | |||
735 | pos = next; | ||
736 | } | ||
737 | |||
738 | if (end > pos) { | ||
739 | memset(&iwe, 0, sizeof(iwe)); | ||
740 | iwe.cmd = IWEVGENIE; | ||
741 | iwe.u.data.length = end - pos; | ||
742 | *current_ev = iwe_stream_add_point(info, *current_ev, | ||
743 | end_buf, &iwe, pos); | ||
744 | } | ||
745 | } | ||
746 | |||
747 | |||
748 | static char * | ||
749 | ieee80211_sta_scan_result(struct ieee80211_local *local, | ||
750 | struct iw_request_info *info, | ||
751 | struct ieee80211_sta_bss *bss, | ||
752 | char *current_ev, char *end_buf) | ||
753 | { | ||
754 | struct iw_event iwe; | ||
755 | char *buf; | ||
756 | |||
757 | if (time_after(jiffies, | ||
758 | bss->last_update + IEEE80211_SCAN_RESULT_EXPIRE)) | ||
759 | return current_ev; | ||
760 | |||
761 | memset(&iwe, 0, sizeof(iwe)); | ||
762 | iwe.cmd = SIOCGIWAP; | ||
763 | iwe.u.ap_addr.sa_family = ARPHRD_ETHER; | ||
764 | memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN); | ||
765 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, | ||
766 | IW_EV_ADDR_LEN); | ||
767 | |||
768 | memset(&iwe, 0, sizeof(iwe)); | ||
769 | iwe.cmd = SIOCGIWESSID; | ||
770 | if (bss_mesh_cfg(bss)) { | ||
771 | iwe.u.data.length = bss_mesh_id_len(bss); | ||
772 | iwe.u.data.flags = 1; | ||
773 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
774 | &iwe, bss_mesh_id(bss)); | ||
775 | } else { | ||
776 | iwe.u.data.length = bss->ssid_len; | ||
777 | iwe.u.data.flags = 1; | ||
778 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
779 | &iwe, bss->ssid); | ||
780 | } | ||
781 | |||
782 | if (bss->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS) | ||
783 | || bss_mesh_cfg(bss)) { | ||
784 | memset(&iwe, 0, sizeof(iwe)); | ||
785 | iwe.cmd = SIOCGIWMODE; | ||
786 | if (bss_mesh_cfg(bss)) | ||
787 | iwe.u.mode = IW_MODE_MESH; | ||
788 | else if (bss->capability & WLAN_CAPABILITY_ESS) | ||
789 | iwe.u.mode = IW_MODE_MASTER; | ||
790 | else | ||
791 | iwe.u.mode = IW_MODE_ADHOC; | ||
792 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, | ||
793 | &iwe, IW_EV_UINT_LEN); | ||
794 | } | ||
795 | |||
796 | memset(&iwe, 0, sizeof(iwe)); | ||
797 | iwe.cmd = SIOCGIWFREQ; | ||
798 | iwe.u.freq.m = ieee80211_frequency_to_channel(bss->freq); | ||
799 | iwe.u.freq.e = 0; | ||
800 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, | ||
801 | IW_EV_FREQ_LEN); | ||
802 | |||
803 | memset(&iwe, 0, sizeof(iwe)); | ||
804 | iwe.cmd = SIOCGIWFREQ; | ||
805 | iwe.u.freq.m = bss->freq; | ||
806 | iwe.u.freq.e = 6; | ||
807 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, | ||
808 | IW_EV_FREQ_LEN); | ||
809 | memset(&iwe, 0, sizeof(iwe)); | ||
810 | iwe.cmd = IWEVQUAL; | ||
811 | iwe.u.qual.qual = bss->qual; | ||
812 | iwe.u.qual.level = bss->signal; | ||
813 | iwe.u.qual.noise = bss->noise; | ||
814 | iwe.u.qual.updated = local->wstats_flags; | ||
815 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, | ||
816 | IW_EV_QUAL_LEN); | ||
817 | |||
818 | memset(&iwe, 0, sizeof(iwe)); | ||
819 | iwe.cmd = SIOCGIWENCODE; | ||
820 | if (bss->capability & WLAN_CAPABILITY_PRIVACY) | ||
821 | iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; | ||
822 | else | ||
823 | iwe.u.data.flags = IW_ENCODE_DISABLED; | ||
824 | iwe.u.data.length = 0; | ||
825 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
826 | &iwe, ""); | ||
827 | |||
828 | ieee80211_sta_add_scan_ies(info, bss, ¤t_ev, end_buf); | ||
829 | |||
830 | if (bss->supp_rates_len > 0) { | ||
831 | /* display all supported rates in readable format */ | ||
832 | char *p = current_ev + iwe_stream_lcp_len(info); | ||
833 | int i; | ||
834 | |||
835 | memset(&iwe, 0, sizeof(iwe)); | ||
836 | iwe.cmd = SIOCGIWRATE; | ||
837 | /* Those two flags are ignored... */ | ||
838 | iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; | ||
839 | |||
840 | for (i = 0; i < bss->supp_rates_len; i++) { | ||
841 | iwe.u.bitrate.value = ((bss->supp_rates[i] & | ||
842 | 0x7f) * 500000); | ||
843 | p = iwe_stream_add_value(info, current_ev, p, | ||
844 | end_buf, &iwe, IW_EV_PARAM_LEN); | ||
845 | } | ||
846 | current_ev = p; | ||
847 | } | ||
848 | |||
849 | buf = kmalloc(30, GFP_ATOMIC); | ||
850 | if (buf) { | ||
851 | memset(&iwe, 0, sizeof(iwe)); | ||
852 | iwe.cmd = IWEVCUSTOM; | ||
853 | sprintf(buf, "tsf=%016llx", (unsigned long long)(bss->timestamp)); | ||
854 | iwe.u.data.length = strlen(buf); | ||
855 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
856 | &iwe, buf); | ||
857 | memset(&iwe, 0, sizeof(iwe)); | ||
858 | iwe.cmd = IWEVCUSTOM; | ||
859 | sprintf(buf, " Last beacon: %dms ago", | ||
860 | jiffies_to_msecs(jiffies - bss->last_update)); | ||
861 | iwe.u.data.length = strlen(buf); | ||
862 | current_ev = iwe_stream_add_point(info, current_ev, | ||
863 | end_buf, &iwe, buf); | ||
864 | kfree(buf); | ||
865 | } | ||
866 | |||
867 | if (bss_mesh_cfg(bss)) { | ||
868 | u8 *cfg = bss_mesh_cfg(bss); | ||
869 | buf = kmalloc(50, GFP_ATOMIC); | ||
870 | if (buf) { | ||
871 | memset(&iwe, 0, sizeof(iwe)); | ||
872 | iwe.cmd = IWEVCUSTOM; | ||
873 | sprintf(buf, "Mesh network (version %d)", cfg[0]); | ||
874 | iwe.u.data.length = strlen(buf); | ||
875 | current_ev = iwe_stream_add_point(info, current_ev, | ||
876 | end_buf, | ||
877 | &iwe, buf); | ||
878 | sprintf(buf, "Path Selection Protocol ID: " | ||
879 | "0x%02X%02X%02X%02X", cfg[1], cfg[2], cfg[3], | ||
880 | cfg[4]); | ||
881 | iwe.u.data.length = strlen(buf); | ||
882 | current_ev = iwe_stream_add_point(info, current_ev, | ||
883 | end_buf, | ||
884 | &iwe, buf); | ||
885 | sprintf(buf, "Path Selection Metric ID: " | ||
886 | "0x%02X%02X%02X%02X", cfg[5], cfg[6], cfg[7], | ||
887 | cfg[8]); | ||
888 | iwe.u.data.length = strlen(buf); | ||
889 | current_ev = iwe_stream_add_point(info, current_ev, | ||
890 | end_buf, | ||
891 | &iwe, buf); | ||
892 | sprintf(buf, "Congestion Control Mode ID: " | ||
893 | "0x%02X%02X%02X%02X", cfg[9], cfg[10], | ||
894 | cfg[11], cfg[12]); | ||
895 | iwe.u.data.length = strlen(buf); | ||
896 | current_ev = iwe_stream_add_point(info, current_ev, | ||
897 | end_buf, | ||
898 | &iwe, buf); | ||
899 | sprintf(buf, "Channel Precedence: " | ||
900 | "0x%02X%02X%02X%02X", cfg[13], cfg[14], | ||
901 | cfg[15], cfg[16]); | ||
902 | iwe.u.data.length = strlen(buf); | ||
903 | current_ev = iwe_stream_add_point(info, current_ev, | ||
904 | end_buf, | ||
905 | &iwe, buf); | ||
906 | kfree(buf); | ||
907 | } | ||
908 | } | ||
909 | |||
910 | return current_ev; | ||
911 | } | ||
912 | |||
913 | |||
914 | int ieee80211_sta_scan_results(struct ieee80211_local *local, | ||
915 | struct iw_request_info *info, | ||
916 | char *buf, size_t len) | ||
917 | { | ||
918 | char *current_ev = buf; | ||
919 | char *end_buf = buf + len; | ||
920 | struct ieee80211_sta_bss *bss; | ||
921 | |||
922 | spin_lock_bh(&local->sta_bss_lock); | ||
923 | list_for_each_entry(bss, &local->sta_bss_list, list) { | ||
924 | if (buf + len - current_ev <= IW_EV_ADDR_LEN) { | ||
925 | spin_unlock_bh(&local->sta_bss_lock); | ||
926 | return -E2BIG; | ||
927 | } | ||
928 | current_ev = ieee80211_sta_scan_result(local, info, bss, | ||
929 | current_ev, end_buf); | ||
930 | } | ||
931 | spin_unlock_bh(&local->sta_bss_lock); | ||
932 | return current_ev - buf; | ||
933 | } | ||
diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c new file mode 100644 index 000000000000..f72bad636d8e --- /dev/null +++ b/net/mac80211/spectmgmt.c | |||
@@ -0,0 +1,86 @@ | |||
1 | /* | ||
2 | * spectrum management | ||
3 | * | ||
4 | * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi> | ||
5 | * Copyright 2002-2005, Instant802 Networks, Inc. | ||
6 | * Copyright 2005-2006, Devicescape Software, Inc. | ||
7 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> | ||
8 | * Copyright 2007, Michael Wu <flamingice@sourmilk.net> | ||
9 | * Copyright 2007-2008, Intel Corporation | ||
10 | * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License version 2 as | ||
14 | * published by the Free Software Foundation. | ||
15 | */ | ||
16 | |||
17 | #include <linux/ieee80211.h> | ||
18 | #include <net/wireless.h> | ||
19 | #include <net/mac80211.h> | ||
20 | #include "ieee80211_i.h" | ||
21 | #include "sta_info.h" | ||
22 | #include "wme.h" | ||
23 | |||
24 | static void ieee80211_send_refuse_measurement_request(struct ieee80211_sub_if_data *sdata, | ||
25 | struct ieee80211_msrment_ie *request_ie, | ||
26 | const u8 *da, const u8 *bssid, | ||
27 | u8 dialog_token) | ||
28 | { | ||
29 | struct ieee80211_local *local = sdata->local; | ||
30 | struct sk_buff *skb; | ||
31 | struct ieee80211_mgmt *msr_report; | ||
32 | |||
33 | skb = dev_alloc_skb(sizeof(*msr_report) + local->hw.extra_tx_headroom + | ||
34 | sizeof(struct ieee80211_msrment_ie)); | ||
35 | |||
36 | if (!skb) { | ||
37 | printk(KERN_ERR "%s: failed to allocate buffer for " | ||
38 | "measurement report frame\n", sdata->dev->name); | ||
39 | return; | ||
40 | } | ||
41 | |||
42 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
43 | msr_report = (struct ieee80211_mgmt *)skb_put(skb, 24); | ||
44 | memset(msr_report, 0, 24); | ||
45 | memcpy(msr_report->da, da, ETH_ALEN); | ||
46 | memcpy(msr_report->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
47 | memcpy(msr_report->bssid, bssid, ETH_ALEN); | ||
48 | msr_report->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
49 | IEEE80211_STYPE_ACTION); | ||
50 | |||
51 | skb_put(skb, 1 + sizeof(msr_report->u.action.u.measurement)); | ||
52 | msr_report->u.action.category = WLAN_CATEGORY_SPECTRUM_MGMT; | ||
53 | msr_report->u.action.u.measurement.action_code = | ||
54 | WLAN_ACTION_SPCT_MSR_RPRT; | ||
55 | msr_report->u.action.u.measurement.dialog_token = dialog_token; | ||
56 | |||
57 | msr_report->u.action.u.measurement.element_id = WLAN_EID_MEASURE_REPORT; | ||
58 | msr_report->u.action.u.measurement.length = | ||
59 | sizeof(struct ieee80211_msrment_ie); | ||
60 | |||
61 | memset(&msr_report->u.action.u.measurement.msr_elem, 0, | ||
62 | sizeof(struct ieee80211_msrment_ie)); | ||
63 | msr_report->u.action.u.measurement.msr_elem.token = request_ie->token; | ||
64 | msr_report->u.action.u.measurement.msr_elem.mode |= | ||
65 | IEEE80211_SPCT_MSR_RPRT_MODE_REFUSED; | ||
66 | msr_report->u.action.u.measurement.msr_elem.type = request_ie->type; | ||
67 | |||
68 | ieee80211_tx_skb(sdata, skb, 0); | ||
69 | } | ||
70 | |||
71 | void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, | ||
72 | struct ieee80211_mgmt *mgmt, | ||
73 | size_t len) | ||
74 | { | ||
75 | /* | ||
76 | * Ignoring measurement request is spec violation. | ||
77 | * Mandatory measurements must be reported optional | ||
78 | * measurements might be refused or reported incapable | ||
79 | * For now just refuse | ||
80 | * TODO: Answer basic measurement as unmeasured | ||
81 | */ | ||
82 | ieee80211_send_refuse_measurement_request(sdata, | ||
83 | &mgmt->u.action.u.measurement.msr_elem, | ||
84 | mgmt->sa, mgmt->bssid, | ||
85 | mgmt->u.action.u.measurement.dialog_token); | ||
86 | } | ||
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index f40c060341ae..c3a22ab2ad2e 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -428,3 +428,187 @@ void ieee80211_iterate_active_interfaces_atomic( | |||
428 | rcu_read_unlock(); | 428 | rcu_read_unlock(); |
429 | } | 429 | } |
430 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic); | 430 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic); |
431 | |||
432 | void ieee802_11_parse_elems(u8 *start, size_t len, | ||
433 | struct ieee802_11_elems *elems) | ||
434 | { | ||
435 | size_t left = len; | ||
436 | u8 *pos = start; | ||
437 | |||
438 | memset(elems, 0, sizeof(*elems)); | ||
439 | elems->ie_start = start; | ||
440 | elems->total_len = len; | ||
441 | |||
442 | while (left >= 2) { | ||
443 | u8 id, elen; | ||
444 | |||
445 | id = *pos++; | ||
446 | elen = *pos++; | ||
447 | left -= 2; | ||
448 | |||
449 | if (elen > left) | ||
450 | return; | ||
451 | |||
452 | switch (id) { | ||
453 | case WLAN_EID_SSID: | ||
454 | elems->ssid = pos; | ||
455 | elems->ssid_len = elen; | ||
456 | break; | ||
457 | case WLAN_EID_SUPP_RATES: | ||
458 | elems->supp_rates = pos; | ||
459 | elems->supp_rates_len = elen; | ||
460 | break; | ||
461 | case WLAN_EID_FH_PARAMS: | ||
462 | elems->fh_params = pos; | ||
463 | elems->fh_params_len = elen; | ||
464 | break; | ||
465 | case WLAN_EID_DS_PARAMS: | ||
466 | elems->ds_params = pos; | ||
467 | elems->ds_params_len = elen; | ||
468 | break; | ||
469 | case WLAN_EID_CF_PARAMS: | ||
470 | elems->cf_params = pos; | ||
471 | elems->cf_params_len = elen; | ||
472 | break; | ||
473 | case WLAN_EID_TIM: | ||
474 | elems->tim = pos; | ||
475 | elems->tim_len = elen; | ||
476 | break; | ||
477 | case WLAN_EID_IBSS_PARAMS: | ||
478 | elems->ibss_params = pos; | ||
479 | elems->ibss_params_len = elen; | ||
480 | break; | ||
481 | case WLAN_EID_CHALLENGE: | ||
482 | elems->challenge = pos; | ||
483 | elems->challenge_len = elen; | ||
484 | break; | ||
485 | case WLAN_EID_WPA: | ||
486 | if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 && | ||
487 | pos[2] == 0xf2) { | ||
488 | /* Microsoft OUI (00:50:F2) */ | ||
489 | if (pos[3] == 1) { | ||
490 | /* OUI Type 1 - WPA IE */ | ||
491 | elems->wpa = pos; | ||
492 | elems->wpa_len = elen; | ||
493 | } else if (elen >= 5 && pos[3] == 2) { | ||
494 | if (pos[4] == 0) { | ||
495 | elems->wmm_info = pos; | ||
496 | elems->wmm_info_len = elen; | ||
497 | } else if (pos[4] == 1) { | ||
498 | elems->wmm_param = pos; | ||
499 | elems->wmm_param_len = elen; | ||
500 | } | ||
501 | } | ||
502 | } | ||
503 | break; | ||
504 | case WLAN_EID_RSN: | ||
505 | elems->rsn = pos; | ||
506 | elems->rsn_len = elen; | ||
507 | break; | ||
508 | case WLAN_EID_ERP_INFO: | ||
509 | elems->erp_info = pos; | ||
510 | elems->erp_info_len = elen; | ||
511 | break; | ||
512 | case WLAN_EID_EXT_SUPP_RATES: | ||
513 | elems->ext_supp_rates = pos; | ||
514 | elems->ext_supp_rates_len = elen; | ||
515 | break; | ||
516 | case WLAN_EID_HT_CAPABILITY: | ||
517 | elems->ht_cap_elem = pos; | ||
518 | elems->ht_cap_elem_len = elen; | ||
519 | break; | ||
520 | case WLAN_EID_HT_EXTRA_INFO: | ||
521 | elems->ht_info_elem = pos; | ||
522 | elems->ht_info_elem_len = elen; | ||
523 | break; | ||
524 | case WLAN_EID_MESH_ID: | ||
525 | elems->mesh_id = pos; | ||
526 | elems->mesh_id_len = elen; | ||
527 | break; | ||
528 | case WLAN_EID_MESH_CONFIG: | ||
529 | elems->mesh_config = pos; | ||
530 | elems->mesh_config_len = elen; | ||
531 | break; | ||
532 | case WLAN_EID_PEER_LINK: | ||
533 | elems->peer_link = pos; | ||
534 | elems->peer_link_len = elen; | ||
535 | break; | ||
536 | case WLAN_EID_PREQ: | ||
537 | elems->preq = pos; | ||
538 | elems->preq_len = elen; | ||
539 | break; | ||
540 | case WLAN_EID_PREP: | ||
541 | elems->prep = pos; | ||
542 | elems->prep_len = elen; | ||
543 | break; | ||
544 | case WLAN_EID_PERR: | ||
545 | elems->perr = pos; | ||
546 | elems->perr_len = elen; | ||
547 | break; | ||
548 | case WLAN_EID_CHANNEL_SWITCH: | ||
549 | elems->ch_switch_elem = pos; | ||
550 | elems->ch_switch_elem_len = elen; | ||
551 | break; | ||
552 | case WLAN_EID_QUIET: | ||
553 | if (!elems->quiet_elem) { | ||
554 | elems->quiet_elem = pos; | ||
555 | elems->quiet_elem_len = elen; | ||
556 | } | ||
557 | elems->num_of_quiet_elem++; | ||
558 | break; | ||
559 | case WLAN_EID_COUNTRY: | ||
560 | elems->country_elem = pos; | ||
561 | elems->country_elem_len = elen; | ||
562 | break; | ||
563 | case WLAN_EID_PWR_CONSTRAINT: | ||
564 | elems->pwr_constr_elem = pos; | ||
565 | elems->pwr_constr_elem_len = elen; | ||
566 | break; | ||
567 | default: | ||
568 | break; | ||
569 | } | ||
570 | |||
571 | left -= elen; | ||
572 | pos += elen; | ||
573 | } | ||
574 | } | ||
575 | |||
576 | void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata) | ||
577 | { | ||
578 | struct ieee80211_local *local = sdata->local; | ||
579 | struct ieee80211_tx_queue_params qparam; | ||
580 | int i; | ||
581 | |||
582 | if (!local->ops->conf_tx) | ||
583 | return; | ||
584 | |||
585 | memset(&qparam, 0, sizeof(qparam)); | ||
586 | |||
587 | qparam.aifs = 2; | ||
588 | |||
589 | if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && | ||
590 | !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)) | ||
591 | qparam.cw_min = 31; | ||
592 | else | ||
593 | qparam.cw_min = 15; | ||
594 | |||
595 | qparam.cw_max = 1023; | ||
596 | qparam.txop = 0; | ||
597 | |||
598 | for (i = 0; i < local_to_hw(local)->queues; i++) | ||
599 | local->ops->conf_tx(local_to_hw(local), i, &qparam); | ||
600 | } | ||
601 | |||
602 | void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | ||
603 | int encrypt) | ||
604 | { | ||
605 | skb->dev = sdata->local->mdev; | ||
606 | skb_set_mac_header(skb, 0); | ||
607 | skb_set_network_header(skb, 0); | ||
608 | skb_set_transport_header(skb, 0); | ||
609 | |||
610 | skb->iif = sdata->dev->ifindex; | ||
611 | skb->do_not_encrypt = !encrypt; | ||
612 | |||
613 | dev_queue_xmit(skb); | ||
614 | } | ||