diff options
Diffstat (limited to 'drivers/net/wireless/b43/main.c')
-rw-r--r-- | drivers/net/wireless/b43/main.c | 248 |
1 files changed, 132 insertions, 116 deletions
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index b44c9f928848..72467c86f8d4 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c | |||
@@ -92,14 +92,6 @@ static char modparam_fwpostfix[16]; | |||
92 | module_param_string(fwpostfix, modparam_fwpostfix, 16, 0444); | 92 | module_param_string(fwpostfix, modparam_fwpostfix, 16, 0444); |
93 | MODULE_PARM_DESC(fwpostfix, "Postfix for the .fw files to load."); | 93 | MODULE_PARM_DESC(fwpostfix, "Postfix for the .fw files to load."); |
94 | 94 | ||
95 | static int modparam_mon_keep_bad; | ||
96 | module_param_named(mon_keep_bad, modparam_mon_keep_bad, int, 0444); | ||
97 | MODULE_PARM_DESC(mon_keep_bad, "Keep bad frames in monitor mode"); | ||
98 | |||
99 | static int modparam_mon_keep_badplcp; | ||
100 | module_param_named(mon_keep_badplcp, modparam_mon_keep_bad, int, 0444); | ||
101 | MODULE_PARM_DESC(mon_keep_badplcp, "Keep frames with bad PLCP in monitor mode"); | ||
102 | |||
103 | static int modparam_hwpctl; | 95 | static int modparam_hwpctl; |
104 | module_param_named(hwpctl, modparam_hwpctl, int, 0444); | 96 | module_param_named(hwpctl, modparam_hwpctl, int, 0444); |
105 | MODULE_PARM_DESC(hwpctl, "Enable hardware-side power control (default off)"); | 97 | MODULE_PARM_DESC(hwpctl, "Enable hardware-side power control (default off)"); |
@@ -561,15 +553,10 @@ static void b43_write_mac_bssid_templates(struct b43_wldev *dev) | |||
561 | } | 553 | } |
562 | } | 554 | } |
563 | 555 | ||
564 | static void b43_upload_card_macaddress(struct b43_wldev *dev, | 556 | static void b43_upload_card_macaddress(struct b43_wldev *dev) |
565 | const u8 * mac_addr) | ||
566 | { | 557 | { |
567 | if (mac_addr) | ||
568 | memcpy(dev->wl->mac_addr, mac_addr, ETH_ALEN); | ||
569 | else | ||
570 | memset(dev->wl->mac_addr, 0, ETH_ALEN); | ||
571 | b43_write_mac_bssid_templates(dev); | 558 | b43_write_mac_bssid_templates(dev); |
572 | b43_macfilter_set(dev, B43_MACFILTER_SELF, mac_addr); | 559 | b43_macfilter_set(dev, B43_MACFILTER_SELF, dev->wl->mac_addr); |
573 | } | 560 | } |
574 | 561 | ||
575 | static void b43_set_slot_time(struct b43_wldev *dev, u16 slot_time) | 562 | static void b43_set_slot_time(struct b43_wldev *dev, u16 slot_time) |
@@ -2052,33 +2039,25 @@ static void b43_adjust_opmode(struct b43_wldev *dev) | |||
2052 | ctl &= ~B43_MACCTL_KEEP_BADPLCP; | 2039 | ctl &= ~B43_MACCTL_KEEP_BADPLCP; |
2053 | ctl &= ~B43_MACCTL_KEEP_BAD; | 2040 | ctl &= ~B43_MACCTL_KEEP_BAD; |
2054 | ctl &= ~B43_MACCTL_PROMISC; | 2041 | ctl &= ~B43_MACCTL_PROMISC; |
2042 | ctl &= ~B43_MACCTL_BEACPROMISC; | ||
2055 | ctl |= B43_MACCTL_INFRA; | 2043 | ctl |= B43_MACCTL_INFRA; |
2056 | 2044 | ||
2057 | if (wl->operating) { | 2045 | if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) |
2058 | switch (wl->if_type) { | 2046 | ctl |= B43_MACCTL_AP; |
2059 | case IEEE80211_IF_TYPE_AP: | 2047 | else if (b43_is_mode(wl, IEEE80211_IF_TYPE_IBSS)) |
2060 | ctl |= B43_MACCTL_AP; | 2048 | ctl &= ~B43_MACCTL_INFRA; |
2061 | break; | 2049 | |
2062 | case IEEE80211_IF_TYPE_IBSS: | 2050 | if (wl->filter_flags & FIF_CONTROL) |
2063 | ctl &= ~B43_MACCTL_INFRA; | ||
2064 | break; | ||
2065 | case IEEE80211_IF_TYPE_STA: | ||
2066 | case IEEE80211_IF_TYPE_MNTR: | ||
2067 | case IEEE80211_IF_TYPE_WDS: | ||
2068 | break; | ||
2069 | default: | ||
2070 | B43_WARN_ON(1); | ||
2071 | } | ||
2072 | } | ||
2073 | if (wl->monitor) { | ||
2074 | ctl |= B43_MACCTL_KEEP_CTL; | 2051 | ctl |= B43_MACCTL_KEEP_CTL; |
2075 | if (modparam_mon_keep_bad) | 2052 | if (wl->filter_flags & FIF_FCSFAIL) |
2076 | ctl |= B43_MACCTL_KEEP_BAD; | 2053 | ctl |= B43_MACCTL_KEEP_BAD; |
2077 | if (modparam_mon_keep_badplcp) | 2054 | if (wl->filter_flags & FIF_PLCPFAIL) |
2078 | ctl |= B43_MACCTL_KEEP_BADPLCP; | 2055 | ctl |= B43_MACCTL_KEEP_BADPLCP; |
2079 | } | 2056 | if (wl->filter_flags & FIF_PROMISC_IN_BSS) |
2080 | if (wl->promisc) | ||
2081 | ctl |= B43_MACCTL_PROMISC; | 2057 | ctl |= B43_MACCTL_PROMISC; |
2058 | if (wl->filter_flags & FIF_BCN_PRBRESP_PROMISC) | ||
2059 | ctl |= B43_MACCTL_BEACPROMISC; | ||
2060 | |||
2082 | /* Workaround: On old hardware the HW-MAC-address-filter | 2061 | /* Workaround: On old hardware the HW-MAC-address-filter |
2083 | * doesn't work properly, so always run promisc in filter | 2062 | * doesn't work properly, so always run promisc in filter |
2084 | * it in software. */ | 2063 | * it in software. */ |
@@ -2254,9 +2233,6 @@ static int b43_chip_init(struct b43_wldev *dev) | |||
2254 | & ~B43_MACCTL_INFRA); | 2233 | & ~B43_MACCTL_INFRA); |
2255 | b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL) | 2234 | b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL) |
2256 | | B43_MACCTL_INFRA); | 2235 | | B43_MACCTL_INFRA); |
2257 | /* Let beacons come through */ | ||
2258 | b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL) | ||
2259 | | B43_MACCTL_BEACPROMISC); | ||
2260 | 2236 | ||
2261 | if (b43_using_pio(dev)) { | 2237 | if (b43_using_pio(dev)) { |
2262 | b43_write32(dev, 0x0210, 0x00000100); | 2238 | b43_write32(dev, 0x0210, 0x00000100); |
@@ -2899,9 +2875,9 @@ static int b43_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) | |||
2899 | return err; | 2875 | return err; |
2900 | } | 2876 | } |
2901 | 2877 | ||
2902 | static int b43_dev_set_key(struct ieee80211_hw *hw, | 2878 | static int b43_dev_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, |
2903 | set_key_cmd cmd, const u8 *local_addr, | 2879 | const u8 *local_addr, const u8 *addr, |
2904 | const u8 *addr, struct ieee80211_key_conf *key) | 2880 | struct ieee80211_key_conf *key) |
2905 | { | 2881 | { |
2906 | struct b43_wl *wl = hw_to_b43_wl(hw); | 2882 | struct b43_wl *wl = hw_to_b43_wl(hw); |
2907 | struct b43_wldev *dev = wl->current_dev; | 2883 | struct b43_wldev *dev = wl->current_dev; |
@@ -3003,21 +2979,40 @@ out: | |||
3003 | return err; | 2979 | return err; |
3004 | } | 2980 | } |
3005 | 2981 | ||
3006 | static void b43_set_multicast_list(struct ieee80211_hw *hw, | 2982 | static void b43_configure_filter(struct ieee80211_hw *hw, |
3007 | unsigned short netflags, int mc_count) | 2983 | unsigned int changed, unsigned int *fflags, |
2984 | int mc_count, struct dev_addr_list *mc_list) | ||
3008 | { | 2985 | { |
3009 | struct b43_wl *wl = hw_to_b43_wl(hw); | 2986 | struct b43_wl *wl = hw_to_b43_wl(hw); |
3010 | struct b43_wldev *dev = wl->current_dev; | 2987 | struct b43_wldev *dev = wl->current_dev; |
3011 | unsigned long flags; | 2988 | unsigned long flags; |
3012 | 2989 | ||
3013 | if (!dev) | 2990 | if (!dev) { |
2991 | *fflags = 0; | ||
3014 | return; | 2992 | return; |
3015 | spin_lock_irqsave(&wl->irq_lock, flags); | ||
3016 | if (wl->promisc != !!(netflags & IFF_PROMISC)) { | ||
3017 | wl->promisc = !!(netflags & IFF_PROMISC); | ||
3018 | if (b43_status(dev) >= B43_STAT_INITIALIZED) | ||
3019 | b43_adjust_opmode(dev); | ||
3020 | } | 2993 | } |
2994 | |||
2995 | spin_lock_irqsave(&wl->irq_lock, flags); | ||
2996 | *fflags &= FIF_PROMISC_IN_BSS | | ||
2997 | FIF_ALLMULTI | | ||
2998 | FIF_FCSFAIL | | ||
2999 | FIF_PLCPFAIL | | ||
3000 | FIF_CONTROL | | ||
3001 | FIF_OTHER_BSS | | ||
3002 | FIF_BCN_PRBRESP_PROMISC; | ||
3003 | |||
3004 | changed &= FIF_PROMISC_IN_BSS | | ||
3005 | FIF_ALLMULTI | | ||
3006 | FIF_FCSFAIL | | ||
3007 | FIF_PLCPFAIL | | ||
3008 | FIF_CONTROL | | ||
3009 | FIF_OTHER_BSS | | ||
3010 | FIF_BCN_PRBRESP_PROMISC; | ||
3011 | |||
3012 | wl->filter_flags = *fflags; | ||
3013 | |||
3014 | if (changed && b43_status(dev) >= B43_STAT_INITIALIZED) | ||
3015 | b43_adjust_opmode(dev); | ||
3021 | spin_unlock_irqrestore(&wl->irq_lock, flags); | 3016 | spin_unlock_irqrestore(&wl->irq_lock, flags); |
3022 | } | 3017 | } |
3023 | 3018 | ||
@@ -3032,21 +3027,19 @@ static int b43_config_interface(struct ieee80211_hw *hw, | |||
3032 | return -ENODEV; | 3027 | return -ENODEV; |
3033 | mutex_lock(&wl->mutex); | 3028 | mutex_lock(&wl->mutex); |
3034 | spin_lock_irqsave(&wl->irq_lock, flags); | 3029 | spin_lock_irqsave(&wl->irq_lock, flags); |
3035 | if (conf->type != IEEE80211_IF_TYPE_MNTR) { | 3030 | B43_WARN_ON(wl->if_id != if_id); |
3036 | B43_WARN_ON(wl->if_id != if_id); | 3031 | if (conf->bssid) |
3037 | if (conf->bssid) | 3032 | memcpy(wl->bssid, conf->bssid, ETH_ALEN); |
3038 | memcpy(wl->bssid, conf->bssid, ETH_ALEN); | 3033 | else |
3039 | else | 3034 | memset(wl->bssid, 0, ETH_ALEN); |
3040 | memset(wl->bssid, 0, ETH_ALEN); | 3035 | if (b43_status(dev) >= B43_STAT_INITIALIZED) { |
3041 | if (b43_status(dev) >= B43_STAT_INITIALIZED) { | 3036 | if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) { |
3042 | if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) { | 3037 | B43_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP); |
3043 | B43_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP); | 3038 | b43_set_ssid(dev, conf->ssid, conf->ssid_len); |
3044 | b43_set_ssid(dev, conf->ssid, conf->ssid_len); | 3039 | if (conf->beacon) |
3045 | if (conf->beacon) | 3040 | b43_refresh_templates(dev, conf->beacon); |
3046 | b43_refresh_templates(dev, conf->beacon); | ||
3047 | } | ||
3048 | b43_write_mac_bssid_templates(dev); | ||
3049 | } | 3041 | } |
3042 | b43_write_mac_bssid_templates(dev); | ||
3050 | } | 3043 | } |
3051 | spin_unlock_irqrestore(&wl->irq_lock, flags); | 3044 | spin_unlock_irqrestore(&wl->irq_lock, flags); |
3052 | mutex_unlock(&wl->mutex); | 3045 | mutex_unlock(&wl->mutex); |
@@ -3472,7 +3465,8 @@ static int b43_wireless_core_init(struct b43_wldev *dev) | |||
3472 | 3465 | ||
3473 | ssb_bus_powerup(bus, 1); /* Enable dynamic PCTL */ | 3466 | ssb_bus_powerup(bus, 1); /* Enable dynamic PCTL */ |
3474 | memset(wl->bssid, 0, ETH_ALEN); | 3467 | memset(wl->bssid, 0, ETH_ALEN); |
3475 | b43_upload_card_macaddress(dev, NULL); | 3468 | memset(wl->mac_addr, 0, ETH_ALEN); |
3469 | b43_upload_card_macaddress(dev); | ||
3476 | b43_security_init(dev); | 3470 | b43_security_init(dev); |
3477 | b43_rng_init(wl); | 3471 | b43_rng_init(wl); |
3478 | 3472 | ||
@@ -3502,21 +3496,80 @@ static int b43_add_interface(struct ieee80211_hw *hw, | |||
3502 | struct b43_wldev *dev; | 3496 | struct b43_wldev *dev; |
3503 | unsigned long flags; | 3497 | unsigned long flags; |
3504 | int err = -EOPNOTSUPP; | 3498 | int err = -EOPNOTSUPP; |
3505 | int did_init = 0; | 3499 | |
3500 | /* TODO: allow WDS/AP devices to coexist */ | ||
3501 | |||
3502 | if (conf->type != IEEE80211_IF_TYPE_AP && | ||
3503 | conf->type != IEEE80211_IF_TYPE_STA && | ||
3504 | conf->type != IEEE80211_IF_TYPE_WDS && | ||
3505 | conf->type != IEEE80211_IF_TYPE_IBSS) | ||
3506 | return -EOPNOTSUPP; | ||
3506 | 3507 | ||
3507 | mutex_lock(&wl->mutex); | 3508 | mutex_lock(&wl->mutex); |
3508 | if ((conf->type != IEEE80211_IF_TYPE_MNTR) && wl->operating) | 3509 | if (wl->operating) |
3509 | goto out_mutex_unlock; | 3510 | goto out_mutex_unlock; |
3510 | 3511 | ||
3511 | b43dbg(wl, "Adding Interface type %d\n", conf->type); | 3512 | b43dbg(wl, "Adding Interface type %d\n", conf->type); |
3512 | 3513 | ||
3513 | dev = wl->current_dev; | 3514 | dev = wl->current_dev; |
3515 | wl->operating = 1; | ||
3516 | wl->if_id = conf->if_id; | ||
3517 | wl->if_type = conf->type; | ||
3518 | memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN); | ||
3519 | |||
3520 | spin_lock_irqsave(&wl->irq_lock, flags); | ||
3521 | b43_adjust_opmode(dev); | ||
3522 | b43_upload_card_macaddress(dev); | ||
3523 | spin_unlock_irqrestore(&wl->irq_lock, flags); | ||
3524 | |||
3525 | err = 0; | ||
3526 | out_mutex_unlock: | ||
3527 | mutex_unlock(&wl->mutex); | ||
3528 | |||
3529 | return err; | ||
3530 | } | ||
3531 | |||
3532 | static void b43_remove_interface(struct ieee80211_hw *hw, | ||
3533 | struct ieee80211_if_init_conf *conf) | ||
3534 | { | ||
3535 | struct b43_wl *wl = hw_to_b43_wl(hw); | ||
3536 | struct b43_wldev *dev = wl->current_dev; | ||
3537 | unsigned long flags; | ||
3538 | |||
3539 | b43dbg(wl, "Removing Interface type %d\n", conf->type); | ||
3540 | |||
3541 | mutex_lock(&wl->mutex); | ||
3542 | |||
3543 | B43_WARN_ON(!wl->operating); | ||
3544 | B43_WARN_ON(wl->if_id != conf->if_id); | ||
3545 | |||
3546 | wl->operating = 0; | ||
3547 | |||
3548 | spin_lock_irqsave(&wl->irq_lock, flags); | ||
3549 | b43_adjust_opmode(dev); | ||
3550 | memset(wl->mac_addr, 0, ETH_ALEN); | ||
3551 | b43_upload_card_macaddress(dev); | ||
3552 | spin_unlock_irqrestore(&wl->irq_lock, flags); | ||
3553 | |||
3554 | mutex_unlock(&wl->mutex); | ||
3555 | } | ||
3556 | |||
3557 | static int b43_start(struct ieee80211_hw *hw) | ||
3558 | { | ||
3559 | struct b43_wl *wl = hw_to_b43_wl(hw); | ||
3560 | struct b43_wldev *dev = wl->current_dev; | ||
3561 | int did_init = 0; | ||
3562 | int err; | ||
3563 | |||
3564 | mutex_lock(&wl->mutex); | ||
3565 | |||
3514 | if (b43_status(dev) < B43_STAT_INITIALIZED) { | 3566 | if (b43_status(dev) < B43_STAT_INITIALIZED) { |
3515 | err = b43_wireless_core_init(dev); | 3567 | err = b43_wireless_core_init(dev); |
3516 | if (err) | 3568 | if (err) |
3517 | goto out_mutex_unlock; | 3569 | goto out_mutex_unlock; |
3518 | did_init = 1; | 3570 | did_init = 1; |
3519 | } | 3571 | } |
3572 | |||
3520 | if (b43_status(dev) < B43_STAT_STARTED) { | 3573 | if (b43_status(dev) < B43_STAT_STARTED) { |
3521 | err = b43_wireless_core_start(dev); | 3574 | err = b43_wireless_core_start(dev); |
3522 | if (err) { | 3575 | if (err) { |
@@ -3526,59 +3579,21 @@ static int b43_add_interface(struct ieee80211_hw *hw, | |||
3526 | } | 3579 | } |
3527 | } | 3580 | } |
3528 | 3581 | ||
3529 | spin_lock_irqsave(&wl->irq_lock, flags); | 3582 | out_mutex_unlock: |
3530 | switch (conf->type) { | ||
3531 | case IEEE80211_IF_TYPE_MNTR: | ||
3532 | wl->monitor++; | ||
3533 | break; | ||
3534 | default: | ||
3535 | wl->operating = 1; | ||
3536 | wl->if_id = conf->if_id; | ||
3537 | wl->if_type = conf->type; | ||
3538 | b43_upload_card_macaddress(dev, conf->mac_addr); | ||
3539 | } | ||
3540 | b43_adjust_opmode(dev); | ||
3541 | spin_unlock_irqrestore(&wl->irq_lock, flags); | ||
3542 | |||
3543 | err = 0; | ||
3544 | out_mutex_unlock: | ||
3545 | mutex_unlock(&wl->mutex); | 3583 | mutex_unlock(&wl->mutex); |
3546 | 3584 | ||
3547 | return err; | 3585 | return err; |
3548 | } | 3586 | } |
3549 | 3587 | ||
3550 | static void b43_remove_interface(struct ieee80211_hw *hw, | 3588 | void b43_stop(struct ieee80211_hw *hw) |
3551 | struct ieee80211_if_init_conf *conf) | ||
3552 | { | 3589 | { |
3553 | struct b43_wl *wl = hw_to_b43_wl(hw); | 3590 | struct b43_wl *wl = hw_to_b43_wl(hw); |
3554 | struct b43_wldev *dev; | 3591 | struct b43_wldev *dev = wl->current_dev; |
3555 | unsigned long flags; | ||
3556 | |||
3557 | b43dbg(wl, "Removing Interface type %d\n", conf->type); | ||
3558 | 3592 | ||
3559 | mutex_lock(&wl->mutex); | 3593 | mutex_lock(&wl->mutex); |
3560 | if (conf->type == IEEE80211_IF_TYPE_MNTR) { | 3594 | if (b43_status(dev) >= B43_STAT_STARTED) |
3561 | wl->monitor--; | 3595 | b43_wireless_core_stop(dev); |
3562 | B43_WARN_ON(wl->monitor < 0); | 3596 | b43_wireless_core_exit(dev); |
3563 | } else { | ||
3564 | B43_WARN_ON(!wl->operating); | ||
3565 | wl->operating = 0; | ||
3566 | } | ||
3567 | |||
3568 | dev = wl->current_dev; | ||
3569 | if (!wl->operating && wl->monitor == 0) { | ||
3570 | /* No interface left. */ | ||
3571 | if (b43_status(dev) >= B43_STAT_STARTED) | ||
3572 | b43_wireless_core_stop(dev); | ||
3573 | b43_wireless_core_exit(dev); | ||
3574 | } else { | ||
3575 | /* Just monitor interfaces left. */ | ||
3576 | spin_lock_irqsave(&wl->irq_lock, flags); | ||
3577 | b43_adjust_opmode(dev); | ||
3578 | if (!wl->operating) | ||
3579 | b43_upload_card_macaddress(dev, NULL); | ||
3580 | spin_unlock_irqrestore(&wl->irq_lock, flags); | ||
3581 | } | ||
3582 | mutex_unlock(&wl->mutex); | 3597 | mutex_unlock(&wl->mutex); |
3583 | } | 3598 | } |
3584 | 3599 | ||
@@ -3589,10 +3604,12 @@ static const struct ieee80211_ops b43_hw_ops = { | |||
3589 | .remove_interface = b43_remove_interface, | 3604 | .remove_interface = b43_remove_interface, |
3590 | .config = b43_dev_config, | 3605 | .config = b43_dev_config, |
3591 | .config_interface = b43_config_interface, | 3606 | .config_interface = b43_config_interface, |
3592 | .set_multicast_list = b43_set_multicast_list, | 3607 | .configure_filter = b43_configure_filter, |
3593 | .set_key = b43_dev_set_key, | 3608 | .set_key = b43_dev_set_key, |
3594 | .get_stats = b43_get_stats, | 3609 | .get_stats = b43_get_stats, |
3595 | .get_tx_stats = b43_get_tx_stats, | 3610 | .get_tx_stats = b43_get_tx_stats, |
3611 | .start = b43_start, | ||
3612 | .stop = b43_stop, | ||
3596 | }; | 3613 | }; |
3597 | 3614 | ||
3598 | /* Hard-reset the chip. Do not call this directly. | 3615 | /* Hard-reset the chip. Do not call this directly. |
@@ -3930,8 +3947,7 @@ static int b43_wireless_init(struct ssb_device *dev) | |||
3930 | } | 3947 | } |
3931 | 3948 | ||
3932 | /* fill hw info */ | 3949 | /* fill hw info */ |
3933 | hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | | 3950 | hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE; |
3934 | IEEE80211_HW_MONITOR_DURING_OPER; | ||
3935 | hw->max_signal = 100; | 3951 | hw->max_signal = 100; |
3936 | hw->max_rssi = -110; | 3952 | hw->max_rssi = -110; |
3937 | hw->max_noise = -110; | 3953 | hw->max_noise = -110; |