#include "eloop.h"
#include "config_ssid.h"
#include "wpa_supplicant_i.h"
+#include "driver_i.h"
#include "wpa.h"
-#include "drivers/driver.h"
#include "ieee802_11_defs.h"
#include "ieee802_11_common.h"
#include "mlme.h"
static int ieee80211_sta_wep_configured(struct wpa_supplicant *wpa_s);
static void ieee80211_sta_timer(void *eloop_ctx, void *timeout_ctx);
static void ieee80211_sta_scan_timer(void *eloop_ctx, void *timeout_ctx);
+static void ieee80211_build_tspec(struct wpabuf *buf);
static int ieee80211_sta_set_channel(struct wpa_supplicant *wpa_s,
- wpa_hw_mode phymode, int chan,
+ hostapd_hw_mode phymode, int chan,
int freq)
{
size_t i;
- struct wpa_hw_modes *mode;
+ struct hostapd_hw_modes *mode;
for (i = 0; i < wpa_s->mlme.num_modes; i++) {
mode = &wpa_s->mlme.modes[i];
}
-
-#if 0 /* FIX */
static int ecw2cw(int ecw)
{
int cw = 1;
}
return cw - 1;
}
-#endif
static void ieee80211_sta_wmm_params(struct wpa_supplicant *wpa_s,
size_t left;
int count;
u8 *pos;
+ u8 wmm_acm;
if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1)
return;
pos = wmm_param + 8;
left = wmm_param_len - 8;
-#if 0 /* FIX */
wmm_acm = 0;
for (; left >= 4; left -= 4, pos += 4) {
int aci = (pos[0] >> 5) & 0x03;
int acm = (pos[0] >> 4) & 0x01;
- int queue;
+ int aifs, cw_max, cw_min, burst_time;
switch (aci) {
- case 1:
- queue = IEEE80211_TX_QUEUE_DATA3;
+ case 1: /* AC_BK */
if (acm)
- wmm_acm |= BIT(1) | BIT(2);
+ wmm_acm |= BIT(1) | BIT(2); /* BK/- */
break;
- case 2:
- queue = IEEE80211_TX_QUEUE_DATA1;
+ case 2: /* AC_VI */
if (acm)
- wmm_acm |= BIT(4) | BIT(5);
+ wmm_acm |= BIT(4) | BIT(5); /* CL/VI */
break;
- case 3:
- queue = IEEE80211_TX_QUEUE_DATA0;
+ case 3: /* AC_VO */
if (acm)
- wmm_acm |= BIT(6) | BIT(7);
+ wmm_acm |= BIT(6) | BIT(7); /* VO/NC */
break;
- case 0:
+ case 0: /* AC_BE */
default:
- queue = IEEE80211_TX_QUEUE_DATA2;
if (acm)
- wpa_s->mlme.wmm_acm |= BIT(0) | BIT(3);
+ wmm_acm |= BIT(0) | BIT(3); /* BE/EE */
break;
}
- params.aifs = pos[0] & 0x0f;
- params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4);
- params.cw_min = ecw2cw(pos[1] & 0x0f);
+ aifs = pos[0] & 0x0f;
+ cw_max = ecw2cw((pos[1] & 0xf0) >> 4);
+ cw_min = ecw2cw(pos[1] & 0x0f);
/* TXOP is in units of 32 usec; burst_time in 0.1 ms */
- params.burst_time = (pos[2] | (pos[3] << 8)) * 32 / 100;
- wpa_printf(MSG_DEBUG, "MLME: WMM queue=%d aci=%d acm=%d "
- "aifs=%d cWmin=%d cWmax=%d burst=%d",
- queue, aci, acm, params.aifs, params.cw_min,
- params.cw_max, params.burst_time);
- /* TODO: handle ACM (block TX, fallback to next lowest allowed
- * AC for now) */
- if (local->hw->conf_tx(local->mdev, queue, ¶ms)) {
- wpa_printf(MSG_DEBUG, "MLME: failed to set TX queue "
- "parameters for queue %d", queue);
- }
+ burst_time = (pos[2] | (pos[3] << 8)) * 32 / 100;
+ wpa_printf(MSG_DEBUG, "MLME: WMM aci=%d acm=%d aifs=%d "
+ "cWmin=%d cWmax=%d burst=%d",
+ aci, acm, aifs, cw_min, cw_max, burst_time);
+ /* TODO: driver configuration */
}
-#endif
}
blen = 0;
capab = wpa_s->mlme.capab;
- if (wpa_s->mlme.phymode == WPA_MODE_IEEE80211G) {
+ if (wpa_s->mlme.phymode == HOSTAPD_MODE_IEEE80211G) {
capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME |
WLAN_CAPABILITY_SHORT_PREAMBLE;
}
supp_rates[0] = WLAN_EID_SUPP_RATES;
supp_rates[1] = 0;
for (i = 0; i < wpa_s->mlme.num_curr_rates; i++) {
- struct wpa_rate_data *rate = &wpa_s->mlme.curr_rates[i];
+ struct hostapd_rate_data *rate = &wpa_s->mlme.curr_rates[i];
if (esupp_rates) {
pos = buf + len;
len++;
case WLAN_AUTH_FT:
{
union wpa_event_data data;
+ struct wpabuf *ric = NULL;
os_memset(&data, 0, sizeof(data));
data.ft_ies.ies = mgmt->u.auth.variable;
data.ft_ies.ies_len = len -
(mgmt->u.auth.variable - (u8 *) mgmt);
os_memcpy(data.ft_ies.target_ap, wpa_s->bssid, ETH_ALEN);
+ if (os_strcmp(wpa_s->driver->name, "test") == 0 &&
+ wpa_s->mlme.wmm_enabled) {
+ ric = wpabuf_alloc(200);
+ if (ric) {
+ /* Build simple RIC-Request: RDIE | TSPEC */
+
+ /* RIC Data (RDIE) */
+ wpabuf_put_u8(ric, WLAN_EID_RIC_DATA);
+ wpabuf_put_u8(ric, 4);
+ wpabuf_put_u8(ric, 0); /* RDIE Identifier */
+ wpabuf_put_u8(ric, 1); /* Resource Descriptor
+ * Count */
+ wpabuf_put_le16(ric, 0); /* Status Code */
+
+ /* WMM TSPEC */
+ ieee80211_build_tspec(ric);
+
+ data.ft_ies.ric_ies = wpabuf_head(ric);
+ data.ft_ies.ric_ies_len = wpabuf_len(ric);
+ }
+ }
+
wpa_supplicant_event(wpa_s, EVENT_FT_RESPONSE, &data);
+ wpabuf_free(ric);
ieee80211_auth_completed(wpa_s);
break;
}
}
+static void ieee80211_build_tspec(struct wpabuf *buf)
+{
+ struct wmm_tspec_element *tspec;
+ int tid, up;
+
+ tspec = wpabuf_put(buf, sizeof(*tspec));
+ tspec->eid = WLAN_EID_VENDOR_SPECIFIC;
+ tspec->length = sizeof(*tspec) - 2;
+ tspec->oui[0] = 0x00;
+ tspec->oui[1] = 0x50;
+ tspec->oui[2] = 0xf2;
+ tspec->oui_type = 2;
+ tspec->oui_subtype = 2;
+ tspec->version = 1;
+
+ tid = 1;
+ up = 6; /* Voice */
+ tspec->ts_info[0] = (tid << 1) |
+ (WMM_TSPEC_DIRECTION_BI_DIRECTIONAL << 5) |
+ BIT(7);
+ tspec->ts_info[1] = up << 3;
+ tspec->nominal_msdu_size = host_to_le16(1530);
+ tspec->mean_data_rate = host_to_le32(128000); /* bits per second */
+ tspec->minimum_phy_rate = host_to_le32(6000000);
+ tspec->surplus_bandwidth_allowance = host_to_le16(0x3000); /* 150% */
+}
+
+
+static void ieee80211_tx_addts(struct wpa_supplicant *wpa_s)
+{
+ struct wpabuf *buf;
+ struct ieee80211_mgmt *mgmt;
+ size_t alen;
+
+ wpa_printf(MSG_DEBUG, "MLME: Send ADDTS Request for Voice TSPEC");
+ mgmt = NULL;
+ alen = mgmt->u.action.u.wmm_action.variable - (u8 *) mgmt;
+
+ buf = wpabuf_alloc(alen + sizeof(struct wmm_tspec_element));
+ if (buf == NULL)
+ return;
+
+ mgmt = wpabuf_put(buf, alen);
+ os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
+ os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
+ os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
+ mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_ACTION);
+ mgmt->u.action.category = WLAN_ACTION_WMM;
+ mgmt->u.action.u.wmm_action.action_code = WMM_ACTION_CODE_ADDTS_REQ;
+ mgmt->u.action.u.wmm_action.dialog_token = 1;
+ mgmt->u.action.u.wmm_action.status_code = 0;
+
+ ieee80211_build_tspec(buf);
+
+ ieee80211_sta_tx(wpa_s, wpabuf_head(buf), wpabuf_len(buf));
+ wpabuf_free(buf);
+}
+
+
static void ieee80211_rx_mgmt_assoc_resp(struct wpa_supplicant *wpa_s,
struct ieee80211_mgmt *mgmt,
size_t len,
"netstack");
}
-#if 0 /* FIX? */
- sta->assoc_ap = 1;
-
- if (elems.wmm && wpa_s->mlme.wmm_enabled) {
- sta->flags |= WLAN_STA_WMM;
+ if (elems.wmm && wpa_s->mlme.wmm_enabled)
ieee80211_sta_wmm_params(wpa_s, elems.wmm, elems.wmm_len);
- }
-#endif
ieee80211_associated(wpa_s);
+
+ if (wpa_s->mlme.auth_alg != WLAN_AUTH_FT &&
+ os_strcmp(wpa_s->driver->name, "test") == 0 &&
+ elems.wmm && wpa_s->mlme.wmm_enabled) {
+ /* Test WMM-AC - send ADDTS for WMM TSPEC */
+ ieee80211_tx_addts(wpa_s);
+ }
}
bss->channel = channel;
bss->freq = wpa_s->mlme.freq;
if (channel != wpa_s->mlme.channel &&
- (wpa_s->mlme.phymode == WPA_MODE_IEEE80211G ||
- wpa_s->mlme.phymode == WPA_MODE_IEEE80211B) &&
+ (wpa_s->mlme.phymode == HOSTAPD_MODE_IEEE80211G ||
+ wpa_s->mlme.phymode == HOSTAPD_MODE_IEEE80211B) &&
channel >= 1 && channel <= 14) {
static const int freq_list[] = {
2412, 2417, 2422, 2427, 2432, 2437, 2442,
#endif /* CONFIG_IEEE80211W */
+static void dump_tspec(struct wmm_tspec_element *tspec)
+{
+ int up, psb, dir, tid;
+ u16 val;
+
+ up = (tspec->ts_info[1] >> 3) & 0x07;
+ psb = (tspec->ts_info[1] >> 2) & 0x01;
+ dir = (tspec->ts_info[0] >> 5) & 0x03;
+ tid = (tspec->ts_info[0] >> 1) & 0x0f;
+ wpa_printf(MSG_DEBUG, "WMM: TS Info: UP=%d PSB=%d Direction=%d TID=%d",
+ up, psb, dir, tid);
+ val = le_to_host16(tspec->nominal_msdu_size);
+ wpa_printf(MSG_DEBUG, "WMM: Nominal MSDU Size: %d%s",
+ val & 0x7fff, val & 0x8000 ? " (fixed)" : "");
+ wpa_printf(MSG_DEBUG, "WMM: Mean Data Rate: %u bps",
+ le_to_host32(tspec->mean_data_rate));
+ wpa_printf(MSG_DEBUG, "WMM: Minimum PHY Rate: %u bps",
+ le_to_host32(tspec->minimum_phy_rate));
+ val = le_to_host16(tspec->surplus_bandwidth_allowance);
+ wpa_printf(MSG_DEBUG, "WMM: Surplus Bandwidth Allowance: %u.%04u",
+ val >> 13, 10000 * (val & 0x1fff) / 0x2000);
+ val = le_to_host16(tspec->medium_time);
+ wpa_printf(MSG_DEBUG, "WMM: Medium Time: %u (= %u usec/sec)",
+ val, 32 * val);
+}
+
+
+static int is_wmm_tspec(const u8 *ie, size_t len)
+{
+ const struct wmm_tspec_element *tspec;
+
+ if (len < sizeof(*tspec))
+ return 0;
+
+ tspec = (const struct wmm_tspec_element *) ie;
+ if (tspec->eid != WLAN_EID_VENDOR_SPECIFIC ||
+ tspec->length < sizeof(*tspec) - 2 ||
+ tspec->oui[0] != 0x00 || tspec->oui[1] != 0x50 ||
+ tspec->oui[2] != 0xf2 || tspec->oui_type != 2 ||
+ tspec->oui_subtype != 2 || tspec->version != 1)
+ return 0;
+
+ return 1;
+}
+
+
+static void ieee80211_rx_addts_resp(
+ struct wpa_supplicant *wpa_s, struct ieee80211_mgmt *mgmt, size_t len,
+ size_t var_len)
+{
+ struct wmm_tspec_element *tspec;
+
+ wpa_printf(MSG_DEBUG, "WMM: Received ADDTS Response");
+ wpa_hexdump(MSG_MSGDUMP, "WMM: ADDTS Response IE(s)",
+ mgmt->u.action.u.wmm_action.variable, var_len);
+ if (!is_wmm_tspec(mgmt->u.action.u.wmm_action.variable, var_len))
+ return;
+ tspec = (struct wmm_tspec_element *)
+ mgmt->u.action.u.wmm_action.variable;
+ dump_tspec(tspec);
+}
+
+
+static void ieee80211_rx_delts(
+ struct wpa_supplicant *wpa_s, struct ieee80211_mgmt *mgmt, size_t len,
+ size_t var_len)
+{
+ struct wmm_tspec_element *tspec;
+
+ wpa_printf(MSG_DEBUG, "WMM: Received DELTS");
+ wpa_hexdump(MSG_MSGDUMP, "WMM: DELTS IE(s)",
+ mgmt->u.action.u.wmm_action.variable, var_len);
+ if (!is_wmm_tspec(mgmt->u.action.u.wmm_action.variable, var_len))
+ return;
+ tspec = (struct wmm_tspec_element *)
+ mgmt->u.action.u.wmm_action.variable;
+ dump_tspec(tspec);
+}
+
+
+static void ieee80211_rx_mgmt_wmm_action(
+ struct wpa_supplicant *wpa_s, struct ieee80211_mgmt *mgmt, size_t len,
+ struct ieee80211_rx_status *rx_status)
+{
+ size_t alen;
+
+ alen = mgmt->u.action.u.wmm_action.variable - (u8 *) mgmt;
+ if (len < alen) {
+ wpa_printf(MSG_DEBUG, "WMM: Received Action frame too short");
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "WMM: Received Action frame: Action Code %d, "
+ "Dialog Token %d, Status Code %d",
+ mgmt->u.action.u.wmm_action.action_code,
+ mgmt->u.action.u.wmm_action.dialog_token,
+ mgmt->u.action.u.wmm_action.status_code);
+
+ switch (mgmt->u.action.u.wmm_action.action_code) {
+ case WMM_ACTION_CODE_ADDTS_RESP:
+ ieee80211_rx_addts_resp(wpa_s, mgmt, len, len - alen);
+ break;
+ case WMM_ACTION_CODE_DELTS:
+ ieee80211_rx_delts(wpa_s, mgmt, len, len - alen);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "WMM: Unsupported Action Code %d",
+ mgmt->u.action.u.wmm_action.action_code);
+ break;
+ }
+}
+
+
static void ieee80211_rx_mgmt_action(struct wpa_supplicant *wpa_s,
struct ieee80211_mgmt *mgmt,
size_t len,
ieee80211_rx_mgmt_sa_query_action(wpa_s, mgmt, len, rx_status);
break;
#endif /* CONFIG_IEEE80211W */
+ case WLAN_ACTION_WMM:
+ ieee80211_rx_mgmt_wmm_action(wpa_s, mgmt, len, rx_status);
+ break;
default:
wpa_printf(MSG_DEBUG, "MLME: unknown Action Category %d",
mgmt->u.action.category);
int c;
for (m = 0; m < wpa_s->mlme.num_modes; m++) {
- struct wpa_hw_modes *mode = &wpa_s->mlme.modes[m];
+ struct hostapd_hw_modes *mode = &wpa_s->mlme.modes[m];
if ((int) mode->mode != (int) wpa_s->mlme.phymode)
continue;
for (c = 0; c < mode->num_channels; c++) {
- struct wpa_channel_data *chan = &mode->channels[c];
- if (chan->flag & WPA_CHAN_W_SCAN &&
+ struct hostapd_channel_data *chan = &mode->channels[c];
+ if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
chan->chan == wpa_s->mlme.channel) {
- if (chan->flag & WPA_CHAN_W_ACTIVE_SCAN)
+ if (!(chan->flag & HOSTAPD_CHAN_PASSIVE_SCAN))
return 1;
break;
}
static void ieee80211_sta_scan_timer(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
- struct wpa_hw_modes *mode;
- struct wpa_channel_data *chan;
+ struct hostapd_hw_modes *mode;
+ struct hostapd_channel_data *chan;
int skip = 0;
int timeout = 0;
struct wpa_ssid *ssid = wpa_s->current_ssid;
}
skip = !(wpa_s->mlme.hw_modes & (1 << mode->mode));
chan = &mode->channels[wpa_s->mlme.scan_channel_idx];
- if (!(chan->flag & WPA_CHAN_W_SCAN) ||
- (adhoc && !(chan->flag & WPA_CHAN_W_IBSS)) ||
- (wpa_s->mlme.hw_modes & (1 << WPA_MODE_IEEE80211G) &&
- mode->mode == WPA_MODE_IEEE80211B &&
+ if ((chan->flag & HOSTAPD_CHAN_DISABLED) ||
+ (adhoc && (chan->flag & HOSTAPD_CHAN_NO_IBSS)) ||
+ (wpa_s->mlme.hw_modes & (1 << HOSTAPD_MODE_IEEE80211G) &&
+ mode->mode == HOSTAPD_MODE_IEEE80211B &&
wpa_s->mlme.scan_skip_11b))
skip = 1;
}
-void ieee80211_sta_free_hw_features(struct wpa_hw_modes *hw_features,
+void ieee80211_sta_free_hw_features(struct hostapd_hw_modes *hw_features,
size_t num_hw_features)
{
size_t i;
wpa_s->mlme.num_modes = num_modes;
- wpa_s->mlme.hw_modes = 1 << WPA_MODE_IEEE80211A;
- wpa_s->mlme.hw_modes |= 1 << WPA_MODE_IEEE80211B;
- wpa_s->mlme.hw_modes |= 1 << WPA_MODE_IEEE80211G;
+ wpa_s->mlme.hw_modes = 1 << HOSTAPD_MODE_IEEE80211A;
+ wpa_s->mlme.hw_modes |= 1 << HOSTAPD_MODE_IEEE80211B;
+ wpa_s->mlme.hw_modes |= 1 << HOSTAPD_MODE_IEEE80211G;
+
+ wpa_s->mlme.wmm_enabled = 1;
return 0;
}