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

Sources/firmware-utils/src/mkzyxelzldfw.c

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  * Copyright (C) 2020 Vincent Wiemann <vw@derowe.com>
  4  *
  5  * This program is derived from ZyXEL's GPL U-Boot code.
  6  * Copyright (C) 2011-2011 ZyXEL Communications, Corp.
  7  */
  8 
  9 #define _POSIX_SOURCE
 10 #define _POSIX_C_SOURCE 199309L /* getopt */
 11 #include <stdio.h>
 12 #include <stdlib.h>
 13 #include <stdint.h>
 14 #include <time.h>
 15 #include <sys/stat.h>
 16 #include <sys/types.h>
 17 #include <string.h>
 18 #include <unistd.h>
 19 #include <netinet/in.h>
 20 #include <limits.h>
 21 #include "md5.h"
 22 
 23 #define ZYXEL_MAGIC     0xdeadbeaf
 24 #define MAX_MODELS      5
 25 #define CHECKSUM_SIZE   sizeof(uint32_t)
 26 #define MAX_FILES       32
 27 #define MAX_FILENAME    64
 28 
 29 #define DATE_SIZE       32
 30 #define REV_SIZE        32
 31 
 32 #define error(fmt, ...)                                                        \
 33         do {                                                                   \
 34                 printf("Error: " fmt, ##__VA_ARGS__);                          \
 35                 exit(1);                                                       \
 36         } while (0)
 37 
 38 enum {
 39         FILE_TYPE_BM = 1,
 40         FILE_TYPE_KERNEL,
 41         FILE_TYPE_CORE,
 42         FILE_TYPE_DB,
 43         FILE_TYPE_CONF,
 44         FILE_TYPE_WTP
 45 };
 46 
 47 struct file_type_tbl {
 48         int type;
 49         char *str;
 50 };
 51 
 52 struct file_type_tbl file_types[] = {
 53         { FILE_TYPE_BM, "bm" },     { FILE_TYPE_KERNEL, "kernel" },
 54         { FILE_TYPE_CORE, "core" }, { FILE_TYPE_DB, "db" },
 55         { FILE_TYPE_CONF, "conf", }, { FILE_TYPE_WTP, "wtp" }
 56 };
 57 static int FILE_TYPE_COUNT = sizeof(file_types) / sizeof(struct file_type_tbl);
 58 
 59 struct fw_header {
 60         uint32_t checksum; /* MD5-based checksum */
 61         uint32_t magic; /* 0xdeadbeaf */
 62         uint16_t version; /* version of the firmware archive */
 63         uint16_t files_count; /* number of files contained */
 64         uint16_t models_count; /* number of supported models */
 65         uint16_t models[MAX_MODELS]; /* supported models' IDs */
 66         uint32_t total_length; /* total length of the firmware archive */
 67         uint16_t files_offset; /* offset of the first file */
 68         uint16_t header_length; /* length of this header */
 69         uint16_t info_length; /* length of the file information header */
 70         uint16_t __padding1[3]; /* reserved for future use */
 71         char capwap_version[32]; /* e.g. "undefined" */
 72         char model_name[32]; /* e.g. "NWA512X-FAT" */
 73 } __attribute__((packed));
 74 
 75 struct fw_header_file {
 76         uint16_t type; /* file type (e.g. FILE_TYPE_KERNEL) */
 77         uint16_t flags; /* unknown */
 78         uint32_t length; /* length of the file */
 79         uint32_t checksum; /* checksum of the file */
 80         uint32_t flash_offset; /* write offset from beginning of flash */
 81         char filename[MAX_FILENAME]; /* original file name */
 82         char target[128]; /* target "file" name (e.g. "kernel", "zldfs") */
 83         char revision[REV_SIZE]; /* revision string */
 84         char date[32]; /* creation date string */
 85 } __attribute__((packed));
 86 
 87 struct fw_header_kernel {
 88         char bm_version[64];
 89         char kernel_version[64];
 90         char core_version[64];
 91         char capwap_version[32];
 92         char model_name[32];
 93         uint32_t bm_checksum;
 94         uint32_t kernel_checksum;
 95         uint32_t zld_checksum;
 96         uint32_t core_checksum;
 97         uint16_t max_models;
 98         uint16_t models[MAX_MODELS];
 99         char padding[512 - 64 * 4 - 4 * 4 - 2 - MAX_MODELS * 2 - 4];
100         uint32_t baudrate;
101 } __attribute__((packed));
102 
103 struct firmware_file {
104         struct fw_header_file header;
105         size_t offset;
106         char filepath[PATH_MAX];
107 };
108 
109 struct firmware {
110         struct fw_header header;
111         struct firmware_file *files;
112         size_t files_count;
113         struct fw_header_kernel kernel_header;
114         char lower_endian;
115 };
116 
117 static size_t get_file_size(FILE *fp)
118 {
119         size_t pos = (size_t)ftell(fp);
120         size_t file_size;
121 
122         fseek(fp, 0, SEEK_END);
123         file_size = (size_t)ftell(fp);
124         fseek(fp, (long int)pos, SEEK_SET);
125 
126         return file_size;
127 }
128 
129 static void copy_from_to_file(FILE *fp_src, size_t src_offset, FILE *fp_dst,
130                        size_t dst_offset, size_t length)
131 {
132         int buf[512];
133         size_t len;
134 
135         if (src_offset)
136                 fseek(fp_src, (long int)src_offset, SEEK_SET);
137 
138         if (dst_offset)
139                 fseek(fp_src, (long int)dst_offset, SEEK_SET);
140 
141         while (length) {
142                 if (length >= sizeof(buf)) {
143                         len = sizeof(buf);
144                 } else {
145                         len = length;
146                 }
147 
148                 length -= len;
149 
150                 if (fread(buf, len, 1, fp_src) != 1)
151                         error("Failed to read");
152 
153                 if (fwrite(buf, len, 1, fp_dst) != 1)
154                         error("Failed to write");
155         }
156 }
157 
158 static void extract_to_file(FILE *fp_src, char *dst, size_t length,
159                             size_t offset)
160 {
161         FILE *fp_dst;
162 
163         if (!(fp_dst = fopen(dst, "wb")))
164                 error("Failed to open %s for writing", dst);
165 
166         copy_from_to_file(fp_src, offset, fp_dst, 0, length);
167 
168         fclose(fp_dst);
169 }
170 
171 static void dump_firmware_header(struct fw_header *header_p)
172 {
173         int i;
174 
175         printf("FIRMWARE HEADER\n");
176         printf("checksum     =   0x%08x, magic          =   0x%08x\n",
177                header_p->checksum, header_p->magic);
178         printf("version      =       0x%04x, files_count    = %12d\n",
179                header_p->version, header_p->files_count);
180         printf("models_count = %12d, total_length   = %12d\n",
181                header_p->models_count, header_p->total_length);
182         printf("files_offset =       0x%04x, header_length  = %12d\n",
183                header_p->files_offset, header_p->header_length);
184         printf("info_length  = %12d, capwap_version = %12s\n",
185                header_p->info_length, header_p->capwap_version);
186         printf("model_name   = %s\n", header_p->model_name);
187         printf("models       =");
188         for (i = 0; i < header_p->models_count && i < MAX_MODELS; i++)
189                 printf(" 0x%04x", header_p->models[i]);
190         printf("\n\n");
191 }
192 
193 static int get_file_type_id(char *type)
194 {
195         struct file_type_tbl *ft = file_types;
196         int i;
197 
198         for (i = 0; i < FILE_TYPE_COUNT; i++, ft++)
199                 if (!strcmp(type, ft->str))
200                         return ft->type;
201 
202         printf("Supported file types:\n");
203         for (i = 0, ft = file_types; i < FILE_TYPE_COUNT; i++, ft++)
204                 printf("%8s (ID 0x%x)\n", ft->str, ft->type);
205 
206         error("Unknown file type \"%s\"\n", type);
207 
208         return 0;
209 }
210 
211 static char *get_file_type_string(int type)
212 {
213         struct file_type_tbl *ft = file_types;
214         int i;
215 
216         for (i = 0; i < FILE_TYPE_COUNT; i++, ft++)
217                 if (ft->type == type)
218                         return ft->str;
219 
220         return NULL;
221 }
222 
223 static void dump_file_header(struct fw_header_file *file_header)
224 {
225         printf("\nfilename=%s, type=%s, flags=0x%x target=%s, revision=%s\n",
226                file_header->filename, get_file_type_string(file_header->type),
227                file_header->flags, file_header->target, file_header->revision);
228         printf("date=%s, length=%u, checksum=0x%08x, flash_offset=0x%08x\n",
229                file_header->date, file_header->length, file_header->checksum,
230                file_header->flash_offset);
231 }
232 
233 static void dump_kernel_header(struct fw_header_kernel *kernel_header)
234 {
235         int i;
236 
237         printf("KERNEL HEADER (%lu bytes)\n", sizeof(struct fw_header_kernel));
238         printf("bm_version = %s\n", kernel_header->bm_version);
239         printf("kernel_version = %s\n", kernel_header->kernel_version);
240         printf("core_version = %s\n", kernel_header->core_version);
241         printf("capwap_version = %s\n", kernel_header->capwap_version);
242         printf("model_name = %s\n", kernel_header->model_name);
243         printf("bm_checksum = 0x%08x\n", kernel_header->bm_checksum);
244         printf("kernel_checksum = 0x%08x\n", kernel_header->kernel_checksum);
245         printf("zld_checksum = 0x%08x\n", kernel_header->zld_checksum);
246         printf("core_checksum = 0x%08x\n", kernel_header->core_checksum);
247         printf("max_models = %u\n", kernel_header->max_models);
248         printf("models =");
249         for (i = 0; i < 5; i++)
250                 printf(" 0x%04x", kernel_header->models[i]);
251         printf("\n");
252         printf("baudrate = %u\n", kernel_header->baudrate);
253         printf("\n");
254 }
255 
256 static void translate_fw_header(struct fw_header *header_p)
257 {
258         int i;
259 
260         header_p->magic = ntohl(header_p->magic);
261         header_p->version = ntohs(header_p->version);
262         header_p->files_count = ntohs(header_p->files_count);
263         header_p->models_count = ntohs(header_p->models_count);
264         for (i = 0; i < MAX_MODELS; i++)
265                 header_p->models[i] = ntohs(header_p->models[i]);
266         header_p->total_length = ntohl(header_p->total_length);
267         header_p->files_offset = ntohs(header_p->files_offset);
268         header_p->header_length = ntohs(header_p->header_length);
269         header_p->info_length = ntohs(header_p->info_length);
270 }
271 
272 static void translate_file_header(struct fw_header_file *file_header)
273 {
274         file_header->type = ntohs(file_header->type);
275         file_header->flags = ntohs(file_header->flags);
276         file_header->length = ntohl(file_header->length);
277         file_header->checksum = ntohl(file_header->checksum);
278         file_header->flash_offset = ntohl(file_header->flash_offset);
279 }
280 
281 static void translate_kernel_header(struct fw_header_kernel *kernel_header)
282 {
283         int i;
284 
285         kernel_header->bm_checksum = ntohl(kernel_header->bm_checksum);
286         kernel_header->kernel_checksum = ntohl(kernel_header->kernel_checksum);
287         /*kernel_header->zld_checksum = ntohl(kernel_header->zld_checksum);*/
288         kernel_header->core_checksum = ntohl(kernel_header->core_checksum);
289 
290         kernel_header->max_models = ntohs(kernel_header->max_models);
291         for (i = 0; i < MAX_MODELS; i++)
292                 kernel_header->models[i] = ntohs(kernel_header->models[i]);
293         kernel_header->baudrate = ntohl(kernel_header->baudrate);
294 }
295 
296 static void checksum_add_from_buf(MD5_CTX *ctx, void *buf,
297                             size_t length, size_t offset)
298 {
299         char *begin = &((char *)buf)[offset];
300 
301         MD5_Update(ctx, begin, length);
302 }
303 
304 static void checksum_add_from_file(MD5_CTX *ctx, FILE *fp_src,
305                             size_t length, size_t offset)
306 {
307         int buf[512];
308         size_t len;
309 
310         fseek(fp_src, (long int)offset, SEEK_SET);
311         while (length) {
312                 if (length >= sizeof(buf)) {
313                         len = sizeof(buf);
314                 } else {
315                         len = length;
316                 }
317 
318                 length -= len;
319 
320                 if (fread(buf, len, 1, fp_src) != 1)
321                         error("Failed to read for checksum calculation");
322 
323                 checksum_add_from_buf(ctx, buf, len, 0);
324         }
325 }
326 
327 static uint32_t checksum_finish(MD5_CTX *ctx)
328 {
329         unsigned char md5sum[16];
330         uint32_t checksum = 0;
331         int i;
332 
333         MD5_Final(md5sum, ctx);
334 
335         for (i = 0; i < 16; i += 4)
336                 checksum += ((uint32_t)md5sum[i] << 24 |
337                              (uint32_t)md5sum[i + 1] << 16 |
338                              (uint32_t)md5sum[i + 2] << 8 |
339                              (uint32_t)md5sum[i + 3]);
340 
341         if (checksum == 0)
342                 checksum = 1;
343 
344         return checksum;
345 }
346 
347 static uint32_t checksum_calculate(FILE *fp, size_t kernel_offset)
348 {
349         struct fw_header_kernel dummy;
350         MD5_CTX ctx;
351         size_t file_size;
352 
353         fseek(fp, 0, SEEK_SET);
354         file_size = get_file_size(fp);
355 
356         MD5_Init(&ctx);
357 
358         checksum_add_from_file(&ctx, fp, kernel_offset - CHECKSUM_SIZE,
359                                CHECKSUM_SIZE);
360 
361         /* use a zeroed out kernel version header */
362         memset(&dummy, 0, sizeof(dummy));
363         checksum_add_from_buf(&ctx, &dummy, sizeof(dummy), 0);
364 
365         checksum_add_from_file(&ctx, fp,
366                                file_size - kernel_offset - sizeof(dummy),
367                                kernel_offset + sizeof(dummy));
368 
369         return checksum_finish(&ctx);
370 }
371 
372 static uint32_t checksum_calculate_file(char *filename)
373 {
374         MD5_CTX ctx;
375         FILE *fp;
376         size_t file_size;
377 
378         if (!(fp = fopen(filename, "rb")))
379                 error("Failed to open %s for writing\n", filename);
380 
381         file_size = get_file_size(fp);
382 
383         MD5_Init(&ctx);
384 
385         checksum_add_from_file(&ctx, fp, file_size, 0);
386 
387         fclose(fp);
388 
389         return checksum_finish(&ctx);
390 }
391 
392 static void parse_firmware(struct firmware *fw, FILE *fp)
393 {
394         struct firmware_file *file;
395         size_t file_size, file_offset, kernel_offset;
396         uint32_t checksum = 0;
397         int i;
398 
399         if (!fw)
400                 error("Failed to allocate firmware struct\n");
401 
402         file_size = get_file_size(fp);
403 
404         if (file_size < sizeof(fw->header))
405                 error("File too small\n");
406 
407         if (1 != fread(&fw->header, sizeof(fw->header), 1, fp))
408                 error("Failed to read firmware header\n");
409 
410         if (ntohl(fw->header.magic) == ZYXEL_MAGIC) {
411                 fw->lower_endian = 1;
412                 translate_fw_header(&fw->header);
413         } else if (fw->header.magic != ZYXEL_MAGIC) {
414                 error("Unsupported magic. Expected 0x%x, but found 0x%x\n",
415                       ZYXEL_MAGIC, fw->header.magic);
416         }
417 
418         if (fw->header.models_count != MAX_MODELS)
419                 error("Wrong number of models. Expected %u, but found %u\n",
420                       MAX_MODELS, fw->header.models_count);
421 
422         dump_firmware_header(&fw->header);
423 
424         if (fw->header.total_length != file_size)
425                 error("File size does not match. Expected %lu, but found %u\n",
426                       file_size, fw->header.total_length);
427 
428         file_offset = sizeof(fw->header) +
429                       fw->header.files_count * sizeof(struct fw_header_file);
430 
431         if (file_offset != fw->header.files_offset)
432                 error("File offset does not match definition in header\n");
433 
434         if (file_size < file_offset)
435                 error("File too small for %u file headers\n",
436                       fw->header.files_count);
437 
438         if (NULL == (fw->files = malloc(fw->header.files_count *
439                                         sizeof(struct firmware_file))))
440                 error("Failed to allocate memory for %u file structs\n",
441                       fw->header.files_count);
442 
443         for (i = 0, file = fw->files; i < fw->header.files_count; i++, file++) {
444                 if (1 != fread(file, sizeof(struct fw_header_file), 1, fp))
445                         error("Failed to read file header #%u\n", i + 1);
446 
447                 if (fw->lower_endian)
448                         translate_file_header(&file->header);
449 
450                 if (file_offset + file->header.length > fw->header.total_length)
451                         error("File offset exceeds size of firmware archive\n");
452 
453                 if (file->header.type == FILE_TYPE_KERNEL)
454                         kernel_offset = file_offset;
455 
456                 file->offset = file_offset;
457 
458                 file_offset += file->header.length;
459         }
460 
461         if (!kernel_offset)
462                 error("Kernel image missing for checksum calculation\n");
463 
464         /* as we know the kernel offset, we can calculate the checksum
465          * as it must be excluded from checksum calculation */
466         checksum = checksum_calculate(fp, kernel_offset);
467 
468         if (fw->lower_endian)
469                 checksum = ntohl(checksum);
470 
471         if (checksum != fw->header.checksum)
472                 printf("WARN: Checksum mismatch. Calculated 0x%x\n", checksum);
473 
474         fseek(fp, (long int)kernel_offset, SEEK_SET);
475         if (1 != fread(&fw->kernel_header, sizeof(fw->kernel_header), 1, fp))
476                 error("Failed to read kernel header\n");
477 
478         if (fw->lower_endian)
479                 translate_kernel_header(&fw->kernel_header);
480 
481         dump_kernel_header(&fw->kernel_header);
482 }
483 
484 static void extract_firmware(struct firmware *fw, char *filename)
485 {
486         struct firmware_file *file;
487         FILE *fp;
488         int i;
489 
490         if (!(fp = fopen(filename, "rb")))
491                 error("Failed to open firmware archive for extraction %s\n",
492                       filename);
493 
494         parse_firmware(fw, fp);
495 
496         printf("Extracting files...");
497 
498         for (i = 0, file = fw->files; i < fw->header.files_count; i++, file++) {
499                 dump_file_header(&file->header);
500                 if (file->header.type == FILE_TYPE_KERNEL) {
501                         /* strip kernel header */
502                         extract_to_file(
503                                 fp, file->header.filename,
504                                 file->header.length -
505                                         sizeof(struct fw_header_kernel),
506                                 file->offset + sizeof(struct fw_header_kernel));
507                 } else {
508                         extract_to_file(fp, file->header.filename,
509                                         file->header.length, file->offset);
510                 }
511 
512                 printf("Calculated file checksum is 0x%08x\n",
513                        checksum_calculate_file(file->header.filename));
514         }
515 
516         free(fw->files);
517         fclose(fp);
518 }
519 
520 static void init_fw_header(struct firmware *fw)
521 {
522         int i;
523 
524         for (i = 0; i < MAX_MODELS; i++)
525                 fw->header.models[i] = 0xffff;
526 
527         fw->kernel_header.baudrate = 115200;
528         fw->kernel_header.max_models = MAX_MODELS;
529         /* ZyXEL messed up their code and included a 32 bit pointer */
530         fw->header.header_length = sizeof(fw->header) + 4;
531         fw->header.magic = ZYXEL_MAGIC;
532 }
533 
534 static void write_headers(FILE *fp, struct firmware *fw)
535 {
536         struct firmware_file *file;
537         unsigned int i;
538 
539         fseek(fp, 0, SEEK_SET);
540 
541         if (1 != fwrite(&fw->header, sizeof(fw->header), 1, fp))
542                 error("Failed to write firmware header\n");
543 
544         for (i = 0, file = fw->files; i < fw->files_count; i++, file++)
545                 if (1 !=
546                     fwrite(&file->header, sizeof(struct fw_header_file), 1, fp))
547                         error("Failed to write file header #%u\n", i + 1);
548 }
549 
550 static void usage(char *progname)
551 {
552         printf("Usage: %s\n"
553                "  For extraction:\n"
554                "    -e <file>           extract firmware <file>\n\n"
555                "  For creation:\n"
556                "    -v <version>        set hexadecimal firmware <version>\n"
557                "    -b <checksum>       set hexadecimal bootmanager <checksum>\n"
558                "    -c <version>        set capwap <version> string\n"
559                "    -m <model>          set <model> string\n"
560                "    -d <model_id>       set (up to %u) hexadecimal <model_id>\n"
561                "    (multiple input files)\n"
562                "     -i <file>          add input <file>\n"
563                "      -o <offset>       set hexadecimal flash offset for file\n"
564                "      -r <revision>     set revision string for file\n"
565                "      -t <type>         choose file <type>\n"
566                "      -x <target>       set (partition) <target> of file\n"
567                "    <output_filename>\n",
568                progname, MAX_MODELS);
569         exit(1);
570 }
571 
572 int main(int argc, char *argv[])
573 {
574         struct firmware fw;
575         struct firmware_file *file;
576         struct firmware_file *core_file = NULL;
577         struct stat attr;
578         static const char *optstr = "e:v:b:c:m:d:i:o:r:t:x:h";
579         const char *capwap_version = "undefined";
580         const char *separator = " | ";
581         char *filename;
582         FILE *fp_src, *fp_dst;
583         size_t kernel_offset = 0;
584         unsigned int i;
585         int opt;
586 
587         memset(&fw, 0, sizeof(fw));
588         init_fw_header(&fw);
589 
590         if (argc < 1)
591                 usage(argv[0]);
592 
593         opt = getopt(argc, argv, optstr);
594         if (opt == -1)
595                 usage(argv[0]);
596         while (opt != -1) {
597                 if (optarg == NULL)
598                         usage(argv[0]);
599 
600                 switch (opt) {
601                 case 'e':
602                         extract_firmware(&fw, optarg);
603                         exit(0);
604                 case 'v':
605                         fw.header.version = (uint16_t)strtol(optarg, NULL, 16);
606                         if (!fw.header.version)
607                                 error("Invalid version number\n");
608                         break;
609                 case 'b':
610                         fw.kernel_header.bm_checksum =
611                                 (uint32_t)strtol(optarg, NULL, 16);
612                         break;
613                 case 'c':
614                         strncpy(fw.header.capwap_version, optarg,
615                                 sizeof(fw.header.capwap_version) - 1);
616                         break;
617                 case 'm':
618                         strncpy(fw.header.model_name, optarg,
619                                 sizeof(fw.header.model_name) - 1);
620                         break;
621                 case 'd':
622                         if (fw.header.models_count == MAX_MODELS)
623                                 error("Max. number of supported models is %u\n",
624                                       MAX_MODELS);
625 
626                         fw.header.models[fw.header.models_count] =
627                                 (uint16_t)strtol(optarg, NULL, 16);
628                         fw.header.models_count++;
629                         break;
630                 case 'i':
631                         filename = optarg;
632 
633                         if (!fw.files &&
634                             NULL == (fw.files = malloc(
635                                              MAX_FILES *
636                                              sizeof(struct firmware_file))))
637                                 error("Failed to allocate %u file structs\n",
638                                       MAX_FILES);
639 
640                         if (fw.files_count == MAX_FILES)
641                                 error("Maximum number of files reached (%u)\n",
642                                       MAX_FILES);
643 
644                         if (stat(optarg, &attr))
645                                 error("Stat failed on %s\n", optarg);
646 
647                         strftime(fw.files[fw.files_count].header.date,
648                                  DATE_SIZE - 1, "%Y-%m-%d %H:%M:%S",
649                                  localtime(&attr.st_mtime));
650 
651                         strncpy(fw.files[fw.files_count].filepath, optarg,
652                                 PATH_MAX - 1);
653 
654                         filename = strrchr(optarg, '/');
655                         if (!filename)
656                                 filename = optarg;
657 
658                         strncpy(fw.files[fw.files_count].header.filename,
659                                 filename, MAX_FILENAME - 1);
660 
661                         fw.files_count++;
662                         break;
663                 case 'o':
664                         if (!fw.files_count)
665                                 error("Specify offset after filename\n");
666 
667                         fw.files[fw.files_count - 1].header.flash_offset =
668                                 (uint32_t)strtol(optarg, NULL, 16);
669                         break;
670                 case 'r':
671                         if (!fw.files_count)
672                                 error("Specify file revision after filename\n");
673 
674                         strncpy(fw.files[fw.files_count - 1].header.revision,
675                                 optarg, REV_SIZE - 1);
676                         break;
677                 case 't':
678                         if (!fw.files_count)
679                                 error("Specify file type after filename!\n");
680 
681                         fw.files[fw.files_count - 1].header.type =
682                                 get_file_type_id(optarg);
683                         break;
684                 case 'x':
685                         if (!fw.files_count)
686                                 error("Specify file target after filename!\n");
687                         strncpy(fw.files[fw.files_count - 1].header.target,
688                                 optarg, sizeof(fw.files[0].header.target) - 1);
689                         break;
690                 case 'h':
691                 default:
692                         usage(argv[0]);
693                 }
694 
695                 opt = getopt(argc, argv, optstr);
696         }
697 
698         if (!fw.header.models_count)
699                 error("Supported model IDs missing (option -d)\n");
700 
701         if (!fw.header.version)
702                 error("Version number missing (e.g. -v 0x100)\n");
703 
704         if (!fw.kernel_header.bm_checksum)
705                 error("Bootmanager checksum is missing (option -b)\n");
706 
707         if (!strlen(fw.header.model_name))
708                 error("Model name missing (option -m)\n");
709 
710         if (!strlen(fw.header.capwap_version))
711                 strncpy(fw.header.capwap_version, capwap_version,
712                         sizeof(fw.header.capwap_version) - 1);
713 
714         fw.header.models_count = MAX_MODELS;
715         fw.header.files_count = fw.files_count;
716         memcpy(fw.kernel_header.models, fw.header.models,
717                sizeof(fw.header.models));
718 
719         for (i = 0; i < fw.files_count; i++) {
720                 if (!fw.files[i].header.type)
721                         error("No file or type specified for file %s\n",
722                               fw.files[i].filepath);
723 
724                 if (!strlen(fw.files[i].header.target))
725                         error("Target missing for %s (e.g. -x zldfs)\n",
726                               fw.files[i].filepath);
727 
728                 if (!strlen(fw.files[i].header.revision))
729                         error("Revision missing for %s\n",
730                               fw.files[i].filepath);
731         }
732 
733         filename = argv[optind];
734         if (!(fp_dst = fopen(filename, "w+b")))
735                 error("Failed to open %s for writing\n", filename);
736 
737         write_headers(fp_dst, &fw);
738 
739         fw.header.info_length = sizeof(struct fw_header_file);
740         fw.header.files_offset =
741                 sizeof(fw.header) + fw.files_count * fw.header.info_length;
742         if ((size_t)ftell(fp_dst) != fw.header.files_offset)
743                 error("Oops. Something went wrong writing the file headers");
744 
745         fw.header.total_length = fw.header.files_offset;
746         for (i = 0, file = fw.files; i < fw.files_count; i++, file++) {
747                 file->header.checksum = checksum_calculate_file(file->filepath);
748 
749                 if (!(fp_src = fopen(file->filepath, "rb")))
750                         error("Failed to open %s for writing\n", filename);
751 
752                 file->offset = fw.header.total_length;
753 
754                 file->header.length = get_file_size(fp_src);
755 
756                 if (file->header.type == FILE_TYPE_KERNEL)
757                         if (1 != fwrite(&fw.kernel_header,
758                                         sizeof(fw.kernel_header), 1, fp_dst))
759                                 error("Failed to write kernel header\n");
760 
761                 copy_from_to_file(fp_src, 0, fp_dst, 0, file->header.length);
762 
763                 if (file->header.type == FILE_TYPE_KERNEL) {
764                         file->header.length += sizeof(fw.kernel_header);
765                         kernel_offset = file->offset;
766                         fw.kernel_header.kernel_checksum =
767                                 file->header.checksum;
768                         if (strlen(file->header.revision) + strlen(separator) +
769                                     strlen(file->header.date) >=
770                             sizeof(fw.kernel_header.kernel_version))
771                                 error("Kernel file revision too long\n");
772 
773                         strcat(fw.kernel_header.kernel_version,
774                                file->header.revision);
775                         strcat(fw.kernel_header.kernel_version, separator);
776                         strcat(fw.kernel_header.kernel_version,
777                                file->header.date);
778                 } else if (file->header.type == FILE_TYPE_CORE) {
779                         core_file = file;
780                 }
781 
782                 fw.header.total_length += file->header.length;
783 
784                 translate_file_header(&file->header);
785 
786                 fclose(fp_src);
787         }
788 
789         /* update headers with correct lengths and endianness */
790         translate_fw_header(&fw.header);
791 
792         write_headers(fp_dst, &fw);
793 
794         if (!kernel_offset)
795                 error("Kernel image needed for checksum calculation\n");
796 
797         /* update headers with correct checksum */
798         fw.header.checksum = htonl(checksum_calculate(fp_dst, kernel_offset));
799         fseek(fp_dst, 0, SEEK_SET);
800         fwrite(&fw.header.checksum, sizeof(fw.header.checksum), 1, fp_dst);
801 
802         fw.kernel_header.zld_checksum = fw.header.checksum;
803         strncpy(fw.kernel_header.model_name, fw.header.model_name,
804                 sizeof(fw.kernel_header.model_name) - 1);
805         strncpy(fw.kernel_header.capwap_version, fw.header.capwap_version,
806                 sizeof(fw.kernel_header.capwap_version) - 1);
807 
808         translate_kernel_header(&fw.kernel_header);
809 
810         if (core_file) {
811                 fw.kernel_header.core_checksum = core_file->header.checksum;
812 
813                 if (strlen(core_file->header.revision) + strlen(separator) +
814                             strlen(core_file->header.date) >=
815                     sizeof(fw.kernel_header.core_version))
816                         error("Core file revision string too long\n");
817 
818                 strcat(fw.kernel_header.core_version,
819                        core_file->header.revision);
820                 strcat(fw.kernel_header.core_version, separator);
821                 strcat(fw.kernel_header.core_version, core_file->header.date);
822         }
823 
824         fseek(fp_dst, (long int)kernel_offset, SEEK_SET);
825         fwrite(&fw.kernel_header, sizeof(fw.kernel_header), 1, fp_dst);
826 
827         fclose(fp_dst);
828 
829         exit(0);
830 }
831 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt