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
@@ -1,9 +1,11 @@
 PACKAGE=	bluetooth
 CONFS=		iwmbtfw.conf
 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
@@ -1,172 +1,193 @@
 /*-
  * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2013 Adrian Chadd <adrian@freebsd.org>
  * Copyright (c) 2019 Vladimir Kondratyev <wulf@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
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. 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 AUTHOR 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 AUTHOR 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 <sys/types.h>
 #include <sys/endian.h>
 #include <sys/stat.h>
 
 #include <err.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
 #include "iwmbt_fw.h"
 #include "iwmbt_dbg.h"
 
 int
 iwmbt_fw_read(struct iwmbt_firmware *fw, const char *fwname)
 {
 	int fd;
 	struct stat sb;
 	unsigned char *buf;
 	ssize_t r;
 
 	fd = open(fwname, O_RDONLY);
 	if (fd < 0) {
 		warn("%s: open: %s", __func__, fwname);
 		return (0);
 	}
 
 	if (fstat(fd, &sb) != 0) {
 		warn("%s: stat: %s", __func__, fwname);
 		close(fd);
 		return (0);
 	}
 
 	buf = calloc(1, sb.st_size);
 	if (buf == NULL) {
 		warn("%s: calloc", __func__);
 		close(fd);
 		return (0);
 	}
 
 	/* XXX handle partial reads */
 	r = read(fd, buf, sb.st_size);
 	if (r < 0) {
 		warn("%s: read", __func__);
 		free(buf);
 		close(fd);
 		return (0);
 	}
 
 	if (r != sb.st_size) {
 		iwmbt_err("read len %d != file size %d",
 		    (int) r,
 		    (int) sb.st_size);
 		free(buf);
 		close(fd);
 		return (0);
 	}
 
 	/* We have everything, so! */
 
 	memset(fw, 0, sizeof(*fw));
 
 	fw->fwname = strdup(fwname);
 	fw->len = sb.st_size;
 	fw->buf = buf;
 
 	close(fd);
 	return (1);
 }
 
 void
 iwmbt_fw_free(struct iwmbt_firmware *fw)
 {
 	if (fw->fwname)
 		free(fw->fwname);
 	if (fw->buf)
 		free(fw->buf);
 	memset(fw, 0, sizeof(*fw));
 }
 
 char *
 iwmbt_get_fwname(struct iwmbt_version *ver, struct iwmbt_boot_params *params,
     const char *prefix, const char *suffix)
 {
 	struct stat sb;
 	char *fwname;
 
 	switch (ver->hw_variant) {
 	case 0x07:	/* 7260 */
 	case 0x08:	/* 7265 */
 		asprintf(&fwname, "%s/ibt-hw-%x.%x.%x-fw-%x.%x.%x.%x.%x.%s",
 		    prefix,
 		    le16toh(ver->hw_platform),
 		    le16toh(ver->hw_variant),
 		    le16toh(ver->hw_revision),
 		    le16toh(ver->fw_variant),
 		    le16toh(ver->fw_revision),
 		    le16toh(ver->fw_build_num),
 		    le16toh(ver->fw_build_ww),
 		    le16toh(ver->fw_build_yy),
 		    suffix);
 		/*
 		 * Fallback to the default firmware patch if
 		 * the correct firmware patch file is not found.
 		 */
 		if (stat(fwname, &sb) != 0 && errno == ENOENT) {
 			free(fwname);
 			asprintf(&fwname, "%s/ibt-hw-%x.%x.%s",
 			    prefix,
 			    le16toh(ver->hw_platform),
 			    le16toh(ver->hw_variant),
 			    suffix);
 		}
 		break;
 
 	case 0x0b:	/* 8260 */
 	case 0x0c:	/* 8265 */
 		asprintf(&fwname, "%s/ibt-%u-%u.%s",
 		    prefix,
 		    le16toh(ver->hw_variant),
 		    le16toh(params->dev_revid),
 		    suffix);
 		break;
 
 	case 0x11:	/* 9560 */
 	case 0x12:	/* 9260 */
 	case 0x13:
 	case 0x14:	/* 22161 */
 		asprintf(&fwname, "%s/ibt-%u-%u-%u.%s",
 		    prefix,
 		    le16toh(ver->hw_variant),
 		    le16toh(ver->hw_revision),
 		    le16toh(ver->fw_revision),
 		    suffix);
 		break;
 
 	default:
 		fwname = NULL;
 	}
 
 	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
@@ -1,77 +1,148 @@
 /*-
  * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2013 Adrian Chadd <adrian@freebsd.org>
  * Copyright (c) 2019 Vladimir Kondratyev <wulf@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
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. 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 AUTHOR 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 AUTHOR 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.
  */
 
 #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;
 	uint8_t hw_variant;
 	uint8_t hw_revision;
 	uint8_t fw_variant;
 	uint8_t fw_revision;
 	uint8_t fw_build_num;
 	uint8_t fw_build_ww;
 	uint8_t fw_build_yy;
 	uint8_t fw_patch_num;
 } __attribute__ ((packed));
 
 struct iwmbt_boot_params {
 	uint8_t status;
 	uint8_t otp_format;
 	uint8_t otp_content;
 	uint8_t otp_patch;
 	uint16_t dev_revid;
 	uint8_t secure_boot;
 	uint8_t key_from_hdr;
 	uint8_t key_type;
 	uint8_t otp_lock;
 	uint8_t api_lock;
 	uint8_t debug_lock;
 	uint8_t otp_bdaddr[6];
 	uint8_t min_fw_build_nn;
 	uint8_t min_fw_build_cw;
 	uint8_t min_fw_build_yy;
 	uint8_t limited_cce;
 	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;
 	unsigned char *buf;
 };
 
 extern	int iwmbt_fw_read(struct iwmbt_firmware *fw, const char *fwname);
 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
@@ -1,601 +1,752 @@
 /*-
  * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2019 Vladimir Kondratyev <wulf@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
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. 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 AUTHOR 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 AUTHOR 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 <sys/param.h>
 #include <sys/endian.h>
 #include <sys/stat.h>
 
+#include <assert.h>
 #include <err.h>
 #include <errno.h>
 #include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
 #include <libusb.h>
 
 #include "iwmbt_fw.h"
 #include "iwmbt_hw.h"
 #include "iwmbt_dbg.h"
 
 #define	XMIN(x, y)	((x) < (y) ? (x) : (y))
 
 static int
 iwmbt_send_fragment(struct libusb_device_handle *hdl,
     uint8_t fragment_type, const void *data, uint8_t len, int timeout)
 {
 	int ret, transferred;
 	uint8_t buf[IWMBT_HCI_MAX_CMD_SIZE];
 	struct iwmbt_hci_cmd *cmd = (struct iwmbt_hci_cmd *) buf;
 
 	memset(buf, 0, sizeof(buf));
 	cmd->opcode = htole16(0xfc09),
 	cmd->length = len + 1,
 	cmd->data[0] = fragment_type;
 	memcpy(cmd->data + 1, data, len);
 
 	ret = libusb_bulk_transfer(hdl,
 	    IWMBT_BULK_OUT_ENDPOINT_ADDR,
 	    (uint8_t *)cmd,
 	    IWMBT_HCI_CMD_SIZE(cmd),
 	    &transferred,
 	    timeout);
 
 	if (ret < 0 || transferred != (int)IWMBT_HCI_CMD_SIZE(cmd)) {
 		iwmbt_err("libusb_bulk_transfer() failed: err=%s, size=%zu",
 		    libusb_strerror(ret),
 		    IWMBT_HCI_CMD_SIZE(cmd));
 		return (-1);
 	}
 
 	ret = libusb_bulk_transfer(hdl,
 	    IWMBT_BULK_IN_ENDPOINT_ADDR,
 	    buf,
 	    sizeof(buf),
 	    &transferred,
 	    timeout);
 
 	if (ret < 0) {
 		iwmbt_err("libusb_bulk_transfer() failed: err=%s",
 		    libusb_strerror(ret));
 		return (-1);
 	}
 
 	return (0);
 }
 
 static int
 iwmbt_hci_command(struct libusb_device_handle *hdl, struct iwmbt_hci_cmd *cmd,
     void *event, int size, int *transferred, int timeout)
 {
 	int ret;
 
 	ret = libusb_control_transfer(hdl,
 	    LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_DEVICE,
 	    0,
 	    0,
 	    0,
 	    (uint8_t *)cmd,
 	    IWMBT_HCI_CMD_SIZE(cmd),
 	    timeout);
 
 	if (ret < 0) {
 		iwmbt_err("libusb_control_transfer() failed: err=%s",
 		    libusb_strerror(ret));
 		return (ret);
 	}
 
 	ret = libusb_interrupt_transfer(hdl,
 	    IWMBT_INTERRUPT_ENDPOINT_ADDR,
 	    event,
 	    size,
 	    transferred,
 	    timeout);
 
 	if (ret < 0)
 		iwmbt_err("libusb_interrupt_transfer() failed: err=%s",
 		    libusb_strerror(ret));
 
 	return (ret);
 }
 
 int
 iwmbt_patch_fwfile(struct libusb_device_handle *hdl,
     const struct iwmbt_firmware *fw)
 {
 	int ret, transferred;
 	struct iwmbt_firmware fw_job = *fw;
 	uint16_t cmd_opcode;
 	uint8_t cmd_length;
 	struct iwmbt_hci_cmd *cmd_buf;
 	uint8_t evt_code;
 	uint8_t evt_length;
 	uint8_t evt_buf[IWMBT_HCI_MAX_EVENT_SIZE];
 	int activate_patch = 0;
 
 	while (fw_job.len > 0) {
 		if (fw_job.len < 4) {
 			iwmbt_err("Invalid firmware, unexpected EOF in HCI "
 			    "command header. Remains=%d", fw_job.len);
 			return (-1);
 		}
 
 		if (fw_job.buf[0] != 0x01) {
 			iwmbt_err("Invalid firmware, expected HCI command (%d)",
 					fw_job.buf[0]);
 			return (-1);
 		}
 
 		/* Advance by one. */
 		fw_job.buf++;
 		fw_job.len--;
 
 		/* Load in the HCI command to perform. */
 		cmd_opcode = le16dec(fw_job.buf);
 		cmd_length = fw_job.buf[2];
 		cmd_buf = (struct iwmbt_hci_cmd *)fw_job.buf;
 
 		iwmbt_debug("opcode=%04x, len=%02x", cmd_opcode, cmd_length);
 
 		/*
 		 * If there is a command that loads a patch in the
 		 * firmware file, then activate the patch upon success,
 		 * otherwise just disable the manufacturer mode.
 		 */
 		if (cmd_opcode == 0xfc8e)
 			activate_patch = 1;
 
 		/* Advance by three. */
 		fw_job.buf += 3;
 		fw_job.len -= 3;
 
 		if (fw_job.len < cmd_length) {
 			iwmbt_err("Invalid firmware, unexpected EOF in HCI "
 			    "command data. len=%d, remains=%d",
 			    cmd_length, fw_job.len);
 			return (-1);
 		}
 
 		/* Advance by data length. */
 		fw_job.buf += cmd_length;
 		fw_job.len -= cmd_length;
 
 		ret = libusb_control_transfer(hdl,
 		    LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_DEVICE,
 		    0,
 		    0,
 		    0,
 		    (uint8_t *)cmd_buf,
 		    IWMBT_HCI_CMD_SIZE(cmd_buf),
 		    IWMBT_HCI_CMD_TIMEOUT);
 
 		if (ret < 0) {
 			iwmbt_err("libusb_control_transfer() failed: err=%s",
 			    libusb_strerror(ret));
 			return (-1);
 		}
 
 		/*
 		 * Every command has its associated event: data must match
 		 * what is recorded in the firmware file. Perform that check
 		 * now.
 		 */
 
 		while (fw_job.len > 0 && fw_job.buf[0] == 0x02) {
 			/* Is this the end of the file? */
 			if (fw_job.len < 3) {
 				iwmbt_err("Invalid firmware, unexpected EOF in"
 				    "event header. remains=%d", fw_job.len);
 				return (-1);
 			}
 
 			/* Advance by one. */
 			fw_job.buf++;
 			fw_job.len--;
 
 			/* Load in the HCI event. */
 			evt_code = fw_job.buf[0];
 			evt_length = fw_job.buf[1];
 
 			/* Advance by two. */
 			fw_job.buf += 2;
 			fw_job.len -= 2;
 
 			/* Prepare HCI event buffer. */
 			memset(evt_buf, 0, IWMBT_HCI_MAX_EVENT_SIZE);
 
 			iwmbt_debug("event=%04x, len=%02x",
 					evt_code, evt_length);
 
 			if (fw_job.len < evt_length) {
 				iwmbt_err("Invalid firmware, unexpected EOF in"
 				    " event data. len=%d, remains=%d",
 				    evt_length, fw_job.len);
 				return (-1);
 			}
 
 			ret = libusb_interrupt_transfer(hdl,
 			    IWMBT_INTERRUPT_ENDPOINT_ADDR,
 			    evt_buf,
 			    IWMBT_HCI_MAX_EVENT_SIZE,
 			    &transferred,
 			    IWMBT_HCI_CMD_TIMEOUT);
 
 			if (ret < 0) {
 				iwmbt_err("libusb_interrupt_transfer() failed:"
 				    " err=%s", libusb_strerror(ret));
 				return (-1);
 			}
 
 			if ((int)evt_length + 2 != transferred ||
 			    memcmp(evt_buf + 2, fw_job.buf, evt_length) != 0) {
 				iwmbt_err("event does not match firmware");
 				return (-1);
 			}
 
 			/* Advance by data length. */
 			fw_job.buf += evt_length;
 			fw_job.len -= evt_length;
 		}
 	}
 
 	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);	\
 									\
 	ret = iwmbt_send_fragment(hdl,					\
 	    fragment_type,						\
 	    fw->buf + sent,						\
 	    XMIN(size, fw->len - sent),					\
 	    IWMBT_HCI_CMD_TIMEOUT);					\
 									\
 	if (ret < 0) {							\
 		iwmbt_debug("Failed to send "msg": code=%d", ret);	\
 		return (-1);						\
 	}								\
 	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");
 	IWMBT_SEND_FRAGMENT(0x03, 0x80, "public key / part 2");
 
 	/* skip 4 bytes */
 	sent += 4;
 
 	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
 	 */
 	while (fw->len - sent - ready >= (int) sizeof(struct iwmbt_hci_cmd)) {
 		cmd = (struct iwmbt_hci_cmd *)(fw->buf + sent + ready);
 		/* Parse firmware for Intel Reset HCI command parameter */
 		if (cmd->opcode == htole16(0xfc0e)) {
 			*boot_param = le32dec(cmd->data);
 			iwmbt_debug("boot_param=0x%08x", *boot_param);
 		}
 		ready += IWMBT_HCI_CMD_SIZE(cmd);
 		while (ready >= 0xFC) {
 			IWMBT_SEND_FRAGMENT(0x01, 0xFC, "firmware chunk");
 			ready -= 0xFC;
 		}
 		if (ready > 0 && ready % 4 == 0) {
 			IWMBT_SEND_FRAGMENT(0x01, ready, "firmware chunk");
 			ready = 0;
 		}
 	}
 
 	/* Wait for firmware download completion event */
 	ret = libusb_interrupt_transfer(hdl,
 	    IWMBT_INTERRUPT_ENDPOINT_ADDR,
 	    buf,
 	    sizeof(buf),
 	    &transferred,
 	    IWMBT_LOADCMPL_TIMEOUT);
 
 	if (ret < 0 || transferred < (int)sizeof(struct iwmbt_hci_event) + 1) {
 		iwmbt_err("libusb_interrupt_transfer() failed: "
 		    "err=%s, size=%d",
 		    libusb_strerror(ret),
 		    transferred);
 		return (-1);
 	}
 
 	/* Expect Vendor Specific Event 0x06 */
 	event = (struct iwmbt_hci_event *)buf;
 	if (event->header.event != 0xFF || event->data[0] != 0x06) {
 		iwmbt_err("firmware download completion event missed");
 		return (-1);
 	}
 
 	return (0);
 }
 
 int
 iwmbt_enter_manufacturer(struct libusb_device_handle *hdl)
 {
 	int ret, transferred;
 	static struct iwmbt_hci_cmd cmd = {
 		.opcode = htole16(0xfc11),
 		.length = 2,
 		.data = { 0x01, 0x00 },
 	};
 	uint8_t buf[IWMBT_HCI_MAX_EVENT_SIZE];
 
 	ret = iwmbt_hci_command(hdl,
 	    &cmd,
 	    buf,
 	    sizeof(buf),
 	    &transferred,
 	    IWMBT_HCI_CMD_TIMEOUT);
 
 	if (ret < 0) {
 		 iwmbt_debug("Can't enter manufacturer mode: code=%d, size=%d",
 		     ret,
 		     transferred);
 		 return (-1);
 	}
 
 	return (0);
 }
 
 int
 iwmbt_exit_manufacturer(struct libusb_device_handle *hdl, int mode)
 {
 	int ret, transferred;
 	static struct iwmbt_hci_cmd cmd = {
 		.opcode = htole16(0xfc11),
 		.length = 2,
 		.data = { 0x00, 0x00 },
 	};
 	uint8_t buf[IWMBT_HCI_MAX_EVENT_SIZE];
 
 	/*
 	 * The mode sets the type of reset we want to perform:
 	 * 0x00: simply exit manufacturer mode without a reset.
 	 * 0x01: exit manufacturer mode with a reset and patches disabled
 	 * 0x02: exit manufacturer mode with a reset and patches enabled
 	 */
 	if (mode > 2) {
 		iwmbt_debug("iwmbt_exit_manufacturer(): unknown mode (%d)",
 				mode);
 	}
 	cmd.data[1] = mode;
 
 	ret = iwmbt_hci_command(hdl,
 	    &cmd,
 	    buf,
 	    sizeof(buf),
 	    &transferred,
 	    IWMBT_HCI_CMD_TIMEOUT);
 
 	if (ret < 0) {
 		 iwmbt_debug("Can't exit manufacturer mode: code=%d, size=%d",
 		     ret,
 		     transferred);
 		 return (-1);
 	}
 
 	return (0);
 }
 
 int
 iwmbt_get_version(struct libusb_device_handle *hdl,
     struct iwmbt_version *version)
 {
 	int ret, transferred;
 	struct iwmbt_hci_event_cmd_compl*event;
 	struct iwmbt_hci_cmd cmd = {
 		.opcode = htole16(0xfc05),
 		.length = 0,
 	};
 	uint8_t buf[IWMBT_HCI_EVT_COMPL_SIZE(struct iwmbt_version)];
 
 	memset(buf, 0, sizeof(buf));
 
 	ret = iwmbt_hci_command(hdl,
 	    &cmd,
 	    buf,
 	    sizeof(buf),
 	    &transferred,
 	    IWMBT_HCI_CMD_TIMEOUT);
 
 	if (ret < 0 || transferred != sizeof(buf)) {
 		 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));
 
 	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)
 {
 	int ret, transferred = 0;
 	struct iwmbt_hci_event_cmd_compl *event;
 	struct iwmbt_hci_cmd cmd = {
 		.opcode = htole16(0xfc0d),
 		.length = 0,
 	};
 	uint8_t buf[IWMBT_HCI_EVT_COMPL_SIZE(struct iwmbt_boot_params)];
 
 	memset(buf, 0, sizeof(buf));
 
 	ret = iwmbt_hci_command(hdl,
 	    &cmd,
 	    buf,
 	    sizeof(buf),
 	    &transferred,
 	    IWMBT_HCI_CMD_TIMEOUT);
 
 	if (ret < 0 || transferred != sizeof(buf)) {
 		 iwmbt_debug("Can't get boot params: code=%d, size=%d",
 		     ret,
 		     transferred);
 		 return (-1);
 	}
 
 	event = (struct iwmbt_hci_event_cmd_compl *)buf;
 	memcpy(params, event->data, sizeof(struct iwmbt_boot_params));
 
 	return (0);
 }
 
 int
 iwmbt_intel_reset(struct libusb_device_handle *hdl, uint32_t boot_param)
 {
 	int ret, transferred = 0;
 	struct iwmbt_hci_event *event;
 	static struct iwmbt_hci_cmd cmd = {
 		.opcode = htole16(0xfc01),
 		.length = 8,
 		.data = { 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00 },
 	};
 	uint8_t buf[IWMBT_HCI_MAX_EVENT_SIZE];
 
 	le32enc(cmd.data + 4, boot_param);
 	memset(buf, 0, sizeof(buf));
 
 	ret = iwmbt_hci_command(hdl,
 	    &cmd,
 	    buf,
 	    sizeof(buf),
 	    &transferred,
 	    IWMBT_HCI_CMD_TIMEOUT);
 
 	if (ret < 0 || transferred < (int)sizeof(struct iwmbt_hci_event) + 1) {
 		 iwmbt_debug("Intel Reset command failed: code=%d, size=%d",
 		    ret,
 		    transferred);
 		 return (ret);
 	}
 
 	/* expect Vendor Specific Event 0x02 */
 	event = (struct iwmbt_hci_event *)buf;
 	if (event->header.event != 0xFF || event->data[0] != 0x02) {
 		iwmbt_err("Intel Reset completion event missed");
 		return (-1);
 	}
 
 	return (0);
 }
 
 int
 iwmbt_load_ddc(struct libusb_device_handle *hdl,
     const struct iwmbt_firmware *ddc)
 {
 	int size, sent = 0;
 	int ret, transferred;
 	uint8_t buf[IWMBT_HCI_MAX_CMD_SIZE];
 	struct iwmbt_hci_cmd *cmd = (struct iwmbt_hci_cmd *)buf;
 
 	size = ddc->len;
 
 	iwmbt_debug("file=%s, size=%d", ddc->fwname, size);
 
 	while (size > 0) {
 
 		memset(buf, 0, sizeof(buf));
 		cmd->opcode = htole16(0xfc8b);
 		cmd->length = ddc->buf[sent] + 1;
 		memcpy(cmd->data, ddc->buf + sent, XMIN(ddc->buf[sent], size));
 
 		iwmbt_debug("transferring %d bytes, offset %d",
 		    cmd->length,
 		    sent);
 
 		size -= cmd->length;
 		sent += cmd->length;
 
 		ret = iwmbt_hci_command(hdl,
 		    cmd,
 		    buf,
 		    sizeof(buf),
 		    &transferred,
 		    IWMBT_HCI_CMD_TIMEOUT);
 
 		if (ret < 0) {
 			 iwmbt_debug("Intel Write DDC failed: code=%d", ret);
 			 return (-1);
 		}
 	}
 
 	return (0);
 }
 
 int
 iwmbt_set_event_mask(struct libusb_device_handle *hdl)
 {
 	int ret, transferred = 0;
 	static struct iwmbt_hci_cmd cmd = {
 		.opcode = htole16(0xfc52),
 		.length = 8,
 		.data = { 0x87, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
 	};
 	uint8_t buf[IWMBT_HCI_MAX_EVENT_SIZE];
 
 	ret = iwmbt_hci_command(hdl,
 	    &cmd,
 	    buf,
 	    sizeof(buf),
 	    &transferred,
 	    IWMBT_HCI_CMD_TIMEOUT);
 
 	if (ret < 0)
 		 iwmbt_debug("Intel Set Event Mask failed: code=%d", ret);
 
 	return (ret);
 }
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
@@ -1,91 +1,101 @@
 /*-
  * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2019 Vladimir Kondratyev <wulf@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
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. 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 AUTHOR 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 AUTHOR 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.
  */
 #ifndef	__IWMBT_HW_H__
 #define	__IWMBT_HW_H__
 
 /* USB control request (HCI command) structure */
 struct iwmbt_hci_cmd {
 	uint16_t	opcode;
 	uint8_t		length;
 	uint8_t		data[];
 } __attribute__ ((packed));
 
 #define IWMBT_HCI_CMD_SIZE(cmd) \
 	((cmd)->length + offsetof(struct iwmbt_hci_cmd, data))
 
 /* USB interrupt transfer HCI event header structure */
 struct iwmbt_hci_evhdr {
 	uint8_t		event;
 	uint8_t		length;
 } __attribute__ ((packed));
 
 /* USB interrupt transfer (generic HCI event) structure */
 struct iwmbt_hci_event {
 	struct iwmbt_hci_evhdr	header;
 	uint8_t			data[];
 } __attribute__ ((packed));
 
 /* USB interrupt transfer (HCI command completion event) structure */
 struct iwmbt_hci_event_cmd_compl {
 	struct iwmbt_hci_evhdr	header;
 	uint8_t			numpkt;
 	uint16_t		opcode;
 	uint8_t			data[];
 } __attribute__ ((packed));
 
 #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
 #define	IWMBT_BULK_IN_ENDPOINT_ADDR	0x82
 #define	IWMBT_BULK_OUT_ENDPOINT_ADDR	0x02
 
 #define	IWMBT_HCI_MAX_CMD_SIZE		256
 #define	IWMBT_HCI_MAX_EVENT_SIZE	16
 
 #define	IWMBT_HCI_CMD_TIMEOUT		2000	/* ms */
 #define	IWMBT_LOADCMPL_TIMEOUT		5000	/* ms */
 
 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,
 	    uint32_t boot_param);
 extern	int iwmbt_load_ddc(struct libusb_device_handle *hdl,
 	    const struct iwmbt_firmware *ddc);
 extern	int iwmbt_set_event_mask(struct libusb_device_handle *hdl);
 
 #endif
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
@@ -1,101 +1,101 @@
 .\"-
 .\" SPDX-License-Identifier: BSD-2-Clause
 .\"
 .\" Copyright (c) 2013, 2016 Adrian Chadd <adrian@freebsd.org>
 .\" Copyright (c) 2019 Vladimir Kondratyev <wulf@FreeBSD.org>
 .\" Copyright (c) 2021 Philippe Michaud-Boudreault <pitwuu@gmail.com>
 .\"
 .\" Redistribution and use in source and binary forms, with or without
 .\" modification, are permitted provided that the following conditions
 .\" are met:
 .\" 1. Redistributions of source code must retain the above copyright
 .\"    notice, this list of conditions and the following disclaimer.
 .\" 2. 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 AUTHOR 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 AUTHOR 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.
 .\"
-.Dd May 31, 2024
+.Dd September 15, 2024
 .Dt IWMBTFW 8
 .Os
 .Sh NAME
 .Nm iwmbtfw
 .Nd download firmware for Intel Wireless AC Bluetooth USB devices
 .Sh SYNOPSIS
 .Nm
 .Op Fl DI
 .Fl d Ar device_name
 .Fl f Ar firmware_path
 .Nm
 .Fl h
 .Sh DESCRIPTION
 The
 .Nm
 utility downloads the specified firmware file to the specified
 .Xr ugen 4
 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
 .Pq Dv USB_VENDOR_INTEL2
 and the product ID should be one of the supported devices.
 .Pp
 Firmware files are available in the
 .Pa comms/iwmbt-firmware
 port.
 .Pp
 The
 .Nm
 utility will query the device to determine which firmware image and board
 configuration to load in at runtime.
 .Pp
 The options are as follows:
 .Bl -tag -width "-f firmware_path"
 .It Fl D
 Enable verbose debugging.
 .It Fl d Ar device_name
 Specify
 .Xr ugen 4
 device name.
 .It Fl f Ar firmware_path
 Specify the directory containing the firmware files to search and upload.
 .It Fl h
 Display usage message and exit.
 .It Fl I
 Enable informational debugging.
 .El
 .Sh EXIT STATUS
 .Ex -std
 .Sh SEE ALSO
 .Xr libusb 3 ,
 .Xr ugen 4 ,
 .Xr devd 8
 .Sh AUTHORS
 .Nm
 is based on
 .Xr ath3kfw 8
 utility used as firmware downloader template and on Linux btintel driver
 source code.
 It is written by
 .An Vladimir Kondratyev Aq Mt wulf@FreeBSD.org .
 .Pp
 Support for the 7260 card added by
 .An Philippe Michaud-Boudreault Aq Mt pitwuu@gmail.com .
 .Sh BUGS
 Most likely.
 Please report if found.
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
@@ -1,578 +1,763 @@
 /*-
  * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2013 Adrian Chadd <adrian@freebsd.org>
  * Copyright (c) 2019 Vladimir Kondratyev <wulf@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
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. 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 AUTHOR 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 AUTHOR 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 <sys/param.h>
 #include <sys/stat.h>
 #include <sys/endian.h>
 
 #include <err.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <libgen.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
 #include <libusb.h>
 
 #include "iwmbt_fw.h"
 #include "iwmbt_hw.h"
 #include "iwmbt_dbg.h"
 
 #define	_DEFAULT_IWMBT_FIRMWARE_PATH	"/usr/share/firmware/intel"
 
 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;
 
 	cnt = libusb_get_device_list(ctx, &list);
 	if (cnt < 0) {
 		iwmbt_err("libusb_get_device_list() failed: code %lld",
 		    (long long int) cnt);
 		return (NULL);
 	}
 
 	/*
 	 * Scan through USB device list.
 	 */
 	for (i = 0; i < cnt; i++) {
 		dev = list[i];
 		if (bus_id == libusb_get_bus_number(dev) &&
 		    dev_id == libusb_get_device_address(dev)) {
 			/* Get the device descriptor for this device entry */
 			r = libusb_get_device_descriptor(dev, &d);
 			if (r != 0) {
 				iwmbt_err("libusb_get_device_descriptor: %s",
 				    libusb_strerror(r));
 				break;
 			}
 
 			/* 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;
 			}
 		}
 	}
 
 	libusb_free_device_list(list, 1);
 	return (found);
 }
 
 static void
 iwmbt_dump_version(struct iwmbt_version *ver)
 {
 	iwmbt_info("status       0x%02x", ver->status);
 	iwmbt_info("hw_platform  0x%02x", ver->hw_platform);
 	iwmbt_info("hw_variant   0x%02x", ver->hw_variant);
 	iwmbt_info("hw_revision  0x%02x", ver->hw_revision);
 	iwmbt_info("fw_variant   0x%02x", ver->fw_variant);
 	iwmbt_info("fw_revision  0x%02x", ver->fw_revision);
 	iwmbt_info("fw_build_num 0x%02x", ver->fw_build_num);
 	iwmbt_info("fw_build_ww  0x%02x", ver->fw_build_ww);
 	iwmbt_info("fw_build_yy  0x%02x", ver->fw_build_yy);
 	iwmbt_info("fw_patch_num 0x%02x", ver->fw_patch_num);
 }
 
 static void
 iwmbt_dump_boot_params(struct iwmbt_boot_params *params)
 {
 	iwmbt_info("Device revision: %u", le16toh(params->dev_revid));
 	iwmbt_info("Secure Boot:  %s", params->secure_boot ? "on" : "off");
 	iwmbt_info("OTP lock:     %s", params->otp_lock    ? "on" : "off");
 	iwmbt_info("API lock:     %s", params->api_lock    ? "on" : "off");
 	iwmbt_info("Debug lock:   %s", params->debug_lock  ? "on" : "off");
 	iwmbt_info("Minimum firmware build %u week %u year %u",
 	    params->min_fw_build_nn,
 	    params->min_fw_build_cw,
 	    2000 + params->min_fw_build_yy);
 	iwmbt_info("OTC BD_ADDR:  %02x:%02x:%02x:%02x:%02x:%02x",
 	    params->otp_bdaddr[5],
 	    params->otp_bdaddr[4],
 	    params->otp_bdaddr[3],
 	    params->otp_bdaddr[2],
 	    params->otp_bdaddr[1],
 	    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)
 {
 	struct iwmbt_firmware fw;
 	int ret;
 
 	iwmbt_debug("loading %s", firmware_path);
 
 	/* Read in the firmware */
 	if (iwmbt_fw_read(&fw, firmware_path) <= 0) {
 		iwmbt_debug("iwmbt_fw_read() failed");
 		return (-1);
 	}
 
 	/* Load in the firmware */
 	ret = iwmbt_patch_fwfile(hdl, &fw);
 	if (ret < 0)
 		iwmbt_debug("Loading firmware file failed");
 
 	/* free it */
 	iwmbt_fw_free(&fw);
 
 	return (ret);
 }
 
 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);
 
 	/* Read in the firmware */
 	if (iwmbt_fw_read(&fw, firmware_path) <= 0) {
 		iwmbt_debug("iwmbt_fw_read() failed");
 		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);
 }
 
 static int
 iwmbt_init_ddc(libusb_device_handle *hdl, const char *ddc_path)
 {
 	struct iwmbt_firmware ddc;
 	int ret;
 
 	iwmbt_debug("loading %s", ddc_path);
 
 	/* Read in the DDC file */
 	if (iwmbt_fw_read(&ddc, ddc_path) <= 0) {
 		iwmbt_debug("iwmbt_fw_read() failed");
 		return (-1);
 	}
 
 	/* Load in the DDC file */
 	ret = iwmbt_load_ddc(hdl, &ddc);
 	if (ret < 0)
 		iwmbt_debug("Loading DDC file failed");
 
 	/* free it */
 	iwmbt_fw_free(&ddc);
 
 	return (ret);
 }
 
 /*
  * Parse ugen name and extract device's bus and address
  */
 
 static int
 parse_ugen_name(char const *ugen, uint8_t *bus, uint8_t *addr)
 {
 	char *ep;
 
 	if (strncmp(ugen, "ugen", 4) != 0)
 		return (-1);
 
 	*bus = (uint8_t) strtoul(ugen + 4, &ep, 10);
 	if (*ep != '.')
 		return (-1);
 
 	*addr = (uint8_t) strtoul(ep + 1, &ep, 10);
 	if (*ep != '\0')
 		return (-1);
 
 	return (0);
 }
 
 static void
 usage(void)
 {
 	fprintf(stderr,
 	    "Usage: iwmbtfw (-D) -d ugenX.Y (-f firmware path) (-I)\n");
 	fprintf(stderr, "    -D: enable debugging\n");
 	fprintf(stderr, "    -d: device to operate upon\n");
 	fprintf(stderr, "    -f: firmware path, if not default\n");
 	fprintf(stderr, "    -I: enable informational output\n");
 	exit(127);
 }
 
 int
 main(int argc, char *argv[])
 {
 	libusb_context *ctx = NULL;
 	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;
 	uint8_t bus_id = 0, dev_id = 0;
 	int devid_set = 0;
 	int n;
 	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) {
 		switch (n) {
 		case 'd': /* ugen device name */
 			devid_set = 1;
 			if (parse_ugen_name(optarg, &bus_id, &dev_id) < 0)
 				usage();
 			break;
 		case 'D':
 			iwmbt_do_debug = 1;
 			break;
 		case 'f': /* firmware dir */
 			if (firmware_dir)
 				free(firmware_dir);
 			firmware_dir = strdup(optarg);
 			break;
 		case 'I':
 			iwmbt_do_info = 1;
 			break;
 		case 'h':
 		default:
 			usage();
 			break;
 			/* NOT REACHED */
 		}
 	}
 
 	/* Ensure the devid was given! */
 	if (devid_set == 0) {
 		usage();
 		/* NOTREACHED */
 	}
 
 	/* libusb setup */
 	r = libusb_init(&ctx);
 	if (r != 0) {
 		iwmbt_err("libusb_init failed: code %d", r);
 		exit(127);
 	}
 
 	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;
 	}
 
 	/* XXX enforce that bInterfaceNumber is 0 */
 
 	/* XXX enforce the device/product id if they're non-zero */
 
 	/* Grab device handle */
 	r = libusb_open(dev, &hdl);
 	if (r != 0) {
 		iwmbt_err("libusb_open() failed: code %d", r);
 		goto shutdown;
 	}
 
 	/* Check if ng_ubt is attached */
 	r = libusb_kernel_driver_active(hdl, 0);
 	if (r < 0) {
 		iwmbt_err("libusb_kernel_driver_active() failed: code %d", r);
 		goto shutdown;
 	}
 	if (r > 0) {
 		iwmbt_info("Firmware has already been downloaded");
 		retcode = 0;
 		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) {
 			iwmbt_info("Firmware has already been downloaded");
 			retcode = 0;
 			goto reset;
 		}
 
 		/* Default the firmware path */
 		if (firmware_dir == NULL)
 			firmware_dir = strdup(_DEFAULT_IWMBT_FIRMWARE_PATH);
 
 		firmware_path = iwmbt_get_fwname(&ver, &params, firmware_dir, "bseq");
 		if (firmware_path == NULL)
 			goto shutdown;
 
 		iwmbt_debug("firmware_path = %s", firmware_path);
 
 		/* Enter manufacturer mode */
 		r = iwmbt_enter_manufacturer(hdl);
 		if (r < 0) {
 			iwmbt_debug("iwmbt_enter_manufacturer() failed code %d", r);
 			goto shutdown;
 		}
 
 		/* Download firmware and parse it for magic Intel Reset parameter */
 		r = iwmbt_patch_firmware(hdl, firmware_path);
 		free(firmware_path);
 		if (r < 0) {
 			(void)iwmbt_exit_manufacturer(hdl, 0x01);
 			goto shutdown;
 		}
 
 		iwmbt_info("Firmware download complete");
 
 		/* Exit manufacturer mode */
 		r = iwmbt_exit_manufacturer(hdl, r == 0 ? 0x00 : 0x02);
 		if (r < 0) {
 			iwmbt_debug("iwmbt_exit_manufacturer() failed code %d", r);
 			goto shutdown;
 		}
 
 		/* 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);
 
 		/* Set Intel Event mask */
 		if (iwmbt_enter_manufacturer(hdl) < 0)
 			goto reset;
 		r = iwmbt_set_event_mask(hdl);
 		if (r == 0)
 			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) {
 			iwmbt_info("Firmware has already been downloaded");
 			retcode = 0;
 			goto reset;
 		}
 
 		if (ver.fw_variant != 0x06){
 			iwmbt_err("unknown fw_variant 0x%02x", (int) ver.fw_variant);
 			goto shutdown;
 		}
 
 		/* Read Intel Secure Boot Params */
 		r = iwmbt_get_boot_params(hdl, &params);
 		if (r < 0) {
 			iwmbt_debug("iwmbt_get_boot_params() failed!");
 			goto shutdown;
 		}
 		iwmbt_dump_boot_params(&params);
 
 		/* Check if firmware fragments are ACKed with a cmd complete event */
 		if (params.limited_cce != 0x00) {
 			iwmbt_err("Unsupported Intel firmware loading method (%u)",
 			   params.limited_cce);
 			goto shutdown;
 		}
 
 		/* Default the firmware path */
 		if (firmware_dir == NULL)
 			firmware_dir = strdup(_DEFAULT_IWMBT_FIRMWARE_PATH);
 
 		firmware_path = iwmbt_get_fwname(&ver, &params, 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);
+		r = iwmbt_init_firmware(hdl, firmware_path, &boot_param, 0, 0);
 		free(firmware_path);
 		if (r < 0)
 			goto shutdown;
 
 		iwmbt_info("Firmware download complete");
 
 		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(&ver, &params, 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");
+
+	} 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:
 
 	/* Ask kernel driver to probe and attach device again */
 	r = libusb_reset_device(hdl);
 	if (r != 0)
 		iwmbt_err("libusb_reset_device() failed: %s",
 		    libusb_strerror(r));
 
 shutdown:
 
 	/* Shutdown */
 
 	if (hdl != NULL)
 		libusb_close(hdl);
 
 	if (dev != NULL)
 		libusb_unref_device(dev);
 
 	if (ctx != NULL)
 		libusb_exit(ctx);
 
 	if (retcode == 0)
 		iwmbt_info("Firmware download is successful!");
 	else
 		iwmbt_err("Firmware download failed!");
 
 	return (retcode);
 }