[PATCH firmware-utils v1 09/10] tplink-safeloader: add QNEW image detection

Sander Vanheule sander at svanheule.net
Fri Feb 3 14:03:23 PST 2023


An incompatible image type is now used, e.g. for the TL-WPA8631P v4,
which has a header containing 0x3C extra bytes. This image type can be
identified by the first four bytes of the image header being "?NEW".

Only detection is implemented at this moment, as the full header format
is not yet understood, and the preamble checksum can no longer be
verified using the current md5sum salt. Devices still appear to accept
images in the "old" format, so image generation is not required at this
moment.

Cc: Andreas Böhler <dev at aboehler.at>
Signed-off-by: Sander Vanheule <sander at svanheule.net>
---
 src/tplink-safeloader.c | 28 ++++++++++++++++++++++++++--
 1 file changed, 26 insertions(+), 2 deletions(-)

diff --git a/src/tplink-safeloader.c b/src/tplink-safeloader.c
index 693745704e87..71dfe7910dbb 100644
--- a/src/tplink-safeloader.c
+++ b/src/tplink-safeloader.c
@@ -142,10 +142,18 @@ struct __attribute__((__packed__)) soft_version {
  *   Header contains up to 0x1000 bytes of vendor data, starting with a big endian
  *   UINT32 size, followed by that number of bytes containing (text) data.
  *   Padded with 0xFF. Payload starts at offset 0x1014.
+ *
+ * SAFELOADER_TYPE_QNEW
+ *   Reversed order preamble, with (apparent) md5 checksum before the image
+ *   size. The size does not include the preamble length.
+ *   Header starts with 0x3C bytes, starting with the string '?NEW' (format not
+ *   understood). Then another 0x1000 bytes follow, with the data payload
+ *   starting at 0x1050.
  */
 enum safeloader_image_type {
 	SAFELOADER_TYPE_DEFAULT,
 	SAFELOADER_TYPE_VENDOR,
+	SAFELOADER_TYPE_QNEW,
 };
 
 /* Internal representation of safeloader image data */
@@ -159,6 +167,10 @@ struct safeloader_image_info {
 #define SAFELOADER_HEADER_SIZE		0x1000
 #define SAFELOADER_PAYLOAD_OFFSET	(SAFELOADER_PREAMBLE_SIZE + SAFELOADER_HEADER_SIZE)
 
+#define SAFELOADER_QNEW_HEADER_SIZE	0x3C
+#define SAFELOADER_QNEW_PAYLOAD_OFFSET	\
+	(SAFELOADER_PREAMBLE_SIZE + SAFELOADER_QNEW_HEADER_SIZE + SAFELOADER_HEADER_SIZE)
+
 #define SAFELOADER_PAYLOAD_TABLE_SIZE	0x800
 
 static const uint8_t jffs2_eof_mark[4] = {0xde, 0xad, 0xc0, 0xde};
@@ -3846,6 +3858,8 @@ static void safeloader_read_partition(FILE *input_file, size_t payload_offset,
 
 static void safeloader_parse_image(FILE *input_file, struct safeloader_image_info *image)
 {
+	static const char *HEADER_ID_QNEW = "?NEW";
+
 	char buf[64];
 
 	if (!input_file)
@@ -3856,12 +3870,22 @@ static void safeloader_parse_image(FILE *input_file, struct safeloader_image_inf
 	if (fread(buf, sizeof(buf), 1, input_file) != 1)
 		error(1, errno, "Can not read image header");
 
-	if (ntohl(*((uint32_t *) &buf[0])) <= SAFELOADER_HEADER_SIZE)
+	if (memcmp(HEADER_ID_QNEW, &buf[0], strlen(HEADER_ID_QNEW)) == 0)
+		image->type = SAFELOADER_TYPE_QNEW;
+	else if (ntohl(*((uint32_t *) &buf[0])) <= SAFELOADER_HEADER_SIZE)
 		image->type = SAFELOADER_TYPE_VENDOR;
 	else
 		image->type = SAFELOADER_TYPE_DEFAULT;
 
-	image->payload_offset = SAFELOADER_PAYLOAD_OFFSET;
+	switch (image->type) {
+	case SAFELOADER_TYPE_DEFAULT:
+	case SAFELOADER_TYPE_VENDOR:
+		image->payload_offset = SAFELOADER_PAYLOAD_OFFSET;
+		break;
+	case SAFELOADER_TYPE_QNEW:
+		image->payload_offset = SAFELOADER_QNEW_PAYLOAD_OFFSET;
+		break;
+	}
 
 	/* Parse image partition table */
 	read_partition_table(input_file, image->payload_offset, &image->entries[0],
-- 
2.39.0




More information about the openwrt-devel mailing list