From: Jérôme Pouiller <jerome.pouiller@xxxxxxxxxx> In case a security flaw is found in a version of firmware, the device offers a way to disallow the loading an older firmware. This patch provides a vendor extension to nl80211 to enable this feature. Signed-off-by: Jérôme Pouiller <jerome.pouiller@xxxxxxxxxx> --- drivers/staging/wfx/hif_api_general.h | 8 ++++++++ drivers/staging/wfx/hif_tx.c | 18 ++++++++++++++++++ drivers/staging/wfx/hif_tx.h | 1 + drivers/staging/wfx/nl80211_vendor.c | 23 +++++++++++++++++++++++ drivers/staging/wfx/nl80211_vendor.h | 11 +++++++++++ 5 files changed, 61 insertions(+) diff --git a/drivers/staging/wfx/hif_api_general.h b/drivers/staging/wfx/hif_api_general.h index dba18a7ae9194..c8af3534700ca 100644 --- a/drivers/staging/wfx/hif_api_general.h +++ b/drivers/staging/wfx/hif_api_general.h @@ -361,4 +361,12 @@ struct hif_cnf_sl_configure { __le32 status; } __packed; +struct hif_req_prevent_rollback { + __le32 magic_word; // Return an error if not equal to 0x5C8912F3 +} __packed; + +struct hif_cnf_prevent_rollback { + __le32 status; +} __packed; + #endif diff --git a/drivers/staging/wfx/hif_tx.c b/drivers/staging/wfx/hif_tx.c index 6db41587cc7a5..899e1eb71a44b 100644 --- a/drivers/staging/wfx/hif_tx.c +++ b/drivers/staging/wfx/hif_tx.c @@ -535,6 +535,24 @@ int hif_update_ie_beacon(struct wfx_vif *wvif, const u8 *ies, size_t ies_len) return ret; } +int hif_burn_prevent_rollback(struct wfx_dev *wdev, u32 magic_word) +{ + int ret; + struct hif_msg *hif; + struct hif_req_prevent_rollback *body = wfx_alloc_hif(sizeof(*body), + &hif); + + if (!hif) + return -ENOMEM; + body->magic_word = cpu_to_le32(magic_word); + wfx_fill_header(hif, -1, HIF_REQ_ID_PREVENT_ROLLBACK, sizeof(*body)); + ret = wfx_cmd_send(wdev, hif, NULL, 0, false); + if (ret == le32_to_cpu(HIF_STATUS_ROLLBACK_SUCCESS)) + ret = 0; + kfree(hif); + return ret; +} + int hif_sl_send_pub_keys(struct wfx_dev *wdev, const u8 *pubkey, const u8 *pubkey_hmac) { diff --git a/drivers/staging/wfx/hif_tx.h b/drivers/staging/wfx/hif_tx.h index e1da28aef706e..d29c72d94789a 100644 --- a/drivers/staging/wfx/hif_tx.h +++ b/drivers/staging/wfx/hif_tx.h @@ -57,6 +57,7 @@ int hif_start(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf, int hif_beacon_transmit(struct wfx_vif *wvif, bool enable); int hif_map_link(struct wfx_vif *wvif, u8 *mac_addr, int flags, int sta_id); int hif_update_ie_beacon(struct wfx_vif *wvif, const u8 *ies, size_t ies_len); +int hif_burn_prevent_rollback(struct wfx_dev *wdev, u32 magic_word); int hif_sl_set_mac_key(struct wfx_dev *wdev, const u8 *slk_key, int destination); int hif_sl_config(struct wfx_dev *wdev, const unsigned long *bitmap); diff --git a/drivers/staging/wfx/nl80211_vendor.c b/drivers/staging/wfx/nl80211_vendor.c index ec2fd2d73885f..1a9d411718a73 100644 --- a/drivers/staging/wfx/nl80211_vendor.c +++ b/drivers/staging/wfx/nl80211_vendor.c @@ -7,6 +7,7 @@ #include "nl80211_vendor.h" #include "wfx.h" #include "sta.h" +#include "hif_tx.h" int wfx_nl_ps_timeout(struct wiphy *wiphy, struct wireless_dev *widev, const void *data, int data_len) @@ -47,3 +48,25 @@ int wfx_nl_ps_timeout(struct wiphy *wiphy, struct wireless_dev *widev, return rc; } +int wfx_nl_burn_antirollback(struct wiphy *wiphy, struct wireless_dev *widev, + const void *data, int data_len) +{ + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct wfx_dev *wdev = (struct wfx_dev *)hw->priv; + struct nlattr *tb[WFX_NL80211_ATTR_MAX]; + u32 magic; + int rc; + + rc = nla_parse(tb, WFX_NL80211_ATTR_MAX - 1, data, data_len, + wfx_nl_policy, NULL); + if (rc) + return rc; + if (!tb[WFX_NL80211_ATTR_ROLLBACK_MAGIC]) + return -EINVAL; + magic = nla_get_u32(tb[WFX_NL80211_ATTR_ROLLBACK_MAGIC]); + rc = hif_burn_prevent_rollback(wdev, magic); + if (rc) + return -EINVAL; + return 0; +} + diff --git a/drivers/staging/wfx/nl80211_vendor.h b/drivers/staging/wfx/nl80211_vendor.h index c069330e240a9..49efe8716a654 100644 --- a/drivers/staging/wfx/nl80211_vendor.h +++ b/drivers/staging/wfx/nl80211_vendor.h @@ -16,18 +16,23 @@ int wfx_nl_ps_timeout(struct wiphy *wiphy, struct wireless_dev *widev, const void *data, int data_len); +int wfx_nl_burn_antirollback(struct wiphy *wiphy, struct wireless_dev *widev, + const void *data, int data_len); enum { WFX_NL80211_SUBCMD_PS_TIMEOUT = 0x10, + WFX_NL80211_SUBCMD_BURN_PREVENT_ROLLBACK = 0x20, }; enum { WFX_NL80211_ATTR_PS_TIMEOUT = 1, + WFX_NL80211_ATTR_ROLLBACK_MAGIC = 2, WFX_NL80211_ATTR_MAX }; static const struct nla_policy wfx_nl_policy[WFX_NL80211_ATTR_MAX] = { [WFX_NL80211_ATTR_PS_TIMEOUT] = NLA_POLICY_RANGE(NLA_S32, -1, 127), + [WFX_NL80211_ATTR_ROLLBACK_MAGIC] = { .type = NLA_U32 }, }; static const struct wiphy_vendor_command wfx_nl80211_vendor_commands[] = { @@ -38,6 +43,12 @@ static const struct wiphy_vendor_command wfx_nl80211_vendor_commands[] = { .policy = wfx_nl_policy, .doit = wfx_nl_ps_timeout, .maxattr = WFX_NL80211_ATTR_MAX - 1, + }, { + .info.vendor_id = WFX_NL80211_ID, + .info.subcmd = WFX_NL80211_SUBCMD_BURN_PREVENT_ROLLBACK, + .policy = wfx_nl_policy, + .doit = wfx_nl_burn_antirollback, + .maxattr = WFX_NL80211_ATTR_MAX - 1, }, }; -- 2.26.2