}
#endif /* CONFIG_P2P */
+ if (elems.wfa_capab)
+ hostapd_wfa_capab(hapd, sta, elems.wfa_capab,
+ elems.wfa_capab + elems.wfa_capab_len);
+
return 0;
fail:
hapd->conf->max_acceptable_idle_period;
}
+ if (elems->wfa_capab)
+ hostapd_wfa_capab(hapd, sta, elems->wfa_capab,
+ elems->wfa_capab + elems->wfa_capab_len);
+
return WLAN_STATUS_SUCCESS;
}
}
+static int hostapd_action_vs(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ const struct ieee80211_mgmt *mgmt, size_t len,
+ unsigned int freq, bool protected)
+{
+ const u8 *pos, *end;
+ u32 oui_type;
+
+ pos = &mgmt->u.action.category;
+ end = ((const u8 *) mgmt) + len;
+
+ if (end - pos < 1 + 4)
+ return -1;
+ pos++;
+
+ oui_type = WPA_GET_BE32(pos);
+ pos += 4;
+
+ switch (oui_type) {
+ case WFA_CAPAB_VENDOR_TYPE:
+ hostapd_wfa_capab(hapd, sta, pos, end);
+ return 0;
+ default:
+ wpa_printf(MSG_DEBUG,
+ "Ignore unknown Vendor Specific Action frame OUI/type %08x%s",
+ oui_type, protected ? " (protected)" : "");
+ break;
+ }
+
+ return -1;
+}
+
+
static int robust_action_frame(u8 category)
{
return category != WLAN_ACTION_PUBLIC &&
(u8 *) mgmt, len, freq) == 0)
return 1;
}
+ if (sta &&
+ hostapd_action_vs(hapd, sta, mgmt, len, freq, false) == 0)
+ return 1;
+ break;
+ case WLAN_ACTION_VENDOR_SPECIFIC_PROTECTED:
+ if (sta &&
+ hostapd_action_vs(hapd, sta, mgmt, len, freq, true) == 0)
+ return 1;
break;
#ifndef CONFIG_NO_RRM
case WLAN_ACTION_RADIO_MEASUREMENT:
int hostapd_get_he_twt_responder(struct hostapd_data *hapd,
enum ieee80211_op_mode mode);
bool hostapd_get_ht_vht_twt_responder(struct hostapd_data *hapd);
+void hostapd_wfa_capab(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *pos, const u8 *end);
u8 * hostapd_eid_cca(struct hostapd_data *hapd, u8 *eid);
void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
const u8 *buf, size_t len, int ack);
(hapd->iface->drv_flags2 &
WPA_DRIVER_FLAGS2_HT_VHT_TWT_RESPONDER);
}
+
+
+static void hostapd_wfa_gen_capab(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ const u8 *capab, size_t len)
+{
+ char *hex;
+ size_t buflen;
+
+ wpa_printf(MSG_DEBUG,
+ "WFA: Received indication of generational capabilities from "
+ MACSTR, MAC2STR(sta->addr));
+ wpa_hexdump(MSG_DEBUG, "WFA: Generational Capabilities", capab, len);
+
+ buflen = 2 * len + 1;
+ hex = os_zalloc(buflen);
+ if (!hex)
+ return;
+ wpa_snprintf_hex(hex, buflen, capab, len);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, WFA_GEN_CAPAB_RX MACSTR " %s",
+ MAC2STR(sta->addr), hex);
+ os_free(hex);
+}
+
+
+void hostapd_wfa_capab(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *pos, const u8 *end)
+{
+ u8 capab_len;
+ const u8 *gen_capa;
+
+ if (end - pos < 1)
+ return;
+ capab_len = *pos++;
+ if (capab_len > end - pos)
+ return;
+ pos += capab_len; /* skip the Capabilities field */
+
+ /* Wi-Fi Alliance Capabilities attributes use a header that is similar
+ * to the one used in Information Elements. */
+ gen_capa = get_ie(pos, end - pos, WFA_CAPA_ATTR_GENERATIONAL_CAPAB);
+ if (gen_capa)
+ hostapd_wfa_gen_capab(hapd, sta, gen_capa + 2, gen_capa[1]);
+}
elems->sae_pk = pos + 4;
elems->sae_pk_len = elen - 4;
break;
+ case WFA_CAPA_OUI_TYPE:
+ elems->wfa_capab = pos + 4;
+ elems->wfa_capab_len = elen - 4;
+ break;
case WFA_RSNE_OVERRIDE_OUI_TYPE:
elems->rsne_override = pos;
elems->rsne_override_len = elen;
const u8 *rsne_override;
const u8 *rsne_override_2;
const u8 *rsn_selection;
+ const u8 *wfa_capab;
u8 ssid_len;
u8 supp_rates_len;
size_t rsne_override_len;
size_t rsne_override_2_len;
size_t rsn_selection_len;
+ u8 wfa_capab_len;
struct mb_ies_info mb_ies;
/* Event triggered for received management frame */
#define AP_MGMT_FRAME_RECEIVED "AP-MGMT-FRAME-RECEIVED "
+/* Event triggerred on AP receiving Wi-Fi Alliance Generational Capabilities
+ * indication.
+ * Parameters: <STA addr> <Generational Capabilities Indication body> */
+#define WFA_GEN_CAPAB_RX "WFA-GEN-CAPAB "
+
#ifndef BIT
#define BIT(x) (1U << (x))
#endif