The branch main has been updated by wulf:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=c1643cedbf243424370162febf6d9180bdd1df58

commit c1643cedbf243424370162febf6d9180bdd1df58
Author:     Vladimir Kondratyev <w...@freebsd.org>
AuthorDate: 2024-11-06 23:26:51 +0000
Commit:     Vladimir Kondratyev <w...@freebsd.org>
CommitDate: 2024-11-06 23:26:51 +0000

    iwmbtfw(4): Add support for 9260/9560 bluetooth adaptors
    
    Required firmware files are already included in to comms/iwmbt-firmware port
    
    Sponsored by:   Future Crew LLC
    MFC after:      1 month
    Reviewed by:    bz
    Differential Revision:  https://reviews.freebsd.org/D46735
---
 usr.sbin/bluetooth/iwmbtfw/Makefile     |   2 +
 usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.c   |  21 +++
 usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.h   |  71 +++++++
 usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.c   | 183 ++++++++++++++++--
 usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.h   |  12 +-
 usr.sbin/bluetooth/iwmbtfw/iwmbtfw.8    |   4 +-
 usr.sbin/bluetooth/iwmbtfw/iwmbtfw.conf |   5 +-
 usr.sbin/bluetooth/iwmbtfw/main.c       | 323 +++++++++++++++++++++++++-------
 8 files changed, 531 insertions(+), 90 deletions(-)

diff --git a/usr.sbin/bluetooth/iwmbtfw/Makefile 
b/usr.sbin/bluetooth/iwmbtfw/Makefile
index dde586b3aa99..c5cf037eac06 100644
--- a/usr.sbin/bluetooth/iwmbtfw/Makefile
+++ b/usr.sbin/bluetooth/iwmbtfw/Makefile
@@ -4,6 +4,8 @@ CONFSDIR=       /etc/devd
 PROG=          iwmbtfw
 MAN=           iwmbtfw.8
 LIBADD+=       usb
+# Not having NDEBUG defined will enable assertions
+CFLAGS+=       -DNDEBUG
 SRCS=          main.c iwmbt_fw.c iwmbt_hw.c
 
 .include <bsd.prog.mk>
diff --git a/usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.c 
b/usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.c
index 6816b152912d..815b40982d5b 100644
--- a/usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.c
+++ b/usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.c
@@ -3,6 +3,7 @@
  *
  * Copyright (c) 2013 Adrian Chadd <adr...@freebsd.org>
  * Copyright (c) 2019 Vladimir Kondratyev <w...@freebsd.org>
+ * Copyright (c) 2023 Future Crew LLC.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -170,3 +171,23 @@ iwmbt_get_fwname(struct iwmbt_version *ver, struct 
iwmbt_boot_params *params,
 
        return (fwname);
 }
+
+char *
+iwmbt_get_fwname_tlv(struct iwmbt_version_tlv *ver, const char *prefix,
+    const char *suffix)
+{
+       char *fwname;
+
+#define        IWMBT_PACK_CNVX_TOP(cnvx_top)   ((uint16_t)(    \
+       ((cnvx_top) & 0x0f000000) >> 16 |               \
+       ((cnvx_top) & 0x0000000f) << 12 |               \
+       ((cnvx_top) & 0x00000ff0) >> 4))
+
+       asprintf(&fwname, "%s/ibt-%04x-%04x.%s",
+           prefix,
+           IWMBT_PACK_CNVX_TOP(ver->cnvi_top),
+           IWMBT_PACK_CNVX_TOP(ver->cnvr_top),
+           suffix);
+
+       return (fwname);
+}
diff --git a/usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.h 
b/usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.h
index f737c1c0c2c8..2666d123c8f0 100644
--- a/usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.h
+++ b/usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.h
@@ -3,6 +3,7 @@
  *
  * Copyright (c) 2013 Adrian Chadd <adr...@freebsd.org>
  * Copyright (c) 2019 Vladimir Kondratyev <w...@freebsd.org>
+ * Copyright (c) 2023 Future Crew LLC.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -29,6 +30,15 @@
 #ifndef        __IWMBT_FW_H__
 #define        __IWMBT_FW_H__
 
+#include <sys/types.h>
+#define        L2CAP_SOCKET_CHECKED
+#include <bluetooth.h>
+
+#define        RSA_HEADER_LEN          644
+#define        ECDSA_HEADER_LEN        320
+#define        ECDSA_OFFSET            RSA_HEADER_LEN
+#define        CSS_HEADER_OFFSET       8
+
 struct iwmbt_version {
        uint8_t status;
        uint8_t hw_platform;
@@ -62,6 +72,65 @@ struct iwmbt_boot_params {
        uint8_t unlocked_state;
 } __attribute__ ((packed));
 
+enum {
+       IWMBT_TLV_CNVI_TOP = 0x10,
+       IWMBT_TLV_CNVR_TOP,
+       IWMBT_TLV_CNVI_BT,
+       IWMBT_TLV_CNVR_BT,
+       IWMBT_TLV_CNVI_OTP,
+       IWMBT_TLV_CNVR_OTP,
+       IWMBT_TLV_DEV_REV_ID,
+       IWMBT_TLV_USB_VENDOR_ID,
+       IWMBT_TLV_USB_PRODUCT_ID,
+       IWMBT_TLV_PCIE_VENDOR_ID,
+       IWMBT_TLV_PCIE_DEVICE_ID,
+       IWMBT_TLV_PCIE_SUBSYSTEM_ID,
+       IWMBT_TLV_IMAGE_TYPE,
+       IWMBT_TLV_TIME_STAMP,
+       IWMBT_TLV_BUILD_TYPE,
+       IWMBT_TLV_BUILD_NUM,
+       IWMBT_TLV_FW_BUILD_PRODUCT,
+       IWMBT_TLV_FW_BUILD_HW,
+       IWMBT_TLV_FW_STEP,
+       IWMBT_TLV_BT_SPEC,
+       IWMBT_TLV_MFG_NAME,
+       IWMBT_TLV_HCI_REV,
+       IWMBT_TLV_LMP_SUBVER,
+       IWMBT_TLV_OTP_PATCH_VER,
+       IWMBT_TLV_SECURE_BOOT,
+       IWMBT_TLV_KEY_FROM_HDR,
+       IWMBT_TLV_OTP_LOCK,
+       IWMBT_TLV_API_LOCK,
+       IWMBT_TLV_DEBUG_LOCK,
+       IWMBT_TLV_MIN_FW,
+       IWMBT_TLV_LIMITED_CCE,
+       IWMBT_TLV_SBE_TYPE,
+       IWMBT_TLV_OTP_BDADDR,
+       IWMBT_TLV_UNLOCKED_STATE
+};
+
+struct iwmbt_version_tlv {
+       uint32_t cnvi_top;
+       uint32_t cnvr_top;
+       uint32_t cnvi_bt;
+       uint32_t cnvr_bt;
+       uint16_t dev_rev_id;
+       uint8_t img_type;
+       uint16_t timestamp;
+       uint8_t build_type;
+       uint32_t build_num;
+       uint8_t secure_boot;
+       uint8_t otp_lock;
+       uint8_t api_lock;
+       uint8_t debug_lock;
+       uint8_t min_fw_build_nn;
+       uint8_t min_fw_build_cw;
+       uint8_t min_fw_build_yy;
+       uint8_t limited_cce;
+       uint8_t sbe_type;
+       bdaddr_t otp_bd_addr;
+};
+
 struct iwmbt_firmware {
        char *fwname;
        int len;
@@ -73,5 +142,7 @@ extern       void iwmbt_fw_free(struct iwmbt_firmware *fw);
 extern char *iwmbt_get_fwname(struct iwmbt_version *ver,
        struct iwmbt_boot_params *params, const char *prefix,
        const char *suffix);
+extern char *iwmbt_get_fwname_tlv(struct iwmbt_version_tlv *ver,
+       const char *prefix, const char *suffix);
 
 #endif
diff --git a/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.c 
b/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.c
index ea732c9925ee..05a851f9d85b 100644
--- a/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.c
+++ b/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.c
@@ -2,6 +2,7 @@
  * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2019 Vladimir Kondratyev <w...@freebsd.org>
+ * Copyright (c) 2023 Future Crew LLC.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -29,6 +30,7 @@
 #include <sys/endian.h>
 #include <sys/stat.h>
 
+#include <assert.h>
 #include <err.h>
 #include <errno.h>
 #include <stddef.h>
@@ -267,16 +269,6 @@ iwmbt_patch_fwfile(struct libusb_device_handle *hdl,
        return (activate_patch);
 }
 
-int
-iwmbt_load_fwfile(struct libusb_device_handle *hdl,
-    const struct iwmbt_firmware *fw, uint32_t *boot_param)
-{
-       int ready = 0, sent = 0;
-       int ret, transferred;
-       struct iwmbt_hci_cmd *cmd;
-       struct iwmbt_hci_event *event;
-       uint8_t buf[IWMBT_HCI_MAX_EVENT_SIZE];
-
 #define        IWMBT_SEND_FRAGMENT(fragment_type, size, msg)   do {            
\
        iwmbt_debug("transferring %d bytes, offset %d", size, sent);    \
                                                                        \
@@ -293,12 +285,11 @@ iwmbt_load_fwfile(struct libusb_device_handle *hdl,
        sent += size;                                                   \
 } while (0)
 
-       if (fw->len < 644) {
-               iwmbt_err("Invalid size of firmware file (%d)", fw->len);
-               return (-1);
-       }
-
-       iwmbt_debug("file=%s, size=%d", fw->fwname, fw->len);
+int
+iwmbt_load_rsa_header(struct libusb_device_handle *hdl,
+    const struct iwmbt_firmware *fw)
+{
+       int ret, sent = 0;
 
        IWMBT_SEND_FRAGMENT(0x00, 0x80, "CCS segment");
        IWMBT_SEND_FRAGMENT(0x03, 0x80, "public key / part 1");
@@ -310,6 +301,32 @@ iwmbt_load_fwfile(struct libusb_device_handle *hdl,
        IWMBT_SEND_FRAGMENT(0x02, 0x80, "signature / part 1");
        IWMBT_SEND_FRAGMENT(0x02, 0x80, "signature / part 2");
 
+       return (0);
+}
+
+int
+iwmbt_load_ecdsa_header(struct libusb_device_handle *hdl,
+    const struct iwmbt_firmware *fw)
+{
+       int ret, sent = ECDSA_OFFSET;
+
+       IWMBT_SEND_FRAGMENT(0x00, 0x80, "CCS segment");
+       IWMBT_SEND_FRAGMENT(0x03, 0x60, "public key");
+       IWMBT_SEND_FRAGMENT(0x02, 0x60, "signature");
+
+       return (0);
+}
+
+int
+iwmbt_load_fwfile(struct libusb_device_handle *hdl,
+    const struct iwmbt_firmware *fw, uint32_t *boot_param, int offset)
+{
+       int ready = 0, sent = offset;
+       int ret, transferred;
+       struct iwmbt_hci_cmd *cmd;
+       struct iwmbt_hci_event *event;
+       uint8_t buf[IWMBT_HCI_MAX_EVENT_SIZE];
+
        /*
         * Send firmware chunks. Chunk len must be 4 byte aligned.
         * multiple commands can be combined
@@ -460,6 +477,140 @@ iwmbt_get_version(struct libusb_device_handle *hdl,
        return (0);
 }
 
+int
+iwmbt_get_version_tlv(struct libusb_device_handle *hdl,
+    struct iwmbt_version_tlv *version)
+{
+       int ret, transferred;
+       struct iwmbt_hci_event_cmd_compl *event;
+       static struct iwmbt_hci_cmd cmd = {
+               .opcode = htole16(0xfc05),
+               .length = 1,
+               .data = { 0xff },
+       };
+       uint8_t status, datalen, type, len;
+       uint8_t *data;
+       uint8_t buf[255];
+
+       memset(buf, 0, sizeof(buf));
+
+       ret = iwmbt_hci_command(hdl,
+           &cmd,
+           buf,
+           sizeof(buf),
+           &transferred,
+           IWMBT_HCI_CMD_TIMEOUT);
+
+       if (ret < 0 || transferred < (int)IWMBT_HCI_EVT_COMPL_SIZE(uint16_t)) {
+                iwmbt_debug("Can't get version: code=%d, size=%d",
+                    ret,
+                    transferred);
+                return (-1);
+       }
+
+       event = (struct iwmbt_hci_event_cmd_compl *)buf;
+       memcpy(version, event->data, sizeof(struct iwmbt_version));
+
+       datalen = event->header.length - IWMBT_HCI_EVENT_COMPL_HEAD_SIZE;
+       data = event->data;
+       status = *data++;
+       if (status != 0)
+               return (-1);
+       datalen--;
+
+       while (datalen >= 2) {
+               type = *data++;
+               len = *data++;
+               datalen -= 2;
+
+               if (datalen < len)
+                       return (-1);
+
+               switch (type) {
+               case IWMBT_TLV_CNVI_TOP:
+                       assert(len == 4);
+                       version->cnvi_top = le32dec(data);
+                       break;
+               case IWMBT_TLV_CNVR_TOP:
+                       assert(len == 4);
+                       version->cnvr_top = le32dec(data);
+                       break;
+               case IWMBT_TLV_CNVI_BT:
+                       assert(len == 4);
+                       version->cnvi_bt = le32dec(data);
+                       break;
+               case IWMBT_TLV_CNVR_BT:
+                       assert(len == 4);
+                       version->cnvr_bt = le32dec(data);
+                       break;
+               case IWMBT_TLV_DEV_REV_ID:
+                       assert(len == 2);
+                       version->dev_rev_id = le16dec(data);
+                       break;
+               case IWMBT_TLV_IMAGE_TYPE:
+                       assert(len == 1);
+                       version->img_type = *data;
+                       break;
+               case IWMBT_TLV_TIME_STAMP:
+                       assert(len == 2);
+                       version->min_fw_build_cw = data[0];
+                       version->min_fw_build_yy = data[1];
+                       version->timestamp = le16dec(data);
+                       break;
+               case IWMBT_TLV_BUILD_TYPE:
+                       assert(len == 1);
+                       version->build_type = *data;
+                       break;
+               case IWMBT_TLV_BUILD_NUM:
+                       assert(len == 4);
+                       version->min_fw_build_nn = *data;
+                       version->build_num = le32dec(data);
+                       break;
+               case IWMBT_TLV_SECURE_BOOT:
+                       assert(len == 1);
+                       version->secure_boot = *data;
+                       break;
+               case IWMBT_TLV_OTP_LOCK:
+                       assert(len == 1);
+                       version->otp_lock = *data;
+                       break;
+               case IWMBT_TLV_API_LOCK:
+                       assert(len == 1);
+                       version->api_lock = *data;
+                       break;
+               case IWMBT_TLV_DEBUG_LOCK:
+                       assert(len == 1);
+                       version->debug_lock = *data;
+                       break;
+               case IWMBT_TLV_MIN_FW:
+                       assert(len == 3);
+                       version->min_fw_build_nn = data[0];
+                       version->min_fw_build_cw = data[1];
+                       version->min_fw_build_yy = data[2];
+                       break;
+               case IWMBT_TLV_LIMITED_CCE:
+                       assert(len == 1);
+                       version->limited_cce = *data;
+                       break;
+               case IWMBT_TLV_SBE_TYPE:
+                       assert(len == 1);
+                       version->sbe_type = *data;
+                       break;
+               case IWMBT_TLV_OTP_BDADDR:
+                       memcpy(&version->otp_bd_addr, data, sizeof(bdaddr_t));
+                       break;
+               default:
+                       /* Ignore other types */
+                       break;
+               }
+
+               datalen -= len;
+               data += len;
+       }
+
+       return (0);
+}
+
 int
 iwmbt_get_boot_params(struct libusb_device_handle *hdl,
     struct iwmbt_boot_params *params)
diff --git a/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.h 
b/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.h
index eafb2c3f31d8..9467c3807a2a 100644
--- a/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.h
+++ b/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.h
@@ -2,6 +2,7 @@
  * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2019 Vladimir Kondratyev <w...@freebsd.org>
+ * Copyright (c) 2023 Future Crew LLC.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -59,6 +60,9 @@ struct iwmbt_hci_event_cmd_compl {
 
 #define IWMBT_HCI_EVT_COMPL_SIZE(payload) \
        (offsetof(struct iwmbt_hci_event_cmd_compl, data) + sizeof(payload))
+#define        IWMBT_HCI_EVENT_COMPL_HEAD_SIZE \
+       (offsetof(struct iwmbt_hci_event_cmd_compl, data) - \
+        offsetof(struct iwmbt_hci_event_cmd_compl, numpkt))
 
 #define        IWMBT_CONTROL_ENDPOINT_ADDR     0x00
 #define        IWMBT_INTERRUPT_ENDPOINT_ADDR   0x81
@@ -73,13 +77,19 @@ struct iwmbt_hci_event_cmd_compl {
 
 extern int iwmbt_patch_fwfile(struct libusb_device_handle *hdl,
            const struct iwmbt_firmware *fw);
+extern int iwmbt_load_rsa_header(struct libusb_device_handle *hdl,
+           const struct iwmbt_firmware *fw);
+extern int iwmbt_load_ecdsa_header(struct libusb_device_handle *hdl,
+           const struct iwmbt_firmware *fw);
 extern int iwmbt_load_fwfile(struct libusb_device_handle *hdl,
-           const struct iwmbt_firmware *fw, uint32_t *boot_param);
+           const struct iwmbt_firmware *fw, uint32_t *boot_param, int offset);
 extern int iwmbt_enter_manufacturer(struct libusb_device_handle *hdl);
 extern int iwmbt_exit_manufacturer(struct libusb_device_handle *hdl,
            int mode);
 extern int iwmbt_get_version(struct libusb_device_handle *hdl,
            struct iwmbt_version *version);
+extern int iwmbt_get_version_tlv(struct libusb_device_handle *hdl,
+           struct iwmbt_version_tlv *version);
 extern int iwmbt_get_boot_params(struct libusb_device_handle *hdl,
            struct iwmbt_boot_params *params);
 extern int iwmbt_intel_reset(struct libusb_device_handle *hdl,
diff --git a/usr.sbin/bluetooth/iwmbtfw/iwmbtfw.8 
b/usr.sbin/bluetooth/iwmbtfw/iwmbtfw.8
index 1924c5f3ce74..2ce828cb5ebe 100644
--- a/usr.sbin/bluetooth/iwmbtfw/iwmbtfw.8
+++ b/usr.sbin/bluetooth/iwmbtfw/iwmbtfw.8
@@ -26,7 +26,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd May 31, 2024
+.Dd September 15, 2024
 .Dt IWMBTFW 8
 .Os
 .Sh NAME
@@ -48,7 +48,7 @@ device.
 .Pp
 This utility will
 .Em only
-work with Intel Wireless 7260/8260/8265 chip based Bluetooth USB devices
+work with Intel Wireless 7260/8260/9260 chip based Bluetooth USB devices
 and some of their successors.
 The identification is currently based on USB vendor ID/product ID pair.
 The vendor ID should be 0x8087
diff --git a/usr.sbin/bluetooth/iwmbtfw/iwmbtfw.conf 
b/usr.sbin/bluetooth/iwmbtfw/iwmbtfw.conf
index ef8d5263383b..e30a3c15ccaa 100644
--- a/usr.sbin/bluetooth/iwmbtfw/iwmbtfw.conf
+++ b/usr.sbin/bluetooth/iwmbtfw/iwmbtfw.conf
@@ -1,11 +1,12 @@
 #
-# Download Intel Wireless 8260/8265 bluetooth adaptor firmware
+# Download Intel Wireless bluetooth adaptor firmware
+#
 
 notify 100 {
        match "system"          "USB";
        match "subsystem"       "DEVICE";
        match "type"            "ATTACH";
        match "vendor"          "0x8087";
-       match "product"         
"(0x07dc|0x0a2a|0x0aa7|0x0a2b|0x0aaa|0x0025|0x0026|0x0029)";
+       match "product"         
"(0x07dc|0x0a2a|0x0aa7|0x0a2b|0x0aaa|0x0025|0x0026|0x0029|0x0032|0x0033)";
        action "/usr/sbin/iwmbtfw -d $cdev -f /usr/local/share/iwmbt-firmware";
 };
diff --git a/usr.sbin/bluetooth/iwmbtfw/main.c 
b/usr.sbin/bluetooth/iwmbtfw/main.c
index 9ef31b906b77..c2b67ce01906 100644
--- a/usr.sbin/bluetooth/iwmbtfw/main.c
+++ b/usr.sbin/bluetooth/iwmbtfw/main.c
@@ -3,6 +3,7 @@
  *
  * Copyright (c) 2013 Adrian Chadd <adr...@freebsd.org>
  * Copyright (c) 2019 Vladimir Kondratyev <w...@freebsd.org>
+ * Copyright (c) 2023 Future Crew LLC.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -50,71 +51,63 @@
 int    iwmbt_do_debug = 0;
 int    iwmbt_do_info = 0;
 
+enum iwmbt_device {
+       IWMBT_DEVICE_UNKNOWN,
+       IWMBT_DEVICE_7260,
+       IWMBT_DEVICE_8260,
+       IWMBT_DEVICE_9260,
+};
+
 struct iwmbt_devid {
        uint16_t product_id;
        uint16_t vendor_id;
+       enum iwmbt_device device;
 };
 
-static struct iwmbt_devid iwmbt_list_72xx[] = {
+static struct iwmbt_devid iwmbt_list[] = {
 
-       /* Intel Wireless 7260/7265 and successors */
-       { .vendor_id = 0x8087, .product_id = 0x07dc },
-       { .vendor_id = 0x8087, .product_id = 0x0a2a },
-       { .vendor_id = 0x8087, .product_id = 0x0aa7 },
-};
+    /* Intel Wireless 7260/7265 and successors */
+    { .vendor_id = 0x8087, .product_id = 0x07dc, .device = IWMBT_DEVICE_7260 },
+    { .vendor_id = 0x8087, .product_id = 0x0a2a, .device = IWMBT_DEVICE_7260 },
+    { .vendor_id = 0x8087, .product_id = 0x0aa7, .device = IWMBT_DEVICE_7260 },
 
-static struct iwmbt_devid iwmbt_list_82xx[] = {
+    /* Intel Wireless 8260/8265 and successors */
+    { .vendor_id = 0x8087, .product_id = 0x0a2b, .device = IWMBT_DEVICE_8260 },
+    { .vendor_id = 0x8087, .product_id = 0x0aaa, .device = IWMBT_DEVICE_8260 },
+    { .vendor_id = 0x8087, .product_id = 0x0025, .device = IWMBT_DEVICE_8260 },
+    { .vendor_id = 0x8087, .product_id = 0x0026, .device = IWMBT_DEVICE_8260 },
+    { .vendor_id = 0x8087, .product_id = 0x0029, .device = IWMBT_DEVICE_8260 },
 
-       /* Intel Wireless 8260/8265 and successors */
-       { .vendor_id = 0x8087, .product_id = 0x0a2b },
-       { .vendor_id = 0x8087, .product_id = 0x0aaa },
-       { .vendor_id = 0x8087, .product_id = 0x0025 },
-       { .vendor_id = 0x8087, .product_id = 0x0026 },
-       { .vendor_id = 0x8087, .product_id = 0x0029 },
+    /* Intel Wireless 9260/9560 and successors */
+    { .vendor_id = 0x8087, .product_id = 0x0032, .device = IWMBT_DEVICE_9260 },
+    { .vendor_id = 0x8087, .product_id = 0x0033, .device = IWMBT_DEVICE_9260 },
 };
 
-static int
-iwmbt_is_7260(struct libusb_device_descriptor *d)
+static enum iwmbt_device
+iwmbt_is_supported(struct libusb_device_descriptor *d)
 {
        int i;
 
        /* Search looking for whether it's an 7260/7265 */
-       for (i = 0; i < (int) nitems(iwmbt_list_72xx); i++) {
-               if ((iwmbt_list_72xx[i].product_id == d->idProduct) &&
-                   (iwmbt_list_72xx[i].vendor_id == d->idVendor)) {
-                       iwmbt_info("found 7260/7265");
-                       return (1);
-               }
-       }
-
-       /* Not found */
-       return (0);
-}
-
-static int
-iwmbt_is_8260(struct libusb_device_descriptor *d)
-{
-       int i;
-
-       /* Search looking for whether it's an 8260/8265 */
-       for (i = 0; i < (int) nitems(iwmbt_list_82xx); i++) {
-               if ((iwmbt_list_82xx[i].product_id == d->idProduct) &&
-                   (iwmbt_list_82xx[i].vendor_id == d->idVendor)) {
-                       iwmbt_info("found 8260/8265");
-                       return (1);
+       for (i = 0; i < (int) nitems(iwmbt_list); i++) {
+               if ((iwmbt_list[i].product_id == d->idProduct) &&
+                   (iwmbt_list[i].vendor_id == d->idVendor)) {
+                       iwmbt_info("found iwmbtfw compatible");
+                       return (iwmbt_list[i].device);
                }
        }
 
        /* Not found */
-       return (0);
+       return (IWMBT_DEVICE_UNKNOWN);
 }
 
 static libusb_device *
 iwmbt_find_device(libusb_context *ctx, int bus_id, int dev_id,
-    int *iwmbt_use_old_method)
+    enum iwmbt_device *iwmbt_device)
 {
        libusb_device **list, *dev = NULL, *found = NULL;
        struct libusb_device_descriptor d;
+       enum iwmbt_device device;
        ssize_t cnt, i;
        int r;
 
@@ -141,20 +134,13 @@ iwmbt_find_device(libusb_context *ctx, int bus_id, int 
dev_id,
                        }
 
                        /* Match on the vendor/product id */
-                       if (iwmbt_is_7260(&d)) {
+                       device = iwmbt_is_supported(&d);
+                       if (device != IWMBT_DEVICE_UNKNOWN) {
                                /*
                                 * Take a reference so it's not freed later on.
                                 */
                                found = libusb_ref_device(dev);
-                               *iwmbt_use_old_method = 1;
-                               break;
-                       } else
-                       if (iwmbt_is_8260(&d)) {
-                               /*
-                                * Take a reference so it's not freed later on.
-                                */
-                               found = libusb_ref_device(dev);
-                               *iwmbt_use_old_method = 0;
+                               *iwmbt_device = device;
                                break;
                        }
                }
@@ -200,6 +186,44 @@ iwmbt_dump_boot_params(struct iwmbt_boot_params *params)
            params->otp_bdaddr[0]);
 }
 
+static void
+iwmbt_dump_version_tlv(struct iwmbt_version_tlv *ver)
+{
+       iwmbt_info("cnvi_top     0x%08x", ver->cnvi_top);
+       iwmbt_info("cnvr_top     0x%08x", ver->cnvr_top);
+       iwmbt_info("cnvi_bt      0x%08x", ver->cnvi_bt);
+       iwmbt_info("cnvr_bt      0x%08x", ver->cnvr_bt);
+       iwmbt_info("dev_rev_id   0x%04x", ver->dev_rev_id);
+       iwmbt_info("img_type     0x%02x", ver->img_type);
+       iwmbt_info("timestamp    0x%04x", ver->timestamp);
+       iwmbt_info("build_type   0x%02x", ver->build_type);
+       iwmbt_info("build_num    0x%08x", ver->build_num);
+       iwmbt_info("Secure Boot:  %s", ver->secure_boot ? "on" : "off");
+       iwmbt_info("OTP lock:     %s", ver->otp_lock    ? "on" : "off");
+       iwmbt_info("API lock:     %s", ver->api_lock    ? "on" : "off");
+       iwmbt_info("Debug lock:   %s", ver->debug_lock  ? "on" : "off");
+       iwmbt_info("Minimum firmware build %u week %u year %u",
+           ver->min_fw_build_nn,
+           ver->min_fw_build_cw,
+           2000 + ver->min_fw_build_yy);
+       iwmbt_info("limited_cce  0x%02x", ver->limited_cce);
+       iwmbt_info("sbe_type     0x%02x", ver->sbe_type);
+       iwmbt_info("OTC BD_ADDR:  %02x:%02x:%02x:%02x:%02x:%02x",
+           ver->otp_bd_addr.b[5],
+           ver->otp_bd_addr.b[4],
+           ver->otp_bd_addr.b[3],
+           ver->otp_bd_addr.b[2],
+           ver->otp_bd_addr.b[1],
+           ver->otp_bd_addr.b[0]);
+       if (ver->img_type == 0x01 || ver->img_type == 0x03)
+               iwmbt_info("%s timestamp %u.%u buildtype %u build %u",
+                   ver->img_type == 0x01 ? "Bootloader" : "Firmware",
+                   2000 + (ver->timestamp >> 8),
+                   ver->timestamp & 0xff,
+                   ver->build_type,
+                   ver->build_num);
+}
+
 static int
 iwmbt_patch_firmware(libusb_device_handle *hdl, const char *firmware_path)
 {
@@ -227,10 +251,10 @@ iwmbt_patch_firmware(libusb_device_handle *hdl, const 
char *firmware_path)
 
 static int
 iwmbt_init_firmware(libusb_device_handle *hdl, const char *firmware_path,
-    uint32_t *boot_param)
+    uint32_t *boot_param, uint8_t hw_variant, uint8_t sbe_type)
 {
        struct iwmbt_firmware fw;
-       int ret;
+       int header_len, ret = -1;
 
        iwmbt_debug("loading %s", firmware_path);
 
@@ -240,12 +264,76 @@ iwmbt_init_firmware(libusb_device_handle *hdl, const char 
*firmware_path,
                return (-1);
        }
 
-       /* Load in the firmware */
-       ret = iwmbt_load_fwfile(hdl, &fw, boot_param);
+       iwmbt_debug("Firmware file size=%d", fw.len);
+
+       if (hw_variant <= 0x14) {
+               /*
+                * Hardware variants 0x0b, 0x0c, 0x11 - 0x14 .sfi file have
+                * a RSA header of 644 bytes followed by Command Buffer.
+                */
+               header_len = RSA_HEADER_LEN;
+               if (fw.len < header_len) {
+                       iwmbt_err("Invalid size of firmware file (%d)", fw.len);
+                       ret = -1;
+                       goto exit;
+               }
+
+               /* Check if the CSS Header version is RSA(0x00010000) */
+               if (le32dec(fw.buf + CSS_HEADER_OFFSET) != 0x00010000) {
+                       iwmbt_err("Invalid CSS Header version");
+                       ret = -1;
+                       goto exit;
+               }
+
+               /* Only RSA secure boot engine supported */
+               if (sbe_type != 0x00) {
+                       iwmbt_err("Invalid SBE type for hardware variant (%d)",
+                           hw_variant);
+                       ret = -1;
+                       goto exit;
+               }
+
+       } else if (hw_variant >= 0x17) {
+               /*
+                * Hardware variants 0x17, 0x18 onwards support both RSA and
+                * ECDSA secure boot engine. As a result, the corresponding sfi
+                * file will have RSA header of 644, ECDSA header of 320 bytes
+                * followed by Command Buffer.
+                */
+               header_len = ECDSA_OFFSET + ECDSA_HEADER_LEN;
+               if (fw.len < header_len) {
+                       iwmbt_err("Invalid size of firmware file (%d)", fw.len);
+                       ret = -1;
+                       goto exit;
+               }
+
+               /* Check if CSS header for ECDSA follows the RSA header */
+               if (fw.buf[ECDSA_OFFSET] != 0x06) {
+                       ret = -1;
+                       goto exit;
+               }
+
+               /* Check if the CSS Header version is ECDSA(0x00020000) */
+               if (le32dec(fw.buf + ECDSA_OFFSET + CSS_HEADER_OFFSET) != 
0x00020000) {
+                       iwmbt_err("Invalid CSS Header version");
+                       ret = -1;
+                       goto exit;
+               }
+       }
+
+       /* Load in the CSS header */
+       if (sbe_type == 0x00)
+               ret = iwmbt_load_rsa_header(hdl, &fw);
+       else if (sbe_type == 0x01)
+               ret = iwmbt_load_ecdsa_header(hdl, &fw);
        if (ret < 0)
-               iwmbt_debug("Loading firmware file failed");
+               goto exit;
 
-       /* free it */
+       /* Load in the Command Buffer */
+       ret = iwmbt_load_fwfile(hdl, &fw, boot_param, header_len);
+
+exit:
+       /* free firmware */
        iwmbt_fw_free(&fw);
 
        return (ret);
@@ -318,6 +406,7 @@ main(int argc, char *argv[])
        libusb_device *dev = NULL;
        libusb_device_handle *hdl = NULL;
        static struct iwmbt_version ver;
+       static struct iwmbt_version_tlv ver_tlv;
        static struct iwmbt_boot_params params;
        uint32_t boot_param;
        int r;
@@ -327,7 +416,7 @@ main(int argc, char *argv[])
        char *firmware_dir = NULL;
        char *firmware_path = NULL;
        int retcode = 1;
-       int iwmbt_use_old_method = 0;
+       enum iwmbt_device iwmbt_device;
 
        /* Parse command line arguments */
        while ((n = getopt(argc, argv, "Dd:f:hIm:p:v:")) != -1) {
@@ -372,7 +461,7 @@ main(int argc, char *argv[])
        iwmbt_debug("opening dev %d.%d", (int) bus_id, (int) dev_id);
 
        /* Find a device based on the bus/dev id */
-       dev = iwmbt_find_device(ctx, bus_id, dev_id, &iwmbt_use_old_method);
+       dev = iwmbt_find_device(ctx, bus_id, dev_id, &iwmbt_device);
        if (dev == NULL) {
                iwmbt_err("device not found");
                goto shutdown;
@@ -401,16 +490,16 @@ main(int argc, char *argv[])
                goto shutdown;
        }
 
-       /* Get Intel version */
-       r = iwmbt_get_version(hdl, &ver);
-       if (r < 0) {
-               iwmbt_debug("iwmbt_get_version() failed code %d", r);
-               goto shutdown;
-       }
-       iwmbt_dump_version(&ver);
-       iwmbt_debug("fw_variant=0x%02x", (int) ver.fw_variant);
+       if (iwmbt_device == IWMBT_DEVICE_7260) {
 
-       if (iwmbt_use_old_method) {
+               /* Get Intel version */
+               r = iwmbt_get_version(hdl, &ver);
+               if (r < 0) {
+                       iwmbt_debug("iwmbt_get_version() failed code %d", r);
+                       goto shutdown;
+               }
+               iwmbt_dump_version(&ver);
+               iwmbt_debug("fw_patch_num=0x%02x", (int) ver.fw_patch_num);
 
                /* fw_patch_num = >0 operational mode */
                if (ver.fw_patch_num > 0x00) {
@@ -469,7 +558,16 @@ main(int argc, char *argv[])
                        iwmbt_info("Intel Event Mask is set");
                (void)iwmbt_exit_manufacturer(hdl, 0x00);
 
-       } else {
+       } else if (iwmbt_device == IWMBT_DEVICE_8260) {
+
+               /* Get Intel version */
+               r = iwmbt_get_version(hdl, &ver);
+               if (r < 0) {
+                       iwmbt_debug("iwmbt_get_version() failed code %d", r);
+                       goto shutdown;
+               }
+               iwmbt_dump_version(&ver);
+               iwmbt_debug("fw_variant=0x%02x", (int) ver.fw_variant);
 
                /* fw_variant = 0x06 bootloader mode / 0x23 operational mode */
                if (ver.fw_variant == 0x23) {
@@ -509,7 +607,7 @@ main(int argc, char *argv[])
                iwmbt_debug("firmware_path = %s", firmware_path);
 
                /* Download firmware and parse it for magic Intel Reset 
parameter */
-               r = iwmbt_init_firmware(hdl, firmware_path, &boot_param);
+               r = iwmbt_init_firmware(hdl, firmware_path, &boot_param, 0, 0);
                free(firmware_path);
                if (r < 0)
                        goto shutdown;
@@ -546,6 +644,93 @@ main(int argc, char *argv[])
                r = iwmbt_set_event_mask(hdl);
                if (r == 0)
                        iwmbt_info("Intel Event Mask is set");
+
+       } else {
+
+               /* Get Intel version */
+               r = iwmbt_get_version_tlv(hdl, &ver_tlv);
+               if (r < 0) {
+                       iwmbt_debug("iwmbt_get_version_tlv() failed code %d", 
r);
+                       goto shutdown;
+               }
+               iwmbt_dump_version_tlv(&ver_tlv);
+               iwmbt_debug("img_type=0x%02x", (int) ver_tlv.img_type);
+
+               /* img_type = 0x01 bootloader mode / 0x03 operational mode */
+               if (ver_tlv.img_type == 0x03) {
+                       iwmbt_info("Firmware has already been downloaded");
+                       retcode = 0;
+                       goto reset;
+               }
+
+               if (ver_tlv.img_type != 0x01){
+                       iwmbt_err("unknown img_type 0x%02x", (int) 
ver_tlv.img_type);
+                       goto shutdown;
+               }
+
+               /* Check if firmware fragments are ACKed with a cmd complete 
event */
+               if (ver_tlv.limited_cce != 0x00) {
+                       iwmbt_err("Unsupported Intel firmware loading method 
(%u)",
+                          ver_tlv.limited_cce);
+                       goto shutdown;
+               }
+
+               /* Check if secure boot engine is supported: 1 (ECDSA) or 0 
(RSA) */
+               if (ver_tlv.sbe_type > 0x01) {
+                       iwmbt_err("Unsupported secure boot engine (%u)",
+                          ver_tlv.sbe_type);
+                       goto shutdown;
+               }
+
+               /* Default the firmware path */
+               if (firmware_dir == NULL)
+                       firmware_dir = strdup(_DEFAULT_IWMBT_FIRMWARE_PATH);
+
+               firmware_path = iwmbt_get_fwname_tlv(&ver_tlv, firmware_dir, 
"sfi");
+               if (firmware_path == NULL)
+                       goto shutdown;
+
+               iwmbt_debug("firmware_path = %s", firmware_path);
+
+               /* Download firmware and parse it for magic Intel Reset 
parameter */
+               r = iwmbt_init_firmware(hdl, firmware_path, &boot_param,
+                   ver_tlv.cnvi_bt >> 16 & 0x3f, ver_tlv.sbe_type);
+               free(firmware_path);
+               if (r < 0)
+                       goto shutdown;
+
+               r = iwmbt_intel_reset(hdl, boot_param);
+               if (r < 0) {
+                       iwmbt_debug("iwmbt_intel_reset() failed!");
+                       goto shutdown;
+               }
+
+               iwmbt_info("Firmware operational");
+
+               /* Once device is running in operational mode we can ignore 
failures */
+               retcode = 0;
+
+               /* Execute Read Intel Version one more time */
+               r = iwmbt_get_version(hdl, &ver);
+               if (r == 0)
+                       iwmbt_dump_version(&ver);
+
+               /* Apply the device configuration (DDC) parameters */
+               firmware_path = iwmbt_get_fwname_tlv(&ver_tlv, firmware_dir, 
"ddc");
+               iwmbt_debug("ddc_path = %s", firmware_path);
+               if (firmware_path != NULL) {
+                       r = iwmbt_init_ddc(hdl, firmware_path);
+                       if (r == 0)
+                               iwmbt_info("DDC download complete");
+                       free(firmware_path);
+               }
+
+               /* Set Intel Event mask */
+               r = iwmbt_set_event_mask(hdl);
+               if (r == 0)
+                       iwmbt_info("Intel Event Mask is set");
+
+               iwmbt_info("Firmware download complete");
        }
 
 reset:

Reply via email to