+static u8 * wpa_ft_process_rdie(u8 *pos, u8 *end, u8 id, u8 descr_count,
+ const u8 *ies, size_t ies_len)
+{
+ struct ieee802_11_elems parse;
+ struct rsn_rdie *rdie;
+
+ wpa_printf(MSG_DEBUG, "FT: Resource Request: id=%d descr_count=%d",
+ id, descr_count);
+ wpa_hexdump(MSG_MSGDUMP, "FT: Resource descriptor IE(s)",
+ ies, ies_len);
+
+ if (end - pos < (int) sizeof(*rdie)) {
+ wpa_printf(MSG_ERROR, "FT: Not enough room for response RDIE");
+ return pos;
+ }
+
+ *pos++ = WLAN_EID_RIC_DATA;
+ *pos++ = sizeof(*rdie);
+ rdie = (struct rsn_rdie *) pos;
+ rdie->id = id;
+ rdie->descr_count = 0;
+ rdie->status_code = host_to_le16(WLAN_STATUS_SUCCESS);
+ pos += sizeof(*rdie);
+
+ if (ieee802_11_parse_elems((u8 *) ies, ies_len, &parse, 1) ==
+ ParseFailed) {
+ wpa_printf(MSG_DEBUG, "FT: Failed to parse request IEs");
+ rdie->status_code =
+ host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE);
+ return pos;
+ }
+
+ if (parse.wmm_tspec) {
+ struct wmm_tspec_element *tspec;
+ int res;
+
+ if (parse.wmm_tspec_len + 2 < (int) sizeof(*tspec)) {
+ wpa_printf(MSG_DEBUG, "FT: Too short WMM TSPEC IE "
+ "(%d)", (int) parse.wmm_tspec_len);
+ rdie->status_code =
+ host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE);
+ return pos;
+ }
+ if (end - pos < (int) sizeof(*tspec)) {
+ wpa_printf(MSG_ERROR, "FT: Not enough room for "
+ "response TSPEC");
+ rdie->status_code =
+ host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE);
+ return pos;
+ }
+ tspec = (struct wmm_tspec_element *) pos;
+ os_memcpy(tspec, parse.wmm_tspec - 2, sizeof(*tspec));
+ res = wmm_process_tspec(tspec);
+ wpa_printf(MSG_DEBUG, "FT: ADDTS processing result: %d", res);
+ if (res == WMM_ADDTS_STATUS_INVALID_PARAMETERS)
+ rdie->status_code =
+ host_to_le16(WLAN_STATUS_INVALID_PARAMETERS);
+ else if (res == WMM_ADDTS_STATUS_REFUSED)
+ rdie->status_code =
+ host_to_le16(WLAN_STATUS_REQUEST_DECLINED);
+ else {
+ /* TSPEC accepted; include updated TSPEC in response */
+ rdie->descr_count = 1;
+ pos += sizeof(*tspec);
+ }
+ return pos;
+ }
+
+ wpa_printf(MSG_DEBUG, "FT: No supported resource requested");
+ rdie->status_code = host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE);
+ return pos;
+}
+
+
+static u8 * wpa_ft_process_ric(u8 *pos, u8 *end, const u8 *ric, size_t ric_len)
+{
+ const u8 *rpos, *start;
+ const struct rsn_rdie *rdie;
+
+ wpa_hexdump(MSG_MSGDUMP, "FT: RIC Request", ric, ric_len);
+
+ rpos = ric;
+ while (rpos + sizeof(*rdie) < ric + ric_len) {
+ if (rpos[0] != WLAN_EID_RIC_DATA || rpos[1] < sizeof(*rdie) ||
+ rpos + 2 + rpos[1] > ric + ric_len)
+ break;
+ rdie = (const struct rsn_rdie *) (rpos + 2);
+ rpos += 2 + rpos[1];
+ start = rpos;
+
+ while (rpos + 2 <= ric + ric_len &&
+ rpos + 2 + rpos[1] <= ric + ric_len) {
+ if (rpos[0] == WLAN_EID_RIC_DATA)
+ break;
+ rpos += 2 + rpos[1];
+ }
+ pos = wpa_ft_process_rdie(pos, end, rdie->id,
+ rdie->descr_count,
+ start, rpos - start);
+ }
+
+ return pos;
+}
+
+