Commit 846239f6 authored by Jérôme Pouiller's avatar Jérôme Pouiller Committed by Greg Kroah-Hartman

staging: wfx: introduce "secure link"

Chip support encryption of the link between host and chip. This feature
is called "secure link". Driver code on github[1] support it. However,
it relies on mbedtls for cryptographic functions. So, I decided to not
import this feature in current patch. However, in order to keep code
synchronized between github and kernel, I imported all code related to
this feature, even if most of it is just no-op.

[1]: https://github.com/SiliconLabs/wfx-linux-driver/Signed-off-by: default avatarJérôme Pouiller <jerome.pouiller@silabs.com>
Link: https://lore.kernel.org/r/20190919142527.31797-14-Jerome.Pouiller@silabs.comSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent f95a29d4
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "wfx.h" #include "wfx.h"
#include "hwio.h" #include "hwio.h"
#include "traces.h" #include "traces.h"
#include "secure_link.h"
#include "hif_rx.h" #include "hif_rx.h"
#include "hif_api_cmd.h" #include "hif_api_cmd.h"
...@@ -74,7 +75,18 @@ static int rx_helper(struct wfx_dev *wdev, size_t read_len, int *is_cnf) ...@@ -74,7 +75,18 @@ static int rx_helper(struct wfx_dev *wdev, size_t read_len, int *is_cnf)
hif = (struct hif_msg *) skb->data; hif = (struct hif_msg *) skb->data;
WARN(hif->encrypted & 0x1, "unsupported encryption type"); WARN(hif->encrypted & 0x1, "unsupported encryption type");
if (hif->encrypted == 0x2) { if (hif->encrypted == 0x2) {
BUG(); // Not yet implemented if (wfx_sl_decode(wdev, (void *) hif)) {
dev_kfree_skb(skb);
// If frame was a confirmation, expect trouble in next
// exchange. However, it is harmless to fail to decode
// an indication frame, so try to continue. Anyway,
// piggyback is probably correct.
return piggyback;
}
le16_to_cpus(hif->len);
computed_len = round_up(hif->len - sizeof(hif->len), 16)
+ sizeof(struct hif_sl_msg)
+ sizeof(struct hif_sl_tag);
} else { } else {
le16_to_cpus(hif->len); le16_to_cpus(hif->len);
computed_len = round_up(hif->len, 2); computed_len = round_up(hif->len, 2);
...@@ -166,7 +178,22 @@ static void tx_helper(struct wfx_dev *wdev, struct hif_msg *hif) ...@@ -166,7 +178,22 @@ static void tx_helper(struct wfx_dev *wdev, struct hif_msg *hif)
hif->seqnum = wdev->hif.tx_seqnum; hif->seqnum = wdev->hif.tx_seqnum;
wdev->hif.tx_seqnum = (wdev->hif.tx_seqnum + 1) % (HIF_COUNTER_MAX + 1); wdev->hif.tx_seqnum = (wdev->hif.tx_seqnum + 1) % (HIF_COUNTER_MAX + 1);
data = hif; if (wfx_is_secure_command(wdev, hif->id)) {
len = round_up(len - sizeof(hif->len), 16) + sizeof(hif->len)
+ sizeof(struct hif_sl_msg_hdr) + sizeof(struct hif_sl_tag);
// AES support encryption in-place. However, mac80211 access to
// 802.11 header after frame was sent (to get MAC addresses).
// So, keep origin buffer clear.
data = kmalloc(len, GFP_KERNEL);
if (!data)
goto end;
is_encrypted = true;
ret = wfx_sl_encode(wdev, hif, data);
if (ret)
goto end;
} else {
data = hif;
}
WARN(len > wdev->hw_caps.size_inp_ch_buf, WARN(len > wdev->hw_caps.size_inp_ch_buf,
"%s: request exceed WFx capability: %zu > %d\n", __func__, "%s: request exceed WFx capability: %zu > %d\n", __func__,
len, wdev->hw_caps.size_inp_ch_buf); len, wdev->hw_caps.size_inp_ch_buf);
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
* Copyright (c) 2010, ST-Ericsson * Copyright (c) 2010, ST-Ericsson
*/ */
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/crc32.h>
#include "debug.h" #include "debug.h"
#include "wfx.h" #include "wfx.h"
...@@ -53,6 +54,21 @@ const char *get_reg_name(unsigned long id) ...@@ -53,6 +54,21 @@ const char *get_reg_name(unsigned long id)
return get_symbol(id, wfx_reg_print_map); return get_symbol(id, wfx_reg_print_map);
} }
static ssize_t wfx_burn_slk_key_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct wfx_dev *wdev = file->private_data;
dev_info(wdev->dev, "this driver does not support secure link\n");
return -EINVAL;
}
static const struct file_operations wfx_burn_slk_key_fops = {
.open = simple_open,
.write = wfx_burn_slk_key_write,
};
struct dbgfs_hif_msg { struct dbgfs_hif_msg {
struct wfx_dev *wdev; struct wfx_dev *wdev;
struct completion complete; struct completion complete;
...@@ -146,6 +162,7 @@ int wfx_debug_init(struct wfx_dev *wdev) ...@@ -146,6 +162,7 @@ int wfx_debug_init(struct wfx_dev *wdev)
struct dentry *d; struct dentry *d;
d = debugfs_create_dir("wfx", wdev->hw->wiphy->debugfsdir); d = debugfs_create_dir("wfx", wdev->hw->wiphy->debugfsdir);
debugfs_create_file("burn_slk_key", 0200, d, wdev, &wfx_burn_slk_key_fops);
debugfs_create_file("send_hif_msg", 0600, d, wdev, &wfx_send_hif_msg_fops); debugfs_create_file("send_hif_msg", 0600, d, wdev, &wfx_send_hif_msg_fops);
return 0; return 0;
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "hif_rx.h" #include "hif_rx.h"
#include "wfx.h" #include "wfx.h"
#include "secure_link.h"
#include "hif_api_cmd.h" #include "hif_api_cmd.h"
static int hif_generic_confirm(struct wfx_dev *wdev, struct hif_msg *hif, void *buf) static int hif_generic_confirm(struct wfx_dev *wdev, struct hif_msg *hif, void *buf)
...@@ -46,6 +47,8 @@ static int hif_generic_confirm(struct wfx_dev *wdev, struct hif_msg *hif, void * ...@@ -46,6 +47,8 @@ static int hif_generic_confirm(struct wfx_dev *wdev, struct hif_msg *hif, void *
} else { } else {
wdev->hif_cmd.buf_send = NULL; wdev->hif_cmd.buf_send = NULL;
mutex_unlock(&wdev->hif_cmd.lock); mutex_unlock(&wdev->hif_cmd.lock);
if (cmd != HIF_REQ_ID_SL_EXCHANGE_PUB_KEYS)
mutex_unlock(&wdev->hif_cmd.key_renew_lock);
} }
return status; return status;
} }
...@@ -68,11 +71,25 @@ static int hif_startup_indication(struct wfx_dev *wdev, struct hif_msg *hif, voi ...@@ -68,11 +71,25 @@ static int hif_startup_indication(struct wfx_dev *wdev, struct hif_msg *hif, voi
return 0; return 0;
} }
static int hif_keys_indication(struct wfx_dev *wdev, struct hif_msg *hif, void *buf)
{
struct hif_ind_sl_exchange_pub_keys *body = buf;
// Compatibility with legacy secure link
if (body->status == SL_PUB_KEY_EXCHANGE_STATUS_SUCCESS)
body->status = 0;
if (body->status)
dev_warn(wdev->dev, "secure link negociation error\n");
wfx_sl_check_pubkey(wdev, body->ncp_pub_key, body->ncp_pub_key_mac);
return 0;
}
static const struct { static const struct {
int msg_id; int msg_id;
int (*handler)(struct wfx_dev *wdev, struct hif_msg *hif, void *buf); int (*handler)(struct wfx_dev *wdev, struct hif_msg *hif, void *buf);
} hif_handlers[] = { } hif_handlers[] = {
{ HIF_IND_ID_STARTUP, hif_startup_indication }, { HIF_IND_ID_STARTUP, hif_startup_indication },
{ HIF_IND_ID_SL_EXCHANGE_PUB_KEYS, hif_keys_indication },
}; };
void wfx_handle_rx(struct wfx_dev *wdev, struct sk_buff *skb) void wfx_handle_rx(struct wfx_dev *wdev, struct sk_buff *skb)
......
...@@ -20,6 +20,7 @@ void wfx_init_hif_cmd(struct wfx_hif_cmd *hif_cmd) ...@@ -20,6 +20,7 @@ void wfx_init_hif_cmd(struct wfx_hif_cmd *hif_cmd)
init_completion(&hif_cmd->ready); init_completion(&hif_cmd->ready);
init_completion(&hif_cmd->done); init_completion(&hif_cmd->done);
mutex_init(&hif_cmd->lock); mutex_init(&hif_cmd->lock);
mutex_init(&hif_cmd->key_renew_lock);
} }
static void wfx_fill_header(struct hif_msg *hif, int if_id, unsigned int cmd, size_t size) static void wfx_fill_header(struct hif_msg *hif, int if_id, unsigned int cmd, size_t size)
...@@ -59,6 +60,9 @@ int wfx_cmd_send(struct wfx_dev *wdev, struct hif_msg *request, void *reply, siz ...@@ -59,6 +60,9 @@ int wfx_cmd_send(struct wfx_dev *wdev, struct hif_msg *request, void *reply, siz
if (wdev->chip_frozen) if (wdev->chip_frozen)
return -ETIMEDOUT; return -ETIMEDOUT;
if (cmd != HIF_REQ_ID_SL_EXCHANGE_PUB_KEYS)
mutex_lock(&wdev->hif_cmd.key_renew_lock);
mutex_lock(&wdev->hif_cmd.lock); mutex_lock(&wdev->hif_cmd.lock);
WARN(wdev->hif_cmd.buf_send, "data locking error"); WARN(wdev->hif_cmd.buf_send, "data locking error");
...@@ -107,6 +111,8 @@ int wfx_cmd_send(struct wfx_dev *wdev, struct hif_msg *request, void *reply, siz ...@@ -107,6 +111,8 @@ int wfx_cmd_send(struct wfx_dev *wdev, struct hif_msg *request, void *reply, siz
"WSM request %s%s%s (%#.2x) on vif %d returned status %d\n", "WSM request %s%s%s (%#.2x) on vif %d returned status %d\n",
get_hif_name(cmd), mib_sep, mib_name, cmd, vif, ret); get_hif_name(cmd), mib_sep, mib_name, cmd, vif, ret);
if (cmd != HIF_REQ_ID_SL_EXCHANGE_PUB_KEYS)
mutex_unlock(&wdev->hif_cmd.key_renew_lock);
return ret; return ret;
} }
......
...@@ -23,6 +23,7 @@ struct wfx_scan_params { ...@@ -23,6 +23,7 @@ struct wfx_scan_params {
struct wfx_hif_cmd { struct wfx_hif_cmd {
struct mutex lock; struct mutex lock;
struct mutex key_renew_lock;
struct completion ready; struct completion ready;
struct completion done; struct completion done;
bool async; bool async;
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "bh.h" #include "bh.h"
#include "sta.h" #include "sta.h"
#include "debug.h" #include "debug.h"
#include "secure_link.h"
#include "hif_api_cmd.h" #include "hif_api_cmd.h"
#include "wfx_version.h" #include "wfx_version.h"
...@@ -39,6 +40,10 @@ static int gpio_wakeup = -2; ...@@ -39,6 +40,10 @@ static int gpio_wakeup = -2;
module_param(gpio_wakeup, int, 0644); module_param(gpio_wakeup, int, 0644);
MODULE_PARM_DESC(gpio_wakeup, "gpio number for wakeup. -1 for none."); MODULE_PARM_DESC(gpio_wakeup, "gpio number for wakeup. -1 for none.");
static char *slk_key;
module_param(slk_key, charp, 0600);
MODULE_PARM_DESC(slk_key, "secret key for secure link (expect 64 hexdecimal digits).");
static const struct ieee80211_ops wfx_ops = { static const struct ieee80211_ops wfx_ops = {
.start = wfx_start, .start = wfx_start,
.stop = wfx_stop, .stop = wfx_stop,
...@@ -84,6 +89,29 @@ struct gpio_desc *wfx_get_gpio(struct device *dev, int override, const char *lab ...@@ -84,6 +89,29 @@ struct gpio_desc *wfx_get_gpio(struct device *dev, int override, const char *lab
return ret; return ret;
} }
static void wfx_fill_sl_key(struct device *dev, struct wfx_platform_data *pdata)
{
const char *ascii_key = NULL;
int ret = 0;
if (slk_key)
ascii_key = slk_key;
if (!ascii_key)
ret = of_property_read_string(dev->of_node, "slk_key", &ascii_key);
if (ret == -EILSEQ || ret == -ENODATA)
dev_err(dev, "ignoring malformatted key from DT\n");
if (!ascii_key)
return;
ret = hex2bin(pdata->slk_key, ascii_key, sizeof(pdata->slk_key));
if (ret) {
dev_err(dev, "ignoring malformatted key: %s\n", ascii_key);
memset(pdata->slk_key, 0, sizeof(pdata->slk_key));
return;
}
dev_err(dev, "secure link is not supported by this driver, ignoring provided key\n");
}
struct wfx_dev *wfx_init_common(struct device *dev, struct wfx_dev *wfx_init_common(struct device *dev,
const struct wfx_platform_data *pdata, const struct wfx_platform_data *pdata,
const struct hwbus_ops *hwbus_ops, const struct hwbus_ops *hwbus_ops,
...@@ -113,6 +141,7 @@ struct wfx_dev *wfx_init_common(struct device *dev, ...@@ -113,6 +141,7 @@ struct wfx_dev *wfx_init_common(struct device *dev,
wdev->hwbus_ops = hwbus_ops; wdev->hwbus_ops = hwbus_ops;
wdev->hwbus_priv = hwbus_priv; wdev->hwbus_priv = hwbus_priv;
memcpy(&wdev->pdata, pdata, sizeof(*pdata)); memcpy(&wdev->pdata, pdata, sizeof(*pdata));
wfx_fill_sl_key(dev, &wdev->pdata);
init_completion(&wdev->firmware_ready); init_completion(&wdev->firmware_ready);
wfx_init_hif_cmd(&wdev->hif_cmd); wfx_init_hif_cmd(&wdev->hif_cmd);
...@@ -167,6 +196,12 @@ int wfx_probe(struct wfx_dev *wdev) ...@@ -167,6 +196,12 @@ int wfx_probe(struct wfx_dev *wdev)
goto err1; goto err1;
} }
err = wfx_sl_init(wdev);
if (err && wdev->hw_caps.capabilities.link_mode == SEC_LINK_ENFORCED) {
dev_err(wdev->dev, "chip require secure_link, but can't negociate it\n");
goto err1;
}
for (i = 0; i < ARRAY_SIZE(wdev->addresses); i++) { for (i = 0; i < ARRAY_SIZE(wdev->addresses); i++) {
eth_zero_addr(wdev->addresses[i].addr); eth_zero_addr(wdev->addresses[i].addr);
macaddr = of_get_mac_address(wdev->dev->of_node); macaddr = of_get_mac_address(wdev->dev->of_node);
...@@ -198,6 +233,7 @@ int wfx_probe(struct wfx_dev *wdev) ...@@ -198,6 +233,7 @@ int wfx_probe(struct wfx_dev *wdev)
void wfx_release(struct wfx_dev *wdev) void wfx_release(struct wfx_dev *wdev)
{ {
wfx_bh_unregister(wdev); wfx_bh_unregister(wdev);
wfx_sl_deinit(wdev);
} }
static int __init wfx_core_init(void) static int __init wfx_core_init(void)
......
...@@ -14,12 +14,14 @@ ...@@ -14,12 +14,14 @@
#include <linux/gpio/consumer.h> #include <linux/gpio/consumer.h>
#include "bus.h" #include "bus.h"
#include "hif_api_general.h"
struct wfx_dev; struct wfx_dev;
struct wfx_platform_data { struct wfx_platform_data {
/* Keyset and ".sec" extention will appended to this string */ /* Keyset and ".sec" extention will appended to this string */
const char *file_fw; const char *file_fw;
unsigned char slk_key[API_KEY_VALUE_SIZE];
struct gpio_desc *gpio_wakeup; struct gpio_desc *gpio_wakeup;
/* /*
* if true HIF D_out is sampled on the rising edge of the clock * if true HIF D_out is sampled on the rising edge of the clock
......
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2019, Silicon Laboratories, Inc.
*/
#ifndef WFX_SECURE_LINK_H
#define WFX_SECURE_LINK_H
#include "hif_api_general.h"
struct wfx_dev;
struct sl_context {
};
static inline bool wfx_is_secure_command(struct wfx_dev *wdev, int cmd_id)
{
return false;
}
static inline int wfx_sl_decode(struct wfx_dev *wdev, struct hif_sl_msg *m)
{
return -EIO;
}
static inline int wfx_sl_encode(struct wfx_dev *wdev, struct hif_msg *input, struct hif_sl_msg *output)
{
return -EIO;
}
static inline int wfx_sl_check_pubkey(struct wfx_dev *wdev, uint8_t *ncp_pubkey, uint8_t *ncp_pubmac)
{
return -EIO;
}
static inline int wfx_sl_init(struct wfx_dev *wdev)
{
return -EIO;
}
static inline void wfx_sl_deinit(struct wfx_dev *wdev)
{
}
#endif
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "bh.h" #include "bh.h"
#include "main.h" #include "main.h"
#include "secure_link.h"
#include "hif_tx.h" #include "hif_tx.h"
#include "hif_api_general.h" #include "hif_api_general.h"
...@@ -33,6 +34,7 @@ struct wfx_dev { ...@@ -33,6 +34,7 @@ struct wfx_dev {
struct completion firmware_ready; struct completion firmware_ready;
struct hif_ind_startup hw_caps; struct hif_ind_startup hw_caps;
struct wfx_hif hif; struct wfx_hif hif;
struct sl_context sl;
int chip_frozen; int chip_frozen;
struct wfx_hif_cmd hif_cmd; struct wfx_hif_cmd hif_cmd;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment