@@ -884,6 +884,8 @@ static int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
int ret;
u8 nei_rep[1000];
u8 *nei_pos = nei_rep;
+ u8 mbo[10];
+ size_t mbo_len;
if (hwaddr_aton(cmd, addr)) {
wpa_printf(MSG_DEBUG, "Invalid STA MAC address");
@@ -1049,10 +1051,64 @@ static int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
if (os_strstr(cmd, " disassoc_imminent=1"))
req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
+ mbo_len = 0;
+ pos = os_strstr(cmd, "mbo=");
+ if (pos) {
+ u8 mbo_reason, cell_pref;
+ u16 reassoc_delay;
+ int ret;
+
+ ret = sscanf(pos, "mbo=%hhu:%hu:%hhu", &mbo_reason,
+ &reassoc_delay, &cell_pref);
+ if (ret != 3) {
+ wpa_printf(MSG_DEBUG,
+ "MBO requires three arguments: mbo=<reason>:<reassoc_delay>:<cell_pref>");
+ return -1;
+ }
+
+ if (mbo_reason > MBO_TRANSITION_REASON_PREMIUM_AP) {
+ wpa_printf(MSG_DEBUG,
+ "Invalid MBO transition reason code %hhu",
+ mbo_reason);
+ return -1;
+ }
+
+ /* Valid values for Cellular preference are: 0, 1, 255 */
+ if (cell_pref > 1 && cell_pref != 255) {
+ wpa_printf(MSG_DEBUG,
+ "Invalid MBO cellular capability %hhu",
+ cell_pref);
+ return -1;
+ }
+
+ if (reassoc_delay &&
+ !(req_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT)) {
+ wpa_printf(MSG_DEBUG,
+ "assoc retry delay is only valid in disassoc imminent mode");
+ return -1;
+ }
+
+ mbo[0] = MBO_ATTR_ID_TRANSITION_REASON;
+ mbo[1] = 1;
+ mbo[2] = mbo_reason;
+ mbo[3] = MBO_ATTR_ID_CELL_DATA_PREF;
+ mbo[4] = 1;
+ mbo[5] = cell_pref;
+
+ if (reassoc_delay) {
+ mbo[6] = MBO_ATTR_ID_ASSOC_RETRY_DELAY;
+ mbo[7] = 2;
+ WPA_PUT_LE16(mbo + 8, reassoc_delay);
+ }
+
+ mbo_len = reassoc_delay ? 10 : 6;
+ }
+
ret = wnm_send_bss_tm_req(hapd, sta, req_mode, disassoc_timer,
valid_int, bss_term_dur, url,
nei_pos > nei_rep ? nei_rep : NULL,
- nei_pos - nei_rep);
+ nei_pos - nei_rep, mbo_len ? mbo : NULL,
+ mbo_len);
os_free(url);
return ret;
}
@@ -527,7 +527,8 @@ int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd,
int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
u8 req_mode, int disassoc_timer, u8 valid_int,
const u8 *bss_term_dur, const char *url,
- const u8 *nei_rep, size_t nei_rep_len)
+ const u8 *nei_rep, size_t nei_rep_len, u8 *mbo_attrs,
+ size_t mbo_len)
{
u8 *buf, *pos;
struct ieee80211_mgmt *mgmt;
@@ -579,6 +580,10 @@ int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
pos += nei_rep_len;
}
+ if (mbo_len > 0)
+ pos += mbo_add_ie(pos, buf + sizeof(buf) - pos, mbo_attrs,
+ mbo_len);
+
if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
wpa_printf(MSG_DEBUG,
"Failed to send BSS Transition Management Request frame");
@@ -21,6 +21,7 @@ int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd,
int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
u8 req_mode, int disassoc_timer, u8 valid_int,
const u8 *bss_term_dur, const char *url,
- const u8 *nei_rep, size_t nei_rep_len);
+ const u8 *nei_rep, size_t nei_rep_len, u8 *mbo_attrs,
+ size_t mbo_len);
#endif /* WNM_AP_H */