mtd: Make fixwrgg command work on DIR-685
authorLinus Walleij <linus.walleij@linaro.org>
Wed, 15 May 2019 20:37:25 +0000 (22:37 +0200)
committerChristian Lamparter <chunkeey@gmail.com>
Sat, 18 May 2019 14:37:30 +0000 (16:37 +0200)
The D-Link DIR-685 has the same problem as the
D-Link DAP-2695: when flashing the factory image, the
checksum includes the whole flashed image, even the
rootfs_data part with the end of filesystem mark.
Also the whole flashed image is stored in the flash,
so on the first boot, the whole rootfs image is loaded
into memory with the kernel.

This is fixed using the fixwrgg command to mtd, but
for this to work we need to make fixwrgg work with
the Little-Endian ARM DIR-685.

The code tries to be endian agnostic but this fails
because the WRGG image loader doesn't. On ARM, the
file size is stored in little endian format, and on
big-endian systems it is stored in big endian format,
so we can just drop all the friendly htonl() that
will make the shdr->size big endian: this will
actually break the little endian systems, and on
the big endian systems the native endianness will
still be correct.

The magic number is always stored in little endian
format however, so make sure this is always read
in LE32 format. I chose to create a straight-forward
le32_to_cpu() static inline that IMO is simple and
easy to read.

Cc: Stijn Tintel <stijn@linux-ipv6.be>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
package/system/mtd/src/wrgg.c

index e0b5ca172d12822b1d18c725f4c661e7d2caad2a..c62f9f5507363508954d4ad6a84e256f2c2d4cf4 100644 (file)
 #include "wrgg.h"
 #include "md5.h"
 
 #include "wrgg.h"
 #include "md5.h"
 
-#if __BYTE_ORDER == __BIG_ENDIAN
-#define STORE32_LE(X)           ((((X) & 0x000000FF) << 24) | (((X) & 0x0000FF00) << 8) | (((X) & 0x00FF0000) >> 8) | (((X) & 0xFF000000) >> 24))
-#elif __BYTE_ORDER == __LITTLE_ENDIAN
-#define STORE32_LE(X)           (X)
-#else
-#error unknown endianness!
-#endif
+static inline uint32_t le32_to_cpu(uint8_t *buf)
+{
+       return buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24;
+}
 
 ssize_t pread(int fd, void *buf, size_t count, off_t offset);
 ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);
 
 ssize_t pread(int fd, void *buf, size_t count, off_t offset);
 ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);
@@ -94,7 +91,7 @@ wrgg_fix_md5(struct wrgg03_header *shdr, int fd, size_t data_offset, size_t data
        }
 
        /* update the size in the image */
        }
 
        /* update the size in the image */
-       shdr->size = htonl(data_size);
+       shdr->size = data_size;
 
        /* update the checksum in the image */
        memcpy(shdr->digest, digest, sizeof(digest));
 
        /* update the checksum in the image */
        memcpy(shdr->digest, digest, sizeof(digest));
@@ -147,12 +144,14 @@ mtd_fixwrgg(const char *mtd, size_t offset, size_t data_size)
        }
 
        shdr = (struct wrgg03_header *)(first_block + offset);
        }
 
        shdr = (struct wrgg03_header *)(first_block + offset);
-       if (shdr->magic1 != htonl(STORE32_LE(WRGG03_MAGIC))) {
-               fprintf(stderr, "magic1 %x\n", shdr->magic1);
-               fprintf(stderr, "htonl(WRGG03_MAGIC) %x\n", WRGG03_MAGIC);
+
+       /* The magic is always stored in little-endian byte order */
+       if (le32_to_cpu((uint8_t *)&shdr->magic1) != WRGG03_MAGIC) {
+               fprintf(stderr, "magic1 = %x\n", shdr->magic1);
+               fprintf(stderr, "WRGG03_MAGIC = %x\n", WRGG03_MAGIC);
                fprintf(stderr, "No WRGG header found\n");
                exit(1);
                fprintf(stderr, "No WRGG header found\n");
                exit(1);
-       } else if (!ntohl(shdr->size)) {
+       } else if (!shdr->size) {
                fprintf(stderr, "WRGG entity with empty image\n");
                exit(1);
        }
                fprintf(stderr, "WRGG entity with empty image\n");
                exit(1);
        }
@@ -160,8 +159,8 @@ mtd_fixwrgg(const char *mtd, size_t offset, size_t data_size)
        data_offset = offset + sizeof(struct wrgg03_header);
        if (!data_size)
                data_size = mtdsize - data_offset;
        data_offset = offset + sizeof(struct wrgg03_header);
        if (!data_size)
                data_size = mtdsize - data_offset;
-       if (data_size > ntohl(shdr->size))
-               data_size = ntohl(shdr->size);
+       if (data_size > shdr->size)
+               data_size = shdr->size;
        if (wrgg_fix_md5(shdr, fd, data_offset, data_size))
                goto out;
 
        if (wrgg_fix_md5(shdr, fd, data_offset, data_size))
                goto out;