*
* @QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY: Set key operation that can be
* used to configure PMK to the driver even when not connected. This can
- * be used to request offloading of key management operations.
+ * be used to request offloading of key management operations. Only used
+ * if device supports QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD.
+ *
* @QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH: An extended version of
* NL80211_CMD_ROAM event with optional attributes including information
* from offloaded key management operation. Uses
- * enum qca_wlan_vendor_attr_roam_auth attributes.
+ * enum qca_wlan_vendor_attr_roam_auth attributes. Only used
+ * if device supports QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD.
*
* @QCA_NL80211_VENDOR_SUBCMD_DO_ACS: ACS command/event which is used to
* invoke the ACS function in device and pass selected channels to
* hostapd.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES: Command to get the features
+ * supported by the driver. enum qca_wlan_vendor_features defines
+ * the possible features.
*/
enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
QCA_NL80211_VENDOR_SUBCMD_APFIND = 52,
/* 53 - reserved for QCA */
QCA_NL80211_VENDOR_SUBCMD_DO_ACS = 54,
+ QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES = 55,
};
* by enum qca_roaming_policy. */
QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY = 5,
QCA_WLAN_VENDOR_ATTR_MAC_ADDR = 6,
+ /* used by QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES */
+ QCA_WLAN_VENDOR_ATTR_FEATURE_FLAGS = 7,
/* keep last */
QCA_WLAN_VENDOR_ATTR_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_MAX = QCA_WLAN_VENDOR_ATTR_AFTER_LAST - 1,
QCA_ACS_MODE_IEEE80211AD,
};
+/**
+ * enum qca_wlan_vendor_features - Vendor device/driver feature flags
+ *
+ * @QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD: Device supports key
+ * management offload, a mechanism where the station's firmware
+ * does the exchange with the AP to establish the temporal keys
+ * after roaming, rather than having the user space wpa_supplicant do it.
+ * @NUM_QCA_WLAN_VENDOR_FEATURES: Number of assigned feature bits
+ */
+enum qca_wlan_vendor_features {
+ QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD = 0,
+ NUM_QCA_WLAN_VENDOR_FEATURES /* keep last */
+};
+
#endif /* QCA_VENDOR_H */
#define WPA_DRIVER_FLAGS_MESH 0x0000000100000000ULL
/* Driver support ACS offload */
#define WPA_DRIVER_FLAGS_ACS_OFFLOAD 0x0000000200000000ULL
+/* Driver supports key management offload */
+#define WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD 0x0000000400000000ULL
u64 flags;
#define WPA_DRIVER_SMPS_MODE_STATIC 0x00000001
struct nl_msg *msg;
int ret;
- if (!drv->key_mgmt_set_key_vendor_cmd_avail)
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD))
return 0;
if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
}
#endif /* CONFIG_TDLS */
- if (alg == WPA_ALG_PMK && drv->key_mgmt_set_key_vendor_cmd_avail) {
+ if (alg == WPA_ALG_PMK &&
+ (drv->capa.flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD)) {
wpa_printf(MSG_DEBUG, "%s: calling issue_key_mgmt_set_key",
__func__);
ret = issue_key_mgmt_set_key(drv, key, key_len);
unsigned int have_low_prio_scan:1;
unsigned int force_connect_cmd:1;
unsigned int addr_changed:1;
- unsigned int key_mgmt_set_key_vendor_cmd_avail:1;
- unsigned int roam_auth_vendor_event_avail:1;
+ unsigned int get_features_vendor_cmd_avail:1;
u64 remain_on_chan_cookie;
u64 send_action_cookie;
case QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY:
drv->dfs_vendor_cmd_avail = 1;
break;
- case QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY:
- drv->key_mgmt_set_key_vendor_cmd_avail = 1;
+ case QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES:
+ drv->get_features_vendor_cmd_avail = 1;
break;
case QCA_NL80211_VENDOR_SUBCMD_DO_ACS:
drv->capa.flags |= WPA_DRIVER_FLAGS_ACS_OFFLOAD;
continue;
}
vinfo = nla_data(nl);
- if (vinfo->subcmd ==
- QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH)
- drv->roam_auth_vendor_event_avail = 1;
wpa_printf(MSG_DEBUG, "nl80211: Supported vendor event: vendor_id=0x%x subcmd=%u",
vinfo->vendor_id, vinfo->subcmd);
}
}
+struct features_info {
+ u8 *flags;
+ size_t flags_len;
+};
+
+
+static int features_info_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct features_info *info = arg;
+ struct nlattr *nl_vend, *attr;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ nl_vend = tb[NL80211_ATTR_VENDOR_DATA];
+ if (nl_vend) {
+ struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_MAX + 1];
+
+ nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_MAX,
+ nla_data(nl_vend), nla_len(nl_vend), NULL);
+
+ attr = tb_vendor[QCA_WLAN_VENDOR_ATTR_FEATURE_FLAGS];
+ if (attr) {
+ info->flags = nla_data(attr);
+ info->flags_len = nla_len(attr);
+ }
+ }
+
+ return NL_SKIP;
+}
+
+
+static int check_feature(enum qca_wlan_vendor_features feature,
+ struct features_info *info)
+{
+ size_t index = feature / 8;
+
+ return (index < info->flags_len) &&
+ (info->flags[index] & BIT(feature % 8));
+}
+
+
+static void qca_nl80211_get_features(struct wpa_driver_nl80211_data *drv)
+{
+ struct nl_msg *msg;
+ struct features_info info;
+ int ret;
+
+ if (!drv->get_features_vendor_cmd_avail)
+ return;
+
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES)) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ os_memset(&info, 0, sizeof(info));
+ ret = send_and_recv_msgs(drv, msg, features_info_handler, &info);
+ if (ret || !info.flags)
+ return;
+
+ if (check_feature(QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD, &info))
+ drv->capa.flags |= WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD;
+}
+
+
int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
{
struct wiphy_info_data info;
drv->capa.flags &= ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
qca_nl80211_check_dfs_capa(drv);
+ qca_nl80211_get_features(drv);
return 0;
}
wpa_printf(MSG_DEBUG, "nl80211: Drv Event %d (%s) received for %s",
cmd, nl80211_command_to_string(cmd), bss->ifname);
- if (cmd == NL80211_CMD_ROAM && drv->roam_auth_vendor_event_avail) {
+ if (cmd == NL80211_CMD_ROAM &&
+ (drv->capa.flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD)) {
/*
* Device will use roam+auth vendor event to indicate
* roaming, so ignore the regular roam event.