diff options
author | Ben Greear <greearb@candelatech.com> | 2010-09-30 15:22:58 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-10-05 13:35:23 -0400 |
commit | b1ae1edf9e9872d3aa657cc34ae40c9aadfbc72f (patch) | |
tree | b2924525915d701ddef46f7c2e3832f8f1e28194 /drivers/net/wireless/ath/ath5k/base.c | |
parent | ea229e682633a18c1fa2c408400a6923cfc47910 (diff) |
ath5k: Allow ath5k to support virtual STA and AP interfaces.
Support up to 4 virtual APs and as many virtual STA interfaces
as desired.
This patch is ported forward from a patch that Patrick McHardy
did for me against 2.6.31.
Signed-off-by: Ben Greear <greearb@candelatech.com>
Acked-by: Bruno Randolf <br1@einfach.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath/ath5k/base.c')
-rw-r--r-- | drivers/net/wireless/ath/ath5k/base.c | 275 |
1 files changed, 232 insertions, 43 deletions
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 94cc3354f3a6..2ed327a8d690 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c | |||
@@ -52,6 +52,7 @@ | |||
52 | #include <linux/ethtool.h> | 52 | #include <linux/ethtool.h> |
53 | #include <linux/uaccess.h> | 53 | #include <linux/uaccess.h> |
54 | #include <linux/slab.h> | 54 | #include <linux/slab.h> |
55 | #include <linux/etherdevice.h> | ||
55 | 56 | ||
56 | #include <net/ieee80211_radiotap.h> | 57 | #include <net/ieee80211_radiotap.h> |
57 | 58 | ||
@@ -509,8 +510,71 @@ ath5k_setcurmode(struct ath5k_softc *sc, unsigned int mode) | |||
509 | } | 510 | } |
510 | } | 511 | } |
511 | 512 | ||
513 | struct ath_vif_iter_data { | ||
514 | const u8 *hw_macaddr; | ||
515 | u8 mask[ETH_ALEN]; | ||
516 | u8 active_mac[ETH_ALEN]; /* first active MAC */ | ||
517 | bool need_set_hw_addr; | ||
518 | bool found_active; | ||
519 | bool any_assoc; | ||
520 | }; | ||
521 | |||
522 | static void ath_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) | ||
523 | { | ||
524 | struct ath_vif_iter_data *iter_data = data; | ||
525 | int i; | ||
526 | |||
527 | if (iter_data->hw_macaddr) | ||
528 | for (i = 0; i < ETH_ALEN; i++) | ||
529 | iter_data->mask[i] &= | ||
530 | ~(iter_data->hw_macaddr[i] ^ mac[i]); | ||
531 | |||
532 | if (!iter_data->found_active) { | ||
533 | iter_data->found_active = true; | ||
534 | memcpy(iter_data->active_mac, mac, ETH_ALEN); | ||
535 | } | ||
536 | |||
537 | if (iter_data->need_set_hw_addr && iter_data->hw_macaddr) | ||
538 | if (compare_ether_addr(iter_data->hw_macaddr, mac) == 0) | ||
539 | iter_data->need_set_hw_addr = false; | ||
540 | |||
541 | if (!iter_data->any_assoc) { | ||
542 | struct ath5k_vif *avf = (void *)vif->drv_priv; | ||
543 | if (avf->assoc) | ||
544 | iter_data->any_assoc = true; | ||
545 | } | ||
546 | } | ||
547 | |||
548 | void ath5k_update_bssid_mask(struct ath5k_softc *sc, struct ieee80211_vif *vif) | ||
549 | { | ||
550 | struct ath_common *common = ath5k_hw_common(sc->ah); | ||
551 | struct ath_vif_iter_data iter_data; | ||
552 | |||
553 | /* | ||
554 | * Use the hardware MAC address as reference, the hardware uses it | ||
555 | * together with the BSSID mask when matching addresses. | ||
556 | */ | ||
557 | iter_data.hw_macaddr = common->macaddr; | ||
558 | memset(&iter_data.mask, 0xff, ETH_ALEN); | ||
559 | iter_data.found_active = false; | ||
560 | iter_data.need_set_hw_addr = true; | ||
561 | |||
562 | if (vif) | ||
563 | ath_vif_iter(&iter_data, vif->addr, vif); | ||
564 | |||
565 | /* Get list of all active MAC addresses */ | ||
566 | ieee80211_iterate_active_interfaces_atomic(sc->hw, ath_vif_iter, | ||
567 | &iter_data); | ||
568 | memcpy(sc->bssidmask, iter_data.mask, ETH_ALEN); | ||
569 | |||
570 | if (iter_data.need_set_hw_addr && iter_data.found_active) | ||
571 | ath5k_hw_set_lladdr(sc->ah, iter_data.active_mac); | ||
572 | |||
573 | ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask); | ||
574 | } | ||
575 | |||
512 | static void | 576 | static void |
513 | ath5k_mode_setup(struct ath5k_softc *sc) | 577 | ath5k_mode_setup(struct ath5k_softc *sc, struct ieee80211_vif *vif) |
514 | { | 578 | { |
515 | struct ath5k_hw *ah = sc->ah; | 579 | struct ath5k_hw *ah = sc->ah; |
516 | u32 rfilt; | 580 | u32 rfilt; |
@@ -520,7 +584,7 @@ ath5k_mode_setup(struct ath5k_softc *sc) | |||
520 | ath5k_hw_set_rx_filter(ah, rfilt); | 584 | ath5k_hw_set_rx_filter(ah, rfilt); |
521 | 585 | ||
522 | if (ath5k_hw_hasbssidmask(ah)) | 586 | if (ath5k_hw_hasbssidmask(ah)) |
523 | ath5k_hw_set_bssid_mask(ah, sc->bssidmask); | 587 | ath5k_update_bssid_mask(sc, vif); |
524 | 588 | ||
525 | /* configure operational mode */ | 589 | /* configure operational mode */ |
526 | ath5k_hw_set_opmode(ah, sc->opmode); | 590 | ath5k_hw_set_opmode(ah, sc->opmode); |
@@ -698,13 +762,13 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, | |||
698 | flags |= AR5K_TXDESC_RTSENA; | 762 | flags |= AR5K_TXDESC_RTSENA; |
699 | cts_rate = ieee80211_get_rts_cts_rate(sc->hw, info)->hw_value; | 763 | cts_rate = ieee80211_get_rts_cts_rate(sc->hw, info)->hw_value; |
700 | duration = le16_to_cpu(ieee80211_rts_duration(sc->hw, | 764 | duration = le16_to_cpu(ieee80211_rts_duration(sc->hw, |
701 | sc->vif, pktlen, info)); | 765 | info->control.vif, pktlen, info)); |
702 | } | 766 | } |
703 | if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { | 767 | if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { |
704 | flags |= AR5K_TXDESC_CTSENA; | 768 | flags |= AR5K_TXDESC_CTSENA; |
705 | cts_rate = ieee80211_get_rts_cts_rate(sc->hw, info)->hw_value; | 769 | cts_rate = ieee80211_get_rts_cts_rate(sc->hw, info)->hw_value; |
706 | duration = le16_to_cpu(ieee80211_ctstoself_duration(sc->hw, | 770 | duration = le16_to_cpu(ieee80211_ctstoself_duration(sc->hw, |
707 | sc->vif, pktlen, info)); | 771 | info->control.vif, pktlen, info)); |
708 | } | 772 | } |
709 | ret = ah->ah_setup_tx_desc(ah, ds, pktlen, | 773 | ret = ah->ah_setup_tx_desc(ah, ds, pktlen, |
710 | ieee80211_get_hdrlen_from_skb(skb), padsize, | 774 | ieee80211_get_hdrlen_from_skb(skb), padsize, |
@@ -806,10 +870,13 @@ ath5k_desc_alloc(struct ath5k_softc *sc, struct pci_dev *pdev) | |||
806 | list_add_tail(&bf->list, &sc->txbuf); | 870 | list_add_tail(&bf->list, &sc->txbuf); |
807 | } | 871 | } |
808 | 872 | ||
809 | /* beacon buffer */ | 873 | /* beacon buffers */ |
810 | bf->desc = ds; | 874 | INIT_LIST_HEAD(&sc->bcbuf); |
811 | bf->daddr = da; | 875 | for (i = 0; i < ATH_BCBUF; i++, bf++, ds++, da += sizeof(*ds)) { |
812 | sc->bbuf = bf; | 876 | bf->desc = ds; |
877 | bf->daddr = da; | ||
878 | list_add_tail(&bf->list, &sc->bcbuf); | ||
879 | } | ||
813 | 880 | ||
814 | return 0; | 881 | return 0; |
815 | err_free: | 882 | err_free: |
@@ -824,11 +891,12 @@ ath5k_desc_free(struct ath5k_softc *sc, struct pci_dev *pdev) | |||
824 | { | 891 | { |
825 | struct ath5k_buf *bf; | 892 | struct ath5k_buf *bf; |
826 | 893 | ||
827 | ath5k_txbuf_free_skb(sc, sc->bbuf); | ||
828 | list_for_each_entry(bf, &sc->txbuf, list) | 894 | list_for_each_entry(bf, &sc->txbuf, list) |
829 | ath5k_txbuf_free_skb(sc, bf); | 895 | ath5k_txbuf_free_skb(sc, bf); |
830 | list_for_each_entry(bf, &sc->rxbuf, list) | 896 | list_for_each_entry(bf, &sc->rxbuf, list) |
831 | ath5k_rxbuf_free_skb(sc, bf); | 897 | ath5k_rxbuf_free_skb(sc, bf); |
898 | list_for_each_entry(bf, &sc->bcbuf, list) | ||
899 | ath5k_txbuf_free_skb(sc, bf); | ||
832 | 900 | ||
833 | /* Free memory associated with all descriptors */ | 901 | /* Free memory associated with all descriptors */ |
834 | pci_free_consistent(pdev, sc->desc_len, sc->desc, sc->desc_daddr); | 902 | pci_free_consistent(pdev, sc->desc_len, sc->desc, sc->desc_daddr); |
@@ -837,7 +905,6 @@ ath5k_desc_free(struct ath5k_softc *sc, struct pci_dev *pdev) | |||
837 | 905 | ||
838 | kfree(sc->bufptr); | 906 | kfree(sc->bufptr); |
839 | sc->bufptr = NULL; | 907 | sc->bufptr = NULL; |
840 | sc->bbuf = NULL; | ||
841 | } | 908 | } |
842 | 909 | ||
843 | 910 | ||
@@ -1083,7 +1150,7 @@ ath5k_rx_start(struct ath5k_softc *sc) | |||
1083 | spin_unlock_bh(&sc->rxbuflock); | 1150 | spin_unlock_bh(&sc->rxbuflock); |
1084 | 1151 | ||
1085 | ath5k_hw_start_rx_dma(ah); /* enable recv descriptors */ | 1152 | ath5k_hw_start_rx_dma(ah); /* enable recv descriptors */ |
1086 | ath5k_mode_setup(sc); /* set filters, etc. */ | 1153 | ath5k_mode_setup(sc, NULL); /* set filters, etc. */ |
1087 | ath5k_hw_start_rx_pcu(ah); /* re-enable PCU/DMA engine */ | 1154 | ath5k_hw_start_rx_pcu(ah); /* re-enable PCU/DMA engine */ |
1088 | 1155 | ||
1089 | return 0; | 1156 | return 0; |
@@ -1750,6 +1817,7 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif) | |||
1750 | { | 1817 | { |
1751 | int ret; | 1818 | int ret; |
1752 | struct ath5k_softc *sc = hw->priv; | 1819 | struct ath5k_softc *sc = hw->priv; |
1820 | struct ath5k_vif *avf = (void *)vif->drv_priv; | ||
1753 | struct sk_buff *skb; | 1821 | struct sk_buff *skb; |
1754 | 1822 | ||
1755 | if (WARN_ON(!vif)) { | 1823 | if (WARN_ON(!vif)) { |
@@ -1766,11 +1834,11 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif) | |||
1766 | 1834 | ||
1767 | ath5k_debug_dump_skb(sc, skb, "BC ", 1); | 1835 | ath5k_debug_dump_skb(sc, skb, "BC ", 1); |
1768 | 1836 | ||
1769 | ath5k_txbuf_free_skb(sc, sc->bbuf); | 1837 | ath5k_txbuf_free_skb(sc, avf->bbuf); |
1770 | sc->bbuf->skb = skb; | 1838 | avf->bbuf->skb = skb; |
1771 | ret = ath5k_beacon_setup(sc, sc->bbuf); | 1839 | ret = ath5k_beacon_setup(sc, avf->bbuf); |
1772 | if (ret) | 1840 | if (ret) |
1773 | sc->bbuf->skb = NULL; | 1841 | avf->bbuf->skb = NULL; |
1774 | out: | 1842 | out: |
1775 | return ret; | 1843 | return ret; |
1776 | } | 1844 | } |
@@ -1786,16 +1854,14 @@ out: | |||
1786 | static void | 1854 | static void |
1787 | ath5k_beacon_send(struct ath5k_softc *sc) | 1855 | ath5k_beacon_send(struct ath5k_softc *sc) |
1788 | { | 1856 | { |
1789 | struct ath5k_buf *bf = sc->bbuf; | ||
1790 | struct ath5k_hw *ah = sc->ah; | 1857 | struct ath5k_hw *ah = sc->ah; |
1858 | struct ieee80211_vif *vif; | ||
1859 | struct ath5k_vif *avf; | ||
1860 | struct ath5k_buf *bf; | ||
1791 | struct sk_buff *skb; | 1861 | struct sk_buff *skb; |
1792 | 1862 | ||
1793 | ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, "in beacon_send\n"); | 1863 | ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, "in beacon_send\n"); |
1794 | 1864 | ||
1795 | if (unlikely(bf->skb == NULL || sc->opmode == NL80211_IFTYPE_STATION)) { | ||
1796 | ATH5K_WARN(sc, "bf=%p bf_skb=%p\n", bf, bf ? bf->skb : NULL); | ||
1797 | return; | ||
1798 | } | ||
1799 | /* | 1865 | /* |
1800 | * Check if the previous beacon has gone out. If | 1866 | * Check if the previous beacon has gone out. If |
1801 | * not, don't don't try to post another: skip this | 1867 | * not, don't don't try to post another: skip this |
@@ -1824,6 +1890,28 @@ ath5k_beacon_send(struct ath5k_softc *sc) | |||
1824 | sc->bmisscount = 0; | 1890 | sc->bmisscount = 0; |
1825 | } | 1891 | } |
1826 | 1892 | ||
1893 | if (sc->opmode == NL80211_IFTYPE_AP && sc->num_ap_vifs > 1) { | ||
1894 | u64 tsf = ath5k_hw_get_tsf64(ah); | ||
1895 | u32 tsftu = TSF_TO_TU(tsf); | ||
1896 | int slot = ((tsftu % sc->bintval) * ATH_BCBUF) / sc->bintval; | ||
1897 | vif = sc->bslot[(slot + 1) % ATH_BCBUF]; | ||
1898 | ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, | ||
1899 | "tsf %llx tsftu %x intval %u slot %u vif %p\n", | ||
1900 | (unsigned long long)tsf, tsftu, sc->bintval, slot, vif); | ||
1901 | } else /* only one interface */ | ||
1902 | vif = sc->bslot[0]; | ||
1903 | |||
1904 | if (!vif) | ||
1905 | return; | ||
1906 | |||
1907 | avf = (void *)vif->drv_priv; | ||
1908 | bf = avf->bbuf; | ||
1909 | if (unlikely(bf->skb == NULL || sc->opmode == NL80211_IFTYPE_STATION || | ||
1910 | sc->opmode == NL80211_IFTYPE_MONITOR)) { | ||
1911 | ATH5K_WARN(sc, "bf=%p bf_skb=%p\n", bf, bf ? bf->skb : NULL); | ||
1912 | return; | ||
1913 | } | ||
1914 | |||
1827 | /* | 1915 | /* |
1828 | * Stop any current dma and put the new frame on the queue. | 1916 | * Stop any current dma and put the new frame on the queue. |
1829 | * This should never fail since we check above that no frames | 1917 | * This should never fail since we check above that no frames |
@@ -1836,17 +1924,17 @@ ath5k_beacon_send(struct ath5k_softc *sc) | |||
1836 | 1924 | ||
1837 | /* refresh the beacon for AP mode */ | 1925 | /* refresh the beacon for AP mode */ |
1838 | if (sc->opmode == NL80211_IFTYPE_AP) | 1926 | if (sc->opmode == NL80211_IFTYPE_AP) |
1839 | ath5k_beacon_update(sc->hw, sc->vif); | 1927 | ath5k_beacon_update(sc->hw, vif); |
1840 | 1928 | ||
1841 | ath5k_hw_set_txdp(ah, sc->bhalq, bf->daddr); | 1929 | ath5k_hw_set_txdp(ah, sc->bhalq, bf->daddr); |
1842 | ath5k_hw_start_tx_dma(ah, sc->bhalq); | 1930 | ath5k_hw_start_tx_dma(ah, sc->bhalq); |
1843 | ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "TXDP[%u] = %llx (%p)\n", | 1931 | ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "TXDP[%u] = %llx (%p)\n", |
1844 | sc->bhalq, (unsigned long long)bf->daddr, bf->desc); | 1932 | sc->bhalq, (unsigned long long)bf->daddr, bf->desc); |
1845 | 1933 | ||
1846 | skb = ieee80211_get_buffered_bc(sc->hw, sc->vif); | 1934 | skb = ieee80211_get_buffered_bc(sc->hw, vif); |
1847 | while (skb) { | 1935 | while (skb) { |
1848 | ath5k_tx_queue(sc->hw, skb, sc->cabq); | 1936 | ath5k_tx_queue(sc->hw, skb, sc->cabq); |
1849 | skb = ieee80211_get_buffered_bc(sc->hw, sc->vif); | 1937 | skb = ieee80211_get_buffered_bc(sc->hw, vif); |
1850 | } | 1938 | } |
1851 | 1939 | ||
1852 | sc->bsent++; | 1940 | sc->bsent++; |
@@ -1876,6 +1964,12 @@ ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf) | |||
1876 | u64 hw_tsf; | 1964 | u64 hw_tsf; |
1877 | 1965 | ||
1878 | intval = sc->bintval & AR5K_BEACON_PERIOD; | 1966 | intval = sc->bintval & AR5K_BEACON_PERIOD; |
1967 | if (sc->opmode == NL80211_IFTYPE_AP && sc->num_ap_vifs > 1) { | ||
1968 | intval /= ATH_BCBUF; /* staggered multi-bss beacons */ | ||
1969 | if (intval < 15) | ||
1970 | ATH5K_WARN(sc, "intval %u is too low, min 15\n", | ||
1971 | intval); | ||
1972 | } | ||
1879 | if (WARN_ON(!intval)) | 1973 | if (WARN_ON(!intval)) |
1880 | return; | 1974 | return; |
1881 | 1975 | ||
@@ -2323,6 +2417,10 @@ ath5k_init(struct ath5k_softc *sc) | |||
2323 | ath_hw_keyreset(common, (u16) i); | 2417 | ath_hw_keyreset(common, (u16) i); |
2324 | 2418 | ||
2325 | ath5k_hw_set_ack_bitrate_high(ah, true); | 2419 | ath5k_hw_set_ack_bitrate_high(ah, true); |
2420 | |||
2421 | for (i = 0; i < ARRAY_SIZE(sc->bslot); i++) | ||
2422 | sc->bslot[i] = NULL; | ||
2423 | |||
2326 | ret = 0; | 2424 | ret = 0; |
2327 | done: | 2425 | done: |
2328 | mmiowb(); | 2426 | mmiowb(); |
@@ -2382,7 +2480,6 @@ ath5k_stop_hw(struct ath5k_softc *sc) | |||
2382 | ATH5K_DBG(sc, ATH5K_DEBUG_RESET, | 2480 | ATH5K_DBG(sc, ATH5K_DEBUG_RESET, |
2383 | "putting device to sleep\n"); | 2481 | "putting device to sleep\n"); |
2384 | } | 2482 | } |
2385 | ath5k_txbuf_free_skb(sc, sc->bbuf); | ||
2386 | 2483 | ||
2387 | mmiowb(); | 2484 | mmiowb(); |
2388 | mutex_unlock(&sc->lock); | 2485 | mutex_unlock(&sc->lock); |
@@ -2587,9 +2684,9 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) | |||
2587 | } | 2684 | } |
2588 | 2685 | ||
2589 | SET_IEEE80211_PERM_ADDR(hw, mac); | 2686 | SET_IEEE80211_PERM_ADDR(hw, mac); |
2687 | memcpy(&sc->lladdr, mac, ETH_ALEN); | ||
2590 | /* All MAC address bits matter for ACKs */ | 2688 | /* All MAC address bits matter for ACKs */ |
2591 | memcpy(sc->bssidmask, ath_bcast_mac, ETH_ALEN); | 2689 | ath5k_update_bssid_mask(sc, NULL); |
2592 | ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask); | ||
2593 | 2690 | ||
2594 | regulatory->current_rd = ah->ah_capabilities.cap_eeprom.ee_regdomain; | 2691 | regulatory->current_rd = ah->ah_capabilities.cap_eeprom.ee_regdomain; |
2595 | ret = ath_regd_init(regulatory, hw->wiphy, ath5k_reg_notifier); | 2692 | ret = ath_regd_init(regulatory, hw->wiphy, ath5k_reg_notifier); |
@@ -2687,31 +2784,91 @@ static int ath5k_add_interface(struct ieee80211_hw *hw, | |||
2687 | { | 2784 | { |
2688 | struct ath5k_softc *sc = hw->priv; | 2785 | struct ath5k_softc *sc = hw->priv; |
2689 | int ret; | 2786 | int ret; |
2787 | struct ath5k_hw *ah = sc->ah; | ||
2788 | struct ath5k_vif *avf = (void *)vif->drv_priv; | ||
2690 | 2789 | ||
2691 | mutex_lock(&sc->lock); | 2790 | mutex_lock(&sc->lock); |
2692 | if (sc->vif) { | 2791 | |
2693 | ret = 0; | 2792 | if ((vif->type == NL80211_IFTYPE_AP || |
2793 | vif->type == NL80211_IFTYPE_ADHOC) | ||
2794 | && (sc->num_ap_vifs + sc->num_adhoc_vifs) >= ATH_BCBUF) { | ||
2795 | ret = -ELNRNG; | ||
2694 | goto end; | 2796 | goto end; |
2695 | } | 2797 | } |
2696 | 2798 | ||
2697 | sc->vif = vif; | 2799 | /* Don't allow other interfaces if one ad-hoc is configured. |
2800 | * TODO: Fix the problems with ad-hoc and multiple other interfaces. | ||
2801 | * We would need to operate the HW in ad-hoc mode to allow TSF updates | ||
2802 | * for the IBSS, but this breaks with additional AP or STA interfaces | ||
2803 | * at the moment. */ | ||
2804 | if (sc->num_adhoc_vifs || | ||
2805 | (sc->nvifs && vif->type == NL80211_IFTYPE_ADHOC)) { | ||
2806 | ATH5K_ERR(sc, "Only one single ad-hoc interface is allowed.\n"); | ||
2807 | ret = -ELNRNG; | ||
2808 | goto end; | ||
2809 | } | ||
2698 | 2810 | ||
2699 | switch (vif->type) { | 2811 | switch (vif->type) { |
2700 | case NL80211_IFTYPE_AP: | 2812 | case NL80211_IFTYPE_AP: |
2701 | case NL80211_IFTYPE_STATION: | 2813 | case NL80211_IFTYPE_STATION: |
2702 | case NL80211_IFTYPE_ADHOC: | 2814 | case NL80211_IFTYPE_ADHOC: |
2703 | case NL80211_IFTYPE_MESH_POINT: | 2815 | case NL80211_IFTYPE_MESH_POINT: |
2704 | sc->opmode = vif->type; | 2816 | avf->opmode = vif->type; |
2705 | break; | 2817 | break; |
2706 | default: | 2818 | default: |
2707 | ret = -EOPNOTSUPP; | 2819 | ret = -EOPNOTSUPP; |
2708 | goto end; | 2820 | goto end; |
2709 | } | 2821 | } |
2710 | 2822 | ||
2711 | ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "add interface mode %d\n", sc->opmode); | 2823 | sc->nvifs++; |
2824 | ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "add interface mode %d\n", avf->opmode); | ||
2712 | 2825 | ||
2826 | /* Assign the vap/adhoc to a beacon xmit slot. */ | ||
2827 | if ((avf->opmode == NL80211_IFTYPE_AP) || | ||
2828 | (avf->opmode == NL80211_IFTYPE_ADHOC)) { | ||
2829 | int slot; | ||
2830 | |||
2831 | WARN_ON(list_empty(&sc->bcbuf)); | ||
2832 | avf->bbuf = list_first_entry(&sc->bcbuf, struct ath5k_buf, | ||
2833 | list); | ||
2834 | list_del(&avf->bbuf->list); | ||
2835 | |||
2836 | avf->bslot = 0; | ||
2837 | for (slot = 0; slot < ATH_BCBUF; slot++) { | ||
2838 | if (!sc->bslot[slot]) { | ||
2839 | avf->bslot = slot; | ||
2840 | break; | ||
2841 | } | ||
2842 | } | ||
2843 | BUG_ON(sc->bslot[avf->bslot] != NULL); | ||
2844 | sc->bslot[avf->bslot] = vif; | ||
2845 | if (avf->opmode == NL80211_IFTYPE_AP) | ||
2846 | sc->num_ap_vifs++; | ||
2847 | else | ||
2848 | sc->num_adhoc_vifs++; | ||
2849 | } | ||
2850 | |||
2851 | /* Set combined mode - when APs are configured, operate in AP mode. | ||
2852 | * Otherwise use the mode of the new interface. This can currently | ||
2853 | * only deal with combinations of APs and STAs. Only one ad-hoc | ||
2854 | * interfaces is allowed above. | ||
2855 | */ | ||
2856 | if (sc->num_ap_vifs) | ||
2857 | sc->opmode = NL80211_IFTYPE_AP; | ||
2858 | else | ||
2859 | sc->opmode = vif->type; | ||
2860 | |||
2861 | ath5k_hw_set_opmode(ah, sc->opmode); | ||
2862 | |||
2863 | /* Any MAC address is fine, all others are included through the | ||
2864 | * filter. | ||
2865 | */ | ||
2866 | memcpy(&sc->lladdr, vif->addr, ETH_ALEN); | ||
2713 | ath5k_hw_set_lladdr(sc->ah, vif->addr); | 2867 | ath5k_hw_set_lladdr(sc->ah, vif->addr); |
2714 | ath5k_mode_setup(sc); | 2868 | |
2869 | memcpy(&avf->lladdr, vif->addr, ETH_ALEN); | ||
2870 | |||
2871 | ath5k_mode_setup(sc, vif); | ||
2715 | 2872 | ||
2716 | ret = 0; | 2873 | ret = 0; |
2717 | end: | 2874 | end: |
@@ -2724,15 +2881,29 @@ ath5k_remove_interface(struct ieee80211_hw *hw, | |||
2724 | struct ieee80211_vif *vif) | 2881 | struct ieee80211_vif *vif) |
2725 | { | 2882 | { |
2726 | struct ath5k_softc *sc = hw->priv; | 2883 | struct ath5k_softc *sc = hw->priv; |
2727 | u8 mac[ETH_ALEN] = {}; | 2884 | struct ath5k_vif *avf = (void *)vif->drv_priv; |
2885 | unsigned int i; | ||
2728 | 2886 | ||
2729 | mutex_lock(&sc->lock); | 2887 | mutex_lock(&sc->lock); |
2730 | if (sc->vif != vif) | 2888 | sc->nvifs--; |
2731 | goto end; | 2889 | |
2890 | if (avf->bbuf) { | ||
2891 | ath5k_txbuf_free_skb(sc, avf->bbuf); | ||
2892 | list_add_tail(&avf->bbuf->list, &sc->bcbuf); | ||
2893 | for (i = 0; i < ATH_BCBUF; i++) { | ||
2894 | if (sc->bslot[i] == vif) { | ||
2895 | sc->bslot[i] = NULL; | ||
2896 | break; | ||
2897 | } | ||
2898 | } | ||
2899 | avf->bbuf = NULL; | ||
2900 | } | ||
2901 | if (avf->opmode == NL80211_IFTYPE_AP) | ||
2902 | sc->num_ap_vifs--; | ||
2903 | else if (avf->opmode == NL80211_IFTYPE_ADHOC) | ||
2904 | sc->num_adhoc_vifs--; | ||
2732 | 2905 | ||
2733 | ath5k_hw_set_lladdr(sc->ah, mac); | 2906 | ath5k_update_bssid_mask(sc, NULL); |
2734 | sc->vif = NULL; | ||
2735 | end: | ||
2736 | mutex_unlock(&sc->lock); | 2907 | mutex_unlock(&sc->lock); |
2737 | } | 2908 | } |
2738 | 2909 | ||
@@ -2815,6 +2986,19 @@ static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw, | |||
2815 | return ((u64)(mfilt[1]) << 32) | mfilt[0]; | 2986 | return ((u64)(mfilt[1]) << 32) | mfilt[0]; |
2816 | } | 2987 | } |
2817 | 2988 | ||
2989 | static bool ath_any_vif_assoc(struct ath5k_softc *sc) | ||
2990 | { | ||
2991 | struct ath_vif_iter_data iter_data; | ||
2992 | iter_data.hw_macaddr = NULL; | ||
2993 | iter_data.any_assoc = false; | ||
2994 | iter_data.need_set_hw_addr = false; | ||
2995 | iter_data.found_active = true; | ||
2996 | |||
2997 | ieee80211_iterate_active_interfaces_atomic(sc->hw, ath_vif_iter, | ||
2998 | &iter_data); | ||
2999 | return iter_data.any_assoc; | ||
3000 | } | ||
3001 | |||
2818 | #define SUPPORTED_FIF_FLAGS \ | 3002 | #define SUPPORTED_FIF_FLAGS \ |
2819 | FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | \ | 3003 | FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | \ |
2820 | FIF_PLCPFAIL | FIF_CONTROL | FIF_OTHER_BSS | \ | 3004 | FIF_PLCPFAIL | FIF_CONTROL | FIF_OTHER_BSS | \ |
@@ -2885,7 +3069,7 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw, | |||
2885 | 3069 | ||
2886 | /* FIF_BCN_PRBRESP_PROMISC really means to enable beacons | 3070 | /* FIF_BCN_PRBRESP_PROMISC really means to enable beacons |
2887 | * and probes for any BSSID */ | 3071 | * and probes for any BSSID */ |
2888 | if (*new_flags & FIF_BCN_PRBRESP_PROMISC) | 3072 | if ((*new_flags & FIF_BCN_PRBRESP_PROMISC) || (sc->nvifs > 1)) |
2889 | rfilt |= AR5K_RX_FILTER_BEACON; | 3073 | rfilt |= AR5K_RX_FILTER_BEACON; |
2890 | 3074 | ||
2891 | /* FIF_CONTROL doc says that if FIF_PROMISC_IN_BSS is not | 3075 | /* FIF_CONTROL doc says that if FIF_PROMISC_IN_BSS is not |
@@ -3070,14 +3254,13 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw, | |||
3070 | struct ieee80211_bss_conf *bss_conf, | 3254 | struct ieee80211_bss_conf *bss_conf, |
3071 | u32 changes) | 3255 | u32 changes) |
3072 | { | 3256 | { |
3257 | struct ath5k_vif *avf = (void *)vif->drv_priv; | ||
3073 | struct ath5k_softc *sc = hw->priv; | 3258 | struct ath5k_softc *sc = hw->priv; |
3074 | struct ath5k_hw *ah = sc->ah; | 3259 | struct ath5k_hw *ah = sc->ah; |
3075 | struct ath_common *common = ath5k_hw_common(ah); | 3260 | struct ath_common *common = ath5k_hw_common(ah); |
3076 | unsigned long flags; | 3261 | unsigned long flags; |
3077 | 3262 | ||
3078 | mutex_lock(&sc->lock); | 3263 | mutex_lock(&sc->lock); |
3079 | if (WARN_ON(sc->vif != vif)) | ||
3080 | goto unlock; | ||
3081 | 3264 | ||
3082 | if (changes & BSS_CHANGED_BSSID) { | 3265 | if (changes & BSS_CHANGED_BSSID) { |
3083 | /* Cache for later use during resets */ | 3266 | /* Cache for later use during resets */ |
@@ -3091,7 +3274,12 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw, | |||
3091 | sc->bintval = bss_conf->beacon_int; | 3274 | sc->bintval = bss_conf->beacon_int; |
3092 | 3275 | ||
3093 | if (changes & BSS_CHANGED_ASSOC) { | 3276 | if (changes & BSS_CHANGED_ASSOC) { |
3094 | sc->assoc = bss_conf->assoc; | 3277 | avf->assoc = bss_conf->assoc; |
3278 | if (bss_conf->assoc) | ||
3279 | sc->assoc = bss_conf->assoc; | ||
3280 | else | ||
3281 | sc->assoc = ath_any_vif_assoc(sc); | ||
3282 | |||
3095 | if (sc->opmode == NL80211_IFTYPE_STATION) | 3283 | if (sc->opmode == NL80211_IFTYPE_STATION) |
3096 | set_beacon_filter(hw, sc->assoc); | 3284 | set_beacon_filter(hw, sc->assoc); |
3097 | ath5k_hw_set_ledstate(sc->ah, sc->assoc ? | 3285 | ath5k_hw_set_ledstate(sc->ah, sc->assoc ? |
@@ -3119,7 +3307,6 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw, | |||
3119 | BSS_CHANGED_BEACON_INT)) | 3307 | BSS_CHANGED_BEACON_INT)) |
3120 | ath5k_beacon_config(sc); | 3308 | ath5k_beacon_config(sc); |
3121 | 3309 | ||
3122 | unlock: | ||
3123 | mutex_unlock(&sc->lock); | 3310 | mutex_unlock(&sc->lock); |
3124 | } | 3311 | } |
3125 | 3312 | ||
@@ -3394,6 +3581,8 @@ ath5k_pci_probe(struct pci_dev *pdev, | |||
3394 | hw->max_rate_tries = 11; | 3581 | hw->max_rate_tries = 11; |
3395 | } | 3582 | } |
3396 | 3583 | ||
3584 | hw->vif_data_size = sizeof(struct ath5k_vif); | ||
3585 | |||
3397 | /* Finish private driver data initialization */ | 3586 | /* Finish private driver data initialization */ |
3398 | ret = ath5k_attach(pdev, hw); | 3587 | ret = ath5k_attach(pdev, hw); |
3399 | if (ret) | 3588 | if (ret) |