mirror of
https://github.com/Telecominfraproject/wlan-ap.git
synced 2025-10-30 01:52:51 +00:00
371 lines
11 KiB
Diff
371 lines
11 KiB
Diff
--- a/hostapd/config_file.c
|
|
+++ b/hostapd/config_file.c
|
|
@@ -4172,10 +4172,12 @@ static int hostapd_config_fill(struct ho
|
|
#ifdef CONFIG_MBO
|
|
} else if (os_strcmp(buf, "mbo") == 0) {
|
|
bss->mbo_enabled = atoi(pos);
|
|
- } else if (os_strcmp(buf, "mbo_cell_data_conn_pref") == 0) {
|
|
- bss->mbo_cell_data_conn_pref = atoi(pos);
|
|
+ } else if (os_strcmp(buf, "mbo_ap_cap_ind") == 0) {
|
|
+ bss->mbo_ap_cap_ind = atoi(pos);
|
|
} else if (os_strcmp(buf, "oce") == 0) {
|
|
bss->oce = atoi(pos);
|
|
+ } else if (os_strcmp(buf, "mbo_cell_data_conn_pref") == 0) {
|
|
+ bss->mbo_cell_data_conn_pref = atoi(pos);
|
|
#endif /* CONFIG_MBO */
|
|
#ifdef CONFIG_TESTING_OPTIONS
|
|
#define PARSE_TEST_PROBABILITY(_val) \
|
|
--- a/hostapd/ctrl_iface.c
|
|
+++ b/hostapd/ctrl_iface.c
|
|
@@ -945,10 +945,11 @@ static int hostapd_ctrl_iface_bss_tm_req
|
|
if (pos) {
|
|
pos += 10;
|
|
req_mode |= WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED;
|
|
- /* TODO: TSF configurable/learnable */
|
|
+ /* TODO: TSF learnable */
|
|
bss_term_dur[0] = 4; /* Subelement ID */
|
|
bss_term_dur[1] = 10; /* Length */
|
|
- os_memset(&bss_term_dur[2], 0, 8);
|
|
+ bss_term_dur[2] = atoi(pos); /* TSF */
|
|
+ os_memset(&bss_term_dur[3], 0, 7);
|
|
end = os_strchr(pos, ',');
|
|
if (end == NULL) {
|
|
wpa_printf(MSG_DEBUG, "Invalid bss_term data");
|
|
@@ -958,7 +959,7 @@ static int hostapd_ctrl_iface_bss_tm_req
|
|
WPA_PUT_LE16(&bss_term_dur[10], atoi(end));
|
|
}
|
|
|
|
- nei_len = ieee802_11_parse_candidate_list(cmd, nei_rep,
|
|
+ nei_len = ieee802_11_parse_candidate_list(cmd, sta, nei_rep,
|
|
sizeof(nei_rep));
|
|
if (nei_len < 0)
|
|
return -1;
|
|
--- a/src/ap/ap_config.h
|
|
+++ b/src/ap/ap_config.h
|
|
@@ -722,6 +722,11 @@ struct hostapd_bss_config {
|
|
* - Set BIT(2) to enable OCE in AP mode
|
|
*/
|
|
unsigned int oce;
|
|
+ /**
|
|
+ * Set BIT(6) to advertise cellular data aware capability
|
|
+ * in AP mode
|
|
+ */
|
|
+ unsigned int mbo_ap_cap_ind;
|
|
int mbo_cell_data_conn_pref;
|
|
#endif /* CONFIG_MBO */
|
|
|
|
--- a/src/ap/gas_serv.c
|
|
+++ b/src/ap/gas_serv.c
|
|
@@ -19,6 +19,7 @@
|
|
#include "dpp_hostapd.h"
|
|
#include "sta_info.h"
|
|
#include "gas_serv.h"
|
|
+#include "neighbor_db.h"
|
|
|
|
|
|
#ifdef CONFIG_DPP
|
|
@@ -603,6 +604,28 @@ static void anqp_add_domain_name(struct
|
|
}
|
|
}
|
|
|
|
+static void anqp_add_neighbor_report(struct hostapd_data *hapd,
|
|
+ struct wpabuf *buf)
|
|
+{
|
|
+ if (anqp_add_override(hapd, buf, ANQP_NEIGHBOR_REPORT))
|
|
+ return;
|
|
+
|
|
+ if (hapd->conf->radio_measurements[0] &
|
|
+ WLAN_RRM_CAPS_NEIGHBOR_REPORT) {
|
|
+ u8* len, *nei_len;
|
|
+ len = gas_anqp_add_element(buf, ANQP_NEIGHBOR_REPORT);
|
|
+ wpabuf_put_u8(buf, WLAN_EID_NEIGHBOR_REPORT);
|
|
+ nei_len = (u8 *)wpabuf_put(buf, 1);
|
|
+
|
|
+ if (hostapd_prepare_neighbor_buf(hapd, hapd->own_addr,
|
|
+ buf)) {
|
|
+ buf->used -= 2;
|
|
+ return;
|
|
+ }
|
|
+ *nei_len = ((u8 *)wpabuf_put(buf, 0) - nei_len - 1);
|
|
+ gas_anqp_set_element_len(buf, len);
|
|
+ }
|
|
+}
|
|
|
|
#ifdef CONFIG_FILS
|
|
static void anqp_add_fils_realm_info(struct hostapd_data *hapd,
|
|
@@ -1028,6 +1051,8 @@ gas_serv_build_gas_resp_payload(struct h
|
|
anqp_add_elem(hapd, buf, ANQP_TDLS_CAPABILITY);
|
|
if (request & ANQP_REQ_EMERGENCY_NAI)
|
|
anqp_add_elem(hapd, buf, ANQP_EMERGENCY_NAI);
|
|
+ if (request & ANQP_REQ_NEIGHBOR_REPORT)
|
|
+ anqp_add_neighbor_report(hapd, buf);
|
|
|
|
for (i = 0; i < num_extra_req; i++) {
|
|
#ifdef CONFIG_FILS
|
|
@@ -1172,6 +1197,12 @@ static void rx_anqp_query_list_id(struct
|
|
"Emergency NAI",
|
|
get_anqp_elem(hapd, info_id) != NULL, qi);
|
|
break;
|
|
+ case ANQP_NEIGHBOR_REPORT:
|
|
+ set_anqp_req(ANQP_REQ_NEIGHBOR_REPORT,
|
|
+ "Neighbor report",
|
|
+ (hapd->conf->radio_measurements[0] &
|
|
+ WLAN_RRM_CAPS_NEIGHBOR_REPORT), qi);
|
|
+ break;
|
|
default:
|
|
#ifdef CONFIG_FILS
|
|
if (info_id == ANQP_FILS_REALM_INFO &&
|
|
--- a/src/ap/gas_serv.h
|
|
+++ b/src/ap/gas_serv.h
|
|
@@ -40,6 +40,8 @@
|
|
(1 << (ANQP_TDLS_CAPABILITY - ANQP_QUERY_LIST))
|
|
#define ANQP_REQ_EMERGENCY_NAI \
|
|
(1 << (ANQP_EMERGENCY_NAI - ANQP_QUERY_LIST))
|
|
+#define ANQP_REQ_NEIGHBOR_REPORT \
|
|
+ (1 << (ANQP_NEIGHBOR_REPORT - ANQP_QUERY_LIST))
|
|
/*
|
|
* First 15 Hotspot 2.0 vendor specific ANQP-elements can be included in the
|
|
* optimized bitmap.
|
|
--- a/src/ap/ieee802_11.h
|
|
+++ b/src/ap/ieee802_11.h
|
|
@@ -132,6 +132,9 @@ static inline void sae_clear_retransmit_
|
|
}
|
|
#endif /* CONFIG_SAE */
|
|
|
|
+u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd,
|
|
+ u8 *eid, size_t len);
|
|
+
|
|
#ifdef CONFIG_MBO
|
|
|
|
u8 * hostapd_eid_mbo(struct hostapd_data *hapd, u8 *eid, size_t len);
|
|
--- a/src/ap/ieee802_11_shared.c
|
|
+++ b/src/ap/ieee802_11_shared.c
|
|
@@ -801,11 +801,13 @@ u8 * hostapd_eid_mbo(struct hostapd_data
|
|
!OCE_STA_CFON_ENABLED(hapd) && !OCE_AP_ENABLED(hapd))
|
|
return eid;
|
|
|
|
- if (hapd->conf->mbo_enabled) {
|
|
+ if (hapd->conf->mbo_enabled && hapd->conf->oce & OCE_AP) {
|
|
*mbo_pos++ = MBO_ATTR_ID_AP_CAPA_IND;
|
|
*mbo_pos++ = 1;
|
|
- /* Not Cellular aware */
|
|
- *mbo_pos++ = 0;
|
|
+ if (hapd->conf->mbo_ap_cap_ind & MBO_AP_CAPA_CELL_AWARE)
|
|
+ *mbo_pos++ = MBO_AP_CAPA_CELL_AWARE;
|
|
+ else
|
|
+ *mbo_pos++ = 0;
|
|
}
|
|
|
|
if (hapd->conf->mbo_enabled && hapd->mbo_assoc_disallow) {
|
|
--- a/src/ap/neighbor_db.c
|
|
+++ b/src/ap/neighbor_db.c
|
|
@@ -160,6 +160,24 @@ fail:
|
|
return -1;
|
|
}
|
|
|
|
+int hostapd_prepare_neighbor_buf(struct hostapd_data *hapd,
|
|
+ const u8 *bssid, struct wpabuf *nrbuf)
|
|
+{
|
|
+ struct hostapd_neighbor_entry *nr;
|
|
+
|
|
+ nr = hostapd_neighbor_get(hapd, bssid, NULL);
|
|
+ if (!nr)
|
|
+ return -1;
|
|
+
|
|
+ if (wpabuf_tailroom(nrbuf) < wpabuf_len(nr->nr)) {
|
|
+ wpa_printf(MSG_ERROR,
|
|
+ "Invalid buf size for Neighbor Report\n");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ wpabuf_put_buf(nrbuf, nr->nr);
|
|
+ return 0;
|
|
+}
|
|
|
|
int hostapd_neighbor_remove(struct hostapd_data *hapd, const u8 *bssid,
|
|
const struct wpa_ssid_value *ssid)
|
|
--- a/src/ap/neighbor_db.h
|
|
+++ b/src/ap/neighbor_db.h
|
|
@@ -19,6 +19,8 @@ int hostapd_neighbor_set(struct hostapd_
|
|
const struct wpabuf *nr, const struct wpabuf *lci,
|
|
const struct wpabuf *civic, int stationary);
|
|
void hostapd_neighbor_set_own_report(struct hostapd_data *hapd);
|
|
+int hostapd_prepare_neighbor_buf(struct hostapd_data *hapd,
|
|
+ const u8 *bssid, struct wpabuf *nrbuf);
|
|
int hostapd_neighbor_remove(struct hostapd_data *hapd, const u8 *bssid,
|
|
const struct wpa_ssid_value *ssid);
|
|
void hostapd_free_neighbor_db(struct hostapd_data *hapd);
|
|
--- a/src/ap/wnm_ap.c
|
|
+++ b/src/ap/wnm_ap.c
|
|
@@ -20,6 +20,7 @@
|
|
#include "ap/wpa_auth.h"
|
|
#include "mbo_ap.h"
|
|
#include "wnm_ap.h"
|
|
+#include "neighbor_db.h"
|
|
|
|
#define MAX_TFS_IE_LEN 1024
|
|
|
|
@@ -366,11 +367,27 @@ static int ieee802_11_send_bss_trans_mgm
|
|
u8 dialog_token)
|
|
{
|
|
struct ieee80211_mgmt *mgmt;
|
|
- size_t len;
|
|
+ size_t len, nr_len = 0;
|
|
u8 *pos;
|
|
+ u8 req_mode = 0;
|
|
int res;
|
|
|
|
- mgmt = os_zalloc(sizeof(*mgmt));
|
|
+#ifdef CONFIG_MBO
|
|
+ u8 *nr_pos;
|
|
+ struct hostapd_neighbor_entry *nr;
|
|
+ struct wpabuf *nrbuf = NULL;
|
|
+ if (hapd->conf->mbo_enabled) {
|
|
+ dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
|
|
+ list)
|
|
+ /* ID and length */
|
|
+ nr_len += wpabuf_len(nr->nr) + 1 + 1;
|
|
+
|
|
+ nrbuf = wpabuf_alloc(nr_len);
|
|
+ if (nrbuf == NULL)
|
|
+ return -1;
|
|
+ }
|
|
+#endif
|
|
+ mgmt = os_zalloc(sizeof(*mgmt) + nr_len);
|
|
if (mgmt == NULL)
|
|
return -1;
|
|
os_memcpy(mgmt->da, addr, ETH_ALEN);
|
|
@@ -381,7 +398,11 @@ static int ieee802_11_send_bss_trans_mgm
|
|
mgmt->u.action.category = WLAN_ACTION_WNM;
|
|
mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
|
|
mgmt->u.action.u.bss_tm_req.dialog_token = dialog_token;
|
|
- mgmt->u.action.u.bss_tm_req.req_mode = 0;
|
|
+#ifdef CONFIG_MBO
|
|
+ if (hapd->conf->mbo_enabled)
|
|
+ req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED;
|
|
+#endif
|
|
+ mgmt->u.action.u.bss_tm_req.req_mode = req_mode;
|
|
mgmt->u.action.u.bss_tm_req.disassoc_timer = host_to_le16(0);
|
|
mgmt->u.action.u.bss_tm_req.validity_interval = 1;
|
|
pos = mgmt->u.action.u.bss_tm_req.variable;
|
|
@@ -395,6 +416,25 @@ static int ieee802_11_send_bss_trans_mgm
|
|
le_to_host16(mgmt->u.action.u.bss_tm_req.disassoc_timer),
|
|
mgmt->u.action.u.bss_tm_req.validity_interval);
|
|
|
|
+#ifdef CONFIG_MBO
|
|
+ if (hapd->conf->mbo_enabled) {
|
|
+ dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
|
|
+ list) {
|
|
+ wpabuf_put_u8(nrbuf, WLAN_EID_NEIGHBOR_REPORT);
|
|
+ /* Length to be filled */
|
|
+ nr_pos = (u8 *)wpabuf_put(nrbuf, 1);
|
|
+ if (hostapd_prepare_neighbor_buf(hapd, nr->bssid,
|
|
+ nrbuf) < 0) {
|
|
+ res = -1;
|
|
+ }
|
|
+ /* Fill in the length field */
|
|
+ *nr_pos = ((u8 *)wpabuf_put(nrbuf, 0) - nr_pos - 1);
|
|
+ }
|
|
+ os_memcpy(pos, nrbuf->buf, nr_len);
|
|
+ pos += nr_len;
|
|
+ wpabuf_free(nrbuf);
|
|
+ }
|
|
+#endif
|
|
len = pos - &mgmt->u.action.category;
|
|
res = hostapd_drv_send_action(hapd, hapd->iface->freq, 0,
|
|
mgmt->da, &mgmt->u.action.category, len);
|
|
--- a/src/common/ieee802_11_common.c
|
|
+++ b/src/common/ieee802_11_common.c
|
|
@@ -2290,11 +2290,21 @@ bool is_6ghz_psc_frequency(int freq)
|
|
}
|
|
|
|
|
|
-int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
|
|
- size_t nei_rep_len)
|
|
+int ieee802_11_parse_candidate_list(const char *pos, struct sta_info *sta,
|
|
+ u8 *nei_rep, size_t nei_rep_len)
|
|
{
|
|
u8 *nei_pos = nei_rep;
|
|
const char *end;
|
|
+#ifdef CONFIG_MBO
|
|
+ u8 non_pref_chan = 0;
|
|
+ u8 *pref_pos = NULL;
|
|
+ int i;
|
|
+
|
|
+ struct mbo_non_pref_chan_info *info = NULL;
|
|
+
|
|
+ if (sta && sta->non_pref_chan)
|
|
+ info = sta->non_pref_chan;
|
|
+#endif
|
|
|
|
/*
|
|
* BSS Transition Candidate List Entries - Neighbor Report elements
|
|
@@ -2350,6 +2360,9 @@ int ieee802_11_parse_candidate_list(cons
|
|
pos++;
|
|
|
|
*nei_pos++ = atoi(pos); /* Channel Number */
|
|
+#ifdef CONFIG_MBO
|
|
+ non_pref_chan = atoi(pos);
|
|
+#endif
|
|
pos = os_strchr(pos, ',');
|
|
if (pos == NULL) {
|
|
wpa_printf(MSG_DEBUG, "Missing PHY Type");
|
|
@@ -2381,6 +2394,25 @@ int ieee802_11_parse_candidate_list(cons
|
|
"Invalid neighbor subelement info");
|
|
return -1;
|
|
}
|
|
+#ifdef CONFIG_MBO
|
|
+ if (info) {
|
|
+ for (i = 0; i < (len / 2); i++)
|
|
+ if (nei_pos[i] == WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE &&
|
|
+ nei_pos[i + 1] == 0x1) /* length */
|
|
+ pref_pos = (nei_pos + i + 2);
|
|
+
|
|
+ /* If STA had updated MBO non-pref chan report,
|
|
+ * use the same candidate preference value in the
|
|
+ * BSS Transition Candidate sub-element.
|
|
+ */
|
|
+ for ( ; info ; info = info->next)
|
|
+ for (i = 0; i < info->num_channels; i++)
|
|
+ if (non_pref_chan == info->channels[i])
|
|
+ *pref_pos = info->pref;
|
|
+
|
|
+ info = sta->non_pref_chan;
|
|
+ }
|
|
+#endif
|
|
nei_pos += len / 2;
|
|
pos = end;
|
|
}
|
|
--- a/src/common/ieee802_11_common.h
|
|
+++ b/src/common/ieee802_11_common.h
|
|
@@ -11,6 +11,7 @@
|
|
|
|
#include "defs.h"
|
|
#include "ieee802_11_defs.h"
|
|
+#include "ap/sta_info.h"
|
|
|
|
struct element {
|
|
u8 id;
|
|
@@ -265,8 +266,8 @@ bool is_6ghz_freq(int freq);
|
|
bool is_6ghz_op_class(u8 op_class);
|
|
bool is_6ghz_psc_frequency(int freq);
|
|
|
|
-int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
|
|
- size_t nei_rep_len);
|
|
+int ieee802_11_parse_candidate_list(const char *pos, struct sta_info *sta,
|
|
+ u8 *nei_rep, size_t nei_rep_len);
|
|
|
|
int ieee802_11_ext_capab(const u8 *ie, unsigned int capab);
|
|
int op_class_to_bandwidth(u8 op_class);
|
|
--- a/wpa_supplicant/wnm_sta.c
|
|
+++ b/wpa_supplicant/wnm_sta.c
|
|
@@ -1630,7 +1630,7 @@ int wnm_send_bss_transition_mgmt_query(s
|
|
return ret;
|
|
}
|
|
|
|
- ret = ieee802_11_parse_candidate_list(btm_candidates,
|
|
+ ret = ieee802_11_parse_candidate_list(btm_candidates, NULL,
|
|
wpabuf_put(buf, 0),
|
|
max_len);
|
|
if (ret < 0) {
|