]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
nl80211: Add QCA vendor specific query of device/driver features
authorChet Lanctot <clanctot@qca.qualcomm.com>
Sat, 6 Dec 2014 00:48:23 +0000 (16:48 -0800)
committerJouni Malinen <j@w1.fi>
Tue, 9 Dec 2014 19:08:21 +0000 (21:08 +0200)
This commit introduces a QCA vendor command that allows interrogation of
the vendor-specific features supported by the device/driver. Currently
the only defined feature is the ability to offload key management.

Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
src/common/qca-vendor.h
src/drivers/driver.h
src/drivers/driver_nl80211.c
src/drivers/driver_nl80211.h
src/drivers/driver_nl80211_capa.c
src/drivers/driver_nl80211_event.c

index 2f1bdcefc4507176827b2b37e70ffc14db82750b..ec1be863d696cc4eb61781b4d742552798efc1ad 100644 (file)
@@ -53,15 +53,22 @@ enum qca_radiotap_vendor_ids {
  *
  * @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,
@@ -107,6 +114,7 @@ enum qca_nl80211_vendor_subcmds {
        QCA_NL80211_VENDOR_SUBCMD_APFIND = 52,
        /* 53 - reserved for QCA */
        QCA_NL80211_VENDOR_SUBCMD_DO_ACS = 54,
+       QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES = 55,
 };
 
 
@@ -124,6 +132,8 @@ enum qca_wlan_vendor_attr {
         * 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,
@@ -170,4 +180,18 @@ enum qca_wlan_vendor_acs_hw_mode {
        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 */
index 9eea524c2df2160aa367131bdc1deee5c60e2eae..54050db16b7791eb67569f329dd84ebbbbee2648 100644 (file)
@@ -1075,6 +1075,8 @@ struct wpa_driver_capa {
 #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
index d3728332d118410ec60bfa35c59b308c119cadf9..321034785ffd7231c94645f85d30f9ae85164584 100644 (file)
@@ -2347,7 +2347,7 @@ static int issue_key_mgmt_set_key(struct wpa_driver_nl80211_data *drv,
        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)) ||
@@ -2397,7 +2397,8 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
        }
 #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);
index 00fe6b719a9968705a41de0b6a0bbf64e28c489f..4a364f71b9dc8fe9729f10d4def64faf35fffdd5 100644 (file)
@@ -143,8 +143,7 @@ struct wpa_driver_nl80211_data {
        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;
index 198ef1d32bb54741f6b73866efdc43fa83489003..657f38c494fdd0f4549ca205b7d8760938389d7d 100644 (file)
@@ -534,8 +534,8 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
                        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;
@@ -558,9 +558,6 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
                                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);
                }
@@ -689,6 +686,77 @@ static void qca_nl80211_check_dfs_capa(struct wpa_driver_nl80211_data *drv)
 }
 
 
+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;
@@ -766,6 +834,7 @@ int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
                drv->capa.flags &= ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
 
        qca_nl80211_check_dfs_capa(drv);
+       qca_nl80211_get_features(drv);
 
        return 0;
 }
index 2226e4c869c278419b032599dfd5b77f53ee1d3c..f4221740c474bf8bd4a0eef61687d420e82da8d6 100644 (file)
@@ -1690,7 +1690,8 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
        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.