aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorBen Greear <greearb@candelatech.com>2011-03-03 17:39:05 -0500
committerJohn W. Linville <linville@tuxdriver.com>2011-03-07 13:48:30 -0500
commite4b0b32aa1c0dd7ae6340833dd6b19de46409a88 (patch)
tree338fb13c5b0b3e0dbeb1aad68ed02ad77bfcbdc8 /drivers/net/wireless
parent410f2bb30d27252cc55a5f41668de60de62e5dc8 (diff)
ath5k: Put hardware in PROMISC mode if there is more than 1 stations.
It seems ath5k has issues receiving broadcast packets (ARPs) when using multiple STA interfaces associated with multiple APs. This patch ensures the NIC is always in PROMISC mode if there are more than 1 stations associated. Signed-off-by: Ben Greear <greearb@candelatech.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c52
-rw-r--r--drivers/net/wireless/ath/ath5k/base.h13
-rw-r--r--drivers/net/wireless/ath/ath5k/mac80211-ops.c19
3 files changed, 53 insertions, 31 deletions
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 91411e9b4b68..e6ff62e60a79 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -442,19 +442,9 @@ ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan)
442 return ath5k_reset(sc, chan, true); 442 return ath5k_reset(sc, chan, true);
443} 443}
444 444
445struct ath_vif_iter_data { 445void ath5k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
446 const u8 *hw_macaddr;
447 u8 mask[ETH_ALEN];
448 u8 active_mac[ETH_ALEN]; /* first active MAC */
449 bool need_set_hw_addr;
450 bool found_active;
451 bool any_assoc;
452 enum nl80211_iftype opmode;
453};
454
455static void ath_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
456{ 446{
457 struct ath_vif_iter_data *iter_data = data; 447 struct ath5k_vif_iter_data *iter_data = data;
458 int i; 448 int i;
459 struct ath5k_vif *avf = (void *)vif->drv_priv; 449 struct ath5k_vif *avf = (void *)vif->drv_priv;
460 450
@@ -484,9 +474,12 @@ static void ath_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
484 */ 474 */
485 if (avf->opmode == NL80211_IFTYPE_AP) 475 if (avf->opmode == NL80211_IFTYPE_AP)
486 iter_data->opmode = NL80211_IFTYPE_AP; 476 iter_data->opmode = NL80211_IFTYPE_AP;
487 else 477 else {
478 if (avf->opmode == NL80211_IFTYPE_STATION)
479 iter_data->n_stas++;
488 if (iter_data->opmode == NL80211_IFTYPE_UNSPECIFIED) 480 if (iter_data->opmode == NL80211_IFTYPE_UNSPECIFIED)
489 iter_data->opmode = avf->opmode; 481 iter_data->opmode = avf->opmode;
482 }
490} 483}
491 484
492void 485void
@@ -494,7 +487,8 @@ ath5k_update_bssid_mask_and_opmode(struct ath5k_softc *sc,
494 struct ieee80211_vif *vif) 487 struct ieee80211_vif *vif)
495{ 488{
496 struct ath_common *common = ath5k_hw_common(sc->ah); 489 struct ath_common *common = ath5k_hw_common(sc->ah);
497 struct ath_vif_iter_data iter_data; 490 struct ath5k_vif_iter_data iter_data;
491 u32 rfilt;
498 492
499 /* 493 /*
500 * Use the hardware MAC address as reference, the hardware uses it 494 * Use the hardware MAC address as reference, the hardware uses it
@@ -505,12 +499,13 @@ ath5k_update_bssid_mask_and_opmode(struct ath5k_softc *sc,
505 iter_data.found_active = false; 499 iter_data.found_active = false;
506 iter_data.need_set_hw_addr = true; 500 iter_data.need_set_hw_addr = true;
507 iter_data.opmode = NL80211_IFTYPE_UNSPECIFIED; 501 iter_data.opmode = NL80211_IFTYPE_UNSPECIFIED;
502 iter_data.n_stas = 0;
508 503
509 if (vif) 504 if (vif)
510 ath_vif_iter(&iter_data, vif->addr, vif); 505 ath5k_vif_iter(&iter_data, vif->addr, vif);
511 506
512 /* Get list of all active MAC addresses */ 507 /* Get list of all active MAC addresses */
513 ieee80211_iterate_active_interfaces_atomic(sc->hw, ath_vif_iter, 508 ieee80211_iterate_active_interfaces_atomic(sc->hw, ath5k_vif_iter,
514 &iter_data); 509 &iter_data);
515 memcpy(sc->bssidmask, iter_data.mask, ETH_ALEN); 510 memcpy(sc->bssidmask, iter_data.mask, ETH_ALEN);
516 511
@@ -528,20 +523,19 @@ ath5k_update_bssid_mask_and_opmode(struct ath5k_softc *sc,
528 523
529 if (ath5k_hw_hasbssidmask(sc->ah)) 524 if (ath5k_hw_hasbssidmask(sc->ah))
530 ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask); 525 ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask);
531}
532 526
533void 527 /* Set up RX Filter */
534ath5k_mode_setup(struct ath5k_softc *sc, struct ieee80211_vif *vif) 528 if (iter_data.n_stas > 1) {
535{ 529 /* If you have multiple STA interfaces connected to
536 struct ath5k_hw *ah = sc->ah; 530 * different APs, ARPs are not received (most of the time?)
537 u32 rfilt; 531 * Enabling PROMISC appears to fix that probem.
532 */
533 sc->filter_flags |= AR5K_RX_FILTER_PROM;
534 }
538 535
539 /* configure rx filter */
540 rfilt = sc->filter_flags; 536 rfilt = sc->filter_flags;
541 ath5k_hw_set_rx_filter(ah, rfilt); 537 ath5k_hw_set_rx_filter(sc->ah, rfilt);
542 ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "RX filter 0x%x\n", rfilt); 538 ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "RX filter 0x%x\n", rfilt);
543
544 ath5k_update_bssid_mask_and_opmode(sc, vif);
545} 539}
546 540
547static inline int 541static inline int
@@ -1117,7 +1111,7 @@ ath5k_rx_start(struct ath5k_softc *sc)
1117 spin_unlock_bh(&sc->rxbuflock); 1111 spin_unlock_bh(&sc->rxbuflock);
1118 1112
1119 ath5k_hw_start_rx_dma(ah); /* enable recv descriptors */ 1113 ath5k_hw_start_rx_dma(ah); /* enable recv descriptors */
1120 ath5k_mode_setup(sc, NULL); /* set filters, etc. */ 1114 ath5k_update_bssid_mask_and_opmode(sc, NULL); /* set filters, etc. */
1121 ath5k_hw_start_rx_pcu(ah); /* re-enable PCU/DMA engine */ 1115 ath5k_hw_start_rx_pcu(ah); /* re-enable PCU/DMA engine */
1122 1116
1123 return 0; 1117 return 0;
@@ -2923,13 +2917,13 @@ ath5k_deinit_softc(struct ath5k_softc *sc)
2923bool 2917bool
2924ath_any_vif_assoc(struct ath5k_softc *sc) 2918ath_any_vif_assoc(struct ath5k_softc *sc)
2925{ 2919{
2926 struct ath_vif_iter_data iter_data; 2920 struct ath5k_vif_iter_data iter_data;
2927 iter_data.hw_macaddr = NULL; 2921 iter_data.hw_macaddr = NULL;
2928 iter_data.any_assoc = false; 2922 iter_data.any_assoc = false;
2929 iter_data.need_set_hw_addr = false; 2923 iter_data.need_set_hw_addr = false;
2930 iter_data.found_active = true; 2924 iter_data.found_active = true;
2931 2925
2932 ieee80211_iterate_active_interfaces_atomic(sc->hw, ath_vif_iter, 2926 ieee80211_iterate_active_interfaces_atomic(sc->hw, ath5k_vif_iter,
2933 &iter_data); 2927 &iter_data);
2934 return iter_data.any_assoc; 2928 return iter_data.any_assoc;
2935} 2929}
diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h
index 8f919dca95f1..8d1df1fa2351 100644
--- a/drivers/net/wireless/ath/ath5k/base.h
+++ b/drivers/net/wireless/ath/ath5k/base.h
@@ -259,6 +259,19 @@ struct ath5k_softc {
259 struct survey_info survey; /* collected survey info */ 259 struct survey_info survey; /* collected survey info */
260}; 260};
261 261
262struct ath5k_vif_iter_data {
263 const u8 *hw_macaddr;
264 u8 mask[ETH_ALEN];
265 u8 active_mac[ETH_ALEN]; /* first active MAC */
266 bool need_set_hw_addr;
267 bool found_active;
268 bool any_assoc;
269 enum nl80211_iftype opmode;
270 int n_stas;
271};
272void ath5k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif);
273
274
262#define ath5k_hw_hasbssidmask(_ah) \ 275#define ath5k_hw_hasbssidmask(_ah) \
263 (ath5k_hw_get_capability(_ah, AR5K_CAP_BSSIDMASK, 0, NULL) == 0) 276 (ath5k_hw_get_capability(_ah, AR5K_CAP_BSSIDMASK, 0, NULL) == 0)
264#define ath5k_hw_hasveol(_ah) \ 277#define ath5k_hw_hasveol(_ah) \
diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
index 1fbe3c0b9f08..c9b0b676adda 100644
--- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c
+++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
@@ -158,8 +158,7 @@ ath5k_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
158 158
159 memcpy(&avf->lladdr, vif->addr, ETH_ALEN); 159 memcpy(&avf->lladdr, vif->addr, ETH_ALEN);
160 160
161 ath5k_mode_setup(sc, vif); 161 ath5k_update_bssid_mask_and_opmode(sc, vif);
162
163 ret = 0; 162 ret = 0;
164end: 163end:
165 mutex_unlock(&sc->lock); 164 mutex_unlock(&sc->lock);
@@ -381,6 +380,7 @@ ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
381 struct ath5k_softc *sc = hw->priv; 380 struct ath5k_softc *sc = hw->priv;
382 struct ath5k_hw *ah = sc->ah; 381 struct ath5k_hw *ah = sc->ah;
383 u32 mfilt[2], rfilt; 382 u32 mfilt[2], rfilt;
383 struct ath5k_vif_iter_data iter_data; /* to count STA interfaces */
384 384
385 mutex_lock(&sc->lock); 385 mutex_lock(&sc->lock);
386 386
@@ -454,6 +454,21 @@ ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
454 break; 454 break;
455 } 455 }
456 456
457 iter_data.hw_macaddr = NULL;
458 iter_data.n_stas = 0;
459 iter_data.need_set_hw_addr = false;
460 ieee80211_iterate_active_interfaces_atomic(sc->hw, ath5k_vif_iter,
461 &iter_data);
462
463 /* Set up RX Filter */
464 if (iter_data.n_stas > 1) {
465 /* If you have multiple STA interfaces connected to
466 * different APs, ARPs are not received (most of the time?)
467 * Enabling PROMISC appears to fix that probem.
468 */
469 rfilt |= AR5K_RX_FILTER_PROM;
470 }
471
457 /* Set filters */ 472 /* Set filters */
458 ath5k_hw_set_rx_filter(ah, rfilt); 473 ath5k_hw_set_rx_filter(ah, rfilt);
459 474