Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F142723679
D50082.id154540.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
12 KB
Referenced Files
None
Subscribers
None
D50082.id154540.diff
View Options
diff --git a/usr.sbin/bluetooth/rtlbtfw/main.c b/usr.sbin/bluetooth/rtlbtfw/main.c
--- a/usr.sbin/bluetooth/rtlbtfw/main.c
+++ b/usr.sbin/bluetooth/rtlbtfw/main.c
@@ -76,7 +76,6 @@
{ .vendor_id = 0x04ca, .product_id = 0x4006 },
{ .vendor_id = 0x0cb8, .product_id = 0xc549 },
-#ifdef RTLBTFW_SUPPORTS_FW_V2
/* Realtek 8852CE Bluetooth devices */
{ .vendor_id = 0x04ca, .product_id = 0x4007 },
{ .vendor_id = 0x04c5, .product_id = 0x1675 },
@@ -84,7 +83,6 @@
{ .vendor_id = 0x13d3, .product_id = 0x3587 },
{ .vendor_id = 0x13d3, .product_id = 0x3586 },
{ .vendor_id = 0x13d3, .product_id = 0x3592 },
-#endif
/* Realtek 8852BE Bluetooth devices */
{ .vendor_id = 0x0cb8, .product_id = 0xc559 },
@@ -312,6 +310,7 @@
char *firmware_dir = NULL;
char *firmware_path = NULL;
char *config_path = NULL;
+ const char *fw_suffix;
int retcode = 1;
const struct rtlbt_id_table *ic;
uint8_t rom_version;
@@ -410,7 +409,8 @@
if (firmware_dir == NULL)
firmware_dir = strdup(_DEFAULT_RTLBT_FIRMWARE_PATH);
- firmware_path = rtlbt_get_fwname(ic->fw_name, firmware_dir, "_fw.bin");
+ fw_suffix = ic->fw_suffix == NULL ? "_fw.bin" : ic->fw_suffix;
+ firmware_path = rtlbt_get_fwname(ic->fw_name, firmware_dir, fw_suffix);
if (firmware_path == NULL)
goto shutdown;
@@ -449,7 +449,18 @@
rtlbt_debug("rom_version = %d", rom_version);
/* Load in the firmware */
- r = rtlbt_parse_fwfile_v1(&fw, rom_version);
+ if (fw_type == RTLBT_FW_TYPE_V2) {
+ uint8_t key_id, reg_val[2];
+ r = rtlbt_read_reg16(hdl, RTLBT_SEC_PROJ, reg_val);
+ if (r < 0) {
+ rtlbt_err("rtlbt_read_reg16() failed code %d", r);
+ goto shutdown;
+ }
+ key_id = reg_val[0];
+ rtlbt_debug("key_id = %d", key_id);
+ r = rtlbt_parse_fwfile_v2(&fw, rom_version, key_id);
+ } else
+ r = rtlbt_parse_fwfile_v1(&fw, rom_version);
if (r < 0) {
rtlbt_err("Parseing firmware file failed");
goto shutdown;
diff --git a/usr.sbin/bluetooth/rtlbtfw/rtlbt_fw.h b/usr.sbin/bluetooth/rtlbtfw/rtlbt_fw.h
--- a/usr.sbin/bluetooth/rtlbtfw/rtlbt_fw.h
+++ b/usr.sbin/bluetooth/rtlbtfw/rtlbt_fw.h
@@ -30,7 +30,8 @@
#ifndef __RTLBT_FW_H__
#define __RTLBT_FW_H__
-#include <stdbool.h>
+#include <sys/queue.h>
+#include <sys/queue_mergesort.h>
#define RTLBT_ROM_LMP_8703B 0x8703
#define RTLBT_ROM_LMP_8723A 0x1200
@@ -41,12 +42,14 @@
#define RTLBT_ROM_LMP_8852A 0x8852
#define RTLBT_ROM_LMP_8851B 0x8851
+#define RTLBT_PATCH_SNIPPETS 0x01
+#define RTLBT_PATCH_DUMMY_HEADER 0x02
+#define RTLBT_PATCH_SECURITY_HEADER 0x03
+
enum rtlbt_fw_type {
RTLBT_FW_TYPE_UNKNOWN,
RTLBT_FW_TYPE_V1,
-#ifdef RTLBTFW_SUPPORTS_FW_V2
RTLBT_FW_TYPE_V2,
-#endif
};
struct rtlbt_id_table {
@@ -58,6 +61,7 @@
#define RTLBT_IC_FLAG_CONFIG (1 << 1)
#define RTLBT_IC_FLAG_MSFT (2 << 1)
const char *fw_name;
+ const char *fw_suffix;
};
struct rtlbt_firmware {
@@ -66,6 +70,21 @@
unsigned char *buf;
};
+SLIST_HEAD(rtlbt_patch_list, rtlbt_patch_entry);
+
+struct rtlbt_patch_entry {
+ SLIST_ENTRY(rtlbt_patch_entry) next;
+ uint32_t opcode;
+ uint32_t len;
+ uint8_t prio;
+ uint8_t *data;
+};
+
+struct rtlbt_iov {
+ uint8_t *data;
+ uint32_t len;
+};
+
struct rtlbt_fw_header_v1 {
uint8_t signature[8];
uint32_t fw_version;
@@ -78,6 +97,32 @@
uint32_t num_sections;
} __attribute__ ((packed));
+struct rtlbt_section {
+ uint32_t opcode;
+ uint32_t len;
+ uint8_t data[];
+} __attribute__ ((packed));
+
+struct rtlbt_sec_hdr {
+ uint16_t num;
+ uint16_t reserved;
+} __attribute__ ((packed));
+
+struct rtlbt_subsec_hdr {
+ uint8_t eco;
+ uint8_t prio;
+ uint8_t cb[2];
+ uint32_t len;
+} __attribute__ ((packed));
+
+struct rtlbt_subsec_security_hdr {
+ uint8_t eco;
+ uint8_t prio;
+ uint8_t key_id;
+ uint8_t reserved;
+ uint32_t len;
+} __attribute__ ((packed));
+
int rtlbt_fw_read(struct rtlbt_firmware *fw, const char *fwname);
void rtlbt_fw_free(struct rtlbt_firmware *fw);
char *rtlbt_get_fwname(const char *fw_name, const char *prefix,
@@ -87,6 +132,8 @@
enum rtlbt_fw_type rtlbt_get_fw_type(struct rtlbt_firmware *fw,
uint16_t *fw_lmp_subversion);
int rtlbt_parse_fwfile_v1(struct rtlbt_firmware *fw, uint8_t rom_version);
+int rtlbt_parse_fwfile_v2(struct rtlbt_firmware *fw, uint8_t rom_version,
+ uint8_t reg_id);
int rtlbt_append_fwfile(struct rtlbt_firmware *fw, struct rtlbt_firmware *opt);
#endif
diff --git a/usr.sbin/bluetooth/rtlbtfw/rtlbt_fw.c b/usr.sbin/bluetooth/rtlbtfw/rtlbt_fw.c
--- a/usr.sbin/bluetooth/rtlbtfw/rtlbt_fw.c
+++ b/usr.sbin/bluetooth/rtlbtfw/rtlbt_fw.c
@@ -105,20 +105,19 @@
.hci_version = 0xb,
.flags = RTLBT_IC_FLAG_MSFT,
.fw_name = "rtl8852bu",
-#ifdef RTLBTFW_SUPPORTS_FW_V2
}, { /* 8852C */
.lmp_subversion = RTLBT_ROM_LMP_8852A,
.hci_revision = 0xc,
.hci_version = 0xc,
.flags = RTLBT_IC_FLAG_MSFT,
.fw_name = "rtl8852cu",
+ .fw_suffix = "_fw_v2.bin",
}, { /* 8851B */
.lmp_subversion = RTLBT_ROM_LMP_8851B,
.hci_revision = 0xb,
.hci_version = 0xc,
.flags = RTLBT_IC_FLAG_MSFT,
.fw_name = "rtl8851bu",
-#endif
},
};
@@ -144,10 +143,8 @@
/* Signatures */
static const uint8_t fw_header_sig_v1[8] =
{0x52, 0x65, 0x61, 0x6C, 0x74, 0x65, 0x63, 0x68}; /* Realtech */
-#ifdef RTLBTFW_SUPPORTS_FW_V2
static const uint8_t fw_header_sig_v2[8] =
{0x52, 0x54, 0x42, 0x54, 0x43, 0x6F, 0x72, 0x65}; /* RTBTCore */
-#endif
static const uint8_t fw_ext_sig[4] = {0x51, 0x04, 0xFD, 0x77};
int
@@ -260,12 +257,10 @@
fw_type = RTLBT_FW_TYPE_V1;
fw_header_len = sizeof(struct rtlbt_fw_header_v1);
} else
-#ifdef RTLBTFW_SUPPORTS_FW_V2
if (memcmp(fw->buf, fw_header_sig_v2, sizeof(fw_header_sig_v2)) == 0) {
fw_type = RTLBT_FW_TYPE_V2;
fw_header_len = sizeof(struct rtlbt_fw_header_v2);
} else
-#endif
return (RTLBT_FW_TYPE_UNKNOWN);
if (fw->len < fw_header_len + sizeof(fw_ext_sig) + 4) {
@@ -367,6 +362,194 @@
return (0);
}
+static void *
+rtlbt_iov_fetch(struct rtlbt_iov *iov, uint32_t len)
+{
+ void *data = NULL;
+
+ if (iov->len >= len) {
+ data = iov->data;
+ iov->data += len;
+ iov->len -= len;
+ }
+
+ return (data);
+}
+
+static int
+rtlbt_patch_entry_cmp(struct rtlbt_patch_entry *a, struct rtlbt_patch_entry *b,
+ void *thunk __unused)
+{
+ return ((a->prio > b->prio) - (a->prio < b->prio));
+}
+
+static int
+rtlbt_parse_section(struct rtlbt_patch_list *patch_list, uint32_t opcode,
+ uint8_t *data, uint32_t len, uint8_t rom_version, uint8_t key_id)
+{
+ struct rtlbt_sec_hdr *hdr;
+ struct rtlbt_patch_entry *entry;
+ struct rtlbt_subsec_hdr *subsec_hdr;
+ struct rtlbt_subsec_security_hdr *subsec_security_hdr;
+ uint16_t num_subsecs;
+ uint8_t *subsec_data;
+ uint32_t subsec_len;
+ int i, sec_len = 0;
+ struct rtlbt_iov iov = {
+ .data = data,
+ .len = len,
+ };
+
+ hdr = rtlbt_iov_fetch(&iov, sizeof(*hdr));
+ if (hdr == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+ num_subsecs = le16toh(hdr->num);
+
+ for (i = 0; i < num_subsecs; i++) {
+ subsec_hdr = rtlbt_iov_fetch(&iov, sizeof(*subsec_hdr));
+ if (subsec_hdr == NULL)
+ break;
+ subsec_len = le32toh(subsec_hdr->len);
+
+ rtlbt_debug("subsection, eco 0x%02x, prio 0x%02x, len 0x%x",
+ subsec_hdr->eco, subsec_hdr->prio, subsec_len);
+
+ subsec_data = rtlbt_iov_fetch(&iov, subsec_len);
+ if (subsec_data == NULL)
+ break;
+
+ if (subsec_hdr->eco == rom_version + 1) {
+ if (opcode == RTLBT_PATCH_SECURITY_HEADER) {
+ subsec_security_hdr = (void *)subsec_hdr;
+ if (subsec_security_hdr->key_id == key_id)
+ break;
+ continue;
+ }
+
+ entry = calloc(1, sizeof(*entry));
+ if (entry == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ *entry = (struct rtlbt_patch_entry) {
+ .opcode = opcode,
+ .len = subsec_len,
+ .prio = subsec_hdr->prio,
+ .data = subsec_data,
+ };
+ SLIST_INSERT_HEAD(patch_list, entry, next);
+ sec_len += subsec_len;
+ }
+ }
+
+ return (sec_len);
+}
+
+int
+rtlbt_parse_fwfile_v2(struct rtlbt_firmware *fw, uint8_t rom_version,
+ uint8_t key_id)
+{
+ struct rtlbt_fw_header_v2 *hdr;
+ struct rtlbt_section *section;
+ struct rtlbt_patch_entry *entry;
+ uint32_t num_sections;
+ uint32_t section_len;
+ uint32_t opcode;
+ int seclen, len = 0, patch_len = 0;
+ uint32_t i;
+ uint8_t *section_data, *patch_buf;
+ struct rtlbt_patch_list patch_list =
+ SLIST_HEAD_INITIALIZER(patch_list);
+ struct rtlbt_iov iov = {
+ .data = fw->buf,
+ .len = fw->len - 7,
+ };
+
+ hdr = rtlbt_iov_fetch(&iov, sizeof(*hdr));
+ if (hdr == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+ num_sections = le32toh(hdr->num_sections);
+
+ rtlbt_debug("FW version %02x%02x%02x%02x-%02x%02x%02x%02x",
+ hdr->fw_version[0], hdr->fw_version[1],
+ hdr->fw_version[2], hdr->fw_version[3],
+ hdr->fw_version[4], hdr->fw_version[5],
+ hdr->fw_version[6], hdr->fw_version[7]);
+
+ for (i = 0; i < num_sections; i++) {
+ section = rtlbt_iov_fetch(&iov, sizeof(*section));
+ if (section == NULL)
+ break;
+ section_len = le32toh(section->len);
+ opcode = le32toh(section->opcode);
+
+ rtlbt_debug("section, opcode 0x%08x", section->opcode);
+
+ section_data = rtlbt_iov_fetch(&iov, section_len);
+ if (section_data == NULL)
+ break;
+
+ seclen = 0;
+ switch (opcode) {
+ case RTLBT_PATCH_SECURITY_HEADER:
+ if (key_id == 0)
+ break;
+ /* FALLTHROUGH */
+ case RTLBT_PATCH_SNIPPETS:
+ case RTLBT_PATCH_DUMMY_HEADER:
+ seclen = rtlbt_parse_section(&patch_list, opcode,
+ section_data, section_len, rom_version, key_id);
+ break;
+ default:
+ break;
+ }
+ if (seclen < 0) {
+ rtlbt_err("Section parse (0x%08x) failed. err %d",
+ opcode, errno);
+ return (-1);
+ }
+ len += seclen;
+ }
+
+ if (len == 0) {
+ errno = ENOMSG;
+ return (-1);
+ }
+
+ patch_buf = calloc(1, len);
+ if (patch_buf == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ SLIST_MERGESORT(&patch_list, NULL,
+ rtlbt_patch_entry_cmp, rtlbt_patch_entry, next);
+ while (!SLIST_EMPTY(&patch_list)) {
+ entry = SLIST_FIRST(&patch_list);
+ rtlbt_debug("opcode 0x%08x, addr 0x%p, len 0x%x",
+ entry->opcode, entry->data, entry->len);
+ memcpy(patch_buf + patch_len, entry->data, entry->len);
+ patch_len += entry->len;
+ SLIST_REMOVE_HEAD(&patch_list, next);
+ free(entry);
+ }
+
+ if (patch_len == 0) {
+ errno = EPERM;
+ return (-1);
+ }
+
+ free(fw->buf);
+ fw->buf = patch_buf;
+ fw->len = patch_len;
+
+ return (0);
+}
+
int
rtlbt_append_fwfile(struct rtlbt_firmware *fw, struct rtlbt_firmware *opt)
{
diff --git a/usr.sbin/bluetooth/rtlbtfw/rtlbt_hw.h b/usr.sbin/bluetooth/rtlbtfw/rtlbt_hw.h
--- a/usr.sbin/bluetooth/rtlbtfw/rtlbt_hw.h
+++ b/usr.sbin/bluetooth/rtlbtfw/rtlbt_hw.h
@@ -95,9 +95,22 @@
uint8_t index;
} __attribute__ ((packed));
+/* Vendor USB request payload */
+struct rtlbt_vendor_cmd {
+ uint8_t data[5];
+} __attribute__ ((packed));
+#define RTLBT_SEC_PROJ (&(struct rtlbt_vendor_cmd) {{0x10, 0xA4, 0x0D, 0x00, 0xb0}})
+
+struct rtlbt_vendor_rp {
+ uint8_t status;
+ uint8_t data[2];
+};
+
int rtlbt_read_local_ver(struct libusb_device_handle *hdl,
ng_hci_read_local_ver_rp *ver);
int rtlbt_read_rom_ver(struct libusb_device_handle *hdl, uint8_t *ver);
+int rtlbt_read_reg16(struct libusb_device_handle *hdl,
+ struct rtlbt_vendor_cmd *cmd, uint8_t *resp);
int rtlbt_load_fwfile(struct libusb_device_handle *hdl,
const struct rtlbt_firmware *fw);
diff --git a/usr.sbin/bluetooth/rtlbtfw/rtlbt_hw.c b/usr.sbin/bluetooth/rtlbtfw/rtlbt_hw.c
--- a/usr.sbin/bluetooth/rtlbtfw/rtlbt_hw.c
+++ b/usr.sbin/bluetooth/rtlbtfw/rtlbt_hw.c
@@ -178,6 +178,41 @@
return (0);
}
+int
+rtlbt_read_reg16(struct libusb_device_handle *hdl,
+ struct rtlbt_vendor_cmd *vcmd, uint8_t *resp)
+{
+ int ret, transferred;
+ struct rtlbt_hci_event_cmd_compl *event;
+ uint8_t cmd_buf[offsetof(struct rtlbt_hci_cmd, data) + sizeof(*vcmd)];
+ struct rtlbt_hci_cmd *cmd = (struct rtlbt_hci_cmd *)cmd_buf;
+ cmd->opcode = htole16(0xfc61);
+ cmd->length = sizeof(struct rtlbt_vendor_cmd);
+ memcpy(cmd->data, vcmd, sizeof(struct rtlbt_vendor_cmd));
+ uint8_t buf[RTLBT_HCI_EVT_COMPL_SIZE(struct rtlbt_vendor_rp)];
+
+ memset(buf, 0, sizeof(buf));
+
+ ret = rtlbt_hci_command(hdl,
+ cmd,
+ buf,
+ sizeof(buf),
+ &transferred,
+ RTLBT_HCI_CMD_TIMEOUT);
+
+ if (ret < 0 || transferred != sizeof(buf)) {
+ rtlbt_debug("Can't read reg16: code=%d, size=%d",
+ ret,
+ transferred);
+ return (-1);
+ }
+
+ event = (struct rtlbt_hci_event_cmd_compl *)buf;
+ memcpy(resp, &(((struct rtlbt_vendor_rp *)event->data)->data), 2);
+
+ return (0);
+}
+
int
rtlbt_load_fwfile(struct libusb_device_handle *hdl,
const struct rtlbt_firmware *fw)
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Jan 23, 5:17 PM (55 m, 11 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27887981
Default Alt Text
D50082.id154540.diff (12 KB)
Attached To
Mode
D50082: rtlbtfw(8): Add support for firmware file format V2
Attached
Detach File
Event Timeline
Log In to Comment