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