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 "drivers/driver.h"
21 #include "ap_config.h"
24 #include "ieee802_11.h"
27 u8
* hostapd_eid_ht_capabilities(struct hostapd_data
*hapd
, u8
*eid
)
29 struct ieee80211_ht_capabilities
*cap
;
32 if (!hapd
->iconf
->ieee80211n
)
35 *pos
++ = WLAN_EID_HT_CAP
;
36 *pos
++ = sizeof(*cap
);
38 cap
= (struct ieee80211_ht_capabilities
*) pos
;
39 os_memset(cap
, 0, sizeof(*cap
));
40 cap
->ht_capabilities_info
= host_to_le16(hapd
->iconf
->ht_capab
);
41 cap
->a_mpdu_params
= hapd
->iface
->current_mode
->a_mpdu_params
;
42 os_memcpy(cap
->supported_mcs_set
, hapd
->iface
->current_mode
->mcs_set
,
45 /* TODO: ht_extended_capabilities (now fully disabled) */
46 /* TODO: tx_bf_capability_info (now fully disabled) */
47 /* TODO: asel_capabilities (now fully disabled) */
55 u8
* hostapd_eid_ht_operation(struct hostapd_data
*hapd
, u8
*eid
)
57 struct ieee80211_ht_operation
*oper
;
60 if (!hapd
->iconf
->ieee80211n
)
63 *pos
++ = WLAN_EID_HT_OPERATION
;
64 *pos
++ = sizeof(*oper
);
66 oper
= (struct ieee80211_ht_operation
*) pos
;
67 os_memset(oper
, 0, sizeof(*oper
));
69 oper
->control_chan
= hapd
->iconf
->channel
;
70 oper
->operation_mode
= host_to_le16(hapd
->iface
->ht_op_mode
);
71 if (hapd
->iconf
->secondary_channel
== 1)
72 oper
->ht_param
|= HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE
|
73 HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH
;
74 if (hapd
->iconf
->secondary_channel
== -1)
75 oper
->ht_param
|= HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW
|
76 HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH
;
86 Set to 0 (HT pure) under the followign conditions
87 - all STAs in the BSS are 20/40 MHz HT in 20/40 MHz BSS or
88 - all STAs in the BSS are 20 MHz HT in 20 MHz BSS
89 Set to 1 (HT non-member protection) if there may be non-HT STAs
90 in both the primary and the secondary channel
91 Set to 2 if only HT STAs are associated in BSS,
92 however and at least one 20 MHz HT STA is associated
93 Set to 3 (HT mixed mode) when one or more non-HT STAs are associated
94 (currently non-GF HT station is considered as non-HT STA also)
96 int hostapd_ht_operation_update(struct hostapd_iface
*iface
)
98 u16 cur_op_mode
, new_op_mode
;
99 int op_mode_changes
= 0;
101 if (!iface
->conf
->ieee80211n
|| iface
->conf
->ht_op_mode_fixed
)
104 wpa_printf(MSG_DEBUG
, "%s current operation mode=0x%X",
105 __func__
, iface
->ht_op_mode
);
107 if (!(iface
->ht_op_mode
& HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT
)
108 && iface
->num_sta_ht_no_gf
) {
110 HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT
;
112 } else if ((iface
->ht_op_mode
&
113 HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT
) &&
114 iface
->num_sta_ht_no_gf
== 0) {
116 ~HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT
;
120 if (!(iface
->ht_op_mode
& HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT
) &&
121 (iface
->num_sta_no_ht
|| iface
->olbc_ht
)) {
122 iface
->ht_op_mode
|= HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT
;
124 } else if ((iface
->ht_op_mode
&
125 HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT
) &&
126 (iface
->num_sta_no_ht
== 0 && !iface
->olbc_ht
)) {
128 ~HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT
;
132 /* Note: currently we switch to the MIXED op mode if HT non-greenfield
133 * station is associated. Probably it's a theoretical case, since
134 * it looks like all known HT STAs support greenfield.
137 if (iface
->num_sta_no_ht
||
138 (iface
->ht_op_mode
& HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT
))
139 new_op_mode
= OP_MODE_MIXED
;
140 else if ((iface
->conf
->ht_capab
& HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET
)
141 && iface
->num_sta_ht_20mhz
)
142 new_op_mode
= OP_MODE_20MHZ_HT_STA_ASSOCED
;
143 else if (iface
->olbc_ht
)
144 new_op_mode
= OP_MODE_MAY_BE_LEGACY_STAS
;
146 new_op_mode
= OP_MODE_PURE
;
148 cur_op_mode
= iface
->ht_op_mode
& HT_INFO_OPERATION_MODE_OP_MODE_MASK
;
149 if (cur_op_mode
!= new_op_mode
) {
150 iface
->ht_op_mode
&= ~HT_INFO_OPERATION_MODE_OP_MODE_MASK
;
151 iface
->ht_op_mode
|= new_op_mode
;
155 wpa_printf(MSG_DEBUG
, "%s new operation mode=0x%X changes=%d",
156 __func__
, iface
->ht_op_mode
, op_mode_changes
);
158 return op_mode_changes
;
162 u16
copy_sta_ht_capab(struct sta_info
*sta
, const u8
*ht_capab
,
166 ht_capab_len
< sizeof(struct ieee80211_ht_capabilities
)) {
167 sta
->flags
&= ~WLAN_STA_HT
;
168 os_free(sta
->ht_capabilities
);
169 sta
->ht_capabilities
= NULL
;
170 return WLAN_STATUS_SUCCESS
;
173 if (sta
->ht_capabilities
== NULL
) {
174 sta
->ht_capabilities
=
175 os_zalloc(sizeof(struct ieee80211_ht_capabilities
));
176 if (sta
->ht_capabilities
== NULL
)
177 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
180 sta
->flags
|= WLAN_STA_HT
;
181 os_memcpy(sta
->ht_capabilities
, ht_capab
,
182 sizeof(struct ieee80211_ht_capabilities
));
184 return WLAN_STATUS_SUCCESS
;
188 static void update_sta_ht(struct hostapd_data
*hapd
, struct sta_info
*sta
)
192 ht_capab
= le_to_host16(sta
->ht_capabilities
->ht_capabilities_info
);
193 wpa_printf(MSG_DEBUG
, "HT: STA " MACSTR
" HT Capabilities Info: "
194 "0x%04x", MAC2STR(sta
->addr
), ht_capab
);
195 if ((ht_capab
& HT_CAP_INFO_GREEN_FIELD
) == 0) {
196 if (!sta
->no_ht_gf_set
) {
197 sta
->no_ht_gf_set
= 1;
198 hapd
->iface
->num_sta_ht_no_gf
++;
200 wpa_printf(MSG_DEBUG
, "%s STA " MACSTR
" - no greenfield, num "
201 "of non-gf stations %d",
202 __func__
, MAC2STR(sta
->addr
),
203 hapd
->iface
->num_sta_ht_no_gf
);
205 if ((ht_capab
& HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET
) == 0) {
206 if (!sta
->ht_20mhz_set
) {
207 sta
->ht_20mhz_set
= 1;
208 hapd
->iface
->num_sta_ht_20mhz
++;
210 wpa_printf(MSG_DEBUG
, "%s STA " MACSTR
" - 20 MHz HT, num of "
212 __func__
, MAC2STR(sta
->addr
),
213 hapd
->iface
->num_sta_ht_20mhz
);
218 static void update_sta_no_ht(struct hostapd_data
*hapd
, struct sta_info
*sta
)
220 if (!sta
->no_ht_set
) {
222 hapd
->iface
->num_sta_no_ht
++;
224 if (hapd
->iconf
->ieee80211n
) {
225 wpa_printf(MSG_DEBUG
, "%s STA " MACSTR
" - no HT, num of "
226 "non-HT stations %d",
227 __func__
, MAC2STR(sta
->addr
),
228 hapd
->iface
->num_sta_no_ht
);
233 void update_ht_state(struct hostapd_data
*hapd
, struct sta_info
*sta
)
235 if ((sta
->flags
& WLAN_STA_HT
) && sta
->ht_capabilities
)
236 update_sta_ht(hapd
, sta
);
238 update_sta_no_ht(hapd
, sta
);
240 if (hostapd_ht_operation_update(hapd
->iface
) > 0)
241 ieee802_11_set_beacons(hapd
->iface
);
245 void hostapd_get_ht_capab(struct hostapd_data
*hapd
,
246 struct ieee80211_ht_capabilities
*ht_cap
,
247 struct ieee80211_ht_capabilities
*neg_ht_cap
)
253 os_memcpy(neg_ht_cap
, ht_cap
, sizeof(*neg_ht_cap
));
254 cap
= le_to_host16(neg_ht_cap
->ht_capabilities_info
);
255 cap
&= hapd
->iconf
->ht_capab
;
256 cap
|= (hapd
->iconf
->ht_capab
& HT_CAP_INFO_SMPS_DISABLED
);
258 /* FIXME: Rx STBC needs to be handled specially */
259 cap
|= (hapd
->iconf
->ht_capab
& HT_CAP_INFO_RX_STBC_MASK
);
260 neg_ht_cap
->ht_capabilities_info
= host_to_le16(cap
);