diff options
| author | Michal Kazior <michal.kazior@tieto.com> | 2015-01-13 09:30:12 -0500 |
|---|---|---|
| committer | Kalle Valo <kvalo@qca.qualcomm.com> | 2015-01-15 05:30:41 -0500 |
| commit | fbb8f1b729b82f2b48350ffc096f107d1a6ea12d (patch) | |
| tree | ca95cf6db75e8d4cb17fb2a0af00dbac80d3d980 | |
| parent | 369242b4e3f9d29ddead61895f97a3118484f2f1 (diff) | |
ath10k: implement support for ap beacon offloading
New firmware revisions support beacon and probe
response templates instead. This means SWBA events
are no longer delivered for these firmware
revisions.
Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
| -rw-r--r-- | drivers/net/wireless/ath/ath10k/mac.c | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index b403cba0afc1..36dde244b95f 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c | |||
| @@ -967,6 +967,143 @@ static int ath10k_vdev_stop(struct ath10k_vif *arvif) | |||
| 967 | return ret; | 967 | return ret; |
| 968 | } | 968 | } |
| 969 | 969 | ||
| 970 | static int ath10k_mac_setup_bcn_p2p_ie(struct ath10k_vif *arvif, | ||
| 971 | struct sk_buff *bcn) | ||
| 972 | { | ||
| 973 | struct ath10k *ar = arvif->ar; | ||
| 974 | struct ieee80211_mgmt *mgmt; | ||
| 975 | const u8 *p2p_ie; | ||
| 976 | int ret; | ||
| 977 | |||
| 978 | if (arvif->vdev_type != WMI_VDEV_TYPE_AP) | ||
| 979 | return 0; | ||
| 980 | |||
| 981 | if (arvif->vdev_subtype != WMI_VDEV_SUBTYPE_P2P_GO) | ||
| 982 | return 0; | ||
| 983 | |||
| 984 | mgmt = (void *)bcn->data; | ||
| 985 | p2p_ie = cfg80211_find_vendor_ie(WLAN_OUI_WFA, WLAN_OUI_TYPE_WFA_P2P, | ||
| 986 | mgmt->u.beacon.variable, | ||
| 987 | bcn->len - (mgmt->u.beacon.variable - | ||
| 988 | bcn->data)); | ||
| 989 | if (!p2p_ie) | ||
| 990 | return -ENOENT; | ||
| 991 | |||
| 992 | ret = ath10k_wmi_p2p_go_bcn_ie(ar, arvif->vdev_id, p2p_ie); | ||
| 993 | if (ret) { | ||
| 994 | ath10k_warn(ar, "failed to submit p2p go bcn ie for vdev %i: %d\n", | ||
| 995 | arvif->vdev_id, ret); | ||
| 996 | return ret; | ||
| 997 | } | ||
| 998 | |||
| 999 | return 0; | ||
| 1000 | } | ||
| 1001 | |||
| 1002 | static int ath10k_mac_remove_vendor_ie(struct sk_buff *skb, unsigned int oui, | ||
| 1003 | u8 oui_type, size_t ie_offset) | ||
| 1004 | { | ||
| 1005 | size_t len; | ||
| 1006 | const u8 *next; | ||
| 1007 | const u8 *end; | ||
| 1008 | u8 *ie; | ||
| 1009 | |||
| 1010 | if (WARN_ON(skb->len < ie_offset)) | ||
| 1011 | return -EINVAL; | ||
| 1012 | |||
| 1013 | ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type, | ||
| 1014 | skb->data + ie_offset, | ||
| 1015 | skb->len - ie_offset); | ||
| 1016 | if (!ie) | ||
| 1017 | return -ENOENT; | ||
| 1018 | |||
| 1019 | len = ie[1] + 2; | ||
| 1020 | end = skb->data + skb->len; | ||
| 1021 | next = ie + len; | ||
| 1022 | |||
| 1023 | if (WARN_ON(next > end)) | ||
| 1024 | return -EINVAL; | ||
| 1025 | |||
| 1026 | memmove(ie, next, end - next); | ||
| 1027 | skb_trim(skb, skb->len - len); | ||
| 1028 | |||
| 1029 | return 0; | ||
| 1030 | } | ||
| 1031 | |||
| 1032 | static int ath10k_mac_setup_bcn_tmpl(struct ath10k_vif *arvif) | ||
| 1033 | { | ||
| 1034 | struct ath10k *ar = arvif->ar; | ||
| 1035 | struct ieee80211_hw *hw = ar->hw; | ||
| 1036 | struct ieee80211_vif *vif = arvif->vif; | ||
| 1037 | struct ieee80211_mutable_offsets offs = {}; | ||
| 1038 | struct sk_buff *bcn; | ||
| 1039 | int ret; | ||
| 1040 | |||
| 1041 | if (!test_bit(WMI_SERVICE_BEACON_OFFLOAD, ar->wmi.svc_map)) | ||
| 1042 | return 0; | ||
| 1043 | |||
| 1044 | bcn = ieee80211_beacon_get_template(hw, vif, &offs); | ||
| 1045 | if (!bcn) { | ||
| 1046 | ath10k_warn(ar, "failed to get beacon template from mac80211\n"); | ||
| 1047 | return -EPERM; | ||
| 1048 | } | ||
| 1049 | |||
| 1050 | ret = ath10k_mac_setup_bcn_p2p_ie(arvif, bcn); | ||
| 1051 | if (ret) { | ||
| 1052 | ath10k_warn(ar, "failed to setup p2p go bcn ie: %d\n", ret); | ||
| 1053 | kfree_skb(bcn); | ||
| 1054 | return ret; | ||
| 1055 | } | ||
| 1056 | |||
| 1057 | /* P2P IE is inserted by firmware automatically (as configured above) | ||
| 1058 | * so remove it from the base beacon template to avoid duplicate P2P | ||
| 1059 | * IEs in beacon frames. | ||
| 1060 | */ | ||
| 1061 | ath10k_mac_remove_vendor_ie(bcn, WLAN_OUI_WFA, WLAN_OUI_TYPE_WFA_P2P, | ||
| 1062 | offsetof(struct ieee80211_mgmt, | ||
| 1063 | u.beacon.variable)); | ||
| 1064 | |||
| 1065 | ret = ath10k_wmi_bcn_tmpl(ar, arvif->vdev_id, offs.tim_offset, bcn, 0, | ||
| 1066 | 0, NULL, 0); | ||
| 1067 | kfree_skb(bcn); | ||
| 1068 | |||
| 1069 | if (ret) { | ||
| 1070 | ath10k_warn(ar, "failed to submit beacon template command: %d\n", | ||
| 1071 | ret); | ||
| 1072 | return ret; | ||
| 1073 | } | ||
| 1074 | |||
| 1075 | return 0; | ||
| 1076 | } | ||
| 1077 | |||
| 1078 | static int ath10k_mac_setup_prb_tmpl(struct ath10k_vif *arvif) | ||
| 1079 | { | ||
| 1080 | struct ath10k *ar = arvif->ar; | ||
| 1081 | struct ieee80211_hw *hw = ar->hw; | ||
| 1082 | struct ieee80211_vif *vif = arvif->vif; | ||
| 1083 | struct sk_buff *prb; | ||
| 1084 | int ret; | ||
| 1085 | |||
| 1086 | if (!test_bit(WMI_SERVICE_BEACON_OFFLOAD, ar->wmi.svc_map)) | ||
| 1087 | return 0; | ||
| 1088 | |||
| 1089 | prb = ieee80211_proberesp_get(hw, vif); | ||
| 1090 | if (!prb) { | ||
| 1091 | ath10k_warn(ar, "failed to get probe resp template from mac80211\n"); | ||
| 1092 | return -EPERM; | ||
| 1093 | } | ||
| 1094 | |||
| 1095 | ret = ath10k_wmi_prb_tmpl(ar, arvif->vdev_id, prb); | ||
| 1096 | kfree_skb(prb); | ||
| 1097 | |||
| 1098 | if (ret) { | ||
| 1099 | ath10k_warn(ar, "failed to submit probe resp template command: %d\n", | ||
| 1100 | ret); | ||
| 1101 | return ret; | ||
| 1102 | } | ||
| 1103 | |||
| 1104 | return 0; | ||
| 1105 | } | ||
| 1106 | |||
| 970 | static void ath10k_control_beaconing(struct ath10k_vif *arvif, | 1107 | static void ath10k_control_beaconing(struct ath10k_vif *arvif, |
| 971 | struct ieee80211_bss_conf *info) | 1108 | struct ieee80211_bss_conf *info) |
| 972 | { | 1109 | { |
| @@ -3283,6 +3420,18 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, | |||
| 3283 | if (ret) | 3420 | if (ret) |
| 3284 | ath10k_warn(ar, "failed to set beacon mode for vdev %d: %i\n", | 3421 | ath10k_warn(ar, "failed to set beacon mode for vdev %d: %i\n", |
| 3285 | arvif->vdev_id, ret); | 3422 | arvif->vdev_id, ret); |
| 3423 | |||
| 3424 | ret = ath10k_mac_setup_bcn_tmpl(arvif); | ||
| 3425 | if (ret) | ||
| 3426 | ath10k_warn(ar, "failed to update beacon template: %d\n", | ||
| 3427 | ret); | ||
| 3428 | } | ||
| 3429 | |||
| 3430 | if (changed & BSS_CHANGED_AP_PROBE_RESP) { | ||
| 3431 | ret = ath10k_mac_setup_prb_tmpl(arvif); | ||
| 3432 | if (ret) | ||
| 3433 | ath10k_warn(ar, "failed to setup probe resp template on vdev %i: %d\n", | ||
| 3434 | arvif->vdev_id, ret); | ||
| 3286 | } | 3435 | } |
| 3287 | 3436 | ||
| 3288 | if (changed & BSS_CHANGED_BEACON_INFO) { | 3437 | if (changed & BSS_CHANGED_BEACON_INFO) { |
| @@ -5130,6 +5279,19 @@ int ath10k_mac_register(struct ath10k *ar) | |||
| 5130 | 5279 | ||
| 5131 | ar->hw->max_listen_interval = ATH10K_MAX_HW_LISTEN_INTERVAL; | 5280 | ar->hw->max_listen_interval = ATH10K_MAX_HW_LISTEN_INTERVAL; |
| 5132 | 5281 | ||
| 5282 | if (test_bit(WMI_SERVICE_BEACON_OFFLOAD, ar->wmi.svc_map)) { | ||
| 5283 | ar->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; | ||
| 5284 | |||
| 5285 | /* Firmware delivers WPS/P2P Probe Requests frames to driver so | ||
| 5286 | * that userspace (e.g. wpa_supplicant/hostapd) can generate | ||
| 5287 | * correct Probe Responses. This is more of a hack advert.. | ||
| 5288 | */ | ||
| 5289 | ar->hw->wiphy->probe_resp_offload |= | ||
| 5290 | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | | ||
| 5291 | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | | ||
| 5292 | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P; | ||
| 5293 | } | ||
| 5294 | |||
| 5133 | ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; | 5295 | ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; |
| 5134 | ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; | 5296 | ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; |
| 5135 | ar->hw->wiphy->max_remain_on_channel_duration = 5000; | 5297 | ar->hw->wiphy->max_remain_on_channel_duration = 5000; |
