plen = frame_len - IEEE80211_HDRLEN - 1;
req = (const struct fst_setup_req *)
(((const u8 *) mgmt) + IEEE80211_HDRLEN + 1);
+ if (req->stie.element_id != WLAN_EID_SESSION_TRANSITION ||
+ req->stie.length < 11) {
+ fst_printf_iface(iface, MSG_WARNING,
+ "FST Request dropped: invalid STIE");
+ return;
+ }
if (req->stie.new_band_id == req->stie.old_band_id) {
fst_printf_iface(iface, MSG_WARNING,
* the initiator’s MAC address, in which case, the responder
* shall delete the received FST Setup Request.
*/
- if (os_memcmp(mgmt->da, mgmt->sa, ETH_ALEN) > 0) {
+ if (fst_session_is_ready_pending(s) &&
+ /* waiting for Setup Response */
+ os_memcmp(mgmt->da, mgmt->sa, ETH_ALEN) > 0) {
fst_printf_session(s, MSG_WARNING,
"FST Request dropped due to MAC comparison (our MAC is "
MACSTR ")",
return;
}
- if (!fst_session_is_ready_pending(s)) {
- fst_printf_session(s, MSG_WARNING,
- "FST Request from " MACSTR
- " dropped due to inappropriate state %s",
- MAC2STR(mgmt->da),
- fst_session_state_name(s->state));
- return;
- }
+ /*
+ * State is SETUP_COMPLETION (either in transition or not) or
+ * TRANSITION_DONE (in transition).
+ * Setup Request arriving in this state could mean:
+ * 1. peer sent it before receiving our Setup Request (race
+ * condition)
+ * 2. peer didn't receive our Setup Response. Peer is retrying
+ * after STT timeout
+ * 3. peer's FST state machines are out of sync due to some
+ * other reason
+ *
+ * We will reset our session and create a new one instead.
+ */
+ fst_printf_session(s, MSG_WARNING,
+ "resetting due to FST request");
/*
* If FST Setup Request arrived with the same FSTS ID as one we
- * initialized before, it means the other side either didn't
- * receive our FST Request or skipped it for some reason (for
- * example, due to numerical MAC comparison).
- *
- * In this case, there's no need to tear down the session.
+ * initialized before, there's no need to tear down the session.
* Moreover, as FSTS ID is the same, the other side will
* associate this tear down with the session it initiated that
* will break the sync.
"Skipping TearDown as the FST request has the same FSTS ID as initiated");
fst_session_set_state(s, FST_SESSION_STATE_INITIAL, &evext);
fst_session_stt_disarm(s);
- fst_printf_session(s, MSG_WARNING, "reset due to FST request");
}
s = fst_session_create(g);
}
res = (const struct fst_setup_res *)
(((const u8 *) mgmt) + IEEE80211_HDRLEN + 1);
+ if (res->stie.element_id != WLAN_EID_SESSION_TRANSITION ||
+ res->stie.length < 11) {
+ fst_printf_iface(iface, MSG_WARNING,
+ "FST Response dropped: invalid STIE");
+ return;
+ }
if (res->dialog_token != s->data.pending_setup_req_dlgt) {
fst_printf_session(s, MSG_WARNING,
},
};
- if (!fst_session_is_in_progress(s)) {
- fst_printf_session(s, MSG_WARNING, "no FST Setup to tear down");
- return;
- }
-
if (plen < sizeof(*td)) {
fst_printf_session(s, MSG_WARNING,
"Too short FST Tear Down dropped");
return -EINVAL;
}
- if (!fst_iface_is_connected(s->data.old_iface, s->data.old_peer_addr)) {
+ if (!fst_iface_is_connected(s->data.old_iface, s->data.old_peer_addr,
+ FALSE)) {
fst_printf_session(s, MSG_ERROR,
"The preset old peer address is not connected");
return -EINVAL;
}
- if (!fst_iface_is_connected(s->data.new_iface, s->data.new_peer_addr)) {
+ if (!fst_iface_is_connected(s->data.new_iface, s->data.new_peer_addr,
+ FALSE)) {
fst_printf_session(s, MSG_ERROR,
"The preset new peer address is not connected");
return -EINVAL;
req.llt = host_to_le32(FST_LLT_MS_TO_VAL(s->data.llt_ms));
/* 8.4.2.147 Session Transition element */
req.stie.element_id = WLAN_EID_SESSION_TRANSITION;
- req.stie.length = sizeof(req.stie);
+ req.stie.length = sizeof(req.stie) - 2;
req.stie.fsts_id = host_to_le32(fsts_id);
req.stie.session_control = SESSION_CONTROL(SESSION_TYPE_BSS, 0);
return -EINVAL;
}
- if (!fst_iface_is_connected(s->data.old_iface, s->data.old_peer_addr)) {
+ if (!fst_iface_is_connected(s->data.old_iface,
+ s->data.old_peer_addr, FALSE)) {
fst_printf_session(s, MSG_ERROR,
"The preset peer address is not in the peer list");
return -EINVAL;
res.dialog_token = s->data.pending_setup_req_dlgt;
res.status_code = status_code;
+ res.stie.element_id = WLAN_EID_SESSION_TRANSITION;
+ res.stie.length = sizeof(res.stie) - 2;
+
if (status_code == WLAN_STATUS_SUCCESS) {
- res.stie.element_id = WLAN_EID_SESSION_TRANSITION;
- res.stie.length = sizeof(res.stie);
res.stie.fsts_id = s->data.fsts_id;
res.stie.session_control = SESSION_CONTROL(SESSION_TYPE_BSS, 0);
struct fst_get_peer_ctx *ctx;
os_memset(s, 0, sizeof(*s));
- *g = dl_list_first(&fst_global_groups_list,
- struct fst_group, global_groups_lentry);
- if (!*g)
- return EINVAL;
-
- s->data.new_iface = dl_list_first(&(*g)->ifaces, struct fst_iface,
- group_lentry);
+ foreach_fst_group(*g) {
+ s->data.new_iface = fst_group_first_iface(*g);
+ if (s->data.new_iface)
+ break;
+ }
if (!s->data.new_iface)
- return EINVAL;
+ return -EINVAL;
s->data.old_iface = dl_list_entry(s->data.new_iface->group_lentry.next,
struct fst_iface, group_lentry);
if (!s->data.old_iface)
- return EINVAL;
+ return -EINVAL;
old_addr = fst_iface_get_peer_first(s->data.old_iface, &ctx, TRUE);
if (!old_addr)
- return EINVAL;
+ return -EINVAL;
new_addr = fst_iface_get_peer_first(s->data.new_iface, &ctx, TRUE);
if (!new_addr)
- return EINVAL;
+ return -EINVAL;
os_memcpy(s->data.old_peer_addr, old_addr, ETH_ALEN);
os_memcpy(s->data.new_peer_addr, new_addr, ETH_ALEN);
u8 channel;
char additional_param[FST_MAX_COMMAND_WORD_NAME_LENGTH];
+ if (params[0] != ' ')
+ return -EINVAL;
+ params++;
fsts_id = fst_read_next_int_param(params, &is_valid, &endp);
if (!is_valid)
- return EINVAL;
+ return -EINVAL;
if (get_group_fill_session(&g, &s))
- return EINVAL;
+ return -EINVAL;
req.action = FST_ACTION_SETUP_REQUEST;
req.dialog_token = g->dialog_token;
req.llt = host_to_le32(FST_LLT_MS_DEFAULT);
/* 8.4.2.147 Session Transition element */
req.stie.element_id = WLAN_EID_SESSION_TRANSITION;
- req.stie.length = sizeof(req.stie);
+ req.stie.length = sizeof(req.stie) - 2;
req.stie.fsts_id = host_to_le32(fsts_id);
req.stie.session_control = SESSION_CONTROL(SESSION_TYPE_BSS, 0);
char response[FST_MAX_COMMAND_WORD_NAME_LENGTH];
struct fst_session *_s;
+ if (params[0] != ' ')
+ return -EINVAL;
+ params++;
fsts_id = fst_read_next_int_param(params, &is_valid, &endp);
if (!is_valid)
- return EINVAL;
+ return -EINVAL;
if (get_group_fill_session(&g, &s))
- return EINVAL;
+ return -EINVAL;
status_code = WLAN_STATUS_SUCCESS;
if (!fst_read_next_text_param(endp, response, sizeof(response),
_s->data.pending_setup_req_dlgt : g->dialog_token;
res.status_code = status_code;
+ res.stie.element_id = WLAN_EID_SESSION_TRANSITION;
+ res.stie.length = sizeof(res.stie) - 2;
+
if (res.status_code == WLAN_STATUS_SUCCESS) {
- res.stie.element_id = WLAN_EID_SESSION_TRANSITION;
- res.stie.length = sizeof(res.stie);
res.stie.fsts_id = fsts_id;
res.stie.session_control = SESSION_CONTROL(SESSION_TYPE_BSS, 0);
struct fst_session s;
struct fst_group *g;
+ if (params[0] != ' ')
+ return -EINVAL;
+ params++;
fsts_id = fst_read_next_int_param(params, &is_valid, &endp);
if (!is_valid)
- return EINVAL;
+ return -EINVAL;
if (get_group_fill_session(&g, &s))
- return EINVAL;
+ return -EINVAL;
os_memset(&req, 0, sizeof(req));
req.action = FST_ACTION_ACK_REQUEST;
struct fst_session s;
struct fst_group *g;
+ if (params[0] != ' ')
+ return -EINVAL;
+ params++;
fsts_id = fst_read_next_int_param(params, &is_valid, &endp);
if (!is_valid)
- return EINVAL;
+ return -EINVAL;
if (get_group_fill_session(&g, &s))
- return EINVAL;
+ return -EINVAL;
os_memset(&res, 0, sizeof(res));
res.action = FST_ACTION_ACK_RESPONSE;
struct fst_session s;
struct fst_group *g;
+ if (params[0] != ' ')
+ return -EINVAL;
+ params++;
fsts_id = fst_read_next_int_param(params, &is_valid, &endp);
if (!is_valid)
- return EINVAL;
+ return -EINVAL;
if (get_group_fill_session(&g, &s))
- return EINVAL;
+ return -EINVAL;
os_memset(&td, 0, sizeof(td));
td.action = FST_ACTION_TEAR_DOWN;
char *endp;
struct fst_session *s;
+ if (params[0] != ' ')
+ return FST_FSTS_ID_NOT_FOUND;
+ params++;
sid = fst_read_next_int_param(params, &is_valid, &endp);
if (!is_valid)
return FST_FSTS_ID_NOT_FOUND;
struct fst_group *g;
struct fst_iface *iface;
+ if (request[0] != ' ')
+ return -EINVAL;
+ request++;
if (fst_read_next_text_param(request, ifname, sizeof(ifname), &endp) ||
!*ifname)
goto problem;