diff options
Diffstat (limited to 'drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c')
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 96 |
1 files changed, 81 insertions, 15 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 6d758f285352..301e572e8923 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | |||
@@ -459,6 +459,38 @@ send_key_to_dongle(struct net_device *ndev, struct brcmf_wsec_key *key) | |||
459 | return err; | 459 | return err; |
460 | } | 460 | } |
461 | 461 | ||
462 | static s32 | ||
463 | brcmf_configure_arp_offload(struct brcmf_if *ifp, bool enable) | ||
464 | { | ||
465 | s32 err; | ||
466 | u32 mode; | ||
467 | |||
468 | if (enable) | ||
469 | mode = BRCMF_ARP_OL_AGENT | BRCMF_ARP_OL_PEER_AUTO_REPLY; | ||
470 | else | ||
471 | mode = 0; | ||
472 | |||
473 | /* Try to set and enable ARP offload feature, this may fail, then it */ | ||
474 | /* is simply not supported and err 0 will be returned */ | ||
475 | err = brcmf_fil_iovar_int_set(ifp, "arp_ol", mode); | ||
476 | if (err) { | ||
477 | brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, err = %d\n", | ||
478 | mode, err); | ||
479 | err = 0; | ||
480 | } else { | ||
481 | err = brcmf_fil_iovar_int_set(ifp, "arpoe", enable); | ||
482 | if (err) { | ||
483 | brcmf_dbg(TRACE, "failed to configure (%d) ARP offload err = %d\n", | ||
484 | enable, err); | ||
485 | err = 0; | ||
486 | } else | ||
487 | brcmf_dbg(TRACE, "successfully configured (%d) ARP offload to 0x%x\n", | ||
488 | enable, mode); | ||
489 | } | ||
490 | |||
491 | return err; | ||
492 | } | ||
493 | |||
462 | static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy, | 494 | static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy, |
463 | const char *name, | 495 | const char *name, |
464 | enum nl80211_iftype type, | 496 | enum nl80211_iftype type, |
@@ -2216,6 +2248,11 @@ brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev, | |||
2216 | } | 2248 | } |
2217 | 2249 | ||
2218 | pm = enabled ? PM_FAST : PM_OFF; | 2250 | pm = enabled ? PM_FAST : PM_OFF; |
2251 | /* Do not enable the power save after assoc if it is a p2p interface */ | ||
2252 | if (ifp->vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) { | ||
2253 | brcmf_dbg(INFO, "Do not enable power save for P2P clients\n"); | ||
2254 | pm = PM_OFF; | ||
2255 | } | ||
2219 | brcmf_dbg(INFO, "power save %s\n", (pm ? "enabled" : "disabled")); | 2256 | brcmf_dbg(INFO, "power save %s\n", (pm ? "enabled" : "disabled")); |
2220 | 2257 | ||
2221 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm); | 2258 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm); |
@@ -3640,10 +3677,28 @@ brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif, | |||
3640 | } | 3677 | } |
3641 | 3678 | ||
3642 | static s32 | 3679 | static s32 |
3680 | brcmf_cfg80211_set_channel(struct brcmf_cfg80211_info *cfg, | ||
3681 | struct brcmf_if *ifp, | ||
3682 | struct ieee80211_channel *channel) | ||
3683 | { | ||
3684 | u16 chanspec; | ||
3685 | s32 err; | ||
3686 | |||
3687 | brcmf_dbg(TRACE, "band=%d, center_freq=%d\n", channel->band, | ||
3688 | channel->center_freq); | ||
3689 | |||
3690 | chanspec = channel_to_chanspec(&cfg->d11inf, channel); | ||
3691 | err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec); | ||
3692 | |||
3693 | return err; | ||
3694 | } | ||
3695 | |||
3696 | static s32 | ||
3643 | brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, | 3697 | brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, |
3644 | struct cfg80211_ap_settings *settings) | 3698 | struct cfg80211_ap_settings *settings) |
3645 | { | 3699 | { |
3646 | s32 ie_offset; | 3700 | s32 ie_offset; |
3701 | struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); | ||
3647 | struct brcmf_if *ifp = netdev_priv(ndev); | 3702 | struct brcmf_if *ifp = netdev_priv(ndev); |
3648 | struct brcmf_tlv *ssid_ie; | 3703 | struct brcmf_tlv *ssid_ie; |
3649 | struct brcmf_ssid_le ssid_le; | 3704 | struct brcmf_ssid_le ssid_le; |
@@ -3683,6 +3738,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, | |||
3683 | } | 3738 | } |
3684 | 3739 | ||
3685 | brcmf_set_mpc(ifp, 0); | 3740 | brcmf_set_mpc(ifp, 0); |
3741 | brcmf_configure_arp_offload(ifp, false); | ||
3686 | 3742 | ||
3687 | /* find the RSN_IE */ | 3743 | /* find the RSN_IE */ |
3688 | rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail, | 3744 | rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail, |
@@ -3713,6 +3769,12 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, | |||
3713 | 3769 | ||
3714 | brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon); | 3770 | brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon); |
3715 | 3771 | ||
3772 | err = brcmf_cfg80211_set_channel(cfg, ifp, settings->chandef.chan); | ||
3773 | if (err < 0) { | ||
3774 | brcmf_err("Set Channel failed, %d\n", err); | ||
3775 | goto exit; | ||
3776 | } | ||
3777 | |||
3716 | if (settings->beacon_interval) { | 3778 | if (settings->beacon_interval) { |
3717 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, | 3779 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, |
3718 | settings->beacon_interval); | 3780 | settings->beacon_interval); |
@@ -3789,8 +3851,10 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, | |||
3789 | set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state); | 3851 | set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state); |
3790 | 3852 | ||
3791 | exit: | 3853 | exit: |
3792 | if (err) | 3854 | if (err) { |
3793 | brcmf_set_mpc(ifp, 1); | 3855 | brcmf_set_mpc(ifp, 1); |
3856 | brcmf_configure_arp_offload(ifp, true); | ||
3857 | } | ||
3794 | return err; | 3858 | return err; |
3795 | } | 3859 | } |
3796 | 3860 | ||
@@ -3831,6 +3895,7 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev) | |||
3831 | brcmf_err("bss_enable config failed %d\n", err); | 3895 | brcmf_err("bss_enable config failed %d\n", err); |
3832 | } | 3896 | } |
3833 | brcmf_set_mpc(ifp, 1); | 3897 | brcmf_set_mpc(ifp, 1); |
3898 | brcmf_configure_arp_offload(ifp, true); | ||
3834 | set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state); | 3899 | set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state); |
3835 | clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state); | 3900 | clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state); |
3836 | 3901 | ||
@@ -4140,11 +4205,15 @@ static const struct ieee80211_iface_limit brcmf_iface_limits[] = { | |||
4140 | .types = BIT(NL80211_IFTYPE_P2P_CLIENT) | | 4205 | .types = BIT(NL80211_IFTYPE_P2P_CLIENT) | |
4141 | BIT(NL80211_IFTYPE_P2P_GO) | 4206 | BIT(NL80211_IFTYPE_P2P_GO) |
4142 | }, | 4207 | }, |
4208 | { | ||
4209 | .max = 1, | ||
4210 | .types = BIT(NL80211_IFTYPE_P2P_DEVICE) | ||
4211 | } | ||
4143 | }; | 4212 | }; |
4144 | static const struct ieee80211_iface_combination brcmf_iface_combos[] = { | 4213 | static const struct ieee80211_iface_combination brcmf_iface_combos[] = { |
4145 | { | 4214 | { |
4146 | .max_interfaces = BRCMF_IFACE_MAX_CNT, | 4215 | .max_interfaces = BRCMF_IFACE_MAX_CNT, |
4147 | .num_different_channels = 1, /* no multi-channel for now */ | 4216 | .num_different_channels = 2, |
4148 | .n_limits = ARRAY_SIZE(brcmf_iface_limits), | 4217 | .n_limits = ARRAY_SIZE(brcmf_iface_limits), |
4149 | .limits = brcmf_iface_limits | 4218 | .limits = brcmf_iface_limits |
4150 | } | 4219 | } |
@@ -4197,7 +4266,8 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev) | |||
4197 | BIT(NL80211_IFTYPE_ADHOC) | | 4266 | BIT(NL80211_IFTYPE_ADHOC) | |
4198 | BIT(NL80211_IFTYPE_AP) | | 4267 | BIT(NL80211_IFTYPE_AP) | |
4199 | BIT(NL80211_IFTYPE_P2P_CLIENT) | | 4268 | BIT(NL80211_IFTYPE_P2P_CLIENT) | |
4200 | BIT(NL80211_IFTYPE_P2P_GO); | 4269 | BIT(NL80211_IFTYPE_P2P_GO) | |
4270 | BIT(NL80211_IFTYPE_P2P_DEVICE); | ||
4201 | wiphy->iface_combinations = brcmf_iface_combos; | 4271 | wiphy->iface_combinations = brcmf_iface_combos; |
4202 | wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos); | 4272 | wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos); |
4203 | wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; | 4273 | wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; |
@@ -4251,20 +4321,16 @@ struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, | |||
4251 | return vif; | 4321 | return vif; |
4252 | } | 4322 | } |
4253 | 4323 | ||
4254 | void brcmf_free_vif(struct brcmf_cfg80211_vif *vif) | 4324 | void brcmf_free_vif(struct brcmf_cfg80211_info *cfg, |
4325 | struct brcmf_cfg80211_vif *vif) | ||
4255 | { | 4326 | { |
4256 | struct brcmf_cfg80211_info *cfg; | ||
4257 | struct wiphy *wiphy; | ||
4258 | |||
4259 | wiphy = vif->wdev.wiphy; | ||
4260 | cfg = wiphy_priv(wiphy); | ||
4261 | list_del(&vif->list); | 4327 | list_del(&vif->list); |
4262 | cfg->vif_cnt--; | 4328 | cfg->vif_cnt--; |
4263 | 4329 | ||
4264 | kfree(vif); | 4330 | kfree(vif); |
4265 | if (!cfg->vif_cnt) { | 4331 | if (!cfg->vif_cnt) { |
4266 | wiphy_unregister(wiphy); | 4332 | wiphy_unregister(cfg->wiphy); |
4267 | wiphy_free(wiphy); | 4333 | wiphy_free(cfg->wiphy); |
4268 | } | 4334 | } |
4269 | } | 4335 | } |
4270 | 4336 | ||
@@ -4641,7 +4707,6 @@ static s32 brcmf_notify_vif_event(struct brcmf_if *ifp, | |||
4641 | return 0; | 4707 | return 0; |
4642 | 4708 | ||
4643 | case BRCMF_E_IF_DEL: | 4709 | case BRCMF_E_IF_DEL: |
4644 | ifp->vif = NULL; | ||
4645 | mutex_unlock(&event->vif_event_lock); | 4710 | mutex_unlock(&event->vif_event_lock); |
4646 | /* event may not be upon user request */ | 4711 | /* event may not be upon user request */ |
4647 | if (brcmf_cfg80211_vif_event_armed(cfg)) | 4712 | if (brcmf_cfg80211_vif_event_armed(cfg)) |
@@ -4847,8 +4912,7 @@ cfg80211_p2p_attach_out: | |||
4847 | wl_deinit_priv(cfg); | 4912 | wl_deinit_priv(cfg); |
4848 | 4913 | ||
4849 | cfg80211_attach_out: | 4914 | cfg80211_attach_out: |
4850 | brcmf_free_vif(vif); | 4915 | brcmf_free_vif(cfg, vif); |
4851 | wiphy_free(wiphy); | ||
4852 | return NULL; | 4916 | return NULL; |
4853 | } | 4917 | } |
4854 | 4918 | ||
@@ -4860,7 +4924,7 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg) | |||
4860 | wl_deinit_priv(cfg); | 4924 | wl_deinit_priv(cfg); |
4861 | brcmf_btcoex_detach(cfg); | 4925 | brcmf_btcoex_detach(cfg); |
4862 | list_for_each_entry_safe(vif, tmp, &cfg->vif_list, list) { | 4926 | list_for_each_entry_safe(vif, tmp, &cfg->vif_list, list) { |
4863 | brcmf_free_vif(vif); | 4927 | brcmf_free_vif(cfg, vif); |
4864 | } | 4928 | } |
4865 | } | 4929 | } |
4866 | 4930 | ||
@@ -5224,6 +5288,8 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg) | |||
5224 | if (err) | 5288 | if (err) |
5225 | goto default_conf_out; | 5289 | goto default_conf_out; |
5226 | 5290 | ||
5291 | brcmf_configure_arp_offload(ifp, true); | ||
5292 | |||
5227 | cfg->dongle_up = true; | 5293 | cfg->dongle_up = true; |
5228 | default_conf_out: | 5294 | default_conf_out: |
5229 | 5295 | ||