+u8 * hostapd_eid_ht_capabilities_info(struct hostapd_data *hapd, u8 *eid)
+{
+#ifdef CONFIG_IEEE80211N
+ struct ieee80211_ht_capability *cap;
+ u8 *pos = eid;
+
+ if (!hapd->iconf->ieee80211n)
+ return eid;
+
+ *pos++ = WLAN_EID_HT_CAP;
+ *pos++ = sizeof(*cap);
+
+ cap = (struct ieee80211_ht_capability *) pos;
+ os_memset(cap, 0, sizeof(*cap));
+ SET_2BIT_U8(&cap->mac_ht_params_info,
+ MAC_HT_PARAM_INFO_MAX_RX_AMPDU_FACTOR_OFFSET,
+ MAX_RX_AMPDU_FACTOR_64KB);
+
+ cap->capabilities_info = host_to_le16(hapd->iconf->ht_capab);
+
+ cap->supported_mcs_set[0] = 0xff;
+ cap->supported_mcs_set[1] = 0xff;
+
+ pos += sizeof(*cap);
+
+ return pos;
+#else /* CONFIG_IEEE80211N */
+ return eid;
+#endif /* CONFIG_IEEE80211N */
+}
+
+
+u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid)
+{
+#ifdef CONFIG_IEEE80211N
+ struct ieee80211_ht_operation *oper;
+ u8 *pos = eid;
+
+ if (!hapd->iconf->ieee80211n)
+ return eid;
+
+ *pos++ = WLAN_EID_HT_OPERATION;
+ *pos++ = sizeof(*oper);
+
+ oper = (struct ieee80211_ht_operation *) pos;
+ os_memset(oper, 0, sizeof(*oper));
+
+ oper->control_chan = hapd->iconf->channel;
+ oper->operation_mode = host_to_le16(hapd->iface->ht_op_mode);
+ if (hapd->iconf->secondary_channel == 1)
+ oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE |
+ HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH;
+ if (hapd->iconf->secondary_channel == -1)
+ oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW |
+ HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH;
+
+ pos += sizeof(*oper);
+
+ return pos;
+#else /* CONFIG_IEEE80211N */
+ return eid;
+#endif /* CONFIG_IEEE80211N */
+}
+
+
+#ifdef CONFIG_IEEE80211N
+
+/*
+op_mode
+Set to 0 (HT pure) under the followign conditions
+ - all STAs in the BSS are 20/40 MHz HT in 20/40 MHz BSS or
+ - all STAs in the BSS are 20 MHz HT in 20 MHz BSS
+Set to 1 (HT non-member protection) if there may be non-HT STAs
+ in both the primary and the secondary channel
+Set to 2 if only HT STAs are associated in BSS,
+ however and at least one 20 MHz HT STA is associated
+Set to 3 (HT mixed mode) when one or more non-HT STAs are associated
+ (currently non-GF HT station is considered as non-HT STA also)
+*/
+int hostapd_ht_operation_update(struct hostapd_iface *iface)
+{
+ u16 cur_op_mode, new_op_mode;
+ int op_mode_changes = 0;
+
+ if (!iface->conf->ieee80211n || iface->conf->ht_op_mode_fixed)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "%s current operation mode=0x%X",
+ __func__, iface->ht_op_mode);
+
+ if (!(iface->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT)
+ && iface->num_sta_ht_no_gf) {
+ iface->ht_op_mode |=
+ HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT;
+ op_mode_changes++;
+ } else if ((iface->ht_op_mode &
+ HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT) &&
+ iface->num_sta_ht_no_gf == 0) {
+ iface->ht_op_mode &=
+ ~HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT;
+ op_mode_changes++;
+ }
+
+ if (!(iface->ht_op_mode & HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) &&
+ (iface->num_sta_no_ht || iface->olbc_ht)) {
+ iface->ht_op_mode |= HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT;
+ op_mode_changes++;
+ } else if ((iface->ht_op_mode &
+ HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) &&
+ (iface->num_sta_no_ht == 0 && !iface->olbc_ht)) {
+ iface->ht_op_mode &=
+ ~HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT;
+ op_mode_changes++;
+ }
+
+ /* Note: currently we switch to the MIXED op mode if HT non-greenfield
+ * station is associated. Probably it's a theoretical case, since
+ * it looks like all known HT STAs support greenfield.
+ */
+ new_op_mode = 0;
+ if (iface->num_sta_no_ht ||
+ (iface->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT))
+ new_op_mode = OP_MODE_MIXED;
+ else if ((iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)
+ && iface->num_sta_ht_20mhz)
+ new_op_mode = OP_MODE_20MHZ_HT_STA_ASSOCED;
+ else if (iface->olbc_ht)
+ new_op_mode = OP_MODE_MAY_BE_LEGACY_STAS;
+ else
+ new_op_mode = OP_MODE_PURE;
+
+ cur_op_mode = iface->ht_op_mode & HT_INFO_OPERATION_MODE_OP_MODE_MASK;
+ if (cur_op_mode != new_op_mode) {
+ iface->ht_op_mode &= ~HT_INFO_OPERATION_MODE_OP_MODE_MASK;
+ iface->ht_op_mode |= new_op_mode;
+ op_mode_changes++;
+ }
+
+ wpa_printf(MSG_DEBUG, "%s new operation mode=0x%X changes=%d",
+ __func__, iface->ht_op_mode, op_mode_changes);
+
+ return op_mode_changes;
+}
+
+#endif /* CONFIG_IEEE80211N */
+
+