diff options
author | Ben Greear <greearb@candelatech.com> | 2011-03-03 17:39:05 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-03-07 13:48:30 -0500 |
commit | e4b0b32aa1c0dd7ae6340833dd6b19de46409a88 (patch) | |
tree | 338fb13c5b0b3e0dbeb1aad68ed02ad77bfcbdc8 /drivers/net/wireless | |
parent | 410f2bb30d27252cc55a5f41668de60de62e5dc8 (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.c | 52 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath5k/base.h | 13 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath5k/mac80211-ops.c | 19 |
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 | ||
445 | struct ath_vif_iter_data { | 445 | void 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 | |||
455 | static 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 | ||
492 | void | 485 | void |
@@ -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 | ||
533 | void | 527 | /* Set up RX Filter */ |
534 | ath5k_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 | ||
547 | static inline int | 541 | static 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) | |||
2923 | bool | 2917 | bool |
2924 | ath_any_vif_assoc(struct ath5k_softc *sc) | 2918 | ath_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 | ||
262 | struct 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 | }; | ||
272 | void 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; |
164 | end: | 163 | end: |
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 | ||