1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2020 Vincent Wiemann <vw@derowe.com>
5 * This program is derived from ZyXEL's GPL U-Boot code.
6 * Copyright (C) 2011-2011 ZyXEL Communications, Corp.
10 #define _POSIX_C_SOURCE 199309L /* getopt */
16 #include <sys/types.h>
19 #include <netinet/in.h>
20 #include <linux/limits.h>
23 #define ZYXEL_MAGIC 0xdeadbeaf
25 #define CHECKSUM_SIZE sizeof(uint32_t)
27 #define MAX_FILENAME 64
32 #define error(fmt, ...) \
34 printf("Error: " fmt, ##__VA_ARGS__); \
47 struct file_type_tbl
{
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" }
57 static int FILE_TYPE_COUNT
= sizeof(file_types
) / sizeof(struct file_type_tbl
);
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
));
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
));
87 struct fw_header_kernel
{
89 char kernel_version
[64];
90 char core_version
[64];
91 char capwap_version
[32];
94 uint32_t kernel_checksum
;
95 uint32_t zld_checksum
;
96 uint32_t core_checksum
;
98 uint16_t models
[MAX_MODELS
];
99 char padding
[512 - 64 * 4 - 4 * 4 - 2 - MAX_MODELS
* 2 - 4];
101 } __attribute__((packed
));
103 struct firmware_file
{
104 struct fw_header_file header
;
106 char filepath
[PATH_MAX
];
110 struct fw_header header
;
111 struct firmware_file
*files
;
113 struct fw_header_kernel kernel_header
;
117 static size_t get_file_size(FILE *fp
)
119 size_t pos
= (size_t)ftell(fp
);
122 fseek(fp
, 0, SEEK_END
);
123 file_size
= (size_t)ftell(fp
);
124 fseek(fp
, (long int)pos
, SEEK_SET
);
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
)
136 fseek(fp_src
, (long int)src_offset
, SEEK_SET
);
139 fseek(fp_src
, (long int)dst_offset
, SEEK_SET
);
142 if (length
>= sizeof(buf
)) {
150 if (fread(buf
, len
, 1, fp_src
) != 1)
151 error("Failed to read");
153 if (fwrite(buf
, len
, 1, fp_dst
) != 1)
154 error("Failed to write");
158 static void extract_to_file(FILE *fp_src
, char *dst
, size_t length
,
163 if (!(fp_dst
= fopen(dst
, "wb")))
164 error("Failed to open %s for writing", dst
);
166 copy_from_to_file(fp_src
, offset
, fp_dst
, 0, length
);
171 static void dump_firmware_header(struct fw_header
*header_p
)
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
);
188 for (i
= 0; i
< header_p
->models_count
&& i
< MAX_MODELS
; i
++)
189 printf(" 0x%04x", header_p
->models
[i
]);
193 static int get_file_type_id(char *type
)
195 struct file_type_tbl
*ft
= file_types
;
198 for (i
= 0; i
< FILE_TYPE_COUNT
; i
++, ft
++)
199 if (!strcmp(type
, ft
->str
))
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
);
206 error("Unknown file type \"%s\"\n", type
);
211 static char *get_file_type_string(int type
)
213 struct file_type_tbl
*ft
= file_types
;
216 for (i
= 0; i
< FILE_TYPE_COUNT
; i
++, ft
++)
217 if (ft
->type
== type
)
223 static void dump_file_header(struct fw_header_file
*file_header
)
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
);
233 static void dump_kernel_header(struct fw_header_kernel
*kernel_header
)
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
);
249 for (i
= 0; i
< 5; i
++)
250 printf(" 0x%04x", kernel_header
->models
[i
]);
252 printf("baudrate = %u\n", kernel_header
->baudrate
);
256 static void translate_fw_header(struct fw_header
*header_p
)
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
);
272 static void translate_file_header(struct fw_header_file
*file_header
)
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
);
281 static void translate_kernel_header(struct fw_header_kernel
*kernel_header
)
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
);
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
);
296 static void checksum_add_from_buf(MD5_CTX
*ctx
, void *buf
,
297 size_t length
, size_t offset
)
299 char *begin
= &((char *)buf
)[offset
];
301 MD5_Update(ctx
, begin
, length
);
304 static void checksum_add_from_file(MD5_CTX
*ctx
, FILE *fp_src
,
305 size_t length
, size_t offset
)
310 fseek(fp_src
, (long int)offset
, SEEK_SET
);
312 if (length
>= sizeof(buf
)) {
320 if (fread(buf
, len
, 1, fp_src
) != 1)
321 error("Failed to read for checksum calculation");
323 checksum_add_from_buf(ctx
, buf
, len
, 0);
327 static uint32_t checksum_finish(MD5_CTX
*ctx
)
329 unsigned char md5sum
[16];
330 uint32_t checksum
= 0;
333 MD5_Final(md5sum
, ctx
);
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]);
347 static uint32_t checksum_calculate(FILE *fp
, size_t kernel_offset
)
349 struct fw_header_kernel dummy
;
353 fseek(fp
, 0, SEEK_SET
);
354 file_size
= get_file_size(fp
);
358 checksum_add_from_file(&ctx
, fp
, kernel_offset
- CHECKSUM_SIZE
,
361 /* use a zeroed out kernel version header */
362 memset(&dummy
, 0, sizeof(dummy
));
363 checksum_add_from_buf(&ctx
, &dummy
, sizeof(dummy
), 0);
365 checksum_add_from_file(&ctx
, fp
,
366 file_size
- kernel_offset
- sizeof(dummy
),
367 kernel_offset
+ sizeof(dummy
));
369 return checksum_finish(&ctx
);
372 static uint32_t checksum_calculate_file(char *filename
)
378 if (!(fp
= fopen(filename
, "rb")))
379 error("Failed to open %s for writing\n", filename
);
381 file_size
= get_file_size(fp
);
385 checksum_add_from_file(&ctx
, fp
, file_size
, 0);
389 return checksum_finish(&ctx
);
392 static void parse_firmware(struct firmware
*fw
, FILE *fp
)
394 struct firmware_file
*file
;
395 size_t file_size
, file_offset
, kernel_offset
;
396 uint32_t checksum
= 0;
400 error("Failed to allocate firmware struct\n");
402 file_size
= get_file_size(fp
);
404 if (file_size
< sizeof(fw
->header
))
405 error("File too small\n");
407 if (1 != fread(&fw
->header
, sizeof(fw
->header
), 1, fp
))
408 error("Failed to read firmware header\n");
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
);
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
);
422 dump_firmware_header(&fw
->header
);
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
);
428 file_offset
= sizeof(fw
->header
) +
429 fw
->header
.files_count
* sizeof(struct fw_header_file
);
431 if (file_offset
!= fw
->header
.files_offset
)
432 error("File offset does not match definition in header\n");
434 if (file_size
< file_offset
)
435 error("File too small for %u file headers\n",
436 fw
->header
.files_count
);
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
);
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);
447 if (fw
->lower_endian
)
448 translate_file_header(&file
->header
);
450 if (file_offset
+ file
->header
.length
> fw
->header
.total_length
)
451 error("File offset exceeds size of firmware archive\n");
453 if (file
->header
.type
== FILE_TYPE_KERNEL
)
454 kernel_offset
= file_offset
;
456 file
->offset
= file_offset
;
458 file_offset
+= file
->header
.length
;
462 error("Kernel image missing for checksum calculation\n");
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
);
468 if (fw
->lower_endian
)
469 checksum
= ntohl(checksum
);
471 if (checksum
!= fw
->header
.checksum
)
472 printf("WARN: Checksum mismatch. Calculated 0x%x\n", checksum
);
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");
478 if (fw
->lower_endian
)
479 translate_kernel_header(&fw
->kernel_header
);
481 dump_kernel_header(&fw
->kernel_header
);
484 static void extract_firmware(struct firmware
*fw
, char *filename
)
486 struct firmware_file
*file
;
490 if (!(fp
= fopen(filename
, "rb")))
491 error("Failed to open firmware archive for extraction %s\n",
494 parse_firmware(fw
, fp
);
496 printf("Extracting files...");
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 */
503 fp
, file
->header
.filename
,
504 file
->header
.length
-
505 sizeof(struct fw_header_kernel
),
506 file
->offset
+ sizeof(struct fw_header_kernel
));
508 extract_to_file(fp
, file
->header
.filename
,
509 file
->header
.length
, file
->offset
);
512 printf("Calculated file checksum is 0x%08x\n",
513 checksum_calculate_file(file
->header
.filename
));
520 static void init_fw_header(struct firmware
*fw
)
524 for (i
= 0; i
< MAX_MODELS
; i
++)
525 fw
->header
.models
[i
] = 0xffff;
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
;
534 static void write_headers(FILE *fp
, struct firmware
*fw
)
536 struct firmware_file
*file
;
539 fseek(fp
, 0, SEEK_SET
);
541 if (1 != fwrite(&fw
->header
, sizeof(fw
->header
), 1, fp
))
542 error("Failed to write firmware header\n");
544 for (i
= 0, file
= fw
->files
; i
< fw
->files_count
; i
++, file
++)
546 fwrite(&file
->header
, sizeof(struct fw_header_file
), 1, fp
))
547 error("Failed to write file header #%u\n", i
+ 1);
550 static void usage(char *progname
)
554 " -e <file> extract firmware <file>\n\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
);
572 int main(int argc
, char *argv
[])
575 struct firmware_file
*file
;
576 struct firmware_file
*core_file
= NULL
;
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
= " | ";
582 FILE *fp_src
, *fp_dst
;
583 size_t kernel_offset
= 0;
587 memset(&fw
, 0, sizeof(fw
));
593 opt
= getopt(argc
, argv
, optstr
);
602 extract_firmware(&fw
, optarg
);
605 fw
.header
.version
= (uint16_t)strtol(optarg
, NULL
, 16);
606 if (!fw
.header
.version
)
607 error("Invalid version number\n");
610 fw
.kernel_header
.bm_checksum
=
611 (uint32_t)strtol(optarg
, NULL
, 16);
614 strncpy(fw
.header
.capwap_version
, optarg
,
615 sizeof(fw
.header
.capwap_version
) - 1);
618 strncpy(fw
.header
.model_name
, optarg
,
619 sizeof(fw
.header
.model_name
) - 1);
622 if (fw
.header
.models_count
== MAX_MODELS
)
623 error("Max. number of supported models is %u\n",
626 fw
.header
.models
[fw
.header
.models_count
] =
627 (uint16_t)strtol(optarg
, NULL
, 16);
628 fw
.header
.models_count
++;
634 NULL
== (fw
.files
= malloc(
636 sizeof(struct firmware_file
))))
637 error("Failed to allocate %u file structs\n",
640 if (fw
.files_count
== MAX_FILES
)
641 error("Maximum number of files reached (%u)\n",
644 if (stat(optarg
, &attr
))
645 error("Stat failed on %s\n", optarg
);
647 strftime(fw
.files
[fw
.files_count
].header
.date
,
648 DATE_SIZE
- 1, "%Y-%m-%d %H:%M:%S",
649 localtime(&attr
.st_mtime
));
651 strncpy(fw
.files
[fw
.files_count
].filepath
, optarg
,
654 filename
= strrchr(optarg
, '/');
658 strncpy(fw
.files
[fw
.files_count
].header
.filename
,
659 filename
, MAX_FILENAME
- 1);
665 error("Specify offset after filename\n");
667 fw
.files
[fw
.files_count
- 1].header
.flash_offset
=
668 (uint32_t)strtol(optarg
, NULL
, 16);
672 error("Specify file revision after filename\n");
674 strncpy(fw
.files
[fw
.files_count
- 1].header
.revision
,
675 optarg
, REV_SIZE
- 1);
679 error("Specify file type after filename!\n");
681 fw
.files
[fw
.files_count
- 1].header
.type
=
682 get_file_type_id(optarg
);
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);
695 opt
= getopt(argc
, argv
, optstr
);
698 if (!fw
.header
.models_count
)
699 error("Supported model IDs missing (option -d)\n");
701 if (!fw
.header
.version
)
702 error("Version number missing (e.g. -v 0x100)\n");
704 if (!fw
.kernel_header
.bm_checksum
)
705 error("Bootmanager checksum is missing (option -b)\n");
707 if (!strlen(fw
.header
.model_name
))
708 error("Model name missing (option -m)\n");
710 if (!strlen(fw
.header
.capwap_version
))
711 strncpy(fw
.header
.capwap_version
, capwap_version
,
712 sizeof(fw
.header
.capwap_version
) - 1);
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
));
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
);
724 if (!strlen(fw
.files
[i
].header
.target
))
725 error("Target missing for %s (e.g. -x zldfs)\n",
726 fw
.files
[i
].filepath
);
728 if (!strlen(fw
.files
[i
].header
.revision
))
729 error("Revision missing for %s\n",
730 fw
.files
[i
].filepath
);
733 filename
= argv
[optind
];
734 if (!(fp_dst
= fopen(filename
, "w+b")))
735 error("Failed to open %s for writing\n", filename
);
737 write_headers(fp_dst
, &fw
);
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");
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
);
749 if (!(fp_src
= fopen(file
->filepath
, "rb")))
750 error("Failed to open %s for writing\n", filename
);
752 file
->offset
= fw
.header
.total_length
;
754 file
->header
.length
= get_file_size(fp_src
);
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");
761 copy_from_to_file(fp_src
, 0, fp_dst
, 0, file
->header
.length
);
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");
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
,
778 } else if (file
->header
.type
== FILE_TYPE_CORE
) {
782 fw
.header
.total_length
+= file
->header
.length
;
784 translate_file_header(&file
->header
);
789 /* update headers with correct lengths and endianness */
790 translate_fw_header(&fw
.header
);
792 write_headers(fp_dst
, &fw
);
795 error("Kernel image needed for checksum calculation\n");
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
);
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);
808 translate_kernel_header(&fw
.kernel_header
);
811 fw
.kernel_header
.core_checksum
= core_file
->header
.checksum
;
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");
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
);
824 fseek(fp_dst
, (long int)kernel_offset
, SEEK_SET
);
825 fwrite(&fw
.kernel_header
, sizeof(fw
.kernel_header
), 1, fp_dst
);