Set NLA_F_NESTED flag with NL80211_ATTR_VENDOR_DATA conditionally

The newer kernel versions enforce strict netlink attribute policy
validation and will cause cfg80211 to reject vendor commands with
NL80211_ATTR_VENDOR_DATA if NLA_F_NESTED attribute is not set but
if the vendor command is expecting nested data within
NL80211_ATTR_VENDOR_DATA attribute.

Most of the earlier instances were addressed by adding NLA_F_NESTED
flag in nla_nest_start(). This commit addresses the remaining
instance in which NL80211_ATTR_VENDOR_DATA is populated using data
set by user through the control interface.

Enhance the control interface VENDOR command to indicate whether the
vendor subcommand uses nested attributes within NL80211_ATTR_VENDOR_DATA
attribute or not.

Set NLA_F_NESTED flag for existing QCA vendor commands which use nested
attributes within the NL80211_ATTR_VENDOR_DATA attributes so that the
old frameworks implementations for already existing commands work
without any issues.

Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
This commit is contained in:
Vinita S. Maloo 2020-10-27 23:33:59 +05:30 committed by Jouni Malinen
parent cd3aa54a37
commit c2c4686228
7 changed files with 88 additions and 21 deletions

View file

@ -350,12 +350,13 @@ static inline int hostapd_drv_br_set_net_param(struct hostapd_data *hapd,
static inline int hostapd_drv_vendor_cmd(struct hostapd_data *hapd,
int vendor_id, int subcmd,
const u8 *data, size_t data_len,
enum nested_attr nested_attr_flag,
struct wpabuf *buf)
{
if (hapd->driver == NULL || hapd->driver->vendor_cmd == NULL)
return -1;
return hapd->driver->vendor_cmd(hapd->drv_priv, vendor_id, subcmd, data,
data_len, buf);
data_len, nested_attr_flag, buf);
}
static inline int hostapd_drv_stop_ap(struct hostapd_data *hapd)

View file

@ -2432,6 +2432,13 @@ struct external_auth {
const u8 *pmkid;
};
/* enum nested_attr - Used to specify if subcommand uses nested attributes */
enum nested_attr {
NESTED_ATTR_NOT_USED = 0,
NESTED_ATTR_USED = 1,
NESTED_ATTR_UNSPECIFIED = 2,
};
/**
* struct wpa_driver_ops - Driver interface API definition
*
@ -3717,6 +3724,8 @@ struct wpa_driver_ops {
* @priv: Private driver interface data
* @vendor_id: Vendor id
* @subcmd: Vendor command id
* @nested_attr_flag: Specifies if vendor subcommand uses nested
* attributes or not
* @data: Vendor command parameters (%NULL if no parameters)
* @data_len: Data length
* @buf: Return buffer (%NULL to ignore reply)
@ -3724,9 +3733,10 @@ struct wpa_driver_ops {
*
* This function handles vendor specific commands that are passed to
* the driver/device. The command is identified by vendor id and
* command id. Parameters can be passed as argument to the command
* in the data buffer. Reply (if any) will be filled in the supplied
* return buffer.
* command id. The nested_attr_flag specifies whether the subcommand
* uses nested attributes or not. Parameters can be passed
* as argument to the command in the data buffer. Reply (if any) will be
* filled in the supplied return buffer.
*
* The exact driver behavior is driver interface and vendor specific. As
* an example, this will be converted to a vendor specific cfg80211
@ -3734,6 +3744,7 @@ struct wpa_driver_ops {
*/
int (*vendor_cmd)(void *priv, unsigned int vendor_id,
unsigned int subcmd, const u8 *data, size_t data_len,
enum nested_attr nested_attr_flag,
struct wpabuf *buf);
/**

View file

@ -9704,14 +9704,35 @@ static int vendor_reply_handler(struct nl_msg *msg, void *arg)
}
static bool is_cmd_with_nested_attrs(unsigned int vendor_id,
unsigned int subcmd)
{
if (vendor_id != OUI_QCA)
return true;
switch (subcmd) {
case QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY:
case QCA_NL80211_VENDOR_SUBCMD_STATS_EXT:
case QCA_NL80211_VENDOR_SUBCMD_SCANNING_MAC_OUI:
case QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY:
case QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_STATUS:
case QCA_NL80211_VENDOR_SUBCMD_NAN:
return false;
default:
return true;
}
}
static int nl80211_vendor_cmd(void *priv, unsigned int vendor_id,
unsigned int subcmd, const u8 *data,
size_t data_len, struct wpabuf *buf)
size_t data_len, enum nested_attr nested_attr,
struct wpabuf *buf)
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
int ret;
int ret, nla_flag;
#ifdef CONFIG_TESTING_OPTIONS
if (vendor_id == 0xffffffff) {
@ -9737,11 +9758,20 @@ static int nl80211_vendor_cmd(void *priv, unsigned int vendor_id,
}
#endif /* CONFIG_TESTING_OPTIONS */
if (nested_attr == NESTED_ATTR_USED)
nla_flag = NLA_F_NESTED;
else if (nested_attr == NESTED_ATTR_UNSPECIFIED &&
is_cmd_with_nested_attrs(vendor_id, subcmd))
nla_flag = NLA_F_NESTED;
else
nla_flag = 0;
if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_VENDOR)) ||
nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, vendor_id) ||
nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, subcmd) ||
(data &&
nla_put(msg, NL80211_ATTR_VENDOR_DATA, data_len, data)))
nla_put(msg, nla_flag | NL80211_ATTR_VENDOR_DATA,
data_len, data)))
goto fail;
ret = send_and_recv_msgs(drv, msg, vendor_reply_handler, buf,