302efc601065cdbb79f0a9a0c2271819fe978888
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>
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License,
14 * version 2 as published by the Free Software Foundation.
26 #include <netinet/in.h>
29 #define BPB 8 /* bits/byte */
31 static uint32_t crc32
[1<<BPB
];
33 static void init_crc32(void)
35 const uint32_t poly
= ntohl(0x2083b8ed);
38 for (n
= 0; n
< 1<<BPB
; n
++) {
42 for (bit
= 0; bit
< BPB
; bit
++)
43 crc
= (crc
& 1) ? (poly
^ (crc
>> 1)) : (crc
>> 1);
48 static uint32_t crc32buf(const unsigned char *buf
, size_t len
)
50 uint32_t crc
= 0xFFFFFFFF;
52 for (; len
; len
--, buf
++)
53 crc
= crc32
[(uint8_t)crc
^ *buf
] ^ (crc
>> BPB
);
57 /* HDR0 reversed, to be stored as BE */
58 #define MAGIC 0x30524448 /* HDR0 reversed, to be stored as BE */
60 /* All numbers are stored as BE */
63 uint32_t len_h
; /* Length of this header */
64 uint32_t len_t
; /* Total length of file */
65 uint32_t crc32_p
; /* Bit inverted 32-bit CRC of image payload */
66 uint8_t verInt
[32]; /* String "5.0.0.0\n" zero padded */
67 uint8_t verExt
[32]; /* String "\n" zero padded */
68 uint32_t len_p
; /* Length of image payload */
69 uint8_t pad1
[12]; /* zero padding(?) */
70 uint8_t code
[164]; /* string "3 6035 122 0\n" zero padded */
71 uint8_t chipid
[8]; /* string "MT7621A" zero padded */
72 uint8_t boardid
[16]; /* string "NR7101" zero padded */
73 uint32_t modelid
; /* modelid as 4 BCD digits: 0x07010001 */
74 uint8_t pad2
[8]; /* zero padding(?) */
75 uint8_t swVersionInt
[32]; /* ZyXEL version string: "1.00(ABUV.0)D0" zero padded */
76 uint8_t swVersionExt
[32]; /* identical to swVersionInt */
77 uint8_t pad4
[4]; /* zero padding(?) */
78 uint32_t kernelChksum
; /* no idea how this is computed - reported but not validated */
79 uint8_t pad5
[4]; /* zero padding(?) */
80 uint32_t crc32_h
; /* Bit inverted 32-bit CRC of this header payload */
81 uint8_t pad6
[4]; /* zero padding(?) */
84 /* static?() field values of unknown meaning - maybe ove to board
85 * table when we know the significance
87 #define VER_INT "5.0.0.0\n"
89 #define CODE "3 6035 122 0\n"
90 #define KERNELCHKSUM 0x12345678
92 /* table of supported devices using this header format */
93 static struct board_t
{
98 { "MT7621A", "NR7101", 0x07010001 },
102 static int find_board(struct zytrx_t
*h
, char *board
)
106 for (p
= boards
; p
->modelid
; p
++) {
107 if (strncmp((const char *)p
->boardid
, board
, sizeof(p
->boardid
)))
109 memcpy(h
->chipid
, p
->chipid
, sizeof(h
->chipid
));
110 memcpy(h
->boardid
, p
->boardid
, sizeof(h
->boardid
));
111 h
->modelid
= htonl(p
->modelid
);
117 static void usage(const char *name
)
121 fprintf(stderr
, "Usage:\n");
122 fprintf(stderr
, " %s -B <board> -v <versionstr> -i <file> [-o <outputfile>]\n\n", name
);
123 fprintf(stderr
, "Supported <board> values:\n");
124 for (p
= boards
; p
->modelid
; p
++)
125 fprintf(stderr
, "\t%-12s\n", p
->boardid
);
126 fprintf(stderr
, "\nExample:\n");
127 fprintf(stderr
, " %s -B %s -v foobar-1.0 -i my.img -o out.img\n\n", name
,
132 static void errexit(const char *msg
)
134 fprintf(stderr
, "ERR: %s: %s\n", msg
, errno
? strerror(errno
) : "unknown");
138 static void *map_input(const char *name
, size_t *len
)
144 fd
= open(name
, O_RDONLY
);
147 if (fstat(fd
, &stat
) < 0) {
152 mapped
= mmap(NULL
, stat
.st_size
, PROT_READ
, MAP_SHARED
, fd
, 0);
158 int main(int argc
, char **argv
)
160 int c
, fdout
= STDOUT_FILENO
;
161 void *input_file
= NULL
;
162 size_t file_len
, len
;
165 .magic
= htonl(MAGIC
),
166 .len_h
= htonl(sizeof(h
)),
170 .kernelChksum
= htonl(KERNELCHKSUM
),
173 while ((c
= getopt(argc
, argv
, "B:v:i:o:")) != -1) {
176 if (find_board(&h
, optarg
) < 0)
177 errexit("unsupported board");
180 len
= strlen(optarg
);
181 if (len
> sizeof(h
.swVersionInt
))
182 errexit("version string too long");
183 memcpy(h
.swVersionInt
, optarg
, len
);
184 memcpy(h
.swVersionExt
, optarg
, len
);
187 input_file
= map_input(optarg
, &file_len
);
192 fdout
= open(optarg
, O_WRONLY
| O_CREAT
, 0644);
201 /* required paremeters */
202 if (!input_file
|| !h
.modelid
|| !h
.swVersionInt
[0])
206 h
.len_t
= htonl(sizeof(h
) + file_len
);
207 h
.len_p
= htonl(file_len
);
211 crc
= crc32buf(input_file
, file_len
);
212 h
.crc32_p
= htonl(~crc
);
213 crc
= crc32buf((unsigned char *)&h
, sizeof(h
));
214 h
.crc32_h
= htonl(~crc
);
217 write(fdout
, &h
, sizeof(h
));
218 write(fdout
, input_file
, file_len
);
221 munmap(input_file
, file_len
);
222 if (fdout
!= STDOUT_FILENO
)