|
@@ -1110,6 +1110,10 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
|
|
|
struct wpa_driver_capa capa;
|
|
|
int assoc_failed = 0;
|
|
|
struct wpa_ssid *old_ssid;
|
|
|
+#ifdef CONFIG_HT_OVERRIDES
|
|
|
+ struct ieee80211_ht_capabilities htcaps;
|
|
|
+ struct ieee80211_ht_capabilities htcaps_mask;
|
|
|
+#endif /* CONFIG_HT_OVERRIDES */
|
|
|
|
|
|
#ifdef CONFIG_IBSS_RSN
|
|
|
ibss_rsn_deinit(wpa_s->ibss_rsn);
|
|
@@ -1411,6 +1415,14 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
|
|
|
else
|
|
|
params.uapsd = -1;
|
|
|
|
|
|
+#ifdef CONFIG_HT_OVERRIDES
|
|
|
+ os_memset(&htcaps, 0, sizeof(htcaps));
|
|
|
+ os_memset(&htcaps_mask, 0, sizeof(htcaps_mask));
|
|
|
+ params.htcaps = (u8 *) &htcaps;
|
|
|
+ params.htcaps_mask = (u8 *) &htcaps_mask;
|
|
|
+ wpa_supplicant_apply_ht_overrides(wpa_s, ssid, ¶ms);
|
|
|
+#endif /* CONFIG_HT_OVERRIDES */
|
|
|
+
|
|
|
ret = wpa_drv_associate(wpa_s, ¶ms);
|
|
|
if (ret < 0) {
|
|
|
wpa_msg(wpa_s, MSG_INFO, "Association request to the driver "
|
|
@@ -2165,6 +2177,183 @@ static struct wpa_supplicant * wpa_supplicant_alloc(void)
|
|
|
}
|
|
|
|
|
|
|
|
|
+#ifdef CONFIG_HT_OVERRIDES
|
|
|
+
|
|
|
+static int wpa_set_htcap_mcs(struct wpa_supplicant *wpa_s,
|
|
|
+ struct ieee80211_ht_capabilities *htcaps,
|
|
|
+ struct ieee80211_ht_capabilities *htcaps_mask,
|
|
|
+ const char *ht_mcs)
|
|
|
+{
|
|
|
+ /* parse ht_mcs into hex array */
|
|
|
+ int i;
|
|
|
+ const char *tmp = ht_mcs;
|
|
|
+ char *end = NULL;
|
|
|
+
|
|
|
+ /* If ht_mcs is null, do not set anything */
|
|
|
+ if (!ht_mcs)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ /* This is what we are setting in the kernel */
|
|
|
+ os_memset(&htcaps->supported_mcs_set, 0, IEEE80211_HT_MCS_MASK_LEN);
|
|
|
+
|
|
|
+ wpa_msg(wpa_s, MSG_DEBUG, "set_htcap, ht_mcs -:%s:-", ht_mcs);
|
|
|
+
|
|
|
+ for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
|
|
|
+ errno = 0;
|
|
|
+ long v = strtol(tmp, &end, 16);
|
|
|
+ if (errno == 0) {
|
|
|
+ wpa_msg(wpa_s, MSG_DEBUG,
|
|
|
+ "htcap value[%i]: %ld end: %p tmp: %p",
|
|
|
+ i, v, end, tmp);
|
|
|
+ if (end == tmp)
|
|
|
+ break;
|
|
|
+
|
|
|
+ htcaps->supported_mcs_set[i] = v;
|
|
|
+ tmp = end;
|
|
|
+ } else {
|
|
|
+ wpa_msg(wpa_s, MSG_ERROR,
|
|
|
+ "Failed to parse ht-mcs: %s, error: %s\n",
|
|
|
+ ht_mcs, strerror(errno));
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If we were able to parse any values, then set mask for the MCS set.
|
|
|
+ */
|
|
|
+ if (i) {
|
|
|
+ os_memset(&htcaps_mask->supported_mcs_set, 0xff,
|
|
|
+ IEEE80211_HT_MCS_MASK_LEN - 1);
|
|
|
+ /* skip the 3 reserved bits */
|
|
|
+ htcaps_mask->supported_mcs_set[IEEE80211_HT_MCS_MASK_LEN - 1] =
|
|
|
+ 0x1f;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static int wpa_disable_max_amsdu(struct wpa_supplicant *wpa_s,
|
|
|
+ struct ieee80211_ht_capabilities *htcaps,
|
|
|
+ struct ieee80211_ht_capabilities *htcaps_mask,
|
|
|
+ int disabled)
|
|
|
+{
|
|
|
+ u16 msk;
|
|
|
+
|
|
|
+ wpa_msg(wpa_s, MSG_DEBUG, "set_disable_max_amsdu: %d", disabled);
|
|
|
+
|
|
|
+ if (disabled == -1)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ msk = host_to_le16(HT_CAP_INFO_MAX_AMSDU_SIZE);
|
|
|
+ htcaps_mask->ht_capabilities_info |= msk;
|
|
|
+ if (disabled)
|
|
|
+ htcaps->ht_capabilities_info &= msk;
|
|
|
+ else
|
|
|
+ htcaps->ht_capabilities_info |= msk;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static int wpa_set_ampdu_factor(struct wpa_supplicant *wpa_s,
|
|
|
+ struct ieee80211_ht_capabilities *htcaps,
|
|
|
+ struct ieee80211_ht_capabilities *htcaps_mask,
|
|
|
+ int factor)
|
|
|
+{
|
|
|
+ wpa_msg(wpa_s, MSG_DEBUG, "set_ampdu_factor: %d", factor);
|
|
|
+
|
|
|
+ if (factor == -1)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ if (factor < 0 || factor > 3) {
|
|
|
+ wpa_msg(wpa_s, MSG_ERROR, "ampdu_factor: %d out of range. "
|
|
|
+ "Must be 0-3 or -1", factor);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ htcaps_mask->a_mpdu_params |= 0x3; /* 2 bits for factor */
|
|
|
+ htcaps->a_mpdu_params &= ~0x3;
|
|
|
+ htcaps->a_mpdu_params |= factor & 0x3;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static int wpa_set_ampdu_density(struct wpa_supplicant *wpa_s,
|
|
|
+ struct ieee80211_ht_capabilities *htcaps,
|
|
|
+ struct ieee80211_ht_capabilities *htcaps_mask,
|
|
|
+ int density)
|
|
|
+{
|
|
|
+ wpa_msg(wpa_s, MSG_DEBUG, "set_ampdu_density: %d", density);
|
|
|
+
|
|
|
+ if (density == -1)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ if (density < 0 || density > 7) {
|
|
|
+ wpa_msg(wpa_s, MSG_ERROR,
|
|
|
+ "ampdu_density: %d out of range. Must be 0-7 or -1.",
|
|
|
+ density);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ htcaps_mask->a_mpdu_params |= 0x1C;
|
|
|
+ htcaps->a_mpdu_params &= ~(0x1C);
|
|
|
+ htcaps->a_mpdu_params |= (density << 2) & 0x1C;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static int wpa_set_disable_ht40(struct wpa_supplicant *wpa_s,
|
|
|
+ struct ieee80211_ht_capabilities *htcaps,
|
|
|
+ struct ieee80211_ht_capabilities *htcaps_mask,
|
|
|
+ int disabled)
|
|
|
+{
|
|
|
+ /* Masking these out disables HT40 */
|
|
|
+ u16 msk = host_to_le16(HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET |
|
|
|
+ HT_CAP_INFO_SHORT_GI40MHZ);
|
|
|
+
|
|
|
+ wpa_msg(wpa_s, MSG_DEBUG, "set_disable_ht40: %d", disabled);
|
|
|
+
|
|
|
+ if (disabled)
|
|
|
+ htcaps->ht_capabilities_info &= ~msk;
|
|
|
+ else
|
|
|
+ htcaps->ht_capabilities_info |= msk;
|
|
|
+
|
|
|
+ htcaps_mask->ht_capabilities_info |= msk;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void wpa_supplicant_apply_ht_overrides(
|
|
|
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
|
|
|
+ struct wpa_driver_associate_params *params)
|
|
|
+{
|
|
|
+ struct ieee80211_ht_capabilities *htcaps;
|
|
|
+ struct ieee80211_ht_capabilities *htcaps_mask;
|
|
|
+
|
|
|
+ if (!ssid)
|
|
|
+ return;
|
|
|
+
|
|
|
+ params->disable_ht = ssid->disable_ht;
|
|
|
+ if (!params->htcaps || !params->htcaps_mask)
|
|
|
+ return;
|
|
|
+
|
|
|
+ htcaps = (struct ieee80211_ht_capabilities *) params->htcaps;
|
|
|
+ htcaps_mask = (struct ieee80211_ht_capabilities *) params->htcaps_mask;
|
|
|
+ wpa_set_htcap_mcs(wpa_s, htcaps, htcaps_mask, ssid->ht_mcs);
|
|
|
+ wpa_disable_max_amsdu(wpa_s, htcaps, htcaps_mask,
|
|
|
+ ssid->disable_max_amsdu);
|
|
|
+ wpa_set_ampdu_factor(wpa_s, htcaps, htcaps_mask, ssid->ampdu_factor);
|
|
|
+ wpa_set_ampdu_density(wpa_s, htcaps, htcaps_mask, ssid->ampdu_density);
|
|
|
+ wpa_set_disable_ht40(wpa_s, htcaps, htcaps_mask, ssid->disable_ht40);
|
|
|
+}
|
|
|
+
|
|
|
+#endif /* CONFIG_HT_OVERRIDES */
|
|
|
+
|
|
|
+
|
|
|
static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
|
|
|
struct wpa_interface *iface)
|
|
|
{
|