From c84d59e72830ce7a7ce67cf7509d37342aa235db Mon Sep 17 00:00:00 2001 From: Stefan Schmidt Date: Mon, 5 Dec 2016 14:47:17 +0100 Subject: [PATCH 1/6] ieee802154: atusb: sync header file from firmware for new features This file is shared between the atusb firmware and the kernel driver. In this update it brings the new interfaces from version 0.3 of the firmware. Signed-off-by: Stefan Schmidt Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/atusb.h | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/net/ieee802154/atusb.h b/drivers/net/ieee802154/atusb.h index 0690edcad57b10..b22bbaa77590dc 100644 --- a/drivers/net/ieee802154/atusb.h +++ b/drivers/net/ieee802154/atusb.h @@ -13,8 +13,8 @@ * Firmware: ben-wpan/atusb/fw/include/atusb/atusb.h */ -#ifndef _ATUSB_H -#define _ATUSB_H +#ifndef _ATUSB_H +#define _ATUSB_H #define ATUSB_VENDOR_ID 0x20b7 /* Qi Hardware*/ #define ATUSB_PRODUCT_ID 0x1540 /* 802.15.4, device 0 */ @@ -46,9 +46,12 @@ enum atusb_requests { ATUSB_SPI_WRITE2_SYNC, ATUSB_RX_MODE = 0x40, /* HardMAC group */ ATUSB_TX, + ATUSB_EUI64_WRITE = 0x50, /* Parameter in EEPROM grp */ + ATUSB_EUI64_READ, }; -/* Direction bRequest wValue wIndex wLength +/* + * Direction bRequest wValue wIndex wLength * * ->host ATUSB_ID - - 3 * ->host ATUSB_BUILD - - #bytes @@ -76,6 +79,8 @@ enum atusb_requests { * * host-> ATUSB_RX_MODE on - 0 * host-> ATUSB_TX flags ack_seq #bytes + * host-> ATUSB_EUI64_WRITE - - #bytes (8) + * ->host ATUSB_EUI64_READ - - #bytes (8) */ #define ATUSB_REQ_FROM_DEV (USB_TYPE_VENDOR | USB_DIR_IN) From 46551564a28e07325140057876f92881d58a219a Mon Sep 17 00:00:00 2001 From: Stefan Schmidt Date: Mon, 5 Dec 2016 14:47:18 +0100 Subject: [PATCH 2/6] ieee802154: atusb: store firmware version after retrieval for later use The firmware versions will be used to enable selective features based on the available firmware on the device. Make sure we do not need to fetch it for every check but store it after the initial retrieval. Signed-off-by: Stefan Schmidt Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/atusb.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/net/ieee802154/atusb.c b/drivers/net/ieee802154/atusb.c index 322864a1a94b8e..9fdea642ffadd2 100644 --- a/drivers/net/ieee802154/atusb.c +++ b/drivers/net/ieee802154/atusb.c @@ -58,6 +58,11 @@ struct atusb { struct urb *tx_urb; struct sk_buff *tx_skb; uint8_t tx_ack_seq; /* current TX ACK sequence number */ + + /* Firmware variable */ + unsigned char fw_ver_maj; /* Firmware major version number */ + unsigned char fw_ver_min; /* Firmware minor version number */ + unsigned char fw_hw_type; /* Firmware hardware type */ }; /* ----- USB commands without data ----------------------------------------- */ @@ -594,14 +599,19 @@ static int atusb_get_and_show_revision(struct atusb *atusb) ret = atusb_control_msg(atusb, usb_rcvctrlpipe(usb_dev, 0), ATUSB_ID, ATUSB_REQ_FROM_DEV, 0, 0, buffer, 3, 1000); - if (ret >= 0) + if (ret >= 0) { + atusb->fw_ver_maj = buffer[0]; + atusb->fw_ver_min = buffer[1]; + atusb->fw_hw_type = buffer[2]; + dev_info(&usb_dev->dev, "Firmware: major: %u, minor: %u, hardware type: %u\n", - buffer[0], buffer[1], buffer[2]); - if (buffer[0] == 0 && buffer[1] < 2) { + atusb->fw_ver_maj, atusb->fw_ver_min, atusb->fw_hw_type); + } + if (atusb->fw_ver_maj == 0 && atusb->fw_ver_min < 2) { dev_info(&usb_dev->dev, - "Firmware version (%u.%u) is predates our first public release.", - buffer[0], buffer[1]); + "Firmware version (%u.%u) predates our first public release.", + atusb->fw_ver_maj, atusb->fw_ver_min); dev_info(&usb_dev->dev, "Please update to version 0.2 or newer"); } From 6cc33eba232cebc9918c558b21b1e3b5fcab27b7 Mon Sep 17 00:00:00 2001 From: Stefan Schmidt Date: Mon, 5 Dec 2016 14:47:19 +0100 Subject: [PATCH 3/6] ieee802154: atusb: try to read permanent extended address from device With version 0.3 the atusb firmware offers an interface to read a permanent EUI64 address from the devices EEPROM. This patch checks if the firmware is new enough and tries to read out and use the address. If this does not work we fall back to the original randomly generated address. Signed-off-by: Stefan Schmidt Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/atusb.c | 40 +++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/drivers/net/ieee802154/atusb.c b/drivers/net/ieee802154/atusb.c index 9fdea642ffadd2..3ed34cc8a2f84a 100644 --- a/drivers/net/ieee802154/atusb.c +++ b/drivers/net/ieee802154/atusb.c @@ -679,6 +679,43 @@ static int atusb_get_and_show_chip(struct atusb *atusb) return -ENODEV; } +static int atusb_set_extended_addr(struct atusb *atusb) +{ + struct usb_device *usb_dev = atusb->usb_dev; + unsigned char buffer[IEEE802154_EXTENDED_ADDR_LEN]; + __le64 extended_addr; + u64 addr; + int ret; + + /* Firmware versions before 0.3 do not support the EUI64_READ command. + * Just use a random address and be done */ + if (atusb->fw_ver_maj == 0 && atusb->fw_ver_min < 3) { + ieee802154_random_extended_addr(&atusb->hw->phy->perm_extended_addr); + return 0; + } + + /* Firmware is new enough so we fetch the address from EEPROM */ + ret = atusb_control_msg(atusb, usb_rcvctrlpipe(usb_dev, 0), + ATUSB_EUI64_READ, ATUSB_REQ_FROM_DEV, 0, 0, + buffer, IEEE802154_EXTENDED_ADDR_LEN, 1000); + if (ret < 0) + dev_err(&usb_dev->dev, "failed to fetch extended address\n"); + + memcpy(&extended_addr, buffer, IEEE802154_EXTENDED_ADDR_LEN); + /* Check if read address is not empty and the unicast bit is set correctly */ + if (!ieee802154_is_valid_extended_unicast_addr(extended_addr)) { + dev_info(&usb_dev->dev, "no permanent extended address found, random address set\n"); + ieee802154_random_extended_addr(&atusb->hw->phy->perm_extended_addr); + } else { + atusb->hw->phy->perm_extended_addr = extended_addr; + addr = swab64((__force u64)atusb->hw->phy->perm_extended_addr); + dev_info(&usb_dev->dev, "Read permanent extended address %8phC from device\n", + &addr); + } + + return ret; +} + /* ----- Setup ------------------------------------------------------------- */ static int atusb_probe(struct usb_interface *interface, @@ -738,13 +775,14 @@ static int atusb_probe(struct usb_interface *interface, hw->phy->supported.tx_powers = atusb_powers; hw->phy->supported.tx_powers_size = ARRAY_SIZE(atusb_powers); hw->phy->transmit_power = hw->phy->supported.tx_powers[0]; - ieee802154_random_extended_addr(&hw->phy->perm_extended_addr); hw->phy->cca_ed_level = hw->phy->supported.cca_ed_levels[7]; atusb_command(atusb, ATUSB_RF_RESET, 0); atusb_get_and_show_chip(atusb); atusb_get_and_show_revision(atusb); atusb_get_and_show_build(atusb); + atusb_set_extended_addr(atusb); + ret = atusb_get_and_clear_error(atusb); if (ret) { dev_err(&atusb->usb_dev->dev, From 5d82288b93db3bc7e943464f89079f1360ac3c50 Mon Sep 17 00:00:00 2001 From: Stefan Schmidt Date: Mon, 5 Dec 2016 14:47:20 +0100 Subject: [PATCH 4/6] ieee802154: atusb: implement .set_frame_retries ops callback From firmware version 0.3 onwards we use the TX_ARET mode allowing for automatic frame retransmissions. To actually make use of this feature we need to implement the callback for setting the frame retries. If the firmware version is to old print a warning and return with invalid value. Signed-off-by: Stefan Schmidt Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/atusb.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/net/ieee802154/atusb.c b/drivers/net/ieee802154/atusb.c index 3ed34cc8a2f84a..1253f864737ae3 100644 --- a/drivers/net/ieee802154/atusb.c +++ b/drivers/net/ieee802154/atusb.c @@ -545,6 +545,21 @@ atusb_set_csma_params(struct ieee802154_hw *hw, u8 min_be, u8 max_be, u8 retries return atusb_write_subreg(atusb, SR_MAX_CSMA_RETRIES, retries); } +static int +atusb_set_frame_retries(struct ieee802154_hw *hw, s8 retries) +{ + struct atusb *atusb = hw->priv; + struct device *dev = &atusb->usb_dev->dev; + + if (atusb->fw_ver_maj == 0 && atusb->fw_ver_min < 3) { + dev_info(dev, "Automatic frame retransmission is only available from " + "firmware version 0.3. Please update if you want this feature."); + return -EINVAL; + } + + return atusb_write_subreg(atusb, SR_MAX_FRAME_RETRIES, retries); +} + static int atusb_set_promiscuous_mode(struct ieee802154_hw *hw, const bool on) { @@ -584,6 +599,7 @@ static const struct ieee802154_ops atusb_ops = { .set_cca_mode = atusb_set_cca_mode, .set_cca_ed_level = atusb_set_cca_ed_level, .set_csma_params = atusb_set_csma_params, + .set_frame_retries = atusb_set_frame_retries, .set_promiscuous_mode = atusb_set_promiscuous_mode, }; @@ -754,7 +770,8 @@ static int atusb_probe(struct usb_interface *interface, hw->parent = &usb_dev->dev; hw->flags = IEEE802154_HW_TX_OMIT_CKSUM | IEEE802154_HW_AFILT | - IEEE802154_HW_PROMISCUOUS | IEEE802154_HW_CSMA_PARAMS; + IEEE802154_HW_PROMISCUOUS | IEEE802154_HW_CSMA_PARAMS | + IEEE802154_HW_FRAME_RETRIES; hw->phy->flags = WPAN_PHY_FLAG_TXPOWER | WPAN_PHY_FLAG_CCA_ED_LEVEL | WPAN_PHY_FLAG_CCA_MODE; From 0705f7b12b57f94032bc1b6cde05d12a0bafc7fa Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Wed, 23 Nov 2016 23:14:01 +0800 Subject: [PATCH 5/6] Bluetooth: btmrvl: drop duplicate header slab.h Drop duplicate header slab.h from btmrvl_drv.h. Signed-off-by: Geliang Tang Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btmrvl_drv.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h index f742384b53f7d1..fc3caf4541ba07 100644 --- a/drivers/bluetooth/btmrvl_drv.h +++ b/drivers/bluetooth/btmrvl_drv.h @@ -32,7 +32,6 @@ #include #include #include -#include #include #define BTM_HEADER_LEN 4 From a62da6f14db79bd7ea435ab095e998b31b3dbb22 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 8 Dec 2016 08:32:54 +0200 Subject: [PATCH 6/6] Bluetooth: SMP: Add support for H7 crypto function and CT2 auth flag Bluetooth 5.0 introduces a new H7 key generation function that's used when both sides of the pairing set the CT2 authentication flag to 1. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 85 ++++++++++++++++++++++++++++++++++++--------- net/bluetooth/smp.h | 1 + 2 files changed, 69 insertions(+), 17 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 43faf2aea2abbb..fae391f1871f13 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -57,7 +57,7 @@ #define SMP_TIMEOUT msecs_to_jiffies(30000) #define AUTH_REQ_MASK(dev) (hci_dev_test_flag(dev, HCI_SC_ENABLED) ? \ - 0x1f : 0x07) + 0x3f : 0x07) #define KEY_DIST_MASK 0x07 /* Maximum message length that can be passed to aes_cmac */ @@ -76,6 +76,7 @@ enum { SMP_FLAG_DHKEY_PENDING, SMP_FLAG_REMOTE_OOB, SMP_FLAG_LOCAL_OOB, + SMP_FLAG_CT2, }; struct smp_dev { @@ -357,6 +358,22 @@ static int smp_h6(struct crypto_shash *tfm_cmac, const u8 w[16], return err; } +static int smp_h7(struct crypto_shash *tfm_cmac, const u8 w[16], + const u8 salt[16], u8 res[16]) +{ + int err; + + SMP_DBG("w %16phN salt %16phN", w, salt); + + err = aes_cmac(tfm_cmac, salt, w, 16, res); + if (err) + return err; + + SMP_DBG("res %16phN", res); + + return err; +} + /* The following functions map to the legacy SMP crypto functions e, c1, * s1 and ah. */ @@ -1130,20 +1147,31 @@ static void sc_add_ltk(struct smp_chan *smp) static void sc_generate_link_key(struct smp_chan *smp) { - /* These constants are as specified in the core specification. - * In ASCII they spell out to 'tmp1' and 'lebr'. - */ - const u8 tmp1[4] = { 0x31, 0x70, 0x6d, 0x74 }; + /* From core spec. Spells out in ASCII as 'lebr'. */ const u8 lebr[4] = { 0x72, 0x62, 0x65, 0x6c }; smp->link_key = kzalloc(16, GFP_KERNEL); if (!smp->link_key) return; - if (smp_h6(smp->tfm_cmac, smp->tk, tmp1, smp->link_key)) { - kzfree(smp->link_key); - smp->link_key = NULL; - return; + if (test_bit(SMP_FLAG_CT2, &smp->flags)) { + /* SALT = 0x00000000000000000000000000000000746D7031 */ + const u8 salt[16] = { 0x31, 0x70, 0x6d, 0x74 }; + + if (smp_h7(smp->tfm_cmac, smp->tk, salt, smp->link_key)) { + kzfree(smp->link_key); + smp->link_key = NULL; + return; + } + } else { + /* From core spec. Spells out in ASCII as 'tmp1'. */ + const u8 tmp1[4] = { 0x31, 0x70, 0x6d, 0x74 }; + + if (smp_h6(smp->tfm_cmac, smp->tk, tmp1, smp->link_key)) { + kzfree(smp->link_key); + smp->link_key = NULL; + return; + } } if (smp_h6(smp->tfm_cmac, smp->link_key, lebr, smp->link_key)) { @@ -1169,10 +1197,7 @@ static void smp_allow_key_dist(struct smp_chan *smp) static void sc_generate_ltk(struct smp_chan *smp) { - /* These constants are as specified in the core specification. - * In ASCII they spell out to 'tmp2' and 'brle'. - */ - const u8 tmp2[4] = { 0x32, 0x70, 0x6d, 0x74 }; + /* From core spec. Spells out in ASCII as 'brle'. */ const u8 brle[4] = { 0x65, 0x6c, 0x72, 0x62 }; struct hci_conn *hcon = smp->conn->hcon; struct hci_dev *hdev = hcon->hdev; @@ -1187,8 +1212,19 @@ static void sc_generate_ltk(struct smp_chan *smp) if (key->type == HCI_LK_DEBUG_COMBINATION) set_bit(SMP_FLAG_DEBUG_KEY, &smp->flags); - if (smp_h6(smp->tfm_cmac, key->val, tmp2, smp->tk)) - return; + if (test_bit(SMP_FLAG_CT2, &smp->flags)) { + /* SALT = 0x00000000000000000000000000000000746D7032 */ + const u8 salt[16] = { 0x32, 0x70, 0x6d, 0x74 }; + + if (smp_h7(smp->tfm_cmac, key->val, salt, smp->tk)) + return; + } else { + /* From core spec. Spells out in ASCII as 'tmp2'. */ + const u8 tmp2[4] = { 0x32, 0x70, 0x6d, 0x74 }; + + if (smp_h6(smp->tfm_cmac, key->val, tmp2, smp->tk)) + return; + } if (smp_h6(smp->tfm_cmac, smp->tk, brle, smp->tk)) return; @@ -1669,6 +1705,7 @@ static void build_bredr_pairing_cmd(struct smp_chan *smp, if (!rsp) { memset(req, 0, sizeof(*req)); + req->auth_req = SMP_AUTH_CT2; req->init_key_dist = local_dist; req->resp_key_dist = remote_dist; req->max_key_size = conn->hcon->enc_key_size; @@ -1680,6 +1717,7 @@ static void build_bredr_pairing_cmd(struct smp_chan *smp, memset(rsp, 0, sizeof(*rsp)); + rsp->auth_req = SMP_AUTH_CT2; rsp->max_key_size = conn->hcon->enc_key_size; rsp->init_key_dist = req->init_key_dist & remote_dist; rsp->resp_key_dist = req->resp_key_dist & local_dist; @@ -1744,6 +1782,9 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) build_bredr_pairing_cmd(smp, req, &rsp); + if (req->auth_req & SMP_AUTH_CT2) + set_bit(SMP_FLAG_CT2, &smp->flags); + key_size = min(req->max_key_size, rsp.max_key_size); if (check_enc_key_size(conn, key_size)) return SMP_ENC_KEY_SIZE; @@ -1761,9 +1802,13 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) build_pairing_cmd(conn, req, &rsp, auth); - if (rsp.auth_req & SMP_AUTH_SC) + if (rsp.auth_req & SMP_AUTH_SC) { set_bit(SMP_FLAG_SC, &smp->flags); + if (rsp.auth_req & SMP_AUTH_CT2) + set_bit(SMP_FLAG_CT2, &smp->flags); + } + if (conn->hcon->io_capability == HCI_IO_NO_INPUT_OUTPUT) sec_level = BT_SECURITY_MEDIUM; else @@ -1917,6 +1962,9 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) */ smp->remote_key_dist &= rsp->resp_key_dist; + if ((req->auth_req & SMP_AUTH_CT2) && (auth & SMP_AUTH_CT2)) + set_bit(SMP_FLAG_CT2, &smp->flags); + /* For BR/EDR this means we're done and can start phase 3 */ if (conn->hcon->type == ACL_LINK) { /* Clear bits which are generated but not distributed */ @@ -2312,8 +2360,11 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level) authreq = seclevel_to_authreq(sec_level); - if (hci_dev_test_flag(hcon->hdev, HCI_SC_ENABLED)) + if (hci_dev_test_flag(hcon->hdev, HCI_SC_ENABLED)) { authreq |= SMP_AUTH_SC; + if (hci_dev_test_flag(hcon->hdev, HCI_SSP_ENABLED)) + authreq |= SMP_AUTH_CT2; + } /* Require MITM if IO Capability allows or the security level * requires it. diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h index ffcc70b6b1997d..0ff6247eaa6c0e 100644 --- a/net/bluetooth/smp.h +++ b/net/bluetooth/smp.h @@ -57,6 +57,7 @@ struct smp_cmd_pairing { #define SMP_AUTH_MITM 0x04 #define SMP_AUTH_SC 0x08 #define SMP_AUTH_KEYPRESS 0x10 +#define SMP_AUTH_CT2 0x20 #define SMP_CMD_PAIRING_CONFIRM 0x03 struct smp_cmd_pairing_confirm {