@@ -976,6 +976,10 @@ OBJS += ../src/fst/fst_ctrl_iface.o
endif
endif
+ifdef CONFIG_MBO
+CFLAGS += -DCONFIG_MBO
+endif
+
ALL=hostapd hostapd_cli
all: verify_config $(ALL)
@@ -3293,6 +3293,10 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "subscr_remediation_method") == 0) {
bss->subscr_remediation_method = atoi(pos);
#endif /* CONFIG_HS20 */
+#ifdef CONFIG_MBO
+ } else if (os_strcmp(buf, "mbo") == 0) {
+ bss->mbo_enabled = atoi(pos);
+#endif /* CONFIG_MBO */
#ifdef CONFIG_TESTING_OPTIONS
#define PARSE_TEST_PROBABILITY(_val) \
} else if (os_strcmp(buf, #_val) == 0) { \
@@ -1376,6 +1376,27 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
} else if (os_strcasecmp(cmd, "ext_eapol_frame_io") == 0) {
hapd->ext_eapol_frame_io = atoi(value);
#endif /* CONFIG_TESTING_OPTIONS */
+#ifdef CONFIG_MBO
+ } else if (os_strcasecmp(cmd, "mbo_assoc_disallow") == 0) {
+ if (!hapd->conf->mbo_enabled) {
+ ret = -1;
+ } else {
+ int val = atoi(value);
+
+ if (val > 1) {
+ ret = -1;
+ } else {
+ hapd->mbo_assoc_disallow = val;
+ ieee802_11_update_beacons(hapd->iface);
+
+ /*
+ * TODO: Need to configure drivers that do
+ * AP MLME offload with disallowing station
+ * logic.
+ */
+ }
+ }
+#endif
} else {
struct sta_info *sta;
int vlan_id;
@@ -329,3 +329,8 @@ CONFIG_IPV6=y
# http://wireless.kernel.org/en/users/Documentation/acs
#
#CONFIG_ACS=y
+#
+# Multiband Operation Support
+# These extentions facilitate efficient use of multiple frequency bands
+# available to the AP and the devices that may associate with it.
+#CONFIG_MBO=y
@@ -572,6 +572,10 @@ struct hostapd_bss_config {
char *no_auth_if_seen_on;
int pbss;
+
+#ifdef CONFIG_MBO
+ int mbo_enabled;
+#endif /* CONFIG_MBO */
};
@@ -200,6 +200,26 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
}
#endif /* CONFIG_HS20 */
+#ifdef CONFIG_MBO
+ if (hapd->conf->mbo_enabled) {
+ pos = buf;
+ pos = hostapd_eid_mbo(hapd, buf, sizeof(buf));
+ if (pos != buf) {
+ if (wpabuf_resize(&beacon, pos - buf) != 0)
+ goto fail;
+ wpabuf_put_data(beacon, buf, pos - buf);
+
+ if (wpabuf_resize(&proberesp, pos - buf) != 0)
+ goto fail;
+ wpabuf_put_data(proberesp, buf, pos - buf);
+
+ if (wpabuf_resize(&assocresp, pos - buf) != 0)
+ goto fail;
+ wpabuf_put_data(assocresp, buf, pos - buf);
+ }
+ }
+#endif /* CONFIG_MBO */
+
if (hapd->conf->vendor_elements) {
size_t add = wpabuf_len(hapd->conf->vendor_elements);
if (wpabuf_resize(&beacon, add) == 0)
@@ -387,6 +387,9 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
buflen += 5 + 2 + sizeof(struct ieee80211_vht_capabilities) +
2 + sizeof(struct ieee80211_vht_operation);
}
+
+ buflen += hostapd_mbo_ie_len(hapd);
+
resp = os_zalloc(buflen);
if (resp == NULL)
return NULL;
@@ -518,6 +521,8 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
pos = hostapd_eid_osen(hapd, pos);
#endif /* CONFIG_HS20 */
+ pos = hostapd_eid_mbo(hapd, pos, (u8 *)resp + buflen - pos);
+
if (hapd->conf->vendor_elements) {
os_memcpy(pos, wpabuf_head(hapd->conf->vendor_elements),
wpabuf_len(hapd->conf->vendor_elements));
@@ -980,6 +985,8 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
}
#endif /* CONFIG_IEEE80211AC */
+ tail_len += hostapd_mbo_ie_len(hapd);
+
tailpos = tail = os_malloc(tail_len);
if (head == NULL || tail == NULL) {
wpa_printf(MSG_ERROR, "Failed to set beacon data");
@@ -1133,6 +1140,8 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
tailpos = hostapd_eid_osen(hapd, tailpos);
#endif /* CONFIG_HS20 */
+ tailpos = hostapd_eid_mbo(hapd, tailpos, tail + tail_len - tailpos);
+
if (hapd->conf->vendor_elements) {
os_memcpy(tailpos, wpabuf_head(hapd->conf->vendor_elements),
wpabuf_len(hapd->conf->vendor_elements));
@@ -281,6 +281,10 @@ struct hostapd_data {
struct l2_packet_data *l2_test;
#endif /* CONFIG_TESTING_OPTIONS */
+
+#ifdef CONFIG_MBO
+ unsigned int mbo_assoc_disallow;
+#endif /* CONFIG_MBO */
};
@@ -1766,6 +1766,8 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
p = hostapd_eid_p2p_manage(hapd, p);
#endif /* CONFIG_P2P_MANAGER */
+ p = hostapd_eid_mbo(hapd, p, buf + sizeof(buf) - p);
+
send_len += p - reply->u.assoc_resp.variable;
if (hostapd_drv_send_mlme(hapd, reply, send_len, 0) < 0)
@@ -1889,6 +1891,13 @@ static void handle_assoc(struct hostapd_data *hapd,
goto fail;
}
+#ifdef CONFIG_MBO
+ if (hapd->conf->mbo_enabled && hapd->mbo_assoc_disallow) {
+ resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
+ goto fail;
+ }
+#endif /* CONFIG_MBO */
+
/* followed by SSID and Supported rates; and HT capabilities if 802.11n
* is used */
resp = check_assoc_ies(hapd, sta, pos, left, reassoc);
@@ -109,4 +109,21 @@ static inline void sae_clear_retransmit_timer(struct hostapd_data *hapd,
}
#endif /* CONFIG_SAE */
+#ifdef CONFIG_MBO
+u8 *hostapd_eid_mbo(struct hostapd_data *hapd, u8 *eid, size_t len);
+
+u8 hostapd_mbo_ie_len(struct hostapd_data *hapd);
+#else /* CONFIG_MBO */
+static inline u8 *hostapd_eid_mbo(struct hostapd_data *hapd, u8 *eid,
+ size_t len)
+{
+ return eid;
+}
+
+static inline u8 hostapd_mbo_ie_len(struct hostapd_data *hapd)
+{
+ return 0;
+}
+#endif /* CONFIG_MBO */
+
#endif /* IEEE802_11_H */
@@ -508,3 +508,43 @@ u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid)
return pos;
}
+
+
+#ifdef CONFIG_MBO
+u8 *hostapd_eid_mbo(struct hostapd_data *hapd, u8 *eid, size_t len)
+{
+ u8 mbo[6];
+ u8 *pos = eid;
+ size_t mbo_len = 3;
+
+ if (hapd->conf->mbo_enabled) {
+ mbo[0] = MBO_ATTR_ID_CAPA_IND;
+ mbo[1] = 1;
+ /* Not Cellular aware */
+ mbo[2] = 0;
+
+ if (hapd->mbo_assoc_disallow) {
+ mbo[3] = MBO_ATTR_ID_ASSOC_DISALLOW;
+ mbo[4] = 1;
+ mbo[5] = hapd->mbo_assoc_disallow;
+ mbo_len = 6;
+ }
+
+ pos += mbo_add_ie(pos, len, mbo, mbo_len);
+ }
+
+ return pos;
+}
+
+
+u8 hostapd_mbo_ie_len(struct hostapd_data *hapd)
+{
+ if (!hapd->conf->mbo_enabled)
+ return 0;
+
+ /* MBO IE header (6) + Capability Indication attribute (3) +
+ * Association Disallowed attribute (3) = 12
+ */
+ return hapd->mbo_assoc_disallow ? 12 : 9;
+}
+#endif /* CONFIG_MBO */