aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c')
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c96
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
462static s32
463brcmf_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
462static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy, 494static 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
3642static s32 3679static s32
3680brcmf_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
3696static s32
3643brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, 3697brcmf_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
3791exit: 3853exit:
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};
4144static const struct ieee80211_iface_combination brcmf_iface_combos[] = { 4213static 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
4254void brcmf_free_vif(struct brcmf_cfg80211_vif *vif) 4324void 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
4849cfg80211_attach_out: 4914cfg80211_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;
5228default_conf_out: 5294default_conf_out:
5229 5295