00001
00017 #include "includes.h"
00018
00019 #include "hostapd.h"
00020 #include "ieee802_11.h"
00021 #include "wme.h"
00022 #include "sta_info.h"
00023 #include "driver_i.h"
00024
00025
00026
00027
00028
00029
00030
00031 static inline u8 wmm_aci_aifsn(int aifsn, int acm, int aci)
00032 {
00033 u8 ret;
00034 ret = (aifsn << WMM_AC_AIFNS_SHIFT) & WMM_AC_AIFSN_MASK;
00035 if (acm)
00036 ret |= WMM_AC_ACM;
00037 ret |= (aci << WMM_AC_ACI_SHIFT) & WMM_AC_ACI_MASK;
00038 return ret;
00039 }
00040
00041
00042 static inline u8 wmm_ecw(int ecwmin, int ecwmax)
00043 {
00044 return ((ecwmin << WMM_AC_ECWMIN_SHIFT) & WMM_AC_ECWMIN_MASK) |
00045 ((ecwmax << WMM_AC_ECWMAX_SHIFT) & WMM_AC_ECWMAX_MASK);
00046 }
00047
00048
00049
00050
00051
00052
00053 u8 * hostapd_eid_wmm(struct hostapd_data *hapd, u8 *eid)
00054 {
00055 u8 *pos = eid;
00056 struct wmm_parameter_element *wmm =
00057 (struct wmm_parameter_element *) (pos + 2);
00058 int e;
00059
00060 if (!hapd->conf->wmm_enabled)
00061 return eid;
00062 eid[0] = WLAN_EID_VENDOR_SPECIFIC;
00063 wmm->oui[0] = 0x00;
00064 wmm->oui[1] = 0x50;
00065 wmm->oui[2] = 0xf2;
00066 wmm->oui_type = WMM_OUI_TYPE;
00067 wmm->oui_subtype = WMM_OUI_SUBTYPE_PARAMETER_ELEMENT;
00068 wmm->version = WMM_VERSION;
00069 wmm->qos_info = hapd->parameter_set_count & 0xf;
00070
00071
00072 for (e = 0; e < 4; e++) {
00073 struct wmm_ac_parameter *ac = &wmm->ac[e];
00074 struct hostapd_wmm_ac_params *acp =
00075 &hapd->iconf->wmm_ac_params[e];
00076
00077 ac->aci_aifsn = wmm_aci_aifsn(acp->aifs,
00078 acp->admission_control_mandatory,
00079 e);
00080 ac->cw = wmm_ecw(acp->cwmin, acp->cwmax);
00081 ac->txop_limit = host_to_le16(acp->txop_limit);
00082 }
00083
00084 pos = (u8 *) (wmm + 1);
00085 eid[1] = pos - eid - 2;
00086
00087 return pos;
00088 }
00089
00090
00091
00092
00093
00094 int hostapd_eid_wmm_valid(struct hostapd_data *hapd, u8 *eid, size_t len)
00095 {
00096 struct wmm_information_element *wmm;
00097
00098 wpa_hexdump(MSG_MSGDUMP, "WMM IE", eid, len);
00099
00100 if (len < sizeof(struct wmm_information_element)) {
00101 wpa_printf(MSG_DEBUG, "Too short WMM IE (len=%lu)",
00102 (unsigned long) len);
00103 return -1;
00104 }
00105
00106 wmm = (struct wmm_information_element *) eid;
00107 wpa_printf(MSG_DEBUG, "Validating WMM IE: OUI %02x:%02x:%02x "
00108 "OUI type %d OUI sub-type %d version %d QoS info 0x%x",
00109 wmm->oui[0], wmm->oui[1], wmm->oui[2], wmm->oui_type,
00110 wmm->oui_subtype, wmm->version, wmm->qos_info);
00111 if (wmm->oui_subtype != WMM_OUI_SUBTYPE_INFORMATION_ELEMENT ||
00112 wmm->version != WMM_VERSION) {
00113 wpa_printf(MSG_DEBUG, "Unsupported WMM IE Subtype/Version");
00114 return -1;
00115 }
00116
00117 return 0;
00118 }
00119
00120
00121
00122
00123
00124 int hostapd_wmm_sta_config(struct hostapd_data *hapd, struct sta_info *sta)
00125 {
00126
00127 if (sta->flags & WLAN_STA_WMM)
00128 hostapd_sta_set_flags(hapd, sta->addr, sta->flags,
00129 WLAN_STA_WMM, ~0);
00130 else
00131 hostapd_sta_set_flags(hapd, sta->addr, sta->flags,
00132 0, ~WLAN_STA_WMM);
00133
00134 return 0;
00135 }
00136
00137
00138 static void wmm_send_action(struct hostapd_data *hapd, const u8 *addr,
00139 const struct wmm_tspec_element *tspec,
00140 u8 action_code, u8 dialogue_token, u8 status_code)
00141 {
00142 u8 buf[256];
00143 struct ieee80211_mgmt *m = (struct ieee80211_mgmt *) buf;
00144 struct wmm_tspec_element *t = (struct wmm_tspec_element *)
00145 m->u.action.u.wmm_action.variable;
00146 int len;
00147
00148 hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
00149 HOSTAPD_LEVEL_DEBUG,
00150 "action response - reason %d", status_code);
00151 os_memset(buf, 0, sizeof(buf));
00152 m->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
00153 WLAN_FC_STYPE_ACTION);
00154 os_memcpy(m->da, addr, ETH_ALEN);
00155 os_memcpy(m->sa, hapd->own_addr, ETH_ALEN);
00156 os_memcpy(m->bssid, hapd->own_addr, ETH_ALEN);
00157 m->u.action.category = WLAN_ACTION_WMM;
00158 m->u.action.u.wmm_action.action_code = action_code;
00159 m->u.action.u.wmm_action.dialog_token = dialogue_token;
00160 m->u.action.u.wmm_action.status_code = status_code;
00161 os_memcpy(t, tspec, sizeof(struct wmm_tspec_element));
00162 len = ((u8 *) (t + 1)) - buf;
00163
00164 if (hostapd_send_mgmt_frame(hapd, m, len) < 0)
00165 perror("wmm_send_action: send");
00166 }
00167
00168
00169 int wmm_process_tspec(struct wmm_tspec_element *tspec)
00170 {
00171 int medium_time, pps, duration;
00172 int up, psb, dir, tid;
00173 u16 val, surplus;
00174
00175 up = (tspec->ts_info[1] >> 3) & 0x07;
00176 psb = (tspec->ts_info[1] >> 2) & 0x01;
00177 dir = (tspec->ts_info[0] >> 5) & 0x03;
00178 tid = (tspec->ts_info[0] >> 1) & 0x0f;
00179 wpa_printf(MSG_DEBUG, "WMM: TS Info: UP=%d PSB=%d Direction=%d TID=%d",
00180 up, psb, dir, tid);
00181 val = le_to_host16(tspec->nominal_msdu_size);
00182 wpa_printf(MSG_DEBUG, "WMM: Nominal MSDU Size: %d%s",
00183 val & 0x7fff, val & 0x8000 ? " (fixed)" : "");
00184 wpa_printf(MSG_DEBUG, "WMM: Mean Data Rate: %u bps",
00185 le_to_host32(tspec->mean_data_rate));
00186 wpa_printf(MSG_DEBUG, "WMM: Minimum PHY Rate: %u bps",
00187 le_to_host32(tspec->minimum_phy_rate));
00188 val = le_to_host16(tspec->surplus_bandwidth_allowance);
00189 wpa_printf(MSG_DEBUG, "WMM: Surplus Bandwidth Allowance: %u.%04u",
00190 val >> 13, 10000 * (val & 0x1fff) / 0x2000);
00191
00192 val = le_to_host16(tspec->nominal_msdu_size);
00193 if (val == 0) {
00194 wpa_printf(MSG_DEBUG, "WMM: Invalid Nominal MSDU Size (0)");
00195 return WMM_ADDTS_STATUS_INVALID_PARAMETERS;
00196 }
00197
00198 pps = ((le_to_host32(tspec->mean_data_rate) / 8) + val - 1) / val;
00199 wpa_printf(MSG_DEBUG, "WMM: Packets-per-second estimate for TSPEC: %d",
00200 pps);
00201
00202 if (le_to_host32(tspec->minimum_phy_rate) < 1000000) {
00203 wpa_printf(MSG_DEBUG, "WMM: Too small Minimum PHY Rate");
00204 return WMM_ADDTS_STATUS_INVALID_PARAMETERS;
00205 }
00206
00207 duration = (le_to_host16(tspec->nominal_msdu_size) & 0x7fff) * 8 /
00208 (le_to_host32(tspec->minimum_phy_rate) / 1000000) +
00209 50 ;
00210
00211
00212
00213 surplus = le_to_host16(tspec->surplus_bandwidth_allowance);
00214 if (surplus <= 0x2000) {
00215 wpa_printf(MSG_DEBUG, "WMM: Surplus Bandwidth Allowance not "
00216 "greater than unity");
00217 return WMM_ADDTS_STATUS_INVALID_PARAMETERS;
00218 }
00219
00220 medium_time = surplus * pps * duration / 0x2000;
00221 wpa_printf(MSG_DEBUG, "WMM: Estimated medium time: %u", medium_time);
00222
00223
00224
00225
00226
00227
00228
00229 if (medium_time > 750000) {
00230 wpa_printf(MSG_DEBUG, "WMM: Refuse TSPEC request for over "
00231 "75%% of available bandwidth");
00232 return WMM_ADDTS_STATUS_REFUSED;
00233 }
00234
00235
00236 tspec->medium_time = host_to_le16(medium_time / 32);
00237
00238 return WMM_ADDTS_STATUS_ADMISSION_ACCEPTED;
00239 }
00240
00241
00242 static void wmm_addts_req(struct hostapd_data *hapd,
00243 struct ieee80211_mgmt *mgmt,
00244 struct wmm_tspec_element *tspec, size_t len)
00245 {
00246 u8 *end = ((u8 *) mgmt) + len;
00247 int res;
00248
00249 if ((u8 *) (tspec + 1) > end) {
00250 wpa_printf(MSG_DEBUG, "WMM: TSPEC overflow in ADDTS Request");
00251 return;
00252 }
00253
00254 wpa_printf(MSG_DEBUG, "WMM: ADDTS Request (Dialog Token %d) for TSPEC "
00255 "from " MACSTR,
00256 mgmt->u.action.u.wmm_action.dialog_token,
00257 MAC2STR(mgmt->sa));
00258
00259 res = wmm_process_tspec(tspec);
00260 wpa_printf(MSG_DEBUG, "WMM: ADDTS processing result: %d", res);
00261
00262 wmm_send_action(hapd, mgmt->sa, tspec, WMM_ACTION_CODE_ADDTS_RESP,
00263 mgmt->u.action.u.wmm_action.dialog_token, res);
00264 }
00265
00266
00267 void hostapd_wmm_action(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt,
00268 size_t len)
00269 {
00270 int action_code;
00271 int left = len - IEEE80211_HDRLEN - 4;
00272 u8 *pos = ((u8 *) mgmt) + IEEE80211_HDRLEN + 4;
00273 struct ieee802_11_elems elems;
00274 struct sta_info *sta = ap_get_sta(hapd, mgmt->sa);
00275
00276
00277 if (!sta ||
00278 (sta->flags & (WLAN_STA_ASSOC | WLAN_STA_WMM)) !=
00279 (WLAN_STA_ASSOC | WLAN_STA_WMM)) {
00280 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
00281 HOSTAPD_LEVEL_DEBUG,
00282 "wmm action received is not from associated wmm"
00283 " station");
00284
00285 return;
00286 }
00287
00288
00289 if (ieee802_11_parse_elems(pos, left, &elems, 1) == ParseFailed) {
00290 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
00291 HOSTAPD_LEVEL_DEBUG,
00292 "hostapd_wmm_action - could not parse wmm "
00293 "action");
00294
00295
00296 return;
00297 }
00298
00299 if (!elems.wmm_tspec ||
00300 elems.wmm_tspec_len != (sizeof(struct wmm_tspec_element) - 2)) {
00301 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
00302 HOSTAPD_LEVEL_DEBUG,
00303 "hostapd_wmm_action - missing or wrong length "
00304 "tspec");
00305
00306
00307 return;
00308 }
00309
00310
00311
00312
00313 action_code = mgmt->u.action.u.wmm_action.action_code;
00314 switch (action_code) {
00315 case WMM_ACTION_CODE_ADDTS_REQ:
00316 wmm_addts_req(hapd, mgmt, (struct wmm_tspec_element *)
00317 (elems.wmm_tspec - 2), len);
00318 return;
00319 #if 0
00320
00321 case WMM_ACTION_CODE_ADDTS_RESP:
00322 wmm_setup_request(hapd, mgmt, len);
00323 return;
00324
00325 case WMM_ACTION_CODE_DELTS:
00326 wmm_teardown(hapd, mgmt, len);
00327 return;
00328 #endif
00329 }
00330
00331 hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
00332 HOSTAPD_LEVEL_DEBUG,
00333 "hostapd_wmm_action - unknown action code %d",
00334 action_code);
00335 }
00336