nl80211: Add QCA vendor specific query of device/driver features
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>
This commit is contained in:
parent
d4913c585e
commit
15badebd47
6 changed files with 108 additions and 12 deletions
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in a new issue