return -1;
}
+
+static int parse_qos_map_set(struct hostapd_bss_config *bss,
+ char *buf, int line)
+{
+ u8 qos_map_set[16 + 2 * 21], count = 0;
+ char *pos = buf;
+ int val;
+
+ for (;;) {
+ if (count == sizeof(qos_map_set)) {
+ wpa_printf(MSG_ERROR, "Line %d: Too many qos_map_set "
+ "parameters '%s'", line, buf);
+ return -1;
+ }
+
+ val = atoi(pos);
+ if (val > 255 || val < 0) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid qos_map_set "
+ "'%s'", line, buf);
+ return -1;
+ }
+
+ qos_map_set[count++] = val;
+ pos = os_strchr(pos, ',');
+ if (!pos)
+ break;
+ pos++;
+ }
+
+ if (count < 16 || count & 1) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid qos_map_set '%s'",
+ line, buf);
+ return -1;
+ }
+
+ os_memcpy(bss->qos_map_set, qos_map_set, count);
+ bss->qos_map_set_len = count;
+
+ return 0;
+}
+
#endif /* CONFIG_INTERWORKING */
bss->gas_frag_limit = atoi(pos);
} else if (os_strcmp(buf, "gas_comeback_delay") == 0) {
bss->gas_comeback_delay = atoi(pos);
+ } else if (os_strcmp(buf, "qos_map_set") == 0) {
+ if (parse_qos_map_set(bss, pos, line) < 0)
+ errors++;
#endif /* CONFIG_INTERWORKING */
#ifdef CONFIG_RADIUS_TEST
} else if (os_strcmp(buf, "dump_msk_file") == 0) {
#endif /* CONFIG_WPS */
+#ifdef CONFIG_INTERWORKING
+
+static int hostapd_ctrl_iface_set_qos_map_set(struct hostapd_data *hapd,
+ const char *cmd)
+{
+ u8 qos_map_set[16 + 2 * 21], count = 0;
+ const char *pos = cmd;
+ int val, ret;
+
+ for (;;) {
+ if (count == sizeof(qos_map_set)) {
+ wpa_printf(MSG_ERROR, "Too many qos_map_set parameters");
+ return -1;
+ }
+
+ val = atoi(pos);
+ if (val < 0 || val > 255) {
+ wpa_printf(MSG_INFO, "Invalid QoS Map Set");
+ return -1;
+ }
+
+ qos_map_set[count++] = val;
+ pos = os_strchr(pos, ',');
+ if (!pos)
+ break;
+ pos++;
+ }
+
+ if (count < 16 || count & 1) {
+ wpa_printf(MSG_INFO, "Invalid QoS Map Set");
+ return -1;
+ }
+
+ ret = hostapd_drv_set_qos_map(hapd, qos_map_set, count);
+ if (ret) {
+ wpa_printf(MSG_INFO, "Failed to set QoS Map Set");
+ return -1;
+ }
+
+ os_memcpy(hapd->conf->qos_map_set, qos_map_set, count);
+ hapd->conf->qos_map_set_len = count;
+
+ return 0;
+}
+
+
+static int hostapd_ctrl_iface_send_qos_map_conf(struct hostapd_data *hapd,
+ const char *cmd)
+{
+ u8 addr[ETH_ALEN];
+ struct sta_info *sta;
+ struct wpabuf *buf;
+ u8 *qos_map_set = hapd->conf->qos_map_set;
+ u8 qos_map_set_len = hapd->conf->qos_map_set_len;
+ int ret;
+
+ if (!qos_map_set_len) {
+ wpa_printf(MSG_INFO, "QoS Map Set is not set");
+ return -1;
+ }
+
+ if (hwaddr_aton(cmd, addr))
+ return -1;
+
+ sta = ap_get_sta(hapd, addr);
+ if (sta == NULL) {
+ wpa_printf(MSG_DEBUG, "Station " MACSTR " not found "
+ "for QoS Map Configuration message",
+ MAC2STR(addr));
+ return -1;
+ }
+
+ if (!sta->qos_map_enabled) {
+ wpa_printf(MSG_DEBUG, "Station " MACSTR " did not indicate "
+ "support for QoS Map", MAC2STR(addr));
+ return -1;
+ }
+
+ buf = wpabuf_alloc(2 + 2 + qos_map_set_len);
+ if (buf == NULL)
+ return -1;
+
+ wpabuf_put_u8(buf, WLAN_ACTION_QOS);
+ wpabuf_put_u8(buf, QOS_QOS_MAP_CONFIG);
+
+ /* QoS Map Set Element */
+ wpabuf_put_u8(buf, WLAN_EID_QOS_MAP_SET);
+ wpabuf_put_u8(buf, qos_map_set_len);
+ wpabuf_put_data(buf, qos_map_set, qos_map_set_len);
+
+ ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
+ wpabuf_head(buf), wpabuf_len(buf));
+ wpabuf_free(buf);
+
+ return ret;
+}
+
+#endif /* CONFIG_INTERWORKING */
+
+
#ifdef CONFIG_WNM
static int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd,
reply_len = -1;
#endif /* CONFIG_WPS_NFC */
#endif /* CONFIG_WPS */
+#ifdef CONFIG_INTERWORKING
+ } else if (os_strncmp(buf, "SET_QOS_MAP_SET ", 16) == 0) {
+ if (hostapd_ctrl_iface_set_qos_map_set(hapd, buf + 16))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "SEND_QOS_MAP_CONF ", 18) == 0) {
+ if (hostapd_ctrl_iface_send_qos_map_conf(hapd, buf + 18))
+ reply_len = -1;
+#endif /* CONFIG_INTERWORKING */
#ifdef CONFIG_WNM
} else if (os_strncmp(buf, "DISASSOC_IMMINENT ", 18) == 0) {
if (hostapd_ctrl_iface_disassoc_imminent(hapd, buf + 18))
# username/password
#nai_realm=0,example.org,13[5:6],21[2:4][5:7]
+# QoS Map Set configuration
+#
+# Comma delimited QoS Map Set in decimal values
+# (see IEEE Std 802.11-2012, 8.4.2.97)
+#
+# format:
+# [<DSCP Exceptions[DSCP,UP]>,]<UP 0 range[low,high]>,...<UP 7 range[low,high]>
+#
+# There can be up to 21 optional DSCP Exceptions which are pairs of DSCP Value
+# (0..63 or 255) and User Priority (0..7). This is followed by eight DSCP Range
+# descriptions with DSCP Low Value and DSCP High Value pairs (0..63 or 255) for
+# each UP starting from 0. If both low and high value are set to 255, the
+# corresponding UP is not used.
+#
+# default: not set
+#qos_map_set=53,2,22,6,8,15,0,7,255,255,16,31,32,39,255,255,40,47,255,255
+
##### Hotspot 2.0 #############################################################
# Enable Hotspot 2.0 support
}
+static int hostapd_cli_cmd_set_qos_map_set(struct wpa_ctrl *ctrl,
+ int argc, char *argv[])
+{
+ char buf[200];
+ int res;
+
+ if (argc != 1) {
+ printf("Invalid 'set_qos_map_set' command - "
+ "one argument (comma delimited QoS map set) "
+ "is needed\n");
+ return -1;
+ }
+
+ res = os_snprintf(buf, sizeof(buf), "SET_QOS_MAP_SET %s", argv[0]);
+ if (res < 0 || res >= (int) sizeof(buf))
+ return -1;
+ return wpa_ctrl_command(ctrl, buf);
+}
+
+
+static int hostapd_cli_cmd_send_qos_map_conf(struct wpa_ctrl *ctrl,
+ int argc, char *argv[])
+{
+ char buf[50];
+ int res;
+
+ if (argc != 1) {
+ printf("Invalid 'send_qos_map_conf' command - "
+ "one argument (STA addr) is needed\n");
+ return -1;
+ }
+
+ res = os_snprintf(buf, sizeof(buf), "SEND_QOS_MAP_CONF %s", argv[0]);
+ if (res < 0 || res >= (int) sizeof(buf))
+ return -1;
+ return wpa_ctrl_command(ctrl, buf);
+}
+
+
static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
hostapd_cli_quit = 1;
{ "quit", hostapd_cli_cmd_quit },
{ "set", hostapd_cli_cmd_set },
{ "get", hostapd_cli_cmd_get },
+ { "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set },
+ { "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf },
{ NULL, NULL }
};
iface->drv_max_acl_mac_addrs = capa.max_acl_mac_addrs;
}
+#ifdef CONFIG_INTERWORKING
+ if (hapd->driver->set_qos_map && conf->qos_map_set_len &&
+ hapd->driver->set_qos_map(hapd->drv_priv, conf->qos_map_set,
+ conf->qos_map_set_len)) {
+ wpa_printf(MSG_ERROR, "Failed to initialize QoS Map.");
+ return -1;
+ }
+#endif /* CONFIG_INTERWORKING */
+
return 0;
}
u16 gas_comeback_delay;
int gas_frag_limit;
+ u8 qos_map_set[16 + 2 * 21];
+ unsigned int qos_map_set_len;
+
#ifdef CONFIG_HS20
int hs20;
int disable_dgaf;
return hapd->driver->start_dfs_cac(hapd->drv_priv, &data);
}
+
+
+int hostapd_drv_set_qos_map(struct hostapd_data *hapd,
+ const u8 *qos_map_set, u8 qos_map_set_len)
+{
+ if (hapd->driver == NULL || hapd->driver->set_qos_map == NULL)
+ return 0;
+ return hapd->driver->set_qos_map(hapd->drv_priv, qos_map_set,
+ qos_map_set_len);
+}
enum wnm_oper oper, const u8 *peer,
u8 *buf, u16 *buf_len);
+int hostapd_drv_set_qos_map(struct hostapd_data *hapd, const u8 *qos_map_set,
+ u8 qos_map_set_len);
+
static inline int hostapd_drv_set_countermeasures(struct hostapd_data *hapd,
int enabled)
{
}
#endif /* CONFIG_P2P */
+#ifdef CONFIG_INTERWORKING
+ if (elems.ext_capab && elems.ext_capab_len > 4) {
+ if (elems.ext_capab[4] & 0x01)
+ sta->qos_map_enabled = 1;
+ }
+#endif /* CONFIG_INTERWORKING */
+
#ifdef CONFIG_HS20
wpabuf_free(sta->hs20_ie);
if (elems.hs20 && elems.hs20_len > 4) {
}
+static u16 check_ext_capab(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *ext_capab_ie, size_t ext_capab_ie_len)
+{
+#ifdef CONFIG_INTERWORKING
+ /* check for QoS Map support */
+ if (ext_capab_ie_len >= 5) {
+ if (ext_capab_ie[4] & 0x01)
+ sta->qos_map_enabled = 1;
+ }
+#endif /* CONFIG_INTERWORKING */
+
+ return WLAN_STATUS_SUCCESS;
+}
+
+
static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ies, size_t ies_len, int reassoc)
{
resp = check_wmm(hapd, sta, elems.wmm, elems.wmm_len);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
+ resp = check_ext_capab(hapd, sta, elems.ext_capab, elems.ext_capab_len);
+ if (resp != WLAN_STATUS_SUCCESS)
+ return resp;
resp = copy_supp_rates(hapd, sta, &elems);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
p = hostapd_eid_ext_capab(hapd, p);
p = hostapd_eid_bss_max_idle_period(hapd, p);
+ if (sta->qos_map_enabled)
+ p = hostapd_eid_qos_map_set(hapd, p);
if (sta->flags & WLAN_STA_WMM)
p = hostapd_eid_wmm(hapd, p);
u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
int probe);
u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_qos_map_set(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid);
*pos |= 0x80; /* Bit 31 - Interworking */
break;
case 4: /* Bits 32-39 */
+ if (hapd->conf->qos_map_set_len)
+ *pos |= 0x01; /* Bit 32 - QoS Map */
if (hapd->conf->tdls & TDLS_PROHIBIT)
*pos |= 0x40; /* Bit 38 - TDLS Prohibited */
if (hapd->conf->tdls & TDLS_PROHIBIT_CHAN_SWITCH) {
}
+u8 * hostapd_eid_qos_map_set(struct hostapd_data *hapd, u8 *eid)
+{
+ u8 *pos = eid;
+ u8 len = hapd->conf->qos_map_set_len;
+
+ if (!len)
+ return eid;
+
+ *pos++ = WLAN_EID_QOS_MAP_SET;
+ *pos++ = len;
+ os_memcpy(pos, hapd->conf->qos_map_set, len);
+ pos += len;
+
+ return pos;
+}
+
+
u8 * hostapd_eid_interworking(struct hostapd_data *hapd, u8 *eid)
{
u8 *pos = eid;
unsigned int no_ht_set:1;
unsigned int ht_20mhz_set:1;
unsigned int no_p2p_set:1;
+ unsigned int qos_map_enabled:1;
u16 auth_alg;
u8 previous_ap[6];
#define WLAN_EID_LINK_ID 101
#define WLAN_EID_INTERWORKING 107
#define WLAN_EID_ADV_PROTO 108
+#define WLAN_EID_QOS_MAP_SET 110
#define WLAN_EID_ROAMING_CONSORTIUM 111
#define WLAN_EID_EXT_CAPAB 127
#define WLAN_EID_CCKM 156
#define WNM_NEIGHBOR_RRM_ENABLED_CAPABILITIES 70
#define WNM_NEIGHBOR_MULTIPLE_BSSID 71
+/* QoS action */
+enum qos_action {
+ QOS_ADDTS_REQ = 0,
+ QOS_ADDTS_RESP = 1,
+ QOS_DELTS = 2,
+ QOS_SCHEDULE = 3,
+ QOS_QOS_MAP_CONFIG = 4,
+};
+
/* IEEE Std 802.11-2012, 8.4.2.62 20/40 BSS Coexistence element */
#define WLAN_20_40_BSS_COEX_INFO_REQ BIT(0)
#define WLAN_20_40_BSS_COEX_40MHZ_INTOL BIT(1)
u8 *buf, u16 *buf_len);
/**
+ * set_qos_map - Set QoS Map
+ * @priv: Private driver interface data
+ * @qos_map_set: QoS Map
+ * @qos_map_set_len: Length of QoS Map
+ */
+ int (*set_qos_map)(void *priv, const u8 *qos_map_set,
+ u8 qos_map_set_len);
+
+ /**
* signal_poll - Get current connection information
* @priv: Private driver interface data
* @signal_info: Connection info structure