}
-static void wpas_mbo_send_wnm_notification(struct wpa_supplicant *wpa_s)
+static void wpas_mbo_send_wnm_notification(struct wpa_supplicant *wpa_s,
+ const u8 *data, size_t len)
{
struct wpabuf *buf;
int res;
!wpa_bss_get_vendor_ie(wpa_s->current_bss, MBO_IE_VENDOR_TYPE))
return;
- buf = wpabuf_alloc(512);
+ buf = wpabuf_alloc(4 + len);
if (!buf)
return;
wpabuf_put_u8(buf, wpa_s->mbo_wnm_token);
wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC); /* Type */
- wpas_mbo_non_pref_chan_attrs(wpa_s, buf, 1);
+ wpabuf_put_data(buf, data, len);
res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
wpa_s->own_addr, wpa_s->bssid,
}
+static void wpas_mbo_non_pref_chan_changed(struct wpa_supplicant *wpa_s)
+{
+ struct wpabuf *buf;
+
+ buf = wpabuf_alloc(512);
+ if (!buf)
+ return;
+
+ wpas_mbo_non_pref_chan_attrs(wpa_s, buf, 1);
+ wpas_mbo_send_wnm_notification(wpa_s, wpabuf_head_u8(buf),
+ wpabuf_len(buf));
+ wpabuf_free(buf);
+}
+
+
static int wpa_non_pref_chan_is_eq(struct wpa_mbo_non_pref_channel *a,
struct wpa_mbo_non_pref_channel *b)
{
os_free(wpa_s->non_pref_chan);
wpa_s->non_pref_chan = chans;
wpa_s->non_pref_chan_num = num;
- wpas_mbo_send_wnm_notification(wpa_s);
+ wpas_mbo_non_pref_chan_changed(wpa_s);
return 0;
}
-enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 channel,
- u8 bw)
+static enum chan_allowed verify_channel(struct hostapd_hw_modes *mode,
+ u8 channel, u8 bw)
{
unsigned int flag = 0;
enum chan_allowed res, res2;
wpabuf_free(buf);
return res;
}
+
+
+void wpas_mbo_ie_trans_req(struct wpa_supplicant *wpa_s, const u8 *mbo_ie,
+ size_t len)
+{
+ const u8 *pos, *cell_pref = NULL, *reason = NULL;
+ u8 id, elen;
+ u16 disallowed_sec = 0;
+
+ if (len <= 4 || WPA_GET_BE24(mbo_ie) != OUI_WFA ||
+ mbo_ie[3] != MBO_OUI_TYPE)
+ return;
+
+ pos = mbo_ie + 4;
+ len -= 4;
+
+ while (len >= 2) {
+ id = *pos++;
+ elen = *pos++;
+ len -= 2;
+
+ if (elen > len)
+ goto fail;
+
+ switch (id) {
+ case MBO_ATTR_ID_CELL_DATA_PREF:
+ if (elen != 1)
+ goto fail;
+
+ if (wpa_s->conf->mbo_cell_capa ==
+ MBO_CELL_CAPA_AVAILABLE)
+ cell_pref = pos;
+ else
+ wpa_printf(MSG_DEBUG,
+ "MBO: Station does not support Cellular data connection");
+ break;
+ case MBO_ATTR_ID_TRANSITION_REASON:
+ if (elen != 1)
+ goto fail;
+
+ reason = pos;
+ break;
+ case MBO_ATTR_ID_ASSOC_RETRY_DELAY:
+ if (elen != 2)
+ goto fail;
+
+ if (wpa_s->wnm_mode &
+ WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) {
+ wpa_printf(MSG_DEBUG,
+ "MBO: Unexpected association retry delay, BSS is terminating");
+ goto fail;
+ } else if (wpa_s->wnm_mode &
+ WNM_BSS_TM_REQ_DISASSOC_IMMINENT) {
+ disallowed_sec = WPA_GET_LE16(pos);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "MBO: Association retry delay attribute not in disassoc imminent mode");
+ }
+
+ break;
+ case MBO_ATTR_ID_AP_CAPA_IND:
+ case MBO_ATTR_ID_NON_PREF_CHAN_REPORT:
+ case MBO_ATTR_ID_CELL_DATA_CAPA:
+ case MBO_ATTR_ID_ASSOC_DISALLOW:
+ case MBO_ATTR_ID_TRANSITION_REJECT_REASON:
+ wpa_printf(MSG_DEBUG,
+ "MBO: Attribute %d should not be included in BTM Request frame",
+ id);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "MBO: Unknown attribute id %u",
+ id);
+ return;
+ }
+
+ pos += elen;
+ len -= elen;
+ }
+
+ if (cell_pref)
+ wpa_msg(wpa_s, MSG_INFO, MBO_CELL_PREFERENCE "preference=%u",
+ *cell_pref);
+
+ if (reason)
+ wpa_msg(wpa_s, MSG_INFO, MBO_TRANSITION_REASON "reason=%u",
+ *reason);
+
+ if (disallowed_sec && wpa_s->current_bss)
+ wpa_bss_tmp_disallow(wpa_s, wpa_s->current_bss->bssid,
+ disallowed_sec);
+
+ return;
+fail:
+ wpa_printf(MSG_DEBUG, "MBO IE parsing failed (id=%u len=%u left=%zu)",
+ id, elen, len);
+}
+
+
+size_t wpas_mbo_ie_bss_trans_reject(struct wpa_supplicant *wpa_s, u8 *pos,
+ size_t len,
+ enum mbo_transition_reject_reason reason)
+{
+ u8 reject_attr[3];
+
+ reject_attr[0] = MBO_ATTR_ID_TRANSITION_REJECT_REASON;
+ reject_attr[1] = 1;
+ reject_attr[2] = reason;
+
+ return mbo_add_ie(pos, len, reject_attr, sizeof(reject_attr));
+}
+
+
+void wpas_mbo_update_cell_capa(struct wpa_supplicant *wpa_s, u8 mbo_cell_capa)
+{
+ u8 cell_capa[7];
+
+ if (wpa_s->conf->mbo_cell_capa == mbo_cell_capa) {
+ wpa_printf(MSG_DEBUG,
+ "MBO: Cellular capability already set to %u",
+ mbo_cell_capa);
+ return;
+ }
+
+ wpa_s->conf->mbo_cell_capa = mbo_cell_capa;
+
+ cell_capa[0] = WLAN_EID_VENDOR_SPECIFIC;
+ cell_capa[1] = 5; /* Length */
+ WPA_PUT_BE24(cell_capa + 2, OUI_WFA);
+ cell_capa[5] = MBO_ATTR_ID_CELL_DATA_CAPA;
+ cell_capa[6] = mbo_cell_capa;
+
+ wpas_mbo_send_wnm_notification(wpa_s, cell_capa, 7);
+}