• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/firmware-utils/src/mkh3cimg.c

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 
  3 #include <stdio.h>
  4 #include <string.h>
  5 #include <stdlib.h>
  6 #include <stdint.h>
  7 #include <sys/types.h>
  8 #include <unistd.h>
  9 #include <byteswap.h>
 10 #include <endian.h>
 11 #include <getopt.h>
 12 
 13 
 14 #if !defined(__BYTE_ORDER)
 15 #error "Unknown byte order"
 16 #endif
 17 
 18 #if __BYTE_ORDER == __BIG_ENDIAN
 19 #define cpu_to_be16(x)  (x)
 20 #define cpu_to_be32(x)  (x)
 21 #elif __BYTE_ORDER == __LITTLE_ENDIAN
 22 #define cpu_to_be16(x)  bswap_16(x)
 23 #define cpu_to_be32(x)  bswap_32(x)
 24 #else
 25 #error "Unsupported endianness"
 26 #endif
 27 
 28 
 29 #define IMAGE_VERSION            1
 30 #define FILE_VERSION             1
 31 #define FILE_DESCRIPTION         "OpenWrt"
 32 #define FILE_TYPE_MASK           0x1
 33 
 34 
 35 #define PACKAGE_FLAG             2
 36 
 37 #define FILE_TYPE_APPLICATION    0x04000000
 38 
 39 #define VERSION_OFFSET_INVALID   0xffffffff
 40 
 41 #define COMPRESSION_TYPE_NONE    0xffffffff
 42 #define COMPRESSION_TYPE_7Z      0x00000002
 43 
 44 
 45 struct file_header {
 46         uint8_t res1[4];
 47 
 48         uint32_t header_crc;
 49 
 50         uint32_t file_type;
 51         uint32_t version;
 52         uint32_t product_id;
 53         uint32_t device_id;
 54 
 55         uint32_t length_unpadded;
 56 
 57         uint32_t version_offset;
 58 
 59         uint16_t year;
 60         uint8_t month;
 61         uint8_t day;
 62         uint8_t res2[1];
 63         uint8_t hour;
 64         uint8_t minute;
 65         uint8_t second;
 66 
 67         uint8_t res3[64];
 68 
 69         char description[224];
 70 
 71         uint32_t length;
 72 
 73         uint32_t file_crc;
 74 
 75         uint32_t compression_type;
 76 } __attribute__ ((packed));
 77 
 78 struct file_desc {
 79         uint32_t file_type;
 80         uint32_t offset;
 81         uint32_t length;
 82         uint32_t file_crc;
 83         uint32_t version;
 84         uint32_t type_mask;
 85 } __attribute__ ((packed));
 86 
 87 struct image_header {
 88         uint32_t version;
 89 
 90         uint32_t file_count;
 91 
 92         uint32_t product_id;
 93         uint32_t device_id;
 94 
 95         uint16_t year;
 96         uint8_t month;
 97         uint8_t day;
 98         uint8_t res1[1];
 99         uint8_t hour;
100         uint8_t minute;
101         uint8_t second;
102 
103         uint16_t package_crc;
104         uint16_t package_flag;
105 
106         uint32_t length;
107 
108         struct file_desc files[128];
109 
110         /* RSA signature, not required */
111         uint8_t res2[3072];
112 
113         uint32_t header_crc;
114 } __attribute__ ((packed));
115 
116 
117 static void *buf;
118 static size_t buflen;
119 
120 static size_t length_unpadded;
121 static size_t length;
122 
123 
124 static uint32_t crc16_xmodem(char *buf, size_t len) {
125         uint32_t poly = 0x1021;
126         uint32_t crc = 0;
127         char b;
128         int i, j;
129 
130         for (i = 0; i < len; i++) {
131                 b = buf[i];
132                 crc = crc ^ (b << 8);
133 
134                 for (j = 0; j < 8; j++) {
135                         crc = crc << 1;
136                         if (crc & 0x10000) {
137                                 crc = (crc ^ poly) & 0xffff;
138                         }
139                 }
140         }
141 
142         return crc;
143 }
144 
145 static int create_buffer_and_read_file(char *filename) {
146         FILE *f;
147 
148         f = fopen(filename, "r");
149         if (f == NULL) {
150                 fprintf(stderr, "failed to open input file\n");
151                 goto err;
152         }
153 
154         fseek(f, 0L, SEEK_END);
155         length_unpadded = ftell(f);
156         rewind(f);
157 
158         length = length_unpadded;
159         if (length_unpadded % 8 != 0) {
160                 length += 8 - length_unpadded % 8;
161         }
162 
163         buflen = sizeof(struct file_header) + sizeof(struct image_header) + length;
164         buf = malloc(buflen);
165         if (!buf) {
166                 fprintf(stderr, "failed to allocate buffer\n");
167                 goto err_close;
168         }
169 
170         memset(buf, 0, buflen);
171 
172         if (fread(buf + sizeof(struct file_header) + sizeof(struct image_header), length_unpadded, 1, f) != 1) {
173                 fprintf(stderr, "failed to read input file\n");
174                 goto err_free;
175         }
176 
177         fclose(f);
178         return 0;
179 
180 err_free:
181         free(buf);
182 err_close:
183         fclose(f);
184 err:
185         return -1;
186 }
187 
188 static void build_file_header(uint32_t product_id, uint32_t device_id, uint32_t compression_type) {
189         struct file_header *header = buf + sizeof(struct image_header);
190         uint32_t crc;
191 
192         header->file_type = cpu_to_be32(FILE_TYPE_APPLICATION);
193 
194         header->version = cpu_to_be32(FILE_VERSION);
195 
196         header->product_id = cpu_to_be32(product_id);
197         header->device_id = cpu_to_be32(device_id);
198 
199         header->length_unpadded = cpu_to_be32(length_unpadded);
200 
201         header->version_offset = cpu_to_be32(VERSION_OFFSET_INVALID);
202 
203         header->year = cpu_to_be16(1970);
204         header->month = 1;
205         header->day = 1;
206         header->hour = 0;
207         header->minute = 0;
208         header->second = 0;
209 
210         snprintf(header->description, sizeof(header->description), "%s", FILE_DESCRIPTION);
211 
212         header->length = cpu_to_be32(length);
213 
214         crc = crc16_xmodem(buf + sizeof(struct image_header) + sizeof(struct file_header), length);
215         header->file_crc = cpu_to_be32(crc);
216 
217         header->compression_type = cpu_to_be32(compression_type);
218 
219         crc = crc16_xmodem((char *)header + sizeof(header->res1) + sizeof(header->header_crc),
220                 sizeof(struct file_header) - sizeof(header->res1) - sizeof(header->header_crc));
221         header->header_crc = cpu_to_be32(crc);
222 }
223 
224 static void build_image_header(uint32_t product_id, uint32_t device_id) {
225         struct image_header *header = buf;
226         struct file_header *file_header = buf + sizeof(struct image_header);
227         uint32_t crc;
228 
229         header->version = cpu_to_be32(IMAGE_VERSION);
230 
231         header->file_count = cpu_to_be32(1);
232 
233         header->product_id = cpu_to_be32(product_id);
234         header->device_id = cpu_to_be32(device_id);
235 
236         header->year = cpu_to_be16(1970);
237         header->month = 1;
238         header->day = 1;
239         header->hour = 0;
240         header->minute = 0;
241         header->second = 0;
242 
243         crc = crc16_xmodem(buf + sizeof(struct file_header), buflen - sizeof(struct file_header));
244         header->package_crc = cpu_to_be16(crc);
245         header->package_flag = cpu_to_be16(PACKAGE_FLAG);
246 
247         header->length = cpu_to_be32(buflen - sizeof(struct image_header));
248 
249         header->files[0].file_type = file_header->file_type;
250         header->files[0].offset = cpu_to_be32(sizeof(struct image_header));
251         header->files[0].length = cpu_to_be32(sizeof(struct file_header) + length);
252         header->files[0].file_crc = file_header->file_crc;
253         header->files[0].version = file_header->version;
254         header->files[0].type_mask = cpu_to_be32(FILE_TYPE_MASK);
255 
256         crc = crc16_xmodem((char *)header, sizeof(struct image_header) - sizeof(header->header_crc));
257         header->header_crc = cpu_to_be32(crc);
258 }
259 
260 static int write_output_file(char *filename) {
261         int ret = 0;
262         FILE *f;
263 
264         f = fopen(filename, "w");
265         if (f == NULL) {
266                 fprintf(stderr, "failed to open output file\n");
267                 ret = -1;
268                 goto err;
269         }
270 
271         if (fwrite(buf, buflen, 1, f) != 1) {
272                 fprintf(stderr, "failed to write output file\n");
273                 ret = -1;
274         }
275 
276         fclose(f);
277 
278 err:
279         return ret;
280 }
281 
282 static void usage(char* argv[]) {
283         printf("Usage: %s [OPTIONS...]\n"
284                "\n"
285                "Options:\n"
286                "  -p <product id>   product id (32-bit unsigned integer)\n"
287                "  -d <device id>    device id (32-bit unsigned integer)\n"
288                "  -c <compression>  compression type of the input file (7z or none)\n"
289                "                    (in case of 7z only LZMA compression is allowed)\n"
290                "  -i <file>         input filename\n"
291                "  -o <file>         output filename\n"
292                , argv[0]);
293 }
294 
295 int main(int argc, char* argv[]) {
296         int ret = EXIT_FAILURE;
297 
298         static uint32_t product_id = 0;
299         static uint32_t device_id = 0;
300         static uint32_t compression_type = COMPRESSION_TYPE_NONE;
301         static char *input_filename = NULL;
302         static char *output_filename = NULL;
303 
304         while ( 1 ) {
305                 int c;
306 
307                 c = getopt(argc, argv, "p:d:c:i:o:");
308                 if (c == -1)
309                         break;
310 
311                 switch (c) {
312                 case 'p':
313                         product_id = strtoul(optarg, NULL, 0);
314                         break;
315                 case 'd':
316                         device_id = strtoul(optarg, NULL, 0);
317                         break;
318                 case 'c':
319                         if (strcmp(optarg, "none") == 0) {
320                                 compression_type = COMPRESSION_TYPE_NONE;
321                         } else if (strcmp(optarg, "7z") == 0) {
322                                 compression_type = COMPRESSION_TYPE_7Z;
323                         } else {
324                                 usage(argv);
325                                 return EXIT_FAILURE;
326                         }
327                         break;
328                 case 'i':
329                         input_filename = optarg;
330                         break;
331                 case 'o':
332                         output_filename = optarg;
333                         break;
334                 default:
335                         usage(argv);
336                         goto err;
337                 }
338         }
339 
340         if (!product_id || !device_id ||
341                 !input_filename || strlen(input_filename) == 0 ||
342                 !output_filename || strlen(output_filename) == 0) {
343 
344                 usage(argv);
345                 goto err;
346         }
347 
348         if (create_buffer_and_read_file(input_filename)) {
349                 goto err;
350         }
351 
352         build_file_header(product_id, device_id, compression_type);
353 
354         build_image_header(product_id, device_id);
355 
356         if (write_output_file(output_filename)) {
357                 goto err_free;
358         }
359 
360         ret = EXIT_SUCCESS;
361 
362 err_free:
363         free(buf);
364 err:
365         return ret;
366 }
367 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt