1 // SPDX-License-Identifier: GPL-2.0-only
3 * zytrx - add header to images for ZyXEL NR7101
5 * Based on add_header.c - partially based on OpenWrt's
8 * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
9 * Gabor Juhos <juhosg@openwrt.org>
10 * Copyright (C) 2021 Bjørn Mork <bjorn@mork.no>
22 #include <netinet/in.h>
25 #define BPB 8 /* bits/byte */
27 static uint32_t crc32
[1<<BPB
];
29 static void init_crc32(void)
31 const uint32_t poly
= ntohl(0x2083b8ed);
34 for (n
= 0; n
< 1<<BPB
; n
++) {
38 for (bit
= 0; bit
< BPB
; bit
++)
39 crc
= (crc
& 1) ? (poly
^ (crc
>> 1)) : (crc
>> 1);
44 static uint32_t crc32buf(const unsigned char *buf
, size_t len
)
46 uint32_t crc
= 0xFFFFFFFF;
48 for (; len
; len
--, buf
++)
49 crc
= crc32
[(uint8_t)crc
^ *buf
] ^ (crc
>> BPB
);
53 /* HDR0 reversed, to be stored as BE */
54 #define MAGIC 0x30524448 /* HDR0 reversed, to be stored as BE */
56 /* All numbers are stored as BE */
59 uint32_t len_h
; /* Length of this header */
60 uint32_t len_t
; /* Total length of file */
61 uint32_t crc32_p
; /* Bit inverted 32-bit CRC of image payload */
62 uint8_t verInt
[32]; /* String "5.0.0.0\n" zero padded */
63 uint8_t verExt
[32]; /* String "\n" zero padded */
64 uint32_t len_p
; /* Length of image payload */
65 uint8_t pad1
[12]; /* zero padding(?) */
66 uint8_t code
[164]; /* string "3 6035 122 0\n" zero padded */
67 uint8_t chipid
[8]; /* string "MT7621A" zero padded */
68 uint8_t boardid
[16]; /* string "NR7101" zero padded */
69 uint32_t modelid
; /* modelid as 4 BCD digits: 0x07010001 */
70 uint8_t pad2
[8]; /* zero padding(?) */
71 uint8_t swVersionInt
[32]; /* ZyXEL version string: "1.00(ABUV.0)D0" zero padded */
72 uint8_t swVersionExt
[32]; /* identical to swVersionInt */
73 uint8_t pad4
[4]; /* zero padding(?) */
74 uint32_t kernelChksum
; /* no idea how this is computed - reported but not validated */
75 uint8_t pad5
[4]; /* zero padding(?) */
76 uint32_t crc32_h
; /* Bit inverted 32-bit CRC of this header payload */
77 uint8_t pad6
[4]; /* zero padding(?) */
80 /* static?() field values of unknown meaning - maybe ove to board
81 * table when we know the significance
83 #define VER_INT "5.0.0.0\n"
85 #define CODE "3 6035 122 0\n"
86 #define KERNELCHKSUM 0x12345678
88 /* table of supported devices using this header format */
89 static struct board_t
{
94 { "MT7621A", "NR7101", 0x07010001 },
95 { "MT7621A", "LTE3301-PLUS", 0x03030001 },
99 static int find_board(struct zytrx_t
*h
, char *board
)
103 for (p
= boards
; p
->modelid
; p
++) {
104 if (strncmp((const char *)p
->boardid
, board
, sizeof(p
->boardid
)))
106 memcpy(h
->chipid
, p
->chipid
, sizeof(h
->chipid
));
107 memcpy(h
->boardid
, p
->boardid
, sizeof(h
->boardid
));
108 h
->modelid
= htonl(p
->modelid
);
114 static void usage(const char *name
)
118 fprintf(stderr
, "Usage:\n");
119 fprintf(stderr
, " %s -B <board> -v <versionstr> -i <file> [-o <outputfile>]\n\n", name
);
120 fprintf(stderr
, "Supported <board> values:\n");
121 for (p
= boards
; p
->modelid
; p
++)
122 fprintf(stderr
, "\t%-12s\n", p
->boardid
);
123 fprintf(stderr
, "\nExample:\n");
124 fprintf(stderr
, " %s -B %s -v foobar-1.0 -i my.img -o out.img\n\n", name
,
129 static void errexit(const char *msg
)
131 fprintf(stderr
, "ERR: %s: %s\n", msg
, errno
? strerror(errno
) : "unknown");
135 static void *map_input(const char *name
, size_t *len
)
141 fd
= open(name
, O_RDONLY
);
144 if (fstat(fd
, &stat
) < 0) {
149 mapped
= mmap(NULL
, stat
.st_size
, PROT_READ
, MAP_SHARED
, fd
, 0);
151 (void) munmap(mapped
, stat
.st_size
);
157 int main(int argc
, char **argv
)
159 int c
, fdout
= STDOUT_FILENO
;
160 void *input_file
= NULL
;
161 size_t file_len
, len
;
164 .magic
= htonl(MAGIC
),
165 .len_h
= htonl(sizeof(h
)),
169 .kernelChksum
= htonl(KERNELCHKSUM
),
172 while ((c
= getopt(argc
, argv
, "B:v:i:o:")) != -1) {
175 if (find_board(&h
, optarg
) < 0)
176 errexit("unsupported board");
179 len
= strlen(optarg
);
180 if (len
> sizeof(h
.swVersionInt
))
181 errexit("version string too long");
182 memcpy(h
.swVersionInt
, optarg
, len
);
183 memcpy(h
.swVersionExt
, optarg
, len
);
186 input_file
= map_input(optarg
, &file_len
);
191 fdout
= open(optarg
, O_WRONLY
| O_CREAT
, 0644);
200 /* required paremeters */
201 if (!input_file
|| !h
.modelid
|| !h
.swVersionInt
[0])
205 h
.len_t
= htonl(sizeof(h
) + file_len
);
206 h
.len_p
= htonl(file_len
);
210 crc
= crc32buf(input_file
, file_len
);
211 h
.crc32_p
= htonl(~crc
);
212 crc
= crc32buf((unsigned char *)&h
, sizeof(h
));
213 h
.crc32_h
= htonl(~crc
);
216 write(fdout
, &h
, sizeof(h
));
217 write(fdout
, input_file
, file_len
);
220 munmap(input_file
, file_len
);
221 if (fdout
!= STDOUT_FILENO
)