Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next
This commit is contained in:
commit
f700076a9d
|
@ -210,6 +210,7 @@ config BT_MRVL_SDIO
|
|||
tristate "Marvell BT-over-SDIO driver"
|
||||
depends on BT_MRVL && MMC
|
||||
select FW_LOADER
|
||||
select WANT_DEV_COREDUMP
|
||||
help
|
||||
The driver for Marvell Bluetooth chipsets with SDIO interface.
|
||||
|
||||
|
|
|
@ -167,6 +167,35 @@ static const struct file_operations btmrvl_hscmd_fops = {
|
|||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static ssize_t btmrvl_fwdump_write(struct file *file, const char __user *ubuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct btmrvl_private *priv = file->private_data;
|
||||
char buf[16];
|
||||
bool result;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
|
||||
return -EFAULT;
|
||||
|
||||
if (strtobool(buf, &result))
|
||||
return -EINVAL;
|
||||
|
||||
if (!result)
|
||||
return -EINVAL;
|
||||
|
||||
btmrvl_firmware_dump(priv);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations btmrvl_fwdump_fops = {
|
||||
.write = btmrvl_fwdump_write,
|
||||
.open = simple_open,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
void btmrvl_debugfs_init(struct hci_dev *hdev)
|
||||
{
|
||||
struct btmrvl_private *priv = hci_get_drvdata(hdev);
|
||||
|
@ -197,6 +226,8 @@ void btmrvl_debugfs_init(struct hci_dev *hdev)
|
|||
priv, &btmrvl_hscmd_fops);
|
||||
debugfs_create_file("hscfgcmd", 0644, dbg->config_dir,
|
||||
priv, &btmrvl_hscfgcmd_fops);
|
||||
debugfs_create_file("fw_dump", 0200, dbg->config_dir,
|
||||
priv, &btmrvl_fwdump_fops);
|
||||
|
||||
dbg->status_dir = debugfs_create_dir("status", hdev->debugfs);
|
||||
debugfs_create_u8("curpsmode", 0444, dbg->status_dir,
|
||||
|
|
|
@ -32,6 +32,24 @@
|
|||
/* Time to wait for command response in millisecond */
|
||||
#define WAIT_UNTIL_CMD_RESP 5000
|
||||
|
||||
enum rdwr_status {
|
||||
RDWR_STATUS_SUCCESS = 0,
|
||||
RDWR_STATUS_FAILURE = 1,
|
||||
RDWR_STATUS_DONE = 2
|
||||
};
|
||||
|
||||
#define FW_DUMP_MAX_NAME_LEN 8
|
||||
#define FW_DUMP_HOST_READY 0xEE
|
||||
#define FW_DUMP_DONE 0xFF
|
||||
#define FW_DUMP_READ_DONE 0xFE
|
||||
|
||||
struct memory_type_mapping {
|
||||
u8 mem_name[FW_DUMP_MAX_NAME_LEN];
|
||||
u8 *mem_ptr;
|
||||
u32 mem_size;
|
||||
u8 done_flag;
|
||||
};
|
||||
|
||||
struct btmrvl_thread {
|
||||
struct task_struct *task;
|
||||
wait_queue_head_t wait_q;
|
||||
|
@ -81,6 +99,7 @@ struct btmrvl_private {
|
|||
u8 *payload, u16 nb);
|
||||
int (*hw_wakeup_firmware) (struct btmrvl_private *priv);
|
||||
int (*hw_process_int_status) (struct btmrvl_private *priv);
|
||||
void (*firmware_dump)(struct btmrvl_private *priv);
|
||||
spinlock_t driver_lock; /* spinlock used by driver */
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
void *debugfs_data;
|
||||
|
@ -151,6 +170,7 @@ int btmrvl_send_hscfg_cmd(struct btmrvl_private *priv);
|
|||
int btmrvl_enable_ps(struct btmrvl_private *priv);
|
||||
int btmrvl_prepare_command(struct btmrvl_private *priv);
|
||||
int btmrvl_enable_hs(struct btmrvl_private *priv);
|
||||
void btmrvl_firmware_dump(struct btmrvl_private *priv);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
void btmrvl_debugfs_init(struct hci_dev *hdev);
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <linux/of.h>
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
#include <linux/mmc/sdio_func.h>
|
||||
|
||||
#include "btmrvl_drv.h"
|
||||
#include "btmrvl_sdio.h"
|
||||
|
@ -42,7 +43,7 @@ void btmrvl_interrupt(struct btmrvl_private *priv)
|
|||
priv->adapter->int_count++;
|
||||
|
||||
if (priv->adapter->hs_state == HS_ACTIVATED) {
|
||||
BT_DBG("BT: HS DEACTIVATED in ISR!\n");
|
||||
BT_DBG("BT: HS DEACTIVATED in ISR!");
|
||||
priv->adapter->hs_state = HS_DEACTIVATED;
|
||||
}
|
||||
|
||||
|
@ -214,7 +215,7 @@ int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, u8 subcmd)
|
|||
|
||||
ret = btmrvl_send_sync_cmd(priv, BT_CMD_MODULE_CFG_REQ, &subcmd, 1);
|
||||
if (ret)
|
||||
BT_ERR("module_cfg_cmd(%x) failed\n", subcmd);
|
||||
BT_ERR("module_cfg_cmd(%x) failed", subcmd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -250,7 +251,7 @@ int btmrvl_send_hscfg_cmd(struct btmrvl_private *priv)
|
|||
|
||||
ret = btmrvl_send_sync_cmd(priv, BT_CMD_HOST_SLEEP_CONFIG, param, 2);
|
||||
if (ret)
|
||||
BT_ERR("HSCFG command failed\n");
|
||||
BT_ERR("HSCFG command failed");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -268,7 +269,7 @@ int btmrvl_enable_ps(struct btmrvl_private *priv)
|
|||
|
||||
ret = btmrvl_send_sync_cmd(priv, BT_CMD_AUTO_SLEEP_MODE, ¶m, 1);
|
||||
if (ret)
|
||||
BT_ERR("PSMODE command failed\n");
|
||||
BT_ERR("PSMODE command failed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -281,7 +282,7 @@ int btmrvl_enable_hs(struct btmrvl_private *priv)
|
|||
|
||||
ret = btmrvl_send_sync_cmd(priv, BT_CMD_HOST_SLEEP_ENABLE, NULL, 0);
|
||||
if (ret) {
|
||||
BT_ERR("Host sleep enable command failed\n");
|
||||
BT_ERR("Host sleep enable command failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -328,13 +329,19 @@ int btmrvl_prepare_command(struct btmrvl_private *priv)
|
|||
} else {
|
||||
ret = priv->hw_wakeup_firmware(priv);
|
||||
priv->adapter->hs_state = HS_DEACTIVATED;
|
||||
BT_DBG("BT: HS DEACTIVATED due to host activity!\n");
|
||||
BT_DBG("BT: HS DEACTIVATED due to host activity!");
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void btmrvl_firmware_dump(struct btmrvl_private *priv)
|
||||
{
|
||||
if (priv->firmware_dump)
|
||||
priv->firmware_dump(priv);
|
||||
}
|
||||
|
||||
static int btmrvl_tx_pkt(struct btmrvl_private *priv, struct sk_buff *skb)
|
||||
{
|
||||
int ret = 0;
|
||||
|
@ -493,7 +500,7 @@ static int btmrvl_download_cal_data(struct btmrvl_private *priv,
|
|||
ret = btmrvl_send_sync_cmd(priv, BT_CMD_LOAD_CONFIG_DATA, data,
|
||||
BT_CAL_HDR_LEN + len);
|
||||
if (ret)
|
||||
BT_ERR("Failed to download caibration data\n");
|
||||
BT_ERR("Failed to download caibration data");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <linux/mmc/sdio_ids.h>
|
||||
#include <linux/mmc/sdio_func.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/devcoredump.h>
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
|
@ -33,6 +34,24 @@
|
|||
|
||||
#define VERSION "1.0"
|
||||
|
||||
static struct memory_type_mapping mem_type_mapping_tbl[] = {
|
||||
{"ITCM", NULL, 0, 0xF0},
|
||||
{"DTCM", NULL, 0, 0xF1},
|
||||
{"SQRAM", NULL, 0, 0xF2},
|
||||
{"APU", NULL, 0, 0xF3},
|
||||
{"CIU", NULL, 0, 0xF4},
|
||||
{"ICU", NULL, 0, 0xF5},
|
||||
{"MAC", NULL, 0, 0xF6},
|
||||
{"EXT7", NULL, 0, 0xF7},
|
||||
{"EXT8", NULL, 0, 0xF8},
|
||||
{"EXT9", NULL, 0, 0xF9},
|
||||
{"EXT10", NULL, 0, 0xFA},
|
||||
{"EXT11", NULL, 0, 0xFB},
|
||||
{"EXT12", NULL, 0, 0xFC},
|
||||
{"EXT13", NULL, 0, 0xFD},
|
||||
{"EXTLAST", NULL, 0, 0xFE},
|
||||
};
|
||||
|
||||
/* The btmrvl_sdio_remove() callback function is called
|
||||
* when user removes this module from kernel space or ejects
|
||||
* the card from the slot. The driver handles these 2 cases
|
||||
|
@ -122,6 +141,9 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_8897 = {
|
|||
.int_read_to_clear = true,
|
||||
.host_int_rsr = 0x01,
|
||||
.card_misc_cfg = 0xcc,
|
||||
.fw_dump_ctrl = 0xe2,
|
||||
.fw_dump_start = 0xe3,
|
||||
.fw_dump_end = 0xea,
|
||||
};
|
||||
|
||||
static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = {
|
||||
|
@ -130,6 +152,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = {
|
|||
.reg = &btmrvl_reg_8688,
|
||||
.support_pscan_win_report = false,
|
||||
.sd_blksz_fw_dl = 64,
|
||||
.supports_fw_dump = false,
|
||||
};
|
||||
|
||||
static const struct btmrvl_sdio_device btmrvl_sdio_sd8787 = {
|
||||
|
@ -138,6 +161,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8787 = {
|
|||
.reg = &btmrvl_reg_87xx,
|
||||
.support_pscan_win_report = false,
|
||||
.sd_blksz_fw_dl = 256,
|
||||
.supports_fw_dump = false,
|
||||
};
|
||||
|
||||
static const struct btmrvl_sdio_device btmrvl_sdio_sd8797 = {
|
||||
|
@ -146,6 +170,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8797 = {
|
|||
.reg = &btmrvl_reg_87xx,
|
||||
.support_pscan_win_report = false,
|
||||
.sd_blksz_fw_dl = 256,
|
||||
.supports_fw_dump = false,
|
||||
};
|
||||
|
||||
static const struct btmrvl_sdio_device btmrvl_sdio_sd8887 = {
|
||||
|
@ -154,6 +179,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8887 = {
|
|||
.reg = &btmrvl_reg_8887,
|
||||
.support_pscan_win_report = true,
|
||||
.sd_blksz_fw_dl = 256,
|
||||
.supports_fw_dump = false,
|
||||
};
|
||||
|
||||
static const struct btmrvl_sdio_device btmrvl_sdio_sd8897 = {
|
||||
|
@ -162,6 +188,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8897 = {
|
|||
.reg = &btmrvl_reg_8897,
|
||||
.support_pscan_win_report = true,
|
||||
.sd_blksz_fw_dl = 256,
|
||||
.supports_fw_dump = true,
|
||||
};
|
||||
|
||||
static const struct sdio_device_id btmrvl_sdio_ids[] = {
|
||||
|
@ -764,8 +791,8 @@ static void btmrvl_sdio_interrupt(struct sdio_func *func)
|
|||
|
||||
card = sdio_get_drvdata(func);
|
||||
if (!card || !card->priv) {
|
||||
BT_ERR("sbi_interrupt(%p) card or priv is "
|
||||
"NULL, card=%p\n", func, card);
|
||||
BT_ERR("sbi_interrupt(%p) card or priv is NULL, card=%p",
|
||||
func, card);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1080,6 +1107,277 @@ static int btmrvl_sdio_wakeup_fw(struct btmrvl_private *priv)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void btmrvl_sdio_dump_regs(struct btmrvl_private *priv)
|
||||
{
|
||||
struct btmrvl_sdio_card *card = priv->btmrvl_dev.card;
|
||||
int ret = 0;
|
||||
unsigned int reg, reg_start, reg_end;
|
||||
char buf[256], *ptr;
|
||||
u8 loop, func, data;
|
||||
int MAX_LOOP = 2;
|
||||
|
||||
btmrvl_sdio_wakeup_fw(priv);
|
||||
sdio_claim_host(card->func);
|
||||
|
||||
for (loop = 0; loop < MAX_LOOP; loop++) {
|
||||
memset(buf, 0, sizeof(buf));
|
||||
ptr = buf;
|
||||
|
||||
if (loop == 0) {
|
||||
/* Read the registers of SDIO function0 */
|
||||
func = loop;
|
||||
reg_start = 0;
|
||||
reg_end = 9;
|
||||
} else {
|
||||
func = 2;
|
||||
reg_start = 0;
|
||||
reg_end = 0x09;
|
||||
}
|
||||
|
||||
ptr += sprintf(ptr, "SDIO Func%d (%#x-%#x): ",
|
||||
func, reg_start, reg_end);
|
||||
for (reg = reg_start; reg <= reg_end; reg++) {
|
||||
if (func == 0)
|
||||
data = sdio_f0_readb(card->func, reg, &ret);
|
||||
else
|
||||
data = sdio_readb(card->func, reg, &ret);
|
||||
|
||||
if (!ret) {
|
||||
ptr += sprintf(ptr, "%02x ", data);
|
||||
} else {
|
||||
ptr += sprintf(ptr, "ERR");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
BT_INFO("%s", buf);
|
||||
}
|
||||
|
||||
sdio_release_host(card->func);
|
||||
}
|
||||
|
||||
/* This function read/write firmware */
|
||||
static enum
|
||||
rdwr_status btmrvl_sdio_rdwr_firmware(struct btmrvl_private *priv,
|
||||
u8 doneflag)
|
||||
{
|
||||
struct btmrvl_sdio_card *card = priv->btmrvl_dev.card;
|
||||
int ret, tries;
|
||||
u8 ctrl_data = 0;
|
||||
|
||||
sdio_writeb(card->func, FW_DUMP_HOST_READY, card->reg->fw_dump_ctrl,
|
||||
&ret);
|
||||
|
||||
if (ret) {
|
||||
BT_ERR("SDIO write err");
|
||||
return RDWR_STATUS_FAILURE;
|
||||
}
|
||||
|
||||
for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
|
||||
ctrl_data = sdio_readb(card->func, card->reg->fw_dump_ctrl,
|
||||
&ret);
|
||||
|
||||
if (ret) {
|
||||
BT_ERR("SDIO read err");
|
||||
return RDWR_STATUS_FAILURE;
|
||||
}
|
||||
|
||||
if (ctrl_data == FW_DUMP_DONE)
|
||||
break;
|
||||
if (doneflag && ctrl_data == doneflag)
|
||||
return RDWR_STATUS_DONE;
|
||||
if (ctrl_data != FW_DUMP_HOST_READY) {
|
||||
BT_INFO("The ctrl reg was changed, re-try again!");
|
||||
sdio_writeb(card->func, FW_DUMP_HOST_READY,
|
||||
card->reg->fw_dump_ctrl, &ret);
|
||||
if (ret) {
|
||||
BT_ERR("SDIO write err");
|
||||
return RDWR_STATUS_FAILURE;
|
||||
}
|
||||
}
|
||||
usleep_range(100, 200);
|
||||
}
|
||||
|
||||
if (ctrl_data == FW_DUMP_HOST_READY) {
|
||||
BT_ERR("Fail to pull ctrl_data");
|
||||
return RDWR_STATUS_FAILURE;
|
||||
}
|
||||
|
||||
return RDWR_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* This function dump sdio register and memory data */
|
||||
static void btmrvl_sdio_dump_firmware(struct btmrvl_private *priv)
|
||||
{
|
||||
struct btmrvl_sdio_card *card = priv->btmrvl_dev.card;
|
||||
int ret = 0;
|
||||
unsigned int reg, reg_start, reg_end;
|
||||
enum rdwr_status stat;
|
||||
u8 *dbg_ptr, *end_ptr, *fw_dump_data, *fw_dump_ptr;
|
||||
u8 dump_num, idx, i, read_reg, doneflag = 0;
|
||||
u32 memory_size, fw_dump_len = 0;
|
||||
|
||||
/* dump sdio register first */
|
||||
btmrvl_sdio_dump_regs(priv);
|
||||
|
||||
if (!card->supports_fw_dump) {
|
||||
BT_ERR("Firmware dump not supported for this card!");
|
||||
return;
|
||||
}
|
||||
|
||||
for (idx = 0; idx < ARRAY_SIZE(mem_type_mapping_tbl); idx++) {
|
||||
struct memory_type_mapping *entry = &mem_type_mapping_tbl[idx];
|
||||
|
||||
if (entry->mem_ptr) {
|
||||
vfree(entry->mem_ptr);
|
||||
entry->mem_ptr = NULL;
|
||||
}
|
||||
entry->mem_size = 0;
|
||||
}
|
||||
|
||||
btmrvl_sdio_wakeup_fw(priv);
|
||||
sdio_claim_host(card->func);
|
||||
|
||||
BT_INFO("== btmrvl firmware dump start ==");
|
||||
|
||||
stat = btmrvl_sdio_rdwr_firmware(priv, doneflag);
|
||||
if (stat == RDWR_STATUS_FAILURE)
|
||||
goto done;
|
||||
|
||||
reg = card->reg->fw_dump_start;
|
||||
/* Read the number of the memories which will dump */
|
||||
dump_num = sdio_readb(card->func, reg, &ret);
|
||||
|
||||
if (ret) {
|
||||
BT_ERR("SDIO read memory length err");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Read the length of every memory which will dump */
|
||||
for (idx = 0; idx < dump_num; idx++) {
|
||||
struct memory_type_mapping *entry = &mem_type_mapping_tbl[idx];
|
||||
|
||||
stat = btmrvl_sdio_rdwr_firmware(priv, doneflag);
|
||||
if (stat == RDWR_STATUS_FAILURE)
|
||||
goto done;
|
||||
|
||||
memory_size = 0;
|
||||
reg = card->reg->fw_dump_start;
|
||||
for (i = 0; i < 4; i++) {
|
||||
read_reg = sdio_readb(card->func, reg, &ret);
|
||||
if (ret) {
|
||||
BT_ERR("SDIO read err");
|
||||
goto done;
|
||||
}
|
||||
memory_size |= (read_reg << i*8);
|
||||
reg++;
|
||||
}
|
||||
|
||||
if (memory_size == 0) {
|
||||
BT_INFO("Firmware dump finished!");
|
||||
break;
|
||||
}
|
||||
|
||||
BT_INFO("%s_SIZE=0x%x", entry->mem_name, memory_size);
|
||||
entry->mem_ptr = vzalloc(memory_size + 1);
|
||||
entry->mem_size = memory_size;
|
||||
if (!entry->mem_ptr) {
|
||||
BT_ERR("Vzalloc %s failed", entry->mem_name);
|
||||
goto done;
|
||||
}
|
||||
|
||||
fw_dump_len += (strlen("========Start dump ") +
|
||||
strlen(entry->mem_name) +
|
||||
strlen("========\n") +
|
||||
(memory_size + 1) +
|
||||
strlen("\n========End dump========\n"));
|
||||
|
||||
dbg_ptr = entry->mem_ptr;
|
||||
end_ptr = dbg_ptr + memory_size;
|
||||
|
||||
doneflag = entry->done_flag;
|
||||
BT_INFO("Start %s output, please wait...",
|
||||
entry->mem_name);
|
||||
|
||||
do {
|
||||
stat = btmrvl_sdio_rdwr_firmware(priv, doneflag);
|
||||
if (stat == RDWR_STATUS_FAILURE)
|
||||
goto done;
|
||||
|
||||
reg_start = card->reg->fw_dump_start;
|
||||
reg_end = card->reg->fw_dump_end;
|
||||
for (reg = reg_start; reg <= reg_end; reg++) {
|
||||
*dbg_ptr = sdio_readb(card->func, reg, &ret);
|
||||
if (ret) {
|
||||
BT_ERR("SDIO read err");
|
||||
goto done;
|
||||
}
|
||||
if (dbg_ptr < end_ptr)
|
||||
dbg_ptr++;
|
||||
else
|
||||
BT_ERR("Allocated buffer not enough");
|
||||
}
|
||||
|
||||
if (stat != RDWR_STATUS_DONE) {
|
||||
continue;
|
||||
} else {
|
||||
BT_INFO("%s done: size=0x%tx",
|
||||
entry->mem_name,
|
||||
dbg_ptr - entry->mem_ptr);
|
||||
break;
|
||||
}
|
||||
} while (1);
|
||||
}
|
||||
|
||||
BT_INFO("== btmrvl firmware dump end ==");
|
||||
|
||||
done:
|
||||
sdio_release_host(card->func);
|
||||
|
||||
if (fw_dump_len == 0)
|
||||
return;
|
||||
|
||||
fw_dump_data = vzalloc(fw_dump_len+1);
|
||||
if (!fw_dump_data) {
|
||||
BT_ERR("Vzalloc fw_dump_data fail!");
|
||||
return;
|
||||
}
|
||||
fw_dump_ptr = fw_dump_data;
|
||||
|
||||
/* Dump all the memory data into single file, a userspace script will
|
||||
be used to split all the memory data to multiple files*/
|
||||
BT_INFO("== btmrvl firmware dump to /sys/class/devcoredump start");
|
||||
for (idx = 0; idx < dump_num; idx++) {
|
||||
struct memory_type_mapping *entry = &mem_type_mapping_tbl[idx];
|
||||
|
||||
if (entry->mem_ptr) {
|
||||
strcpy(fw_dump_ptr, "========Start dump ");
|
||||
fw_dump_ptr += strlen("========Start dump ");
|
||||
|
||||
strcpy(fw_dump_ptr, entry->mem_name);
|
||||
fw_dump_ptr += strlen(entry->mem_name);
|
||||
|
||||
strcpy(fw_dump_ptr, "========\n");
|
||||
fw_dump_ptr += strlen("========\n");
|
||||
|
||||
memcpy(fw_dump_ptr, entry->mem_ptr, entry->mem_size);
|
||||
fw_dump_ptr += entry->mem_size;
|
||||
|
||||
strcpy(fw_dump_ptr, "\n========End dump========\n");
|
||||
fw_dump_ptr += strlen("\n========End dump========\n");
|
||||
|
||||
vfree(mem_type_mapping_tbl[idx].mem_ptr);
|
||||
mem_type_mapping_tbl[idx].mem_ptr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* fw_dump_data will be free in device coredump release function
|
||||
after 5 min*/
|
||||
dev_coredumpv(&priv->btmrvl_dev.hcidev->dev, fw_dump_data,
|
||||
fw_dump_len, GFP_KERNEL);
|
||||
BT_INFO("== btmrvl firmware dump to /sys/class/devcoredump end");
|
||||
}
|
||||
|
||||
static int btmrvl_sdio_probe(struct sdio_func *func,
|
||||
const struct sdio_device_id *id)
|
||||
{
|
||||
|
@ -1103,6 +1401,7 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
|
|||
card->reg = data->reg;
|
||||
card->sd_blksz_fw_dl = data->sd_blksz_fw_dl;
|
||||
card->support_pscan_win_report = data->support_pscan_win_report;
|
||||
card->supports_fw_dump = data->supports_fw_dump;
|
||||
}
|
||||
|
||||
if (btmrvl_sdio_register_dev(card) < 0) {
|
||||
|
@ -1134,6 +1433,7 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
|
|||
priv->hw_host_to_card = btmrvl_sdio_host_to_card;
|
||||
priv->hw_wakeup_firmware = btmrvl_sdio_wakeup_fw;
|
||||
priv->hw_process_int_status = btmrvl_sdio_process_int_status;
|
||||
priv->firmware_dump = btmrvl_sdio_dump_firmware;
|
||||
|
||||
if (btmrvl_register_hdev(priv)) {
|
||||
BT_ERR("Register hdev failed!");
|
||||
|
|
|
@ -81,6 +81,9 @@ struct btmrvl_sdio_card_reg {
|
|||
bool int_read_to_clear;
|
||||
u8 host_int_rsr;
|
||||
u8 card_misc_cfg;
|
||||
u8 fw_dump_ctrl;
|
||||
u8 fw_dump_start;
|
||||
u8 fw_dump_end;
|
||||
};
|
||||
|
||||
struct btmrvl_sdio_card {
|
||||
|
@ -90,6 +93,7 @@ struct btmrvl_sdio_card {
|
|||
const char *firmware;
|
||||
const struct btmrvl_sdio_card_reg *reg;
|
||||
bool support_pscan_win_report;
|
||||
bool supports_fw_dump;
|
||||
u16 sd_blksz_fw_dl;
|
||||
u8 rx_unit;
|
||||
struct btmrvl_private *priv;
|
||||
|
@ -101,6 +105,7 @@ struct btmrvl_sdio_device {
|
|||
const struct btmrvl_sdio_card_reg *reg;
|
||||
const bool support_pscan_win_report;
|
||||
u16 sd_blksz_fw_dl;
|
||||
bool supports_fw_dump;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -110,7 +110,8 @@ static const struct usb_device_id btusb_table[] = {
|
|||
.driver_info = BTUSB_BCM_PATCHRAM },
|
||||
|
||||
/* Foxconn - Hon Hai */
|
||||
{ USB_VENDOR_AND_INTERFACE_INFO(0x0489, 0xff, 0x01, 0x01) },
|
||||
{ USB_VENDOR_AND_INTERFACE_INFO(0x0489, 0xff, 0x01, 0x01),
|
||||
.driver_info = BTUSB_BCM_PATCHRAM },
|
||||
|
||||
/* Broadcom devices with vendor specific id */
|
||||
{ USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01),
|
||||
|
|
|
@ -858,7 +858,7 @@ static int cc2520_probe(struct spi_device *spi)
|
|||
pinctrl = devm_pinctrl_get_select_default(&spi->dev);
|
||||
if (IS_ERR(pinctrl))
|
||||
dev_warn(&spi->dev,
|
||||
"pinctrl pins are not configured");
|
||||
"pinctrl pins are not configured\n");
|
||||
|
||||
pdata = cc2520_get_platform_data(spi);
|
||||
if (!pdata) {
|
||||
|
|
|
@ -163,6 +163,7 @@ enum {
|
|||
enum {
|
||||
HCI_DUT_MODE,
|
||||
HCI_FORCE_SC,
|
||||
HCI_FORCE_LESC,
|
||||
HCI_FORCE_STATIC_ADDR,
|
||||
};
|
||||
|
||||
|
@ -342,6 +343,7 @@ enum {
|
|||
#define HCI_LE_ENCRYPTION 0x01
|
||||
#define HCI_LE_CONN_PARAM_REQ_PROC 0x02
|
||||
#define HCI_LE_PING 0x10
|
||||
#define HCI_LE_EXT_SCAN_POLICY 0x80
|
||||
|
||||
/* Connection modes */
|
||||
#define HCI_CM_ACTIVE 0x0000
|
||||
|
@ -411,6 +413,7 @@ enum {
|
|||
|
||||
/* The core spec defines 127 as the "not available" value */
|
||||
#define HCI_TX_POWER_INVALID 127
|
||||
#define HCI_RSSI_INVALID 127
|
||||
|
||||
#define HCI_ROLE_MASTER 0x00
|
||||
#define HCI_ROLE_SLAVE 0x01
|
||||
|
@ -1749,6 +1752,25 @@ struct hci_ev_le_conn_complete {
|
|||
__u8 clk_accurancy;
|
||||
} __packed;
|
||||
|
||||
/* Advertising report event types */
|
||||
#define LE_ADV_IND 0x00
|
||||
#define LE_ADV_DIRECT_IND 0x01
|
||||
#define LE_ADV_SCAN_IND 0x02
|
||||
#define LE_ADV_NONCONN_IND 0x03
|
||||
#define LE_ADV_SCAN_RSP 0x04
|
||||
|
||||
#define ADDR_LE_DEV_PUBLIC 0x00
|
||||
#define ADDR_LE_DEV_RANDOM 0x01
|
||||
|
||||
#define HCI_EV_LE_ADVERTISING_REPORT 0x02
|
||||
struct hci_ev_le_advertising_info {
|
||||
__u8 evt_type;
|
||||
__u8 bdaddr_type;
|
||||
bdaddr_t bdaddr;
|
||||
__u8 length;
|
||||
__u8 data[0];
|
||||
} __packed;
|
||||
|
||||
#define HCI_EV_LE_CONN_UPDATE_COMPLETE 0x03
|
||||
struct hci_ev_le_conn_update_complete {
|
||||
__u8 status;
|
||||
|
@ -1774,23 +1796,14 @@ struct hci_ev_le_remote_conn_param_req {
|
|||
__le16 timeout;
|
||||
} __packed;
|
||||
|
||||
/* Advertising report event types */
|
||||
#define LE_ADV_IND 0x00
|
||||
#define LE_ADV_DIRECT_IND 0x01
|
||||
#define LE_ADV_SCAN_IND 0x02
|
||||
#define LE_ADV_NONCONN_IND 0x03
|
||||
#define LE_ADV_SCAN_RSP 0x04
|
||||
|
||||
#define ADDR_LE_DEV_PUBLIC 0x00
|
||||
#define ADDR_LE_DEV_RANDOM 0x01
|
||||
|
||||
#define HCI_EV_LE_ADVERTISING_REPORT 0x02
|
||||
struct hci_ev_le_advertising_info {
|
||||
#define HCI_EV_LE_DIRECT_ADV_REPORT 0x0B
|
||||
struct hci_ev_le_direct_adv_info {
|
||||
__u8 evt_type;
|
||||
__u8 bdaddr_type;
|
||||
bdaddr_t bdaddr;
|
||||
__u8 length;
|
||||
__u8 data[0];
|
||||
__u8 direct_addr_type;
|
||||
bdaddr_t direct_addr;
|
||||
__s8 rssi;
|
||||
} __packed;
|
||||
|
||||
/* Internal events generated by Bluetooth stack */
|
||||
|
|
|
@ -75,6 +75,10 @@ struct discovery_state {
|
|||
u32 last_adv_flags;
|
||||
u8 last_adv_data[HCI_MAX_AD_LENGTH];
|
||||
u8 last_adv_data_len;
|
||||
bool report_invalid_rssi;
|
||||
s8 rssi;
|
||||
u16 uuid_count;
|
||||
u8 (*uuids)[16];
|
||||
};
|
||||
|
||||
struct hci_conn_hash {
|
||||
|
@ -140,6 +144,7 @@ struct link_key {
|
|||
struct oob_data {
|
||||
struct list_head list;
|
||||
bdaddr_t bdaddr;
|
||||
u8 bdaddr_type;
|
||||
u8 hash192[16];
|
||||
u8 rand192[16];
|
||||
u8 hash256[16];
|
||||
|
@ -306,6 +311,7 @@ struct hci_dev {
|
|||
__u32 req_result;
|
||||
|
||||
void *smp_data;
|
||||
void *smp_bredr_data;
|
||||
|
||||
struct discovery_state discovery;
|
||||
struct hci_conn_hash conn_hash;
|
||||
|
@ -501,6 +507,17 @@ static inline void discovery_init(struct hci_dev *hdev)
|
|||
INIT_LIST_HEAD(&hdev->discovery.all);
|
||||
INIT_LIST_HEAD(&hdev->discovery.unknown);
|
||||
INIT_LIST_HEAD(&hdev->discovery.resolve);
|
||||
hdev->discovery.report_invalid_rssi = true;
|
||||
hdev->discovery.rssi = HCI_RSSI_INVALID;
|
||||
}
|
||||
|
||||
static inline void hci_discovery_filter_clear(struct hci_dev *hdev)
|
||||
{
|
||||
hdev->discovery.report_invalid_rssi = true;
|
||||
hdev->discovery.rssi = HCI_RSSI_INVALID;
|
||||
hdev->discovery.uuid_count = 0;
|
||||
kfree(hdev->discovery.uuids);
|
||||
hdev->discovery.uuids = NULL;
|
||||
}
|
||||
|
||||
bool hci_discovery_active(struct hci_dev *hdev);
|
||||
|
@ -559,6 +576,7 @@ enum {
|
|||
HCI_CONN_AUTH_INITIATOR,
|
||||
HCI_CONN_DROP,
|
||||
HCI_CONN_PARAM_REMOVAL_PEND,
|
||||
HCI_CONN_NEW_LINK_KEY,
|
||||
};
|
||||
|
||||
static inline bool hci_conn_ssp_enabled(struct hci_conn *conn)
|
||||
|
@ -921,13 +939,11 @@ struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);
|
|||
struct link_key *hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn,
|
||||
bdaddr_t *bdaddr, u8 *val, u8 type,
|
||||
u8 pin_len, bool *persistent);
|
||||
struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, __le64 rand,
|
||||
u8 role);
|
||||
struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
u8 addr_type, u8 type, u8 authenticated,
|
||||
u8 tk[16], u8 enc_size, __le16 ediv, __le64 rand);
|
||||
struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
u8 addr_type, u8 role);
|
||||
struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
u8 addr_type, u8 role);
|
||||
int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 bdaddr_type);
|
||||
void hci_smp_ltks_clear(struct hci_dev *hdev);
|
||||
int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);
|
||||
|
@ -942,13 +958,12 @@ void hci_smp_irks_clear(struct hci_dev *hdev);
|
|||
|
||||
void hci_remote_oob_data_clear(struct hci_dev *hdev);
|
||||
struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev,
|
||||
bdaddr_t *bdaddr);
|
||||
bdaddr_t *bdaddr, u8 bdaddr_type);
|
||||
int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
u8 *hash, u8 *rand);
|
||||
int hci_add_remote_oob_ext_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
u8 *hash192, u8 *rand192,
|
||||
u8 *hash256, u8 *rand256);
|
||||
int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr);
|
||||
u8 bdaddr_type, u8 *hash192, u8 *rand192,
|
||||
u8 *hash256, u8 *rand256);
|
||||
int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
u8 bdaddr_type);
|
||||
|
||||
void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
|
||||
|
||||
|
@ -999,6 +1014,9 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
|
|||
|
||||
#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
|
||||
!test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
|
||||
#define bredr_sc_enabled(dev) ((lmp_sc_capable(dev) || \
|
||||
test_bit(HCI_FORCE_SC, &(dev)->dbg_flags)) && \
|
||||
test_bit(HCI_SC_ENABLED, &(dev)->dev_flags))
|
||||
|
||||
/* ----- HCI protocols ----- */
|
||||
#define HCI_PROTO_DEFER 0x01
|
||||
|
|
|
@ -141,6 +141,7 @@ struct l2cap_conninfo {
|
|||
#define L2CAP_FC_ATT 0x10
|
||||
#define L2CAP_FC_SIG_LE 0x20
|
||||
#define L2CAP_FC_SMP_LE 0x40
|
||||
#define L2CAP_FC_SMP_BREDR 0x80
|
||||
|
||||
/* L2CAP Control Field bit masks */
|
||||
#define L2CAP_CTRL_SAR 0xC000
|
||||
|
@ -255,6 +256,7 @@ struct l2cap_conn_rsp {
|
|||
#define L2CAP_CID_ATT 0x0004
|
||||
#define L2CAP_CID_LE_SIGNALING 0x0005
|
||||
#define L2CAP_CID_SMP 0x0006
|
||||
#define L2CAP_CID_SMP_BREDR 0x0007
|
||||
#define L2CAP_CID_DYN_START 0x0040
|
||||
#define L2CAP_CID_DYN_END 0xffff
|
||||
#define L2CAP_CID_LE_DYN_END 0x007f
|
||||
|
@ -619,8 +621,8 @@ struct l2cap_conn {
|
|||
unsigned int mtu;
|
||||
|
||||
__u32 feat_mask;
|
||||
__u8 fixed_chan_mask;
|
||||
bool hs_enabled;
|
||||
__u8 remote_fixed_chan;
|
||||
__u8 local_fixed_chan;
|
||||
|
||||
__u8 info_state;
|
||||
__u8 info_ident;
|
||||
|
|
|
@ -184,6 +184,9 @@ struct mgmt_cp_load_link_keys {
|
|||
|
||||
#define MGMT_LTK_UNAUTHENTICATED 0x00
|
||||
#define MGMT_LTK_AUTHENTICATED 0x01
|
||||
#define MGMT_LTK_P256_UNAUTH 0x02
|
||||
#define MGMT_LTK_P256_AUTH 0x03
|
||||
#define MGMT_LTK_P256_DEBUG 0x04
|
||||
|
||||
struct mgmt_ltk_info {
|
||||
struct mgmt_addr_info addr;
|
||||
|
@ -495,6 +498,15 @@ struct mgmt_cp_set_public_address {
|
|||
} __packed;
|
||||
#define MGMT_SET_PUBLIC_ADDRESS_SIZE 6
|
||||
|
||||
#define MGMT_OP_START_SERVICE_DISCOVERY 0x003A
|
||||
struct mgmt_cp_start_service_discovery {
|
||||
__u8 type;
|
||||
__s8 rssi;
|
||||
__le16 uuid_count;
|
||||
__u8 uuids[0][16];
|
||||
} __packed;
|
||||
#define MGMT_START_SERVICE_DISCOVERY_SIZE 4
|
||||
|
||||
#define MGMT_EV_CMD_COMPLETE 0x0001
|
||||
struct mgmt_ev_cmd_complete {
|
||||
__le16 opcode;
|
||||
|
|
|
@ -15,9 +15,6 @@
|
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
/* Jon's code is based on 6lowpan implementation for Contiki which is:
|
||||
|
|
|
@ -10,6 +10,7 @@ menuconfig BT
|
|||
select CRYPTO
|
||||
select CRYPTO_BLKCIPHER
|
||||
select CRYPTO_AES
|
||||
select CRYPTO_CMAC
|
||||
select CRYPTO_ECB
|
||||
select CRYPTO_SHA256
|
||||
help
|
||||
|
|
|
@ -13,6 +13,6 @@ bluetooth_6lowpan-y := 6lowpan.o
|
|||
|
||||
bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
|
||||
hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \
|
||||
a2mp.o amp.o
|
||||
a2mp.o amp.o ecc.o
|
||||
|
||||
subdir-ccflags-y += -D__CHECK_ENDIAN__
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <linux/proc_fs.h>
|
||||
|
||||
#define VERSION "2.19"
|
||||
#define VERSION "2.20"
|
||||
|
||||
/* Bluetooth sockets */
|
||||
#define BT_MAX_PROTO 8
|
||||
|
|
|
@ -0,0 +1,816 @@
|
|||
/*
|
||||
* Copyright (c) 2013, Kenneth MacKay
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <linux/random.h>
|
||||
|
||||
#include "ecc.h"
|
||||
|
||||
/* 256-bit curve */
|
||||
#define ECC_BYTES 32
|
||||
|
||||
#define MAX_TRIES 16
|
||||
|
||||
/* Number of u64's needed */
|
||||
#define NUM_ECC_DIGITS (ECC_BYTES / 8)
|
||||
|
||||
struct ecc_point {
|
||||
u64 x[NUM_ECC_DIGITS];
|
||||
u64 y[NUM_ECC_DIGITS];
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
u64 m_low;
|
||||
u64 m_high;
|
||||
} uint128_t;
|
||||
|
||||
#define CURVE_P_32 { 0xFFFFFFFFFFFFFFFFull, 0x00000000FFFFFFFFull, \
|
||||
0x0000000000000000ull, 0xFFFFFFFF00000001ull }
|
||||
|
||||
#define CURVE_G_32 { \
|
||||
{ 0xF4A13945D898C296ull, 0x77037D812DEB33A0ull, \
|
||||
0xF8BCE6E563A440F2ull, 0x6B17D1F2E12C4247ull }, \
|
||||
{ 0xCBB6406837BF51F5ull, 0x2BCE33576B315ECEull, \
|
||||
0x8EE7EB4A7C0F9E16ull, 0x4FE342E2FE1A7F9Bull } \
|
||||
}
|
||||
|
||||
#define CURVE_N_32 { 0xF3B9CAC2FC632551ull, 0xBCE6FAADA7179E84ull, \
|
||||
0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFF00000000ull }
|
||||
|
||||
static u64 curve_p[NUM_ECC_DIGITS] = CURVE_P_32;
|
||||
static struct ecc_point curve_g = CURVE_G_32;
|
||||
static u64 curve_n[NUM_ECC_DIGITS] = CURVE_N_32;
|
||||
|
||||
static void vli_clear(u64 *vli)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_ECC_DIGITS; i++)
|
||||
vli[i] = 0;
|
||||
}
|
||||
|
||||
/* Returns true if vli == 0, false otherwise. */
|
||||
static bool vli_is_zero(const u64 *vli)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_ECC_DIGITS; i++) {
|
||||
if (vli[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns nonzero if bit bit of vli is set. */
|
||||
static u64 vli_test_bit(const u64 *vli, unsigned int bit)
|
||||
{
|
||||
return (vli[bit / 64] & ((u64) 1 << (bit % 64)));
|
||||
}
|
||||
|
||||
/* Counts the number of 64-bit "digits" in vli. */
|
||||
static unsigned int vli_num_digits(const u64 *vli)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Search from the end until we find a non-zero digit.
|
||||
* We do it in reverse because we expect that most digits will
|
||||
* be nonzero.
|
||||
*/
|
||||
for (i = NUM_ECC_DIGITS - 1; i >= 0 && vli[i] == 0; i--);
|
||||
|
||||
return (i + 1);
|
||||
}
|
||||
|
||||
/* Counts the number of bits required for vli. */
|
||||
static unsigned int vli_num_bits(const u64 *vli)
|
||||
{
|
||||
unsigned int i, num_digits;
|
||||
u64 digit;
|
||||
|
||||
num_digits = vli_num_digits(vli);
|
||||
if (num_digits == 0)
|
||||
return 0;
|
||||
|
||||
digit = vli[num_digits - 1];
|
||||
for (i = 0; digit; i++)
|
||||
digit >>= 1;
|
||||
|
||||
return ((num_digits - 1) * 64 + i);
|
||||
}
|
||||
|
||||
/* Sets dest = src. */
|
||||
static void vli_set(u64 *dest, const u64 *src)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_ECC_DIGITS; i++)
|
||||
dest[i] = src[i];
|
||||
}
|
||||
|
||||
/* Returns sign of left - right. */
|
||||
static int vli_cmp(const u64 *left, const u64 *right)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = NUM_ECC_DIGITS - 1; i >= 0; i--) {
|
||||
if (left[i] > right[i])
|
||||
return 1;
|
||||
else if (left[i] < right[i])
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Computes result = in << c, returning carry. Can modify in place
|
||||
* (if result == in). 0 < shift < 64.
|
||||
*/
|
||||
static u64 vli_lshift(u64 *result, const u64 *in,
|
||||
unsigned int shift)
|
||||
{
|
||||
u64 carry = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_ECC_DIGITS; i++) {
|
||||
u64 temp = in[i];
|
||||
|
||||
result[i] = (temp << shift) | carry;
|
||||
carry = temp >> (64 - shift);
|
||||
}
|
||||
|
||||
return carry;
|
||||
}
|
||||
|
||||
/* Computes vli = vli >> 1. */
|
||||
static void vli_rshift1(u64 *vli)
|
||||
{
|
||||
u64 *end = vli;
|
||||
u64 carry = 0;
|
||||
|
||||
vli += NUM_ECC_DIGITS;
|
||||
|
||||
while (vli-- > end) {
|
||||
u64 temp = *vli;
|
||||
*vli = (temp >> 1) | carry;
|
||||
carry = temp << 63;
|
||||
}
|
||||
}
|
||||
|
||||
/* Computes result = left + right, returning carry. Can modify in place. */
|
||||
static u64 vli_add(u64 *result, const u64 *left,
|
||||
const u64 *right)
|
||||
{
|
||||
u64 carry = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_ECC_DIGITS; i++) {
|
||||
u64 sum;
|
||||
|
||||
sum = left[i] + right[i] + carry;
|
||||
if (sum != left[i])
|
||||
carry = (sum < left[i]);
|
||||
|
||||
result[i] = sum;
|
||||
}
|
||||
|
||||
return carry;
|
||||
}
|
||||
|
||||
/* Computes result = left - right, returning borrow. Can modify in place. */
|
||||
static u64 vli_sub(u64 *result, const u64 *left, const u64 *right)
|
||||
{
|
||||
u64 borrow = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_ECC_DIGITS; i++) {
|
||||
u64 diff;
|
||||
|
||||
diff = left[i] - right[i] - borrow;
|
||||
if (diff != left[i])
|
||||
borrow = (diff > left[i]);
|
||||
|
||||
result[i] = diff;
|
||||
}
|
||||
|
||||
return borrow;
|
||||
}
|
||||
|
||||
static uint128_t mul_64_64(u64 left, u64 right)
|
||||
{
|
||||
u64 a0 = left & 0xffffffffull;
|
||||
u64 a1 = left >> 32;
|
||||
u64 b0 = right & 0xffffffffull;
|
||||
u64 b1 = right >> 32;
|
||||
u64 m0 = a0 * b0;
|
||||
u64 m1 = a0 * b1;
|
||||
u64 m2 = a1 * b0;
|
||||
u64 m3 = a1 * b1;
|
||||
uint128_t result;
|
||||
|
||||
m2 += (m0 >> 32);
|
||||
m2 += m1;
|
||||
|
||||
/* Overflow */
|
||||
if (m2 < m1)
|
||||
m3 += 0x100000000ull;
|
||||
|
||||
result.m_low = (m0 & 0xffffffffull) | (m2 << 32);
|
||||
result.m_high = m3 + (m2 >> 32);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static uint128_t add_128_128(uint128_t a, uint128_t b)
|
||||
{
|
||||
uint128_t result;
|
||||
|
||||
result.m_low = a.m_low + b.m_low;
|
||||
result.m_high = a.m_high + b.m_high + (result.m_low < a.m_low);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void vli_mult(u64 *result, const u64 *left, const u64 *right)
|
||||
{
|
||||
uint128_t r01 = { 0, 0 };
|
||||
u64 r2 = 0;
|
||||
unsigned int i, k;
|
||||
|
||||
/* Compute each digit of result in sequence, maintaining the
|
||||
* carries.
|
||||
*/
|
||||
for (k = 0; k < NUM_ECC_DIGITS * 2 - 1; k++) {
|
||||
unsigned int min;
|
||||
|
||||
if (k < NUM_ECC_DIGITS)
|
||||
min = 0;
|
||||
else
|
||||
min = (k + 1) - NUM_ECC_DIGITS;
|
||||
|
||||
for (i = min; i <= k && i < NUM_ECC_DIGITS; i++) {
|
||||
uint128_t product;
|
||||
|
||||
product = mul_64_64(left[i], right[k - i]);
|
||||
|
||||
r01 = add_128_128(r01, product);
|
||||
r2 += (r01.m_high < product.m_high);
|
||||
}
|
||||
|
||||
result[k] = r01.m_low;
|
||||
r01.m_low = r01.m_high;
|
||||
r01.m_high = r2;
|
||||
r2 = 0;
|
||||
}
|
||||
|
||||
result[NUM_ECC_DIGITS * 2 - 1] = r01.m_low;
|
||||
}
|
||||
|
||||
static void vli_square(u64 *result, const u64 *left)
|
||||
{
|
||||
uint128_t r01 = { 0, 0 };
|
||||
u64 r2 = 0;
|
||||
int i, k;
|
||||
|
||||
for (k = 0; k < NUM_ECC_DIGITS * 2 - 1; k++) {
|
||||
unsigned int min;
|
||||
|
||||
if (k < NUM_ECC_DIGITS)
|
||||
min = 0;
|
||||
else
|
||||
min = (k + 1) - NUM_ECC_DIGITS;
|
||||
|
||||
for (i = min; i <= k && i <= k - i; i++) {
|
||||
uint128_t product;
|
||||
|
||||
product = mul_64_64(left[i], left[k - i]);
|
||||
|
||||
if (i < k - i) {
|
||||
r2 += product.m_high >> 63;
|
||||
product.m_high = (product.m_high << 1) |
|
||||
(product.m_low >> 63);
|
||||
product.m_low <<= 1;
|
||||
}
|
||||
|
||||
r01 = add_128_128(r01, product);
|
||||
r2 += (r01.m_high < product.m_high);
|
||||
}
|
||||
|
||||
result[k] = r01.m_low;
|
||||
r01.m_low = r01.m_high;
|
||||
r01.m_high = r2;
|
||||
r2 = 0;
|
||||
}
|
||||
|
||||
result[NUM_ECC_DIGITS * 2 - 1] = r01.m_low;
|
||||
}
|
||||
|
||||
/* Computes result = (left + right) % mod.
|
||||
* Assumes that left < mod and right < mod, result != mod.
|
||||
*/
|
||||
static void vli_mod_add(u64 *result, const u64 *left, const u64 *right,
|
||||
const u64 *mod)
|
||||
{
|
||||
u64 carry;
|
||||
|
||||
carry = vli_add(result, left, right);
|
||||
|
||||
/* result > mod (result = mod + remainder), so subtract mod to
|
||||
* get remainder.
|
||||
*/
|
||||
if (carry || vli_cmp(result, mod) >= 0)
|
||||
vli_sub(result, result, mod);
|
||||
}
|
||||
|
||||
/* Computes result = (left - right) % mod.
|
||||
* Assumes that left < mod and right < mod, result != mod.
|
||||
*/
|
||||
static void vli_mod_sub(u64 *result, const u64 *left, const u64 *right,
|
||||
const u64 *mod)
|
||||
{
|
||||
u64 borrow = vli_sub(result, left, right);
|
||||
|
||||
/* In this case, p_result == -diff == (max int) - diff.
|
||||
* Since -x % d == d - x, we can get the correct result from
|
||||
* result + mod (with overflow).
|
||||
*/
|
||||
if (borrow)
|
||||
vli_add(result, result, mod);
|
||||
}
|
||||
|
||||
/* Computes result = product % curve_p
|
||||
from http://www.nsa.gov/ia/_files/nist-routines.pdf */
|
||||
static void vli_mmod_fast(u64 *result, const u64 *product)
|
||||
{
|
||||
u64 tmp[NUM_ECC_DIGITS];
|
||||
int carry;
|
||||
|
||||
/* t */
|
||||
vli_set(result, product);
|
||||
|
||||
/* s1 */
|
||||
tmp[0] = 0;
|
||||
tmp[1] = product[5] & 0xffffffff00000000ull;
|
||||
tmp[2] = product[6];
|
||||
tmp[3] = product[7];
|
||||
carry = vli_lshift(tmp, tmp, 1);
|
||||
carry += vli_add(result, result, tmp);
|
||||
|
||||
/* s2 */
|
||||
tmp[1] = product[6] << 32;
|
||||
tmp[2] = (product[6] >> 32) | (product[7] << 32);
|
||||
tmp[3] = product[7] >> 32;
|
||||
carry += vli_lshift(tmp, tmp, 1);
|
||||
carry += vli_add(result, result, tmp);
|
||||
|
||||
/* s3 */
|
||||
tmp[0] = product[4];
|
||||
tmp[1] = product[5] & 0xffffffff;
|
||||
tmp[2] = 0;
|
||||
tmp[3] = product[7];
|
||||
carry += vli_add(result, result, tmp);
|
||||
|
||||
/* s4 */
|
||||
tmp[0] = (product[4] >> 32) | (product[5] << 32);
|
||||
tmp[1] = (product[5] >> 32) | (product[6] & 0xffffffff00000000ull);
|
||||
tmp[2] = product[7];
|
||||
tmp[3] = (product[6] >> 32) | (product[4] << 32);
|
||||
carry += vli_add(result, result, tmp);
|
||||
|
||||
/* d1 */
|
||||
tmp[0] = (product[5] >> 32) | (product[6] << 32);
|
||||
tmp[1] = (product[6] >> 32);
|
||||
tmp[2] = 0;
|
||||
tmp[3] = (product[4] & 0xffffffff) | (product[5] << 32);
|
||||
carry -= vli_sub(result, result, tmp);
|
||||
|
||||
/* d2 */
|
||||
tmp[0] = product[6];
|
||||
tmp[1] = product[7];
|
||||
tmp[2] = 0;
|
||||
tmp[3] = (product[4] >> 32) | (product[5] & 0xffffffff00000000ull);
|
||||
carry -= vli_sub(result, result, tmp);
|
||||
|
||||
/* d3 */
|
||||
tmp[0] = (product[6] >> 32) | (product[7] << 32);
|
||||
tmp[1] = (product[7] >> 32) | (product[4] << 32);
|
||||
tmp[2] = (product[4] >> 32) | (product[5] << 32);
|
||||
tmp[3] = (product[6] << 32);
|
||||
carry -= vli_sub(result, result, tmp);
|
||||
|
||||
/* d4 */
|
||||
tmp[0] = product[7];
|
||||
tmp[1] = product[4] & 0xffffffff00000000ull;
|
||||
tmp[2] = product[5];
|
||||
tmp[3] = product[6] & 0xffffffff00000000ull;
|
||||
carry -= vli_sub(result, result, tmp);
|
||||
|
||||
if (carry < 0) {
|
||||
do {
|
||||
carry += vli_add(result, result, curve_p);
|
||||
} while (carry < 0);
|
||||
} else {
|
||||
while (carry || vli_cmp(curve_p, result) != 1)
|
||||
carry -= vli_sub(result, result, curve_p);
|
||||
}
|
||||
}
|
||||
|
||||
/* Computes result = (left * right) % curve_p. */
|
||||
static void vli_mod_mult_fast(u64 *result, const u64 *left, const u64 *right)
|
||||
{
|
||||
u64 product[2 * NUM_ECC_DIGITS];
|
||||
|
||||
vli_mult(product, left, right);
|
||||
vli_mmod_fast(result, product);
|
||||
}
|
||||
|
||||
/* Computes result = left^2 % curve_p. */
|
||||
static void vli_mod_square_fast(u64 *result, const u64 *left)
|
||||
{
|
||||
u64 product[2 * NUM_ECC_DIGITS];
|
||||
|
||||
vli_square(product, left);
|
||||
vli_mmod_fast(result, product);
|
||||
}
|
||||
|
||||
#define EVEN(vli) (!(vli[0] & 1))
|
||||
/* Computes result = (1 / p_input) % mod. All VLIs are the same size.
|
||||
* See "From Euclid's GCD to Montgomery Multiplication to the Great Divide"
|
||||
* https://labs.oracle.com/techrep/2001/smli_tr-2001-95.pdf
|
||||
*/
|
||||
static void vli_mod_inv(u64 *result, const u64 *input, const u64 *mod)
|
||||
{
|
||||
u64 a[NUM_ECC_DIGITS], b[NUM_ECC_DIGITS];
|
||||
u64 u[NUM_ECC_DIGITS], v[NUM_ECC_DIGITS];
|
||||
u64 carry;
|
||||
int cmp_result;
|
||||
|
||||
if (vli_is_zero(input)) {
|
||||
vli_clear(result);
|
||||
return;
|
||||
}
|
||||
|
||||
vli_set(a, input);
|
||||
vli_set(b, mod);
|
||||
vli_clear(u);
|
||||
u[0] = 1;
|
||||
vli_clear(v);
|
||||
|
||||
while ((cmp_result = vli_cmp(a, b)) != 0) {
|
||||
carry = 0;
|
||||
|
||||
if (EVEN(a)) {
|
||||
vli_rshift1(a);
|
||||
|
||||
if (!EVEN(u))
|
||||
carry = vli_add(u, u, mod);
|
||||
|
||||
vli_rshift1(u);
|
||||
if (carry)
|
||||
u[NUM_ECC_DIGITS - 1] |= 0x8000000000000000ull;
|
||||
} else if (EVEN(b)) {
|
||||
vli_rshift1(b);
|
||||
|
||||
if (!EVEN(v))
|
||||
carry = vli_add(v, v, mod);
|
||||
|
||||
vli_rshift1(v);
|
||||
if (carry)
|
||||
v[NUM_ECC_DIGITS - 1] |= 0x8000000000000000ull;
|
||||
} else if (cmp_result > 0) {
|
||||
vli_sub(a, a, b);
|
||||
vli_rshift1(a);
|
||||
|
||||
if (vli_cmp(u, v) < 0)
|
||||
vli_add(u, u, mod);
|
||||
|
||||
vli_sub(u, u, v);
|
||||
if (!EVEN(u))
|
||||
carry = vli_add(u, u, mod);
|
||||
|
||||
vli_rshift1(u);
|
||||
if (carry)
|
||||
u[NUM_ECC_DIGITS - 1] |= 0x8000000000000000ull;
|
||||
} else {
|
||||
vli_sub(b, b, a);
|
||||
vli_rshift1(b);
|
||||
|
||||
if (vli_cmp(v, u) < 0)
|
||||
vli_add(v, v, mod);
|
||||
|
||||
vli_sub(v, v, u);
|
||||
if (!EVEN(v))
|
||||
carry = vli_add(v, v, mod);
|
||||
|
||||
vli_rshift1(v);
|
||||
if (carry)
|
||||
v[NUM_ECC_DIGITS - 1] |= 0x8000000000000000ull;
|
||||
}
|
||||
}
|
||||
|
||||
vli_set(result, u);
|
||||
}
|
||||
|
||||
/* ------ Point operations ------ */
|
||||
|
||||
/* Returns true if p_point is the point at infinity, false otherwise. */
|
||||
static bool ecc_point_is_zero(const struct ecc_point *point)
|
||||
{
|
||||
return (vli_is_zero(point->x) && vli_is_zero(point->y));
|
||||
}
|
||||
|
||||
/* Point multiplication algorithm using Montgomery's ladder with co-Z
|
||||
* coordinates. From http://eprint.iacr.org/2011/338.pdf
|
||||
*/
|
||||
|
||||
/* Double in place */
|
||||
static void ecc_point_double_jacobian(u64 *x1, u64 *y1, u64 *z1)
|
||||
{
|
||||
/* t1 = x, t2 = y, t3 = z */
|
||||
u64 t4[NUM_ECC_DIGITS];
|
||||
u64 t5[NUM_ECC_DIGITS];
|
||||
|
||||
if (vli_is_zero(z1))
|
||||
return;
|
||||
|
||||
vli_mod_square_fast(t4, y1); /* t4 = y1^2 */
|
||||
vli_mod_mult_fast(t5, x1, t4); /* t5 = x1*y1^2 = A */
|
||||
vli_mod_square_fast(t4, t4); /* t4 = y1^4 */
|
||||
vli_mod_mult_fast(y1, y1, z1); /* t2 = y1*z1 = z3 */
|
||||
vli_mod_square_fast(z1, z1); /* t3 = z1^2 */
|
||||
|
||||
vli_mod_add(x1, x1, z1, curve_p); /* t1 = x1 + z1^2 */
|
||||
vli_mod_add(z1, z1, z1, curve_p); /* t3 = 2*z1^2 */
|
||||
vli_mod_sub(z1, x1, z1, curve_p); /* t3 = x1 - z1^2 */
|
||||
vli_mod_mult_fast(x1, x1, z1); /* t1 = x1^2 - z1^4 */
|
||||
|
||||
vli_mod_add(z1, x1, x1, curve_p); /* t3 = 2*(x1^2 - z1^4) */
|
||||
vli_mod_add(x1, x1, z1, curve_p); /* t1 = 3*(x1^2 - z1^4) */
|
||||
if (vli_test_bit(x1, 0)) {
|
||||
u64 carry = vli_add(x1, x1, curve_p);
|
||||
vli_rshift1(x1);
|
||||
x1[NUM_ECC_DIGITS - 1] |= carry << 63;
|
||||
} else {
|
||||
vli_rshift1(x1);
|
||||
}
|
||||
/* t1 = 3/2*(x1^2 - z1^4) = B */
|
||||
|
||||
vli_mod_square_fast(z1, x1); /* t3 = B^2 */
|
||||
vli_mod_sub(z1, z1, t5, curve_p); /* t3 = B^2 - A */
|
||||
vli_mod_sub(z1, z1, t5, curve_p); /* t3 = B^2 - 2A = x3 */
|
||||
vli_mod_sub(t5, t5, z1, curve_p); /* t5 = A - x3 */
|
||||
vli_mod_mult_fast(x1, x1, t5); /* t1 = B * (A - x3) */
|
||||
vli_mod_sub(t4, x1, t4, curve_p); /* t4 = B * (A - x3) - y1^4 = y3 */
|
||||
|
||||
vli_set(x1, z1);
|
||||
vli_set(z1, y1);
|
||||
vli_set(y1, t4);
|
||||
}
|
||||
|
||||
/* Modify (x1, y1) => (x1 * z^2, y1 * z^3) */
|
||||
static void apply_z(u64 *x1, u64 *y1, u64 *z)
|
||||
{
|
||||
u64 t1[NUM_ECC_DIGITS];
|
||||
|
||||
vli_mod_square_fast(t1, z); /* z^2 */
|
||||
vli_mod_mult_fast(x1, x1, t1); /* x1 * z^2 */
|
||||
vli_mod_mult_fast(t1, t1, z); /* z^3 */
|
||||
vli_mod_mult_fast(y1, y1, t1); /* y1 * z^3 */
|
||||
}
|
||||
|
||||
/* P = (x1, y1) => 2P, (x2, y2) => P' */
|
||||
static void xycz_initial_double(u64 *x1, u64 *y1, u64 *x2, u64 *y2,
|
||||
u64 *p_initial_z)
|
||||
{
|
||||
u64 z[NUM_ECC_DIGITS];
|
||||
|
||||
vli_set(x2, x1);
|
||||
vli_set(y2, y1);
|
||||
|
||||
vli_clear(z);
|
||||
z[0] = 1;
|
||||
|
||||
if (p_initial_z)
|
||||
vli_set(z, p_initial_z);
|
||||
|
||||
apply_z(x1, y1, z);
|
||||
|
||||
ecc_point_double_jacobian(x1, y1, z);
|
||||
|
||||
apply_z(x2, y2, z);
|
||||
}
|
||||
|
||||
/* Input P = (x1, y1, Z), Q = (x2, y2, Z)
|
||||
* Output P' = (x1', y1', Z3), P + Q = (x3, y3, Z3)
|
||||
* or P => P', Q => P + Q
|
||||
*/
|
||||
static void xycz_add(u64 *x1, u64 *y1, u64 *x2, u64 *y2)
|
||||
{
|
||||
/* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
|
||||
u64 t5[NUM_ECC_DIGITS];
|
||||
|
||||
vli_mod_sub(t5, x2, x1, curve_p); /* t5 = x2 - x1 */
|
||||
vli_mod_square_fast(t5, t5); /* t5 = (x2 - x1)^2 = A */
|
||||
vli_mod_mult_fast(x1, x1, t5); /* t1 = x1*A = B */
|
||||
vli_mod_mult_fast(x2, x2, t5); /* t3 = x2*A = C */
|
||||
vli_mod_sub(y2, y2, y1, curve_p); /* t4 = y2 - y1 */
|
||||
vli_mod_square_fast(t5, y2); /* t5 = (y2 - y1)^2 = D */
|
||||
|
||||
vli_mod_sub(t5, t5, x1, curve_p); /* t5 = D - B */
|
||||
vli_mod_sub(t5, t5, x2, curve_p); /* t5 = D - B - C = x3 */
|
||||
vli_mod_sub(x2, x2, x1, curve_p); /* t3 = C - B */
|
||||
vli_mod_mult_fast(y1, y1, x2); /* t2 = y1*(C - B) */
|
||||
vli_mod_sub(x2, x1, t5, curve_p); /* t3 = B - x3 */
|
||||
vli_mod_mult_fast(y2, y2, x2); /* t4 = (y2 - y1)*(B - x3) */
|
||||
vli_mod_sub(y2, y2, y1, curve_p); /* t4 = y3 */
|
||||
|
||||
vli_set(x2, t5);
|
||||
}
|
||||
|
||||
/* Input P = (x1, y1, Z), Q = (x2, y2, Z)
|
||||
* Output P + Q = (x3, y3, Z3), P - Q = (x3', y3', Z3)
|
||||
* or P => P - Q, Q => P + Q
|
||||
*/
|
||||
static void xycz_add_c(u64 *x1, u64 *y1, u64 *x2, u64 *y2)
|
||||
{
|
||||
/* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
|
||||
u64 t5[NUM_ECC_DIGITS];
|
||||
u64 t6[NUM_ECC_DIGITS];
|
||||
u64 t7[NUM_ECC_DIGITS];
|
||||
|
||||
vli_mod_sub(t5, x2, x1, curve_p); /* t5 = x2 - x1 */
|
||||
vli_mod_square_fast(t5, t5); /* t5 = (x2 - x1)^2 = A */
|
||||
vli_mod_mult_fast(x1, x1, t5); /* t1 = x1*A = B */
|
||||
vli_mod_mult_fast(x2, x2, t5); /* t3 = x2*A = C */
|
||||
vli_mod_add(t5, y2, y1, curve_p); /* t4 = y2 + y1 */
|
||||
vli_mod_sub(y2, y2, y1, curve_p); /* t4 = y2 - y1 */
|
||||
|
||||
vli_mod_sub(t6, x2, x1, curve_p); /* t6 = C - B */
|
||||
vli_mod_mult_fast(y1, y1, t6); /* t2 = y1 * (C - B) */
|
||||
vli_mod_add(t6, x1, x2, curve_p); /* t6 = B + C */
|
||||
vli_mod_square_fast(x2, y2); /* t3 = (y2 - y1)^2 */
|
||||
vli_mod_sub(x2, x2, t6, curve_p); /* t3 = x3 */
|
||||
|
||||
vli_mod_sub(t7, x1, x2, curve_p); /* t7 = B - x3 */
|
||||
vli_mod_mult_fast(y2, y2, t7); /* t4 = (y2 - y1)*(B - x3) */
|
||||
vli_mod_sub(y2, y2, y1, curve_p); /* t4 = y3 */
|
||||
|
||||
vli_mod_square_fast(t7, t5); /* t7 = (y2 + y1)^2 = F */
|
||||
vli_mod_sub(t7, t7, t6, curve_p); /* t7 = x3' */
|
||||
vli_mod_sub(t6, t7, x1, curve_p); /* t6 = x3' - B */
|
||||
vli_mod_mult_fast(t6, t6, t5); /* t6 = (y2 + y1)*(x3' - B) */
|
||||
vli_mod_sub(y1, t6, y1, curve_p); /* t2 = y3' */
|
||||
|
||||
vli_set(x1, t7);
|
||||
}
|
||||
|
||||
static void ecc_point_mult(struct ecc_point *result,
|
||||
const struct ecc_point *point, u64 *scalar,
|
||||
u64 *initial_z, int num_bits)
|
||||
{
|
||||
/* R0 and R1 */
|
||||
u64 rx[2][NUM_ECC_DIGITS];
|
||||
u64 ry[2][NUM_ECC_DIGITS];
|
||||
u64 z[NUM_ECC_DIGITS];
|
||||
int i, nb;
|
||||
|
||||
vli_set(rx[1], point->x);
|
||||
vli_set(ry[1], point->y);
|
||||
|
||||
xycz_initial_double(rx[1], ry[1], rx[0], ry[0], initial_z);
|
||||
|
||||
for (i = num_bits - 2; i > 0; i--) {
|
||||
nb = !vli_test_bit(scalar, i);
|
||||
xycz_add_c(rx[1 - nb], ry[1 - nb], rx[nb], ry[nb]);
|
||||
xycz_add(rx[nb], ry[nb], rx[1 - nb], ry[1 - nb]);
|
||||
}
|
||||
|
||||
nb = !vli_test_bit(scalar, 0);
|
||||
xycz_add_c(rx[1 - nb], ry[1 - nb], rx[nb], ry[nb]);
|
||||
|
||||
/* Find final 1/Z value. */
|
||||
vli_mod_sub(z, rx[1], rx[0], curve_p); /* X1 - X0 */
|
||||
vli_mod_mult_fast(z, z, ry[1 - nb]); /* Yb * (X1 - X0) */
|
||||
vli_mod_mult_fast(z, z, point->x); /* xP * Yb * (X1 - X0) */
|
||||
vli_mod_inv(z, z, curve_p); /* 1 / (xP * Yb * (X1 - X0)) */
|
||||
vli_mod_mult_fast(z, z, point->y); /* yP / (xP * Yb * (X1 - X0)) */
|
||||
vli_mod_mult_fast(z, z, rx[1 - nb]); /* Xb * yP / (xP * Yb * (X1 - X0)) */
|
||||
/* End 1/Z calculation */
|
||||
|
||||
xycz_add(rx[nb], ry[nb], rx[1 - nb], ry[1 - nb]);
|
||||
|
||||
apply_z(rx[0], ry[0], z);
|
||||
|
||||
vli_set(result->x, rx[0]);
|
||||
vli_set(result->y, ry[0]);
|
||||
}
|
||||
|
||||
static void ecc_bytes2native(const u8 bytes[ECC_BYTES],
|
||||
u64 native[NUM_ECC_DIGITS])
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_ECC_DIGITS; i++) {
|
||||
const u8 *digit = bytes + 8 * (NUM_ECC_DIGITS - 1 - i);
|
||||
|
||||
native[NUM_ECC_DIGITS - 1 - i] =
|
||||
((u64) digit[0] << 0) |
|
||||
((u64) digit[1] << 8) |
|
||||
((u64) digit[2] << 16) |
|
||||
((u64) digit[3] << 24) |
|
||||
((u64) digit[4] << 32) |
|
||||
((u64) digit[5] << 40) |
|
||||
((u64) digit[6] << 48) |
|
||||
((u64) digit[7] << 56);
|
||||
}
|
||||
}
|
||||
|
||||
static void ecc_native2bytes(const u64 native[NUM_ECC_DIGITS],
|
||||
u8 bytes[ECC_BYTES])
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_ECC_DIGITS; i++) {
|
||||
u8 *digit = bytes + 8 * (NUM_ECC_DIGITS - 1 - i);
|
||||
|
||||
digit[0] = native[NUM_ECC_DIGITS - 1 - i] >> 0;
|
||||
digit[1] = native[NUM_ECC_DIGITS - 1 - i] >> 8;
|
||||
digit[2] = native[NUM_ECC_DIGITS - 1 - i] >> 16;
|
||||
digit[3] = native[NUM_ECC_DIGITS - 1 - i] >> 24;
|
||||
digit[4] = native[NUM_ECC_DIGITS - 1 - i] >> 32;
|
||||
digit[5] = native[NUM_ECC_DIGITS - 1 - i] >> 40;
|
||||
digit[6] = native[NUM_ECC_DIGITS - 1 - i] >> 48;
|
||||
digit[7] = native[NUM_ECC_DIGITS - 1 - i] >> 56;
|
||||
}
|
||||
}
|
||||
|
||||
bool ecc_make_key(u8 public_key[64], u8 private_key[32])
|
||||
{
|
||||
struct ecc_point pk;
|
||||
u64 priv[NUM_ECC_DIGITS];
|
||||
unsigned int tries = 0;
|
||||
|
||||
do {
|
||||
if (tries++ >= MAX_TRIES)
|
||||
return false;
|
||||
|
||||
get_random_bytes(priv, ECC_BYTES);
|
||||
|
||||
if (vli_is_zero(priv))
|
||||
continue;
|
||||
|
||||
/* Make sure the private key is in the range [1, n-1]. */
|
||||
if (vli_cmp(curve_n, priv) != 1)
|
||||
continue;
|
||||
|
||||
ecc_point_mult(&pk, &curve_g, priv, NULL, vli_num_bits(priv));
|
||||
} while (ecc_point_is_zero(&pk));
|
||||
|
||||
ecc_native2bytes(priv, private_key);
|
||||
ecc_native2bytes(pk.x, public_key);
|
||||
ecc_native2bytes(pk.y, &public_key[32]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ecdh_shared_secret(const u8 public_key[64], const u8 private_key[32],
|
||||
u8 secret[32])
|
||||
{
|
||||
u64 priv[NUM_ECC_DIGITS];
|
||||
u64 rand[NUM_ECC_DIGITS];
|
||||
struct ecc_point product, pk;
|
||||
|
||||
get_random_bytes(rand, ECC_BYTES);
|
||||
|
||||
ecc_bytes2native(public_key, pk.x);
|
||||
ecc_bytes2native(&public_key[32], pk.y);
|
||||
ecc_bytes2native(private_key, priv);
|
||||
|
||||
ecc_point_mult(&product, &pk, priv, rand, vli_num_bits(priv));
|
||||
|
||||
ecc_native2bytes(product.x, secret);
|
||||
|
||||
return !ecc_point_is_zero(&product);
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright (c) 2013, Kenneth MacKay
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* Create a public/private key pair.
|
||||
* Outputs:
|
||||
* public_key - Will be filled in with the public key.
|
||||
* private_key - Will be filled in with the private key.
|
||||
*
|
||||
* Returns true if the key pair was generated successfully, false
|
||||
* if an error occurred. The keys are with the LSB first.
|
||||
*/
|
||||
bool ecc_make_key(u8 public_key[64], u8 private_key[32]);
|
||||
|
||||
/* Compute a shared secret given your secret key and someone else's
|
||||
* public key.
|
||||
* Note: It is recommended that you hash the result of ecdh_shared_secret
|
||||
* before using it for symmetric encryption or HMAC.
|
||||
*
|
||||
* Inputs:
|
||||
* public_key - The public key of the remote party
|
||||
* private_key - Your private key.
|
||||
*
|
||||
* Outputs:
|
||||
* secret - Will be filled in with the shared secret value.
|
||||
*
|
||||
* Returns true if the shared secret was generated successfully, false
|
||||
* if an error occurred. Both input and output parameters are with the
|
||||
* LSB first.
|
||||
*/
|
||||
bool ecdh_shared_secret(const u8 public_key[64], const u8 private_key[32],
|
||||
u8 secret[32]);
|
|
@ -449,6 +449,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,
|
|||
conn->io_capability = hdev->io_capability;
|
||||
conn->remote_auth = 0xff;
|
||||
conn->key_type = 0xff;
|
||||
conn->rssi = HCI_RSSI_INVALID;
|
||||
conn->tx_power = HCI_TX_POWER_INVALID;
|
||||
conn->max_tx_power = HCI_TX_POWER_INVALID;
|
||||
|
||||
|
|
|
@ -406,6 +406,49 @@ static const struct file_operations force_sc_support_fops = {
|
|||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static ssize_t force_lesc_support_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct hci_dev *hdev = file->private_data;
|
||||
char buf[3];
|
||||
|
||||
buf[0] = test_bit(HCI_FORCE_LESC, &hdev->dbg_flags) ? 'Y': 'N';
|
||||
buf[1] = '\n';
|
||||
buf[2] = '\0';
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
|
||||
}
|
||||
|
||||
static ssize_t force_lesc_support_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct hci_dev *hdev = file->private_data;
|
||||
char buf[32];
|
||||
size_t buf_size = min(count, (sizeof(buf)-1));
|
||||
bool enable;
|
||||
|
||||
if (copy_from_user(buf, user_buf, buf_size))
|
||||
return -EFAULT;
|
||||
|
||||
buf[buf_size] = '\0';
|
||||
if (strtobool(buf, &enable))
|
||||
return -EINVAL;
|
||||
|
||||
if (enable == test_bit(HCI_FORCE_LESC, &hdev->dbg_flags))
|
||||
return -EALREADY;
|
||||
|
||||
change_bit(HCI_FORCE_LESC, &hdev->dbg_flags);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations force_lesc_support_fops = {
|
||||
.open = simple_open,
|
||||
.read = force_lesc_support_read,
|
||||
.write = force_lesc_support_write,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static ssize_t sc_only_mode_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
|
@ -1692,6 +1735,28 @@ static void hci_init3_req(struct hci_request *req, unsigned long opt)
|
|||
* Parameter Request
|
||||
*/
|
||||
|
||||
/* If the controller supports Extended Scanner Filter
|
||||
* Policies, enable the correspondig event.
|
||||
*/
|
||||
if (hdev->le_features[0] & HCI_LE_EXT_SCAN_POLICY)
|
||||
events[1] |= 0x04; /* LE Direct Advertising
|
||||
* Report
|
||||
*/
|
||||
|
||||
/* If the controller supports the LE Read Local P-256
|
||||
* Public Key command, enable the corresponding event.
|
||||
*/
|
||||
if (hdev->commands[34] & 0x02)
|
||||
events[0] |= 0x80; /* LE Read Local P-256
|
||||
* Public Key Complete
|
||||
*/
|
||||
|
||||
/* If the controller supports the LE Generate DHKey
|
||||
* command, enable the corresponding event.
|
||||
*/
|
||||
if (hdev->commands[34] & 0x04)
|
||||
events[1] |= 0x01; /* LE Generate DHKey Complete */
|
||||
|
||||
hci_req_add(req, HCI_OP_LE_SET_EVENT_MASK, sizeof(events),
|
||||
events);
|
||||
|
||||
|
@ -1734,9 +1799,7 @@ static void hci_init4_req(struct hci_request *req, unsigned long opt)
|
|||
hci_req_add(req, HCI_OP_READ_SYNC_TRAIN_PARAMS, 0, NULL);
|
||||
|
||||
/* Enable Secure Connections if supported and configured */
|
||||
if ((lmp_sc_capable(hdev) ||
|
||||
test_bit(HCI_FORCE_SC, &hdev->dbg_flags)) &&
|
||||
test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) {
|
||||
if (bredr_sc_enabled(hdev)) {
|
||||
u8 support = 0x01;
|
||||
hci_req_add(req, HCI_OP_WRITE_SC_SUPPORT,
|
||||
sizeof(support), &support);
|
||||
|
@ -1819,6 +1882,10 @@ static int __hci_init(struct hci_dev *hdev)
|
|||
hdev, &force_sc_support_fops);
|
||||
debugfs_create_file("sc_only_mode", 0444, hdev->debugfs,
|
||||
hdev, &sc_only_mode_fops);
|
||||
if (lmp_le_capable(hdev))
|
||||
debugfs_create_file("force_lesc_support", 0644,
|
||||
hdev->debugfs, hdev,
|
||||
&force_lesc_support_fops);
|
||||
}
|
||||
|
||||
if (lmp_sniff_capable(hdev)) {
|
||||
|
@ -2115,7 +2182,7 @@ u32 hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data,
|
|||
|
||||
BT_DBG("cache %p, %pMR", cache, &data->bdaddr);
|
||||
|
||||
hci_remove_remote_oob_data(hdev, &data->bdaddr);
|
||||
hci_remove_remote_oob_data(hdev, &data->bdaddr, BDADDR_BREDR);
|
||||
|
||||
if (!data->ssp_mode)
|
||||
flags |= MGMT_DEV_FOUND_LEGACY_PAIRING;
|
||||
|
@ -3162,6 +3229,10 @@ static bool hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn,
|
|||
if (!conn)
|
||||
return true;
|
||||
|
||||
/* BR/EDR key derived using SC from an LE link */
|
||||
if (conn->type == LE_LINK)
|
||||
return true;
|
||||
|
||||
/* Neither local nor remote side had no-bonding as requirement */
|
||||
if (conn->auth_type > 0x01 && conn->remote_auth > 0x01)
|
||||
return true;
|
||||
|
@ -3187,37 +3258,17 @@ static u8 ltk_role(u8 type)
|
|||
return HCI_ROLE_SLAVE;
|
||||
}
|
||||
|
||||
struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, __le64 rand,
|
||||
u8 role)
|
||||
struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
u8 addr_type, u8 role)
|
||||
{
|
||||
struct smp_ltk *k;
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(k, &hdev->long_term_keys, list) {
|
||||
if (k->ediv != ediv || k->rand != rand)
|
||||
if (addr_type != k->bdaddr_type || bacmp(bdaddr, &k->bdaddr))
|
||||
continue;
|
||||
|
||||
if (ltk_role(k->type) != role)
|
||||
continue;
|
||||
|
||||
rcu_read_unlock();
|
||||
return k;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
u8 addr_type, u8 role)
|
||||
{
|
||||
struct smp_ltk *k;
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(k, &hdev->long_term_keys, list) {
|
||||
if (addr_type == k->bdaddr_type &&
|
||||
bacmp(bdaddr, &k->bdaddr) == 0 &&
|
||||
ltk_role(k->type) == role) {
|
||||
if (smp_ltk_is_sc(k) || ltk_role(k->type) == role) {
|
||||
rcu_read_unlock();
|
||||
return k;
|
||||
}
|
||||
|
@ -3327,7 +3378,7 @@ struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
|||
struct smp_ltk *key, *old_key;
|
||||
u8 role = ltk_role(type);
|
||||
|
||||
old_key = hci_find_ltk_by_addr(hdev, bdaddr, addr_type, role);
|
||||
old_key = hci_find_ltk(hdev, bdaddr, addr_type, role);
|
||||
if (old_key)
|
||||
key = old_key;
|
||||
else {
|
||||
|
@ -3442,26 +3493,31 @@ static void hci_cmd_timeout(struct work_struct *work)
|
|||
}
|
||||
|
||||
struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev,
|
||||
bdaddr_t *bdaddr)
|
||||
bdaddr_t *bdaddr, u8 bdaddr_type)
|
||||
{
|
||||
struct oob_data *data;
|
||||
|
||||
list_for_each_entry(data, &hdev->remote_oob_data, list)
|
||||
if (bacmp(bdaddr, &data->bdaddr) == 0)
|
||||
return data;
|
||||
list_for_each_entry(data, &hdev->remote_oob_data, list) {
|
||||
if (bacmp(bdaddr, &data->bdaddr) != 0)
|
||||
continue;
|
||||
if (data->bdaddr_type != bdaddr_type)
|
||||
continue;
|
||||
return data;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr)
|
||||
int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
u8 bdaddr_type)
|
||||
{
|
||||
struct oob_data *data;
|
||||
|
||||
data = hci_find_remote_oob_data(hdev, bdaddr);
|
||||
data = hci_find_remote_oob_data(hdev, bdaddr, bdaddr_type);
|
||||
if (!data)
|
||||
return -ENOENT;
|
||||
|
||||
BT_DBG("%s removing %pMR", hdev->name, bdaddr);
|
||||
BT_DBG("%s removing %pMR (%u)", hdev->name, bdaddr, bdaddr_type);
|
||||
|
||||
list_del(&data->list);
|
||||
kfree(data);
|
||||
|
@ -3480,52 +3536,37 @@ void hci_remote_oob_data_clear(struct hci_dev *hdev)
|
|||
}
|
||||
|
||||
int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
u8 *hash, u8 *rand)
|
||||
u8 bdaddr_type, u8 *hash192, u8 *rand192,
|
||||
u8 *hash256, u8 *rand256)
|
||||
{
|
||||
struct oob_data *data;
|
||||
|
||||
data = hci_find_remote_oob_data(hdev, bdaddr);
|
||||
data = hci_find_remote_oob_data(hdev, bdaddr, bdaddr_type);
|
||||
if (!data) {
|
||||
data = kmalloc(sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
bacpy(&data->bdaddr, bdaddr);
|
||||
data->bdaddr_type = bdaddr_type;
|
||||
list_add(&data->list, &hdev->remote_oob_data);
|
||||
}
|
||||
|
||||
memcpy(data->hash192, hash, sizeof(data->hash192));
|
||||
memcpy(data->rand192, rand, sizeof(data->rand192));
|
||||
|
||||
memset(data->hash256, 0, sizeof(data->hash256));
|
||||
memset(data->rand256, 0, sizeof(data->rand256));
|
||||
|
||||
BT_DBG("%s for %pMR", hdev->name, bdaddr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hci_add_remote_oob_ext_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
u8 *hash192, u8 *rand192,
|
||||
u8 *hash256, u8 *rand256)
|
||||
{
|
||||
struct oob_data *data;
|
||||
|
||||
data = hci_find_remote_oob_data(hdev, bdaddr);
|
||||
if (!data) {
|
||||
data = kmalloc(sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
bacpy(&data->bdaddr, bdaddr);
|
||||
list_add(&data->list, &hdev->remote_oob_data);
|
||||
if (hash192 && rand192) {
|
||||
memcpy(data->hash192, hash192, sizeof(data->hash192));
|
||||
memcpy(data->rand192, rand192, sizeof(data->rand192));
|
||||
} else {
|
||||
memset(data->hash192, 0, sizeof(data->hash192));
|
||||
memset(data->rand192, 0, sizeof(data->rand192));
|
||||
}
|
||||
|
||||
memcpy(data->hash192, hash192, sizeof(data->hash192));
|
||||
memcpy(data->rand192, rand192, sizeof(data->rand192));
|
||||
|
||||
memcpy(data->hash256, hash256, sizeof(data->hash256));
|
||||
memcpy(data->rand256, rand256, sizeof(data->rand256));
|
||||
if (hash256 && rand256) {
|
||||
memcpy(data->hash256, hash256, sizeof(data->hash256));
|
||||
memcpy(data->rand256, rand256, sizeof(data->rand256));
|
||||
} else {
|
||||
memset(data->hash256, 0, sizeof(data->hash256));
|
||||
memset(data->rand256, 0, sizeof(data->rand256));
|
||||
}
|
||||
|
||||
BT_DBG("%s for %pMR", hdev->name, bdaddr);
|
||||
|
||||
|
@ -4225,6 +4266,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
|
|||
hci_remote_oob_data_clear(hdev);
|
||||
hci_bdaddr_list_clear(&hdev->le_white_list);
|
||||
hci_conn_params_clear_all(hdev);
|
||||
hci_discovery_filter_clear(hdev);
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
hci_dev_put(hdev);
|
||||
|
@ -5597,6 +5639,19 @@ void hci_req_add_le_passive_scan(struct hci_request *req)
|
|||
*/
|
||||
filter_policy = update_white_list(req);
|
||||
|
||||
/* When the controller is using random resolvable addresses and
|
||||
* with that having LE privacy enabled, then controllers with
|
||||
* Extended Scanner Filter Policies support can now enable support
|
||||
* for handling directed advertising.
|
||||
*
|
||||
* So instead of using filter polices 0x00 (no whitelist)
|
||||
* and 0x01 (whitelist enabled) use the new filter policies
|
||||
* 0x02 (no whitelist) and 0x03 (whitelist enabled).
|
||||
*/
|
||||
if (test_bit(HCI_PRIVACY, &hdev->dev_flags) &&
|
||||
(hdev->le_features[0] & HCI_LE_EXT_SCAN_POLICY))
|
||||
filter_policy |= 0x02;
|
||||
|
||||
memset(¶m_cp, 0, sizeof(param_cp));
|
||||
param_cp.type = LE_SCAN_PASSIVE;
|
||||
param_cp.interval = cpu_to_le16(hdev->le_scan_interval);
|
||||
|
@ -5648,6 +5703,15 @@ void hci_update_background_scan(struct hci_dev *hdev)
|
|||
if (hdev->discovery.state != DISCOVERY_STOPPED)
|
||||
return;
|
||||
|
||||
/* Reset RSSI and UUID filters when starting background scanning
|
||||
* since these filters are meant for service discovery only.
|
||||
*
|
||||
* The Start Discovery and Start Service Discovery operations
|
||||
* ensure to set proper values for RSSI threshold and UUID
|
||||
* filter list. So it is safe to just reset them here.
|
||||
*/
|
||||
hci_discovery_filter_clear(hdev);
|
||||
|
||||
hci_req_init(&req, hdev);
|
||||
|
||||
if (list_empty(&hdev->pend_le_conns) &&
|
||||
|
|
|
@ -2043,13 +2043,14 @@ static void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
data.pscan_mode = info->pscan_mode;
|
||||
memcpy(data.dev_class, info->dev_class, 3);
|
||||
data.clock_offset = info->clock_offset;
|
||||
data.rssi = 0x00;
|
||||
data.rssi = HCI_RSSI_INVALID;
|
||||
data.ssp_mode = 0x00;
|
||||
|
||||
flags = hci_inquiry_cache_update(hdev, &data, false);
|
||||
|
||||
mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
|
||||
info->dev_class, 0, flags, NULL, 0, NULL, 0);
|
||||
info->dev_class, HCI_RSSI_INVALID,
|
||||
flags, NULL, 0, NULL, 0);
|
||||
}
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
|
@ -3249,6 +3250,8 @@ static void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
|
||||
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
|
||||
if (conn) {
|
||||
clear_bit(HCI_CONN_NEW_LINK_KEY, &conn->flags);
|
||||
|
||||
if ((key->type == HCI_LK_UNAUTH_COMBINATION_P192 ||
|
||||
key->type == HCI_LK_UNAUTH_COMBINATION_P256) &&
|
||||
conn->auth_type != 0xff && (conn->auth_type & 0x01)) {
|
||||
|
@ -3294,12 +3297,15 @@ static void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
hci_dev_lock(hdev);
|
||||
|
||||
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
|
||||
if (conn) {
|
||||
hci_conn_hold(conn);
|
||||
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
|
||||
hci_conn_drop(conn);
|
||||
conn_set_key(conn, ev->key_type, conn->pin_length);
|
||||
}
|
||||
if (!conn)
|
||||
goto unlock;
|
||||
|
||||
hci_conn_hold(conn);
|
||||
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
|
||||
hci_conn_drop(conn);
|
||||
|
||||
set_bit(HCI_CONN_NEW_LINK_KEY, &conn->flags);
|
||||
conn_set_key(conn, ev->key_type, conn->pin_length);
|
||||
|
||||
if (!test_bit(HCI_MGMT, &hdev->dev_flags))
|
||||
goto unlock;
|
||||
|
@ -3326,13 +3332,14 @@ static void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
!test_bit(HCI_KEEP_DEBUG_KEYS, &hdev->dev_flags)) {
|
||||
list_del_rcu(&key->list);
|
||||
kfree_rcu(key, rcu);
|
||||
} else if (conn) {
|
||||
if (persistent)
|
||||
clear_bit(HCI_CONN_FLUSH_KEY, &conn->flags);
|
||||
else
|
||||
set_bit(HCI_CONN_FLUSH_KEY, &conn->flags);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (persistent)
|
||||
clear_bit(HCI_CONN_FLUSH_KEY, &conn->flags);
|
||||
else
|
||||
set_bit(HCI_CONN_FLUSH_KEY, &conn->flags);
|
||||
|
||||
unlock:
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
@ -3767,7 +3774,7 @@ static void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
|
||||
cp.authentication = conn->auth_type;
|
||||
|
||||
if (hci_find_remote_oob_data(hdev, &conn->dst) &&
|
||||
if (hci_find_remote_oob_data(hdev, &conn->dst, BDADDR_BREDR) &&
|
||||
(conn->out || test_bit(HCI_CONN_REMOTE_OOB, &conn->flags)))
|
||||
cp.oob_data = 0x01;
|
||||
else
|
||||
|
@ -4022,9 +4029,9 @@ static void hci_remote_oob_data_request_evt(struct hci_dev *hdev,
|
|||
if (!test_bit(HCI_MGMT, &hdev->dev_flags))
|
||||
goto unlock;
|
||||
|
||||
data = hci_find_remote_oob_data(hdev, &ev->bdaddr);
|
||||
data = hci_find_remote_oob_data(hdev, &ev->bdaddr, BDADDR_BREDR);
|
||||
if (data) {
|
||||
if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) {
|
||||
if (bredr_sc_enabled(hdev)) {
|
||||
struct hci_cp_remote_oob_ext_data_reply cp;
|
||||
|
||||
bacpy(&cp.bdaddr, &ev->bdaddr);
|
||||
|
@ -4419,7 +4426,8 @@ static struct hci_conn *check_pending_le_conn(struct hci_dev *hdev,
|
|||
}
|
||||
|
||||
static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
|
||||
u8 bdaddr_type, s8 rssi, u8 *data, u8 len)
|
||||
u8 bdaddr_type, bdaddr_t *direct_addr,
|
||||
u8 direct_addr_type, s8 rssi, u8 *data, u8 len)
|
||||
{
|
||||
struct discovery_state *d = &hdev->discovery;
|
||||
struct smp_irk *irk;
|
||||
|
@ -4427,6 +4435,32 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
|
|||
bool match;
|
||||
u32 flags;
|
||||
|
||||
/* If the direct address is present, then this report is from
|
||||
* a LE Direct Advertising Report event. In that case it is
|
||||
* important to see if the address is matching the local
|
||||
* controller address.
|
||||
*/
|
||||
if (direct_addr) {
|
||||
/* Only resolvable random addresses are valid for these
|
||||
* kind of reports and others can be ignored.
|
||||
*/
|
||||
if (!hci_bdaddr_is_rpa(direct_addr, direct_addr_type))
|
||||
return;
|
||||
|
||||
/* If the controller is not using resolvable random
|
||||
* addresses, then this report can be ignored.
|
||||
*/
|
||||
if (!test_bit(HCI_PRIVACY, &hdev->dev_flags))
|
||||
return;
|
||||
|
||||
/* If the local IRK of the controller does not match
|
||||
* with the resolvable random address provided, then
|
||||
* this report can be ignored.
|
||||
*/
|
||||
if (!smp_irk_matches(hdev, hdev->irk, direct_addr))
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if we need to convert to identity address */
|
||||
irk = hci_get_irk(hdev, bdaddr, bdaddr_type);
|
||||
if (irk) {
|
||||
|
@ -4563,7 +4597,8 @@ static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
|
||||
rssi = ev->data[ev->length];
|
||||
process_adv_report(hdev, ev->evt_type, &ev->bdaddr,
|
||||
ev->bdaddr_type, rssi, ev->data, ev->length);
|
||||
ev->bdaddr_type, NULL, 0, rssi,
|
||||
ev->data, ev->length);
|
||||
|
||||
ptr += sizeof(*ev) + ev->length + 1;
|
||||
}
|
||||
|
@ -4587,10 +4622,20 @@ static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
if (conn == NULL)
|
||||
goto not_found;
|
||||
|
||||
ltk = hci_find_ltk(hdev, ev->ediv, ev->rand, conn->role);
|
||||
if (ltk == NULL)
|
||||
ltk = hci_find_ltk(hdev, &conn->dst, conn->dst_type, conn->role);
|
||||
if (!ltk)
|
||||
goto not_found;
|
||||
|
||||
if (smp_ltk_is_sc(ltk)) {
|
||||
/* With SC both EDiv and Rand are set to zero */
|
||||
if (ev->ediv || ev->rand)
|
||||
goto not_found;
|
||||
} else {
|
||||
/* For non-SC keys check that EDiv and Rand match */
|
||||
if (ev->ediv != ltk->ediv || ev->rand != ltk->rand)
|
||||
goto not_found;
|
||||
}
|
||||
|
||||
memcpy(cp.ltk, ltk->val, sizeof(ltk->val));
|
||||
cp.handle = cpu_to_le16(conn->handle);
|
||||
|
||||
|
@ -4694,6 +4739,27 @@ static void hci_le_remote_conn_param_req_evt(struct hci_dev *hdev,
|
|||
hci_send_cmd(hdev, HCI_OP_LE_CONN_PARAM_REQ_REPLY, sizeof(cp), &cp);
|
||||
}
|
||||
|
||||
static void hci_le_direct_adv_report_evt(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
u8 num_reports = skb->data[0];
|
||||
void *ptr = &skb->data[1];
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
while (num_reports--) {
|
||||
struct hci_ev_le_direct_adv_info *ev = ptr;
|
||||
|
||||
process_adv_report(hdev, ev->evt_type, &ev->bdaddr,
|
||||
ev->bdaddr_type, &ev->direct_addr,
|
||||
ev->direct_addr_type, ev->rssi, NULL, 0);
|
||||
|
||||
ptr += sizeof(*ev);
|
||||
}
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_le_meta *le_ev = (void *) skb->data;
|
||||
|
@ -4721,6 +4787,10 @@ static void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
hci_le_remote_conn_param_req_evt(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_EV_LE_DIRECT_ADV_REPORT:
|
||||
hci_le_direct_adv_report_evt(hdev, skb);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -46,7 +46,6 @@
|
|||
bool disable_ertm;
|
||||
|
||||
static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN | L2CAP_FEAT_UCD;
|
||||
static u8 l2cap_fixed_chan[8] = { L2CAP_FC_SIG_BREDR | L2CAP_FC_CONNLESS, };
|
||||
|
||||
static LIST_HEAD(chan_list);
|
||||
static DEFINE_RWLOCK(chan_list_lock);
|
||||
|
@ -1120,10 +1119,10 @@ static bool __amp_capable(struct l2cap_chan *chan)
|
|||
struct hci_dev *hdev;
|
||||
bool amp_available = false;
|
||||
|
||||
if (!conn->hs_enabled)
|
||||
if (!(conn->local_fixed_chan & L2CAP_FC_A2MP))
|
||||
return false;
|
||||
|
||||
if (!(conn->fixed_chan_mask & L2CAP_FC_A2MP))
|
||||
if (!(conn->remote_fixed_chan & L2CAP_FC_A2MP))
|
||||
return false;
|
||||
|
||||
read_lock(&hci_dev_list_lock);
|
||||
|
@ -3096,12 +3095,14 @@ static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
|
|||
|
||||
static inline bool __l2cap_ews_supported(struct l2cap_conn *conn)
|
||||
{
|
||||
return conn->hs_enabled && conn->feat_mask & L2CAP_FEAT_EXT_WINDOW;
|
||||
return ((conn->local_fixed_chan & L2CAP_FC_A2MP) &&
|
||||
(conn->feat_mask & L2CAP_FEAT_EXT_WINDOW));
|
||||
}
|
||||
|
||||
static inline bool __l2cap_efs_supported(struct l2cap_conn *conn)
|
||||
{
|
||||
return conn->hs_enabled && conn->feat_mask & L2CAP_FEAT_EXT_FLOW;
|
||||
return ((conn->local_fixed_chan & L2CAP_FC_A2MP) &&
|
||||
(conn->feat_mask & L2CAP_FEAT_EXT_FLOW));
|
||||
}
|
||||
|
||||
static void __l2cap_set_ertm_timeouts(struct l2cap_chan *chan,
|
||||
|
@ -3330,7 +3331,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
|
|||
break;
|
||||
|
||||
case L2CAP_CONF_EWS:
|
||||
if (!chan->conn->hs_enabled)
|
||||
if (!(chan->conn->local_fixed_chan & L2CAP_FC_A2MP))
|
||||
return -ECONNREFUSED;
|
||||
|
||||
set_bit(FLAG_EXT_CTRL, &chan->flags);
|
||||
|
@ -4334,7 +4335,7 @@ static inline int l2cap_information_req(struct l2cap_conn *conn,
|
|||
if (!disable_ertm)
|
||||
feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
|
||||
| L2CAP_FEAT_FCS;
|
||||
if (conn->hs_enabled)
|
||||
if (conn->local_fixed_chan & L2CAP_FC_A2MP)
|
||||
feat_mask |= L2CAP_FEAT_EXT_FLOW
|
||||
| L2CAP_FEAT_EXT_WINDOW;
|
||||
|
||||
|
@ -4345,14 +4346,10 @@ static inline int l2cap_information_req(struct l2cap_conn *conn,
|
|||
u8 buf[12];
|
||||
struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
|
||||
|
||||
if (conn->hs_enabled)
|
||||
l2cap_fixed_chan[0] |= L2CAP_FC_A2MP;
|
||||
else
|
||||
l2cap_fixed_chan[0] &= ~L2CAP_FC_A2MP;
|
||||
|
||||
rsp->type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
|
||||
rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
|
||||
memcpy(rsp->data, l2cap_fixed_chan, sizeof(l2cap_fixed_chan));
|
||||
rsp->data[0] = conn->local_fixed_chan;
|
||||
memset(rsp->data + 1, 0, 7);
|
||||
l2cap_send_cmd(conn, cmd->ident, L2CAP_INFO_RSP, sizeof(buf),
|
||||
buf);
|
||||
} else {
|
||||
|
@ -4418,7 +4415,7 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn,
|
|||
break;
|
||||
|
||||
case L2CAP_IT_FIXED_CHAN:
|
||||
conn->fixed_chan_mask = rsp->data[0];
|
||||
conn->remote_fixed_chan = rsp->data[0];
|
||||
conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
|
||||
conn->info_ident = 0;
|
||||
|
||||
|
@ -4442,7 +4439,7 @@ static int l2cap_create_channel_req(struct l2cap_conn *conn,
|
|||
if (cmd_len != sizeof(*req))
|
||||
return -EPROTO;
|
||||
|
||||
if (!conn->hs_enabled)
|
||||
if (!(conn->local_fixed_chan & L2CAP_FC_A2MP))
|
||||
return -EINVAL;
|
||||
|
||||
psm = le16_to_cpu(req->psm);
|
||||
|
@ -4872,7 +4869,7 @@ static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
|
|||
|
||||
BT_DBG("icid 0x%4.4x, dest_amp_id %d", icid, req->dest_amp_id);
|
||||
|
||||
if (!conn->hs_enabled)
|
||||
if (!(conn->local_fixed_chan & L2CAP_FC_A2MP))
|
||||
return -EINVAL;
|
||||
|
||||
chan = l2cap_get_chan_by_dcid(conn, icid);
|
||||
|
@ -6964,9 +6961,15 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon)
|
|||
|
||||
conn->feat_mask = 0;
|
||||
|
||||
if (hcon->type == ACL_LINK)
|
||||
conn->hs_enabled = test_bit(HCI_HS_ENABLED,
|
||||
&hcon->hdev->dev_flags);
|
||||
conn->local_fixed_chan = L2CAP_FC_SIG_BREDR | L2CAP_FC_CONNLESS;
|
||||
|
||||
if (hcon->type == ACL_LINK &&
|
||||
test_bit(HCI_HS_ENABLED, &hcon->hdev->dev_flags))
|
||||
conn->local_fixed_chan |= L2CAP_FC_A2MP;
|
||||
|
||||
if (bredr_sc_enabled(hcon->hdev) &&
|
||||
test_bit(HCI_LE_ENABLED, &hcon->hdev->dev_flags))
|
||||
conn->local_fixed_chan |= L2CAP_FC_SMP_BREDR;
|
||||
|
||||
mutex_init(&conn->ident_lock);
|
||||
mutex_init(&conn->chan_lock);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
1583
net/bluetooth/smp.c
1583
net/bluetooth/smp.c
File diff suppressed because it is too large
Load Diff
|
@ -50,10 +50,13 @@ struct smp_cmd_pairing {
|
|||
#define SMP_DIST_ENC_KEY 0x01
|
||||
#define SMP_DIST_ID_KEY 0x02
|
||||
#define SMP_DIST_SIGN 0x04
|
||||
#define SMP_DIST_LINK_KEY 0x08
|
||||
|
||||
#define SMP_AUTH_NONE 0x00
|
||||
#define SMP_AUTH_BONDING 0x01
|
||||
#define SMP_AUTH_MITM 0x04
|
||||
#define SMP_AUTH_SC 0x08
|
||||
#define SMP_AUTH_KEYPRESS 0x10
|
||||
|
||||
#define SMP_CMD_PAIRING_CONFIRM 0x03
|
||||
struct smp_cmd_pairing_confirm {
|
||||
|
@ -102,7 +105,23 @@ struct smp_cmd_security_req {
|
|||
__u8 auth_req;
|
||||
} __packed;
|
||||
|
||||
#define SMP_CMD_MAX 0x0b
|
||||
#define SMP_CMD_PUBLIC_KEY 0x0c
|
||||
struct smp_cmd_public_key {
|
||||
__u8 x[32];
|
||||
__u8 y[32];
|
||||
} __packed;
|
||||
|
||||
#define SMP_CMD_DHKEY_CHECK 0x0d
|
||||
struct smp_cmd_dhkey_check {
|
||||
__u8 e[16];
|
||||
} __packed;
|
||||
|
||||
#define SMP_CMD_KEYPRESS_NOTIFY 0x0e
|
||||
struct smp_cmd_keypress_notify {
|
||||
__u8 value;
|
||||
} __packed;
|
||||
|
||||
#define SMP_CMD_MAX 0x0e
|
||||
|
||||
#define SMP_PASSKEY_ENTRY_FAILED 0x01
|
||||
#define SMP_OOB_NOT_AVAIL 0x02
|
||||
|
@ -114,6 +133,10 @@ struct smp_cmd_security_req {
|
|||
#define SMP_UNSPECIFIED 0x08
|
||||
#define SMP_REPEATED_ATTEMPTS 0x09
|
||||
#define SMP_INVALID_PARAMS 0x0a
|
||||
#define SMP_DHKEY_CHECK_FAILED 0x0b
|
||||
#define SMP_NUMERIC_COMP_FAILED 0x0c
|
||||
#define SMP_BREDR_PAIRING_IN_PROGRESS 0x0d
|
||||
#define SMP_CROSS_TRANSP_NOT_ALLOWED 0x0e
|
||||
|
||||
#define SMP_MIN_ENC_KEY_SIZE 7
|
||||
#define SMP_MAX_ENC_KEY_SIZE 16
|
||||
|
@ -123,12 +146,29 @@ enum {
|
|||
SMP_STK,
|
||||
SMP_LTK,
|
||||
SMP_LTK_SLAVE,
|
||||
SMP_LTK_P256,
|
||||
SMP_LTK_P256_DEBUG,
|
||||
};
|
||||
|
||||
static inline bool smp_ltk_is_sc(struct smp_ltk *key)
|
||||
{
|
||||
switch (key->type) {
|
||||
case SMP_LTK_P256:
|
||||
case SMP_LTK_P256_DEBUG:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline u8 smp_ltk_sec_level(struct smp_ltk *key)
|
||||
{
|
||||
if (key->authenticated)
|
||||
return BT_SECURITY_HIGH;
|
||||
if (key->authenticated) {
|
||||
if (smp_ltk_is_sc(key))
|
||||
return BT_SECURITY_FIPS;
|
||||
else
|
||||
return BT_SECURITY_HIGH;
|
||||
}
|
||||
|
||||
return BT_SECURITY_MEDIUM;
|
||||
}
|
||||
|
@ -145,8 +185,9 @@ bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level,
|
|||
int smp_conn_security(struct hci_conn *hcon, __u8 sec_level);
|
||||
int smp_user_confirm_reply(struct hci_conn *conn, u16 mgmt_op, __le32 passkey);
|
||||
|
||||
bool smp_irk_matches(struct hci_dev *hdev, u8 irk[16], bdaddr_t *bdaddr);
|
||||
int smp_generate_rpa(struct hci_dev *hdev, u8 irk[16], bdaddr_t *rpa);
|
||||
bool smp_irk_matches(struct hci_dev *hdev, const u8 irk[16],
|
||||
const bdaddr_t *bdaddr);
|
||||
int smp_generate_rpa(struct hci_dev *hdev, const u8 irk[16], bdaddr_t *rpa);
|
||||
|
||||
int smp_register(struct hci_dev *hdev);
|
||||
void smp_unregister(struct hci_dev *hdev);
|
||||
|
|
|
@ -439,7 +439,6 @@ static void lowpan_set_lockdep_class_one(struct net_device *dev,
|
|||
&lowpan_netdev_xmit_lock_key);
|
||||
}
|
||||
|
||||
|
||||
static int lowpan_dev_init(struct net_device *dev)
|
||||
{
|
||||
netdev_for_each_tx_queue(dev, lowpan_set_lockdep_class_one, NULL);
|
||||
|
|
|
@ -99,6 +99,7 @@ static int ieee802154_sock_release(struct socket *sock)
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ieee802154_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
|
||||
struct msghdr *msg, size_t len)
|
||||
{
|
||||
|
@ -231,7 +232,6 @@ static const struct proto_ops ieee802154_dgram_ops = {
|
|||
#endif
|
||||
};
|
||||
|
||||
|
||||
/* Create a socket. Initialise the socket, blank the addresses
|
||||
* set the state.
|
||||
*/
|
||||
|
@ -320,7 +320,6 @@ drop:
|
|||
return NET_RX_DROP;
|
||||
}
|
||||
|
||||
|
||||
static struct packet_type ieee802154_packet_type = {
|
||||
.type = htons(ETH_P_IEEE802154),
|
||||
.func = ieee802154_rcv,
|
||||
|
@ -354,6 +353,7 @@ err_dgram:
|
|||
out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void __exit af_ieee802154_remove(void)
|
||||
{
|
||||
dev_remove_pack(&ieee802154_packet_type);
|
||||
|
|
|
@ -154,7 +154,6 @@ static int dgram_ioctl(struct sock *sk, int cmd, unsigned long arg)
|
|||
spin_unlock_bh(&sk->sk_receive_queue.lock);
|
||||
return put_user(amount, (int __user *)arg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return -ENOIOCTLCMD;
|
||||
|
|
|
@ -73,7 +73,7 @@ out:
|
|||
}
|
||||
|
||||
struct sk_buff *ieee802154_nl_new_reply(struct genl_info *info,
|
||||
int flags, u8 req)
|
||||
int flags, u8 req)
|
||||
{
|
||||
void *hdr;
|
||||
struct sk_buff *msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
|
||||
|
@ -147,7 +147,6 @@ static const struct genl_multicast_group ieee802154_mcgrps[] = {
|
|||
[IEEE802154_BEACON_MCGRP] = { .name = IEEE802154_MCAST_BEACON_NAME, },
|
||||
};
|
||||
|
||||
|
||||
int __init ieee802154_nl_init(void)
|
||||
{
|
||||
return genl_register_family_with_ops_groups(&nl802154_family,
|
||||
|
|
|
@ -346,7 +346,6 @@ int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info)
|
|||
else
|
||||
page = 0;
|
||||
|
||||
|
||||
if (addr.short_addr == cpu_to_le16(IEEE802154_ADDR_BROADCAST)) {
|
||||
ieee802154_nl_start_confirm(dev, IEEE802154_NO_SHORT_ADDRESS);
|
||||
dev_put(dev);
|
||||
|
@ -397,7 +396,6 @@ int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info)
|
|||
else
|
||||
page = 0;
|
||||
|
||||
|
||||
ret = ieee802154_mlme_ops(dev)->scan_req(dev, type, channels,
|
||||
page, duration);
|
||||
|
||||
|
@ -548,8 +546,6 @@ out:
|
|||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int
|
||||
ieee802154_llsec_parse_key_id(struct genl_info *info,
|
||||
struct ieee802154_llsec_key_id *desc)
|
||||
|
@ -765,8 +761,6 @@ out:
|
|||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct llsec_dump_data {
|
||||
struct sk_buff *skb;
|
||||
int s_idx, s_idx2;
|
||||
|
@ -843,8 +837,6 @@ ieee802154_nl_llsec_change(struct sk_buff *skb, struct genl_info *info,
|
|||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int
|
||||
ieee802154_llsec_parse_key(struct genl_info *info,
|
||||
struct ieee802154_llsec_key *key)
|
||||
|
@ -989,8 +981,6 @@ int ieee802154_llsec_dump_keys(struct sk_buff *skb, struct netlink_callback *cb)
|
|||
return ieee802154_llsec_dump_table(skb, cb, llsec_iter_keys);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int
|
||||
llsec_parse_dev(struct genl_info *info,
|
||||
struct ieee802154_llsec_device *dev)
|
||||
|
@ -1121,8 +1111,6 @@ int ieee802154_llsec_dump_devs(struct sk_buff *skb, struct netlink_callback *cb)
|
|||
return ieee802154_llsec_dump_table(skb, cb, llsec_iter_devs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int llsec_add_devkey(struct net_device *dev, struct genl_info *info)
|
||||
{
|
||||
struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev);
|
||||
|
@ -1237,8 +1225,6 @@ int ieee802154_llsec_dump_devkeys(struct sk_buff *skb,
|
|||
return ieee802154_llsec_dump_table(skb, cb, llsec_iter_devkeys);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int
|
||||
llsec_parse_seclevel(struct genl_info *info,
|
||||
struct ieee802154_llsec_seclevel *sl)
|
||||
|
|
|
@ -94,7 +94,6 @@ int ieee802154_list_phy(struct sk_buff *skb, struct genl_info *info)
|
|||
if (name[nla_len(info->attrs[IEEE802154_ATTR_PHY_NAME]) - 1] != '\0')
|
||||
return -EINVAL; /* phy name should be null-terminated */
|
||||
|
||||
|
||||
phy = wpan_phy_find(name);
|
||||
if (!phy)
|
||||
return -ENODEV;
|
||||
|
|
|
@ -221,7 +221,6 @@ static int raw_rcv_skb(struct sock *sk, struct sk_buff *skb)
|
|||
return NET_RX_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
void ieee802154_raw_deliver(struct net_device *dev, struct sk_buff *skb)
|
||||
{
|
||||
struct sock *sk;
|
||||
|
|
|
@ -75,8 +75,6 @@ void mac802154_llsec_destroy(struct mac802154_llsec *sec)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int mac802154_llsec_get_params(struct mac802154_llsec *sec,
|
||||
struct ieee802154_llsec_params *params)
|
||||
{
|
||||
|
@ -117,8 +115,6 @@ int mac802154_llsec_set_params(struct mac802154_llsec *sec,
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static struct mac802154_llsec_key*
|
||||
llsec_key_alloc(const struct ieee802154_llsec_key *template)
|
||||
{
|
||||
|
@ -294,8 +290,6 @@ int mac802154_llsec_key_del(struct mac802154_llsec *sec,
|
|||
return -ENOENT;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static bool llsec_dev_use_shortaddr(__le16 short_addr)
|
||||
{
|
||||
return short_addr != cpu_to_le16(IEEE802154_ADDR_UNDEF) &&
|
||||
|
@ -304,12 +298,12 @@ static bool llsec_dev_use_shortaddr(__le16 short_addr)
|
|||
|
||||
static u32 llsec_dev_hash_short(__le16 short_addr, __le16 pan_id)
|
||||
{
|
||||
return ((__force u16) short_addr) << 16 | (__force u16) pan_id;
|
||||
return ((__force u16)short_addr) << 16 | (__force u16)pan_id;
|
||||
}
|
||||
|
||||
static u64 llsec_dev_hash_long(__le64 hwaddr)
|
||||
{
|
||||
return (__force u64) hwaddr;
|
||||
return (__force u64)hwaddr;
|
||||
}
|
||||
|
||||
static struct mac802154_llsec_device*
|
||||
|
@ -411,8 +405,6 @@ int mac802154_llsec_dev_del(struct mac802154_llsec *sec, __le64 device_addr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static struct mac802154_llsec_device_key*
|
||||
llsec_devkey_find(struct mac802154_llsec_device *dev,
|
||||
const struct ieee802154_llsec_key_id *key)
|
||||
|
@ -475,8 +467,6 @@ int mac802154_llsec_devkey_del(struct mac802154_llsec *sec,
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static struct mac802154_llsec_seclevel*
|
||||
llsec_find_seclevel(const struct mac802154_llsec *sec,
|
||||
const struct ieee802154_llsec_seclevel *sl)
|
||||
|
@ -532,8 +522,6 @@ int mac802154_llsec_seclevel_del(struct mac802154_llsec *sec,
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int llsec_recover_addr(struct mac802154_llsec *sec,
|
||||
struct ieee802154_addr *addr)
|
||||
{
|
||||
|
@ -609,7 +597,6 @@ found:
|
|||
return llsec_key_get(key);
|
||||
}
|
||||
|
||||
|
||||
static void llsec_geniv(u8 iv[16], __le64 addr,
|
||||
const struct ieee802154_sechdr *sec)
|
||||
{
|
||||
|
@ -786,8 +773,6 @@ fail:
|
|||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static struct mac802154_llsec_device*
|
||||
llsec_lookup_dev(struct mac802154_llsec *sec,
|
||||
const struct ieee802154_addr *addr)
|
||||
|
|
|
@ -104,7 +104,6 @@ void mac802154_dev_set_page_channel(struct net_device *dev, u8 page, u8 chan)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
int mac802154_get_params(struct net_device *dev,
|
||||
struct ieee802154_llsec_params *params)
|
||||
{
|
||||
|
@ -136,7 +135,6 @@ int mac802154_set_params(struct net_device *dev,
|
|||
return res;
|
||||
}
|
||||
|
||||
|
||||
int mac802154_add_key(struct net_device *dev,
|
||||
const struct ieee802154_llsec_key_id *id,
|
||||
const struct ieee802154_llsec_key *key)
|
||||
|
@ -168,7 +166,6 @@ int mac802154_del_key(struct net_device *dev,
|
|||
return res;
|
||||
}
|
||||
|
||||
|
||||
int mac802154_add_dev(struct net_device *dev,
|
||||
const struct ieee802154_llsec_device *llsec_dev)
|
||||
{
|
||||
|
@ -198,7 +195,6 @@ int mac802154_del_dev(struct net_device *dev, __le64 dev_addr)
|
|||
return res;
|
||||
}
|
||||
|
||||
|
||||
int mac802154_add_devkey(struct net_device *dev,
|
||||
__le64 device_addr,
|
||||
const struct ieee802154_llsec_device_key *key)
|
||||
|
@ -231,7 +227,6 @@ int mac802154_del_devkey(struct net_device *dev,
|
|||
return res;
|
||||
}
|
||||
|
||||
|
||||
int mac802154_add_seclevel(struct net_device *dev,
|
||||
const struct ieee802154_llsec_seclevel *sl)
|
||||
{
|
||||
|
@ -262,7 +257,6 @@ int mac802154_del_seclevel(struct net_device *dev,
|
|||
return res;
|
||||
}
|
||||
|
||||
|
||||
void mac802154_lock_table(struct net_device *dev)
|
||||
{
|
||||
struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
|
||||
|
|
|
@ -85,8 +85,7 @@ ieee802154_subif_frame(struct ieee802154_sub_if_data *sdata,
|
|||
default:
|
||||
spin_unlock_bh(&sdata->mib_lock);
|
||||
pr_debug("invalid dest mode\n");
|
||||
kfree_skb(skb);
|
||||
return NET_RX_DROP;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
spin_unlock_bh(&sdata->mib_lock);
|
||||
|
|
Loading…
Reference in New Issue