2 * hostapd / IEEE 802.11n HT
3 * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
4 * Copyright (c) 2007-2008, Intel Corporation
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
10 * Alternatively, this software may be distributed under the terms of BSD
13 * See README and COPYING for more details.
16 #include "utils/includes.h"
18 #include "utils/common.h"
19 #include "common/ieee802_11_defs.h"
20 #include "drivers/driver.h"
22 #include "ap_config.h"
25 #include "ieee802_11.h"
28 u8
* hostapd_eid_ht_capabilities(struct hostapd_data
*hapd
, u8
*eid
)
30 struct ieee80211_ht_capabilities
*cap
;
33 if (!hapd
->iconf
->ieee80211n
)
36 *pos
++ = WLAN_EID_HT_CAP
;
37 *pos
++ = sizeof(*cap
);
39 cap
= (struct ieee80211_ht_capabilities
*) pos
;
40 os_memset(cap
, 0, sizeof(*cap
));
41 cap
->ht_capabilities_info
= host_to_le16(hapd
->iconf
->ht_capab
);
42 cap
->a_mpdu_params
= hapd
->iface
->current_mode
->a_mpdu_params
;
43 os_memcpy(cap
->supported_mcs_set
, hapd
->iface
->current_mode
->mcs_set
,
46 /* TODO: ht_extended_capabilities (now fully disabled) */
47 /* TODO: tx_bf_capability_info (now fully disabled) */
48 /* TODO: asel_capabilities (now fully disabled) */
56 u8
* hostapd_eid_ht_operation(struct hostapd_data
*hapd
, u8
*eid
)
58 struct ieee80211_ht_operation
*oper
;
61 if (!hapd
->iconf
->ieee80211n
)
64 *pos
++ = WLAN_EID_HT_OPERATION
;
65 *pos
++ = sizeof(*oper
);
67 oper
= (struct ieee80211_ht_operation
*) pos
;
68 os_memset(oper
, 0, sizeof(*oper
));
70 oper
->control_chan
= hapd
->iconf
->channel
;
71 oper
->operation_mode
= host_to_le16(hapd
->iface
->ht_op_mode
);
72 if (hapd
->iconf
->secondary_channel
== 1)
73 oper
->ht_param
|= HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE
|
74 HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH
;
75 if (hapd
->iconf
->secondary_channel
== -1)
76 oper
->ht_param
|= HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW
|
77 HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH
;
87 Set to 0 (HT pure) under the followign conditions
88 - all STAs in the BSS are 20/40 MHz HT in 20/40 MHz BSS or
89 - all STAs in the BSS are 20 MHz HT in 20 MHz BSS
90 Set to 1 (HT non-member protection) if there may be non-HT STAs
91 in both the primary and the secondary channel
92 Set to 2 if only HT STAs are associated in BSS,
93 however and at least one 20 MHz HT STA is associated
94 Set to 3 (HT mixed mode) when one or more non-HT STAs are associated
95 (currently non-GF HT station is considered as non-HT STA also)
97 int hostapd_ht_operation_update(struct hostapd_iface
*iface
)
99 u16 cur_op_mode
, new_op_mode
;
100 int op_mode_changes
= 0;
102 if (!iface
->conf
->ieee80211n
|| iface
->conf
->ht_op_mode_fixed
)
105 wpa_printf(MSG_DEBUG
, "%s current operation mode=0x%X",
106 __func__
, iface
->ht_op_mode
);
108 if (!(iface
->ht_op_mode
& HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT
)
109 && iface
->num_sta_ht_no_gf
) {
111 HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT
;
113 } else if ((iface
->ht_op_mode
&
114 HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT
) &&
115 iface
->num_sta_ht_no_gf
== 0) {
117 ~HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT
;
121 if (!(iface
->ht_op_mode
& HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT
) &&
122 (iface
->num_sta_no_ht
|| iface
->olbc_ht
)) {
123 iface
->ht_op_mode
|= HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT
;
125 } else if ((iface
->ht_op_mode
&
126 HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT
) &&
127 (iface
->num_sta_no_ht
== 0 && !iface
->olbc_ht
)) {
129 ~HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT
;
133 /* Note: currently we switch to the MIXED op mode if HT non-greenfield
134 * station is associated. Probably it's a theoretical case, since
135 * it looks like all known HT STAs support greenfield.
138 if (iface
->num_sta_no_ht
||
139 (iface
->ht_op_mode
& HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT
))
140 new_op_mode
= OP_MODE_MIXED
;
141 else if ((iface
->conf
->ht_capab
& HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET
)
142 && iface
->num_sta_ht_20mhz
)
143 new_op_mode
= OP_MODE_20MHZ_HT_STA_ASSOCED
;
144 else if (iface
->olbc_ht
)
145 new_op_mode
= OP_MODE_MAY_BE_LEGACY_STAS
;
147 new_op_mode
= OP_MODE_PURE
;
149 cur_op_mode
= iface
->ht_op_mode
& HT_INFO_OPERATION_MODE_OP_MODE_MASK
;
150 if (cur_op_mode
!= new_op_mode
) {
151 iface
->ht_op_mode
&= ~HT_INFO_OPERATION_MODE_OP_MODE_MASK
;
152 iface
->ht_op_mode
|= new_op_mode
;
156 wpa_printf(MSG_DEBUG
, "%s new operation mode=0x%X changes=%d",
157 __func__
, iface
->ht_op_mode
, op_mode_changes
);
159 return op_mode_changes
;
163 u16
copy_sta_ht_capab(struct sta_info
*sta
, const u8
*ht_capab
,
167 ht_capab_len
< sizeof(struct ieee80211_ht_capabilities
)) {
168 sta
->flags
&= ~WLAN_STA_HT
;
169 os_free(sta
->ht_capabilities
);
170 sta
->ht_capabilities
= NULL
;
171 return WLAN_STATUS_SUCCESS
;
174 if (sta
->ht_capabilities
== NULL
) {
175 sta
->ht_capabilities
=
176 os_zalloc(sizeof(struct ieee80211_ht_capabilities
));
177 if (sta
->ht_capabilities
== NULL
)
178 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
181 sta
->flags
|= WLAN_STA_HT
;
182 os_memcpy(sta
->ht_capabilities
, ht_capab
,
183 sizeof(struct ieee80211_ht_capabilities
));
185 return WLAN_STATUS_SUCCESS
;
189 static void update_sta_ht(struct hostapd_data
*hapd
, struct sta_info
*sta
)
193 ht_capab
= le_to_host16(sta
->ht_capabilities
->ht_capabilities_info
);
194 wpa_printf(MSG_DEBUG
, "HT: STA " MACSTR
" HT Capabilities Info: "
195 "0x%04x", MAC2STR(sta
->addr
), ht_capab
);
196 if ((ht_capab
& HT_CAP_INFO_GREEN_FIELD
) == 0) {
197 if (!sta
->no_ht_gf_set
) {
198 sta
->no_ht_gf_set
= 1;
199 hapd
->iface
->num_sta_ht_no_gf
++;
201 wpa_printf(MSG_DEBUG
, "%s STA " MACSTR
" - no greenfield, num "
202 "of non-gf stations %d",
203 __func__
, MAC2STR(sta
->addr
),
204 hapd
->iface
->num_sta_ht_no_gf
);
206 if ((ht_capab
& HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET
) == 0) {
207 if (!sta
->ht_20mhz_set
) {
208 sta
->ht_20mhz_set
= 1;
209 hapd
->iface
->num_sta_ht_20mhz
++;
211 wpa_printf(MSG_DEBUG
, "%s STA " MACSTR
" - 20 MHz HT, num of "
213 __func__
, MAC2STR(sta
->addr
),
214 hapd
->iface
->num_sta_ht_20mhz
);
219 static void update_sta_no_ht(struct hostapd_data
*hapd
, struct sta_info
*sta
)
221 if (!sta
->no_ht_set
) {
223 hapd
->iface
->num_sta_no_ht
++;
225 if (hapd
->iconf
->ieee80211n
) {
226 wpa_printf(MSG_DEBUG
, "%s STA " MACSTR
" - no HT, num of "
227 "non-HT stations %d",
228 __func__
, MAC2STR(sta
->addr
),
229 hapd
->iface
->num_sta_no_ht
);
234 void update_ht_state(struct hostapd_data
*hapd
, struct sta_info
*sta
)
236 if ((sta
->flags
& WLAN_STA_HT
) && sta
->ht_capabilities
)
237 update_sta_ht(hapd
, sta
);
239 update_sta_no_ht(hapd
, sta
);
241 if (hostapd_ht_operation_update(hapd
->iface
) > 0)
242 ieee802_11_set_beacons(hapd
->iface
);
246 void hostapd_get_ht_capab(struct hostapd_data
*hapd
,
247 struct ieee80211_ht_capabilities
*ht_cap
,
248 struct ieee80211_ht_capabilities
*neg_ht_cap
)
254 os_memcpy(neg_ht_cap
, ht_cap
, sizeof(*neg_ht_cap
));
255 cap
= le_to_host16(neg_ht_cap
->ht_capabilities_info
);
256 cap
&= hapd
->iconf
->ht_capab
;
257 cap
|= (hapd
->iconf
->ht_capab
& HT_CAP_INFO_SMPS_DISABLED
);
259 /* FIXME: Rx STBC needs to be handled specially */
260 cap
|= (hapd
->iconf
->ht_capab
& HT_CAP_INFO_RX_STBC_MASK
);
261 neg_ht_cap
->ht_capabilities_info
= host_to_le16(cap
);