tplink-safeloader: add QNEW image detection
authorSander Vanheule <sander@svanheule.net>
Fri, 3 Feb 2023 22:03:23 +0000 (23:03 +0100)
committerSander Vanheule <sander@svanheule.net>
Sun, 12 Mar 2023 12:35:51 +0000 (13:35 +0100)
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@aboehler.at>
Signed-off-by: Sander Vanheule <sander@svanheule.net>
src/tplink-safeloader.c

index 693745704e875d0d8fa5a9bdfe904aca61890183..71dfe7910dbb536679386a35268941c664158b97 100644 (file)
@@ -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],