1 // SPDX-License-Identifier: GPL-2.0-or-later OR MIT 2 /* 3 * Luxul's firmware container format 4 * 5 * Copyright 2020 Legrand AV Inc. 6 */ 7 8 #define _GNU_SOURCE 9 10 #include <byteswap.h> 11 #include <endian.h> 12 #include <errno.h> 13 #include <libgen.h> 14 #include <stddef.h> 15 #include <stdint.h> 16 #include <stdio.h> 17 #include <stdlib.h> 18 #include <string.h> 19 #include <unistd.h> 20 21 #if __BYTE_ORDER == __BIG_ENDIAN 22 #define cpu_to_le32(x) bswap_32(x) 23 #define cpu_to_le16(x) bswap_16(x) 24 #define le32_to_cpu(x) bswap_32(x) 25 #define le16_to_cpu(x) bswap_16(x) 26 #elif __BYTE_ORDER == __LITTLE_ENDIAN 27 #define cpu_to_le32(x) (x) 28 #define cpu_to_le16(x) (x) 29 #define le32_to_cpu(x) (x) 30 #define le16_to_cpu(x) (x) 31 #endif 32 33 #define min(a, b) \ 34 ({ \ 35 __typeof__ (a) _a = (a); \ 36 __typeof__ (b) _b = (b); \ 37 _a < _b ? _a : _b; \ 38 }) 39 40 #define max(a, b) \ 41 ({ \ 42 __typeof__ (a) _a = (a); \ 43 __typeof__ (b) _b = (b); \ 44 _a > _b ? _a : _b; \ 45 }) 46 47 #define MAX_SUPPORTED_VERSION 3 48 49 #define LXL_FLAGS_VENDOR_LUXUL 0x00000001 50 51 #define LXL_BLOB_CERTIFICATE 0x0001 52 #define LXL_BLOB_SIGNATURE 0x0002 53 54 struct lxl_hdr { 55 char magic[4]; /* "LXL#" */ 56 uint32_t version; 57 uint32_t hdr_len; 58 uint8_t v0_end[0]; 59 /* Version: 1+ */ 60 uint32_t flags; 61 char board[16]; 62 uint8_t v1_end[0]; 63 /* Version: 2+ */ 64 uint8_t release[4]; 65 uint8_t v2_end[0]; 66 /* Version: 3+ */ 67 uint32_t blobs_offset; 68 uint32_t blobs_len; 69 uint8_t v3_end[0]; 70 } __attribute__((packed)); 71 72 struct lxl_blob { 73 char magic[2]; /* "D#" */ 74 uint16_t type; 75 uint32_t len; 76 uint8_t data[0]; 77 } __attribute__((packed)); 78 79 /************************************************** 80 * Helpers 81 **************************************************/ 82 83 static uint32_t lxlfw_hdr_len(uint32_t version) 84 { 85 switch (version) { 86 case 0: 87 return offsetof(struct lxl_hdr, v0_end); 88 case 1: 89 return offsetof(struct lxl_hdr, v1_end); 90 case 2: 91 return offsetof(struct lxl_hdr, v2_end); 92 case 3: 93 return offsetof(struct lxl_hdr, v3_end); 94 default: 95 fprintf(stderr, "Unsupported version %d\n", version); 96 return 0; 97 } 98 } 99 100 /** 101 * lxlfw_open - open Luxul firmware file and validate it 102 * 103 * @pathname: Luxul firmware file 104 * @hdr: struct to read to 105 */ 106 static FILE *lxlfw_open(const char *pathname, struct lxl_hdr *hdr) 107 { 108 size_t v0_len = lxlfw_hdr_len(0); 109 size_t min_hdr_len; 110 uint32_t version; 111 uint32_t hdr_len; 112 size_t bytes; 113 FILE *lxl; 114 115 lxl = fopen(pathname, "r"); 116 if (!lxl) { 117 fprintf(stderr, "Could not open \"%s\" file\n", pathname); 118 goto err_out; 119 } 120 121 bytes = fread(hdr, 1, v0_len, lxl); 122 if (bytes != v0_len) { 123 fprintf(stderr, "Input file too small to use Luxul format\n"); 124 goto err_close; 125 } 126 127 if (memcmp(hdr->magic, "LXL#", 4)) { 128 fprintf(stderr, "File <file> does not use Luxul's format\n"); 129 goto err_close; 130 } 131 132 version = le32_to_cpu(hdr->version); 133 134 min_hdr_len = lxlfw_hdr_len(min(version, MAX_SUPPORTED_VERSION)); 135 136 bytes = fread(((uint8_t *)hdr) + v0_len, 1, min_hdr_len - v0_len, lxl); 137 if (bytes != min_hdr_len - v0_len) { 138 fprintf(stderr, "Input file too small for header version %d\n", version); 139 goto err_close; 140 } 141 142 hdr_len = le32_to_cpu(hdr->hdr_len); 143 144 if (hdr_len < min_hdr_len) { 145 fprintf(stderr, "Header length mismatch: 0x%x (expected: 0x%zx)\n", hdr_len, min_hdr_len); 146 goto err_close; 147 } 148 149 if (version >= 3 && hdr->blobs_offset && hdr->blobs_len) { 150 uint32_t blobs_end = le32_to_cpu(hdr->blobs_offset) + le32_to_cpu(hdr->blobs_len); 151 152 if (blobs_end > hdr_len) { 153 fprintf(stderr, "Blobs section ends beyond header end: 0x%x (max: 0x%x)\n", blobs_end, hdr_len); 154 goto err_close; 155 } 156 } 157 158 return lxl; 159 160 err_close: 161 fclose(lxl); 162 err_out: 163 return NULL; 164 } 165 166 /** 167 * lxlfw_copy_data - read data from one stream and write to another 168 * 169 * @from: input stream 170 * @to: output stream 171 * @size: amount of bytes to copy (0 to copy all data) 172 */ 173 static ssize_t lxlfw_copy_data(FILE *from, FILE *to, size_t size) 174 { 175 int copy_all = size == 0; 176 char buf[512]; 177 size_t ret = 0; 178 179 while (copy_all || size) { 180 size_t to_read = copy_all ? sizeof(buf) : min(size, sizeof(buf)); 181 size_t bytes; 182 183 bytes = fread(buf, 1, to_read, from); 184 if (bytes == 0 && copy_all) { 185 break; 186 } else if (bytes <= 0) { 187 fprintf(stderr, "Failed to read data\n"); 188 return -EIO; 189 } 190 191 if (fwrite(buf, 1, bytes, to) != bytes) { 192 fprintf(stderr, "Failed to write data\n"); 193 return -EIO; 194 } 195 196 if (!copy_all) 197 size -= bytes; 198 ret += bytes; 199 } 200 201 return ret; 202 } 203 204 /** 205 * lxlfw_write_blob - read data from external file and write blob to stream 206 * 207 * @lxl: stream to write to 208 * @type: blob type 209 * @pathname: external file pathname to read blob data from 210 */ 211 static ssize_t lxlfw_write_blob(FILE *lxl, uint16_t type, const char *pathname) 212 { 213 struct lxl_blob blob = { 214 .magic = { 'D', '#' }, 215 .type = cpu_to_le16(type), 216 }; 217 char buf[512]; 218 size_t blob_data_len; 219 size_t bytes; 220 FILE *data; 221 222 data = fopen(pathname, "r"); 223 if (!data) { 224 fprintf(stderr, "Could not open input file %s\n", pathname); 225 return -EIO; 226 } 227 228 blob_data_len = 0; 229 fseek(lxl, sizeof(blob), SEEK_CUR); 230 while ((bytes = fread(buf, 1, sizeof(buf), data)) > 0) { 231 if (fwrite(buf, 1, bytes, lxl) != bytes) { 232 fprintf(stderr, "Could not copy %zu bytes from input file\n", bytes); 233 fclose(data); 234 return -EIO; 235 } 236 blob_data_len += bytes; 237 } 238 239 fclose(data); 240 241 blob.len = cpu_to_le32(blob_data_len); 242 243 fseek(lxl, -(blob_data_len + sizeof(blob)), SEEK_CUR); 244 bytes = fwrite(&blob, 1, sizeof(blob), lxl); 245 if (bytes != sizeof(blob)) { 246 fprintf(stderr, "Could not write Luxul's header\n"); 247 return -EIO; 248 } 249 250 fseek(lxl, blob_data_len, SEEK_CUR); 251 252 return blob_data_len + sizeof(blob); 253 } 254 255 /************************************************** 256 * Info 257 **************************************************/ 258 259 static int lxlfw_info(int argc, char **argv) { 260 struct lxl_hdr hdr; 261 uint32_t version; 262 char board[17]; 263 int err = 0; 264 FILE *lxl; 265 int flags; 266 267 if (argc < 3) { 268 fprintf(stderr, "Missing <file> argument\n"); 269 err = -EINVAL; 270 goto out; 271 } 272 273 lxl = lxlfw_open(argv[2], &hdr); 274 if (!lxl) { 275 fprintf(stderr, "Could not open \"%s\" Luxul firmware\n", argv[2]); 276 err = -ENOENT; 277 goto out; 278 } 279 280 version = le32_to_cpu(hdr.version); 281 282 printf("Format version:\t%d\n", version); 283 printf("Header length:\t%d\n", le32_to_cpu(hdr.hdr_len)); 284 if (version >= 1) { 285 printf("Flags:\t\t"); 286 flags = le32_to_cpu(hdr.flags); 287 if (flags & LXL_FLAGS_VENDOR_LUXUL) 288 printf("VENDOR_LUXUL "); 289 printf("\n"); 290 memcpy(board, hdr.board, sizeof(hdr.board)); 291 board[16] = '\0'; 292 printf("Board:\t\t%s\n", board); 293 } 294 if (version >= 2) { 295 printf("Release:\t"); 296 if (hdr.release[0] || hdr.release[1] || hdr.release[2] || hdr.release[3]) { 297 printf("%hu.%hu.%hu", hdr.release[0], hdr.release[1], hdr.release[2]); 298 if (hdr.release[3]) 299 printf(".%hu", hdr.release[3]); 300 } 301 printf("\n"); 302 } 303 if (version >= 3) { 304 printf("Blobs offset:\t%d\n", le32_to_cpu(hdr.blobs_offset)); 305 printf("Blobs length:\t%d\n", le32_to_cpu(hdr.blobs_len)); 306 } 307 308 if (version >= 3 && hdr.blobs_offset) { 309 size_t offset; 310 311 fseek(lxl, le32_to_cpu(hdr.blobs_offset), SEEK_SET); 312 for (offset = 0; offset < le32_to_cpu(hdr.blobs_len); ) { 313 struct lxl_blob blob; 314 size_t bytes; 315 size_t len; 316 317 bytes = fread(&blob, 1, sizeof(blob), lxl); 318 if (bytes != sizeof(blob)) { 319 fprintf(stderr, "Failed to read blob section\n"); 320 err = -ENXIO; 321 goto err_close; 322 } 323 324 len = le32_to_cpu(blob.len); 325 326 printf("\n"); 327 printf("Blob\n"); 328 printf("Magic:\t\t%s\n", blob.magic); 329 printf("Type:\t\t0x%04x\n", le16_to_cpu(blob.type)); 330 printf("Length:\t\t%zu\n", len); 331 332 offset += sizeof(blob) + len; 333 fseek(lxl, len, SEEK_CUR); 334 } 335 336 if (offset != le32_to_cpu(hdr.blobs_len)) { 337 printf("\n"); 338 fprintf(stderr, "Blobs size (0x%zx) doesn't match declared length (0x%x)\n", offset, le32_to_cpu(hdr.blobs_len)); 339 } 340 } 341 342 err_close: 343 fclose(lxl); 344 out: 345 return err; 346 } 347 348 /************************************************** 349 * Extract 350 **************************************************/ 351 352 static int lxlfw_extract(int argc, char **argv) { 353 struct lxl_hdr hdr; 354 char *out_path = NULL; 355 ssize_t bytes; 356 int err = 0; 357 FILE *lxl; 358 FILE *out; 359 int c; 360 361 if (argc < 3) { 362 fprintf(stderr, "Missing <file> argument\n"); 363 err = -EINVAL; 364 goto out; 365 } 366 367 optind = 3; 368 while ((c = getopt(argc, argv, "O:")) != -1) { 369 switch (c) { 370 case 'O': 371 out_path = optarg; 372 break; 373 } 374 } 375 376 if (!out_path) { 377 fprintf(stderr, "Missing output file path\n"); 378 err = -EINVAL; 379 goto out; 380 } 381 382 lxl = lxlfw_open(argv[2], &hdr); 383 if (!lxl) { 384 fprintf(stderr, "Failed to open \"%s\" Luxul firmware\n", argv[2]); 385 err = -ENOENT; 386 goto out; 387 } 388 389 fseek(lxl, le32_to_cpu(hdr.hdr_len), SEEK_SET); 390 391 if (!strcmp(out_path, "-")) { 392 out = stdout; 393 } else { 394 out = fopen(out_path, "w+"); 395 if (!out) { 396 fprintf(stderr, "Failed to open \"%s\" file\n", out_path); 397 err = -EIO; 398 goto err_close_lxl; 399 } 400 } 401 402 bytes = lxlfw_copy_data(lxl, out, 0); 403 if (bytes < 0) { 404 fprintf(stderr, "Failed to copy image: %zd\n", bytes); 405 err = -EIO; 406 goto err_close_lxl; 407 } 408 409 if (out != stdout) { 410 fclose(out); 411 } 412 413 err_close_lxl: 414 fclose(lxl); 415 out: 416 return err; 417 } 418 419 /************************************************** 420 * Blobs 421 **************************************************/ 422 423 /** 424 * lxlfw_blob_save - save blob data to external file 425 * 426 * @lxl: Luxul firmware FILE with position seeked to blob data 427 * @len: blob data length 428 * @path: external file pathname to write 429 */ 430 static int lxlfw_blob_save(FILE *lxl, size_t len, const char *path) { 431 char buf[256]; 432 size_t bytes; 433 FILE *out; 434 int err = 0; 435 436 out = fopen(path, "w+"); 437 if (!out) { 438 fprintf(stderr, "Could not open \"%s\" file\n", path); 439 err = -EIO; 440 goto err_out; 441 } 442 443 while (len && (bytes = fread(buf, 1, min(len, sizeof(buf)), lxl)) > 0) { 444 if (fwrite(buf, 1, bytes, out) != bytes) { 445 fprintf(stderr, "Could not copy %zu bytes from input file\n", bytes); 446 err = -EIO; 447 goto err_close_out; 448 } 449 len -= bytes; 450 } 451 452 if (len) { 453 fprintf(stderr, "Could not copy all signature\n"); 454 err = -EIO; 455 goto err_close_out; 456 } 457 458 err_close_out: 459 fclose(out); 460 err_out: 461 return err; 462 } 463 464 static int lxlfw_blobs(int argc, char **argv) { 465 char *certificate_path = NULL; 466 char *signature_path = NULL; 467 struct lxl_hdr hdr; 468 uint32_t version; 469 size_t offset; 470 size_t bytes; 471 int err = 0; 472 FILE *lxl; 473 int c; 474 475 if (argc < 3) { 476 fprintf(stderr, "Missing <file> argument\n"); 477 err = -EINVAL; 478 goto out; 479 } 480 481 optind = 3; 482 while ((c = getopt(argc, argv, "c:s:")) != -1) { 483 switch (c) { 484 case 'c': 485 certificate_path = optarg; 486 break; 487 case 's': 488 signature_path = optarg; 489 break; 490 } 491 } 492 493 if (!certificate_path && !signature_path) { 494 fprintf(stderr, "Missing info on blobs to extract\n"); 495 err = -EINVAL; 496 goto out; 497 } 498 499 lxl = lxlfw_open(argv[2], &hdr); 500 if (!lxl) { 501 fprintf(stderr, "Failed to open \"%s\" Luxul firmware\n", argv[2]); 502 err = -ENOENT; 503 goto out; 504 } 505 506 version = le32_to_cpu(hdr.version); 507 508 if (version < 3 || !hdr.blobs_offset) { 509 fprintf(stderr, "File <file> doesn't contain any blobs\n"); 510 err = -ENOENT; 511 goto err_close; 512 } 513 514 fseek(lxl, le32_to_cpu(hdr.blobs_offset), SEEK_SET); 515 for (offset = 0; offset < le32_to_cpu(hdr.blobs_len); ) { 516 struct lxl_blob blob; 517 uint16_t type; 518 size_t len; 519 520 bytes = fread(&blob, 1, sizeof(blob), lxl); 521 if (bytes != sizeof(blob)) { 522 fprintf(stderr, "Failed to read blob section\n"); 523 err = -ENXIO; 524 goto err_close; 525 } 526 offset += bytes; 527 528 if (memcmp(blob.magic, "D#", 2)) { 529 fprintf(stderr, "Failed to parse blob section\n"); 530 err = -ENXIO; 531 goto err_close; 532 } 533 534 type = le16_to_cpu(blob.type); 535 len = le32_to_cpu(blob.len); 536 537 if (type == LXL_BLOB_CERTIFICATE && certificate_path) { 538 err = lxlfw_blob_save(lxl, len, certificate_path); 539 certificate_path = NULL; 540 } else if (type == LXL_BLOB_SIGNATURE && signature_path) { 541 err = lxlfw_blob_save(lxl, len, signature_path); 542 signature_path = NULL; 543 } else { 544 fseek(lxl, len, SEEK_CUR); 545 } 546 if (err) { 547 fprintf(stderr, "Failed to save blob section\n"); 548 goto err_close; 549 } 550 offset += len; 551 } 552 553 if (certificate_path) { 554 fprintf(stderr, "Failed to find certificate blob\n"); 555 err = -ENOENT; 556 } 557 if (signature_path) { 558 fprintf(stderr, "Failed to find signature blob\n"); 559 err = -ENOENT; 560 } 561 562 err_close: 563 fclose(lxl); 564 out: 565 return err; 566 } 567 568 /************************************************** 569 * Create 570 **************************************************/ 571 572 static int lxlfw_create(int argc, char **argv) { 573 struct lxl_hdr hdr = { 574 .magic = { 'L', 'X', 'L', '#' }, 575 }; 576 char *certificate_path = NULL; 577 char *signature_path = NULL; 578 char *in_path = NULL; 579 uint32_t version = 0; 580 uint32_t hdr_raw_len; /* Header length without blobs */ 581 uint32_t hdr_len; /* Header length with blobs */ 582 uint32_t blobs_len; 583 ssize_t bytes; 584 int err = 0; 585 FILE *lxl; 586 FILE *in; 587 int c; 588 589 if (argc < 3) { 590 fprintf(stderr, "Missing <file> argument\n"); 591 err = -EINVAL; 592 goto out; 593 } 594 595 optind = 3; 596 while ((c = getopt(argc, argv, "i:lb:r:")) != -1) { 597 switch (c) { 598 case 'i': 599 in_path = optarg; 600 break; 601 case 'l': 602 hdr.flags |= cpu_to_le32(LXL_FLAGS_VENDOR_LUXUL); 603 version = max(version, 1); 604 break; 605 case 'b': 606 memcpy(hdr.board, optarg, strlen(optarg) > 16 ? 16 : strlen(optarg)); 607 version = max(version, 1); 608 break; 609 case 'r': 610 if (sscanf(optarg, "%hhu.%hhu.%hhu.%hhu", &hdr.release[0], &hdr.release[1], &hdr.release[2], &hdr.release[3]) < 1) { 611 fprintf(stderr, "Failed to parse release number \"%s\"\n", optarg); 612 err = -EINVAL; 613 goto out; 614 } 615 version = max(version, 2); 616 break; 617 case 'c': 618 certificate_path = optarg; 619 version = max(version, 3); 620 break; 621 case 's': 622 signature_path = optarg; 623 version = max(version, 3); 624 break; 625 } 626 } 627 628 hdr_raw_len = lxlfw_hdr_len(version); 629 hdr_len = hdr_raw_len; 630 631 if (!in_path) { 632 fprintf(stderr, "Missing input file argument\n"); 633 err = -EINVAL; 634 goto out; 635 } 636 637 in = fopen(in_path, "r"); 638 if (!in) { 639 fprintf(stderr, "Could not open input file %s\n", in_path); 640 err = -EIO; 641 goto out; 642 } 643 644 lxl = fopen(argv[2], "w+"); 645 if (!lxl) { 646 fprintf(stderr, "Could not open \"%s\" file\n", argv[2]); 647 err = -EIO; 648 goto err_close_in; 649 } 650 651 /* Write blobs */ 652 653 blobs_len = 0; 654 655 fseek(lxl, hdr_raw_len, SEEK_SET); 656 if (certificate_path) { 657 bytes = lxlfw_write_blob(lxl, LXL_BLOB_CERTIFICATE, certificate_path); 658 if (bytes <= 0) { 659 fprintf(stderr, "Failed to write certificate\n"); 660 goto err_close_lxl; 661 } 662 blobs_len += bytes; 663 } 664 if (signature_path) { 665 bytes = lxlfw_write_blob(lxl, LXL_BLOB_SIGNATURE, signature_path); 666 if (bytes <= 0) { 667 fprintf(stderr, "Failed to write signature\n"); 668 goto err_close_lxl; 669 } 670 blobs_len += bytes; 671 } 672 673 if (blobs_len) { 674 hdr.blobs_offset = cpu_to_le32(hdr_raw_len); 675 hdr.blobs_len = cpu_to_le32(blobs_len); 676 hdr_len += blobs_len; 677 } 678 679 /* Write header */ 680 681 hdr.version = cpu_to_le32(version); 682 hdr.hdr_len = cpu_to_le32(hdr_len); 683 684 fseek(lxl, 0, SEEK_SET); 685 bytes = fwrite(&hdr, 1, hdr_raw_len, lxl); 686 if (bytes != hdr_raw_len) { 687 fprintf(stderr, "Could not write Luxul's header\n"); 688 err = -EIO; 689 goto err_close_lxl; 690 } 691 692 /* Write input data */ 693 694 fseek(lxl, 0, SEEK_END); 695 bytes = lxlfw_copy_data(in, lxl, 0); 696 if (bytes < 0) { 697 fprintf(stderr, "Could not copy %zu bytes from input file\n", bytes); 698 err = -EIO; 699 goto err_close_lxl; 700 } 701 702 err_close_lxl: 703 fclose(lxl); 704 err_close_in: 705 fclose(in); 706 out: 707 return err; 708 } 709 710 /************************************************** 711 * Insert 712 **************************************************/ 713 714 static int lxlfw_insert(int argc, char **argv) { 715 struct lxl_hdr hdr = { }; 716 char *certificate_path = NULL; 717 char *signature_path = NULL; 718 char *tmp_path = NULL; 719 uint32_t version = 0; 720 uint32_t hdr_raw_len; /* Header length without blobs */ 721 uint32_t hdr_len; /* Header length with blobs */ 722 uint32_t blobs_len; 723 ssize_t bytes; 724 char *path; 725 FILE *lxl; 726 FILE *tmp; 727 int fd; 728 int c; 729 int err = 0; 730 731 if (argc < 3) { 732 fprintf(stderr, "Missing <file> argument\n"); 733 err = -EINVAL; 734 goto out; 735 } 736 737 optind = 3; 738 while ((c = getopt(argc, argv, "c:s:")) != -1) { 739 switch (c) { 740 case 'c': 741 certificate_path = optarg; 742 break; 743 case 's': 744 signature_path = optarg; 745 break; 746 } 747 } 748 749 if (!certificate_path && !signature_path) { 750 fprintf(stderr, "Missing info on blobs to insert\n"); 751 err = -EINVAL; 752 goto out; 753 } 754 755 lxl = lxlfw_open(argv[2], &hdr); 756 if (!lxl) { 757 fprintf(stderr, "Failed to open \"%s\" Luxul firmware\n", argv[2]); 758 err = -ENOENT; 759 goto out; 760 } 761 762 version = le32_to_cpu(hdr.version); 763 if (version > MAX_SUPPORTED_VERSION) { 764 fprintf(stderr, "Unsupported <file> version %d\n", version); 765 err = -EIO; 766 goto err_close_lxl; 767 } 768 769 version = max(version, 3); 770 771 hdr_raw_len = lxlfw_hdr_len(version); 772 hdr_len = hdr_raw_len; 773 774 /* Temporary file */ 775 776 path = strdup(argv[2]); 777 if (!path) { 778 err = -ENOMEM; 779 goto err_close_lxl; 780 } 781 asprintf(&tmp_path, "%s/lxlfwXXXXXX", dirname(path)); 782 free(path); 783 if (!tmp_path) { 784 err = -ENOMEM; 785 goto err_close_lxl; 786 } 787 788 fd = mkstemp(tmp_path); 789 if (fd < 0) { 790 err = -errno; 791 fprintf(stderr, "Failed to open temporary file\n"); 792 goto err_free_path; 793 } 794 tmp = fdopen(fd, "w+"); 795 796 /* Blobs */ 797 798 fseek(tmp, hdr_raw_len, SEEK_SET); 799 blobs_len = 0; 800 801 /* Copy old blobs */ 802 803 if (hdr.blobs_offset) { 804 size_t offset; 805 806 fseek(lxl, le32_to_cpu(hdr.blobs_offset), SEEK_SET); 807 for (offset = 0; offset < le32_to_cpu(hdr.blobs_len); ) { 808 struct lxl_blob blob; 809 uint16_t type; 810 size_t len; 811 812 bytes = fread(&blob, 1, sizeof(blob), lxl); 813 if (bytes != sizeof(blob)) { 814 fprintf(stderr, "Failed to read blob section\n"); 815 err = -ENXIO; 816 goto err_close_tmp; 817 } 818 819 type = le16_to_cpu(blob.type); 820 len = le32_to_cpu(blob.len); 821 822 /* Don't copy blobs that have to be replaced */ 823 if ((type == LXL_BLOB_CERTIFICATE && certificate_path) || 824 (type == LXL_BLOB_SIGNATURE && signature_path)) { 825 fseek(lxl, len, SEEK_CUR); 826 } else { 827 fseek(lxl, -sizeof(blob), SEEK_CUR); 828 bytes = lxlfw_copy_data(lxl, tmp, sizeof(blob) + len); 829 if (bytes != sizeof(blob) + len) { 830 fprintf(stderr, "Failed to copy original blob\n"); 831 err = -EIO; 832 goto err_close_tmp; 833 } 834 blobs_len += sizeof(blob) + len; 835 } 836 837 offset += sizeof(blob) + len; 838 } 839 } 840 841 /* Write new blobs */ 842 843 if (certificate_path) { 844 bytes = lxlfw_write_blob(tmp, LXL_BLOB_CERTIFICATE, certificate_path); 845 if (bytes <= 0) { 846 fprintf(stderr, "Failed to write certificate\n"); 847 goto err_close_tmp; 848 } 849 blobs_len += bytes; 850 } 851 if (signature_path) { 852 bytes = lxlfw_write_blob(tmp, LXL_BLOB_SIGNATURE, signature_path); 853 if (bytes <= 0) { 854 fprintf(stderr, "Failed to write signature\n"); 855 goto err_close_tmp; 856 } 857 blobs_len += bytes; 858 } 859 860 hdr.blobs_offset = cpu_to_le32(hdr_raw_len); 861 hdr.blobs_len = cpu_to_le32(blobs_len); 862 hdr_len += blobs_len; 863 864 /* Write header */ 865 866 hdr.version = cpu_to_le32(version); 867 hdr.hdr_len = cpu_to_le32(hdr_len); 868 869 fseek(tmp, 0, SEEK_SET); 870 bytes = fwrite(&hdr, 1, hdr_raw_len, tmp); 871 if (bytes != hdr_raw_len) { 872 fprintf(stderr, "Could not write Luxul's header\n"); 873 err = -EIO; 874 goto err_close_tmp; 875 } 876 877 /* Write original data */ 878 879 fseek(tmp, 0, SEEK_END); 880 bytes = lxlfw_copy_data(lxl, tmp, 0); 881 if (bytes < 0) { 882 fprintf(stderr, "Failed to copy original file\n"); 883 err = -EIO; 884 goto err_close_tmp; 885 } 886 887 fclose(tmp); 888 889 fclose(lxl); 890 891 /* Replace original file */ 892 893 if (rename(tmp_path, argv[2])) { 894 err = -errno; 895 fprintf(stderr, "Failed to rename %s: %d\n", tmp_path, err); 896 unlink(tmp_path); 897 goto out; 898 } 899 900 return 0; 901 902 err_close_tmp: 903 fclose(tmp); 904 err_free_path: 905 free(tmp_path); 906 err_close_lxl: 907 fclose(lxl); 908 out: 909 return err; 910 } 911 912 /************************************************** 913 * Start 914 **************************************************/ 915 916 static void usage() { 917 printf("Usage:\n"); 918 printf("\n"); 919 printf("Get info about Luxul firmware:\n"); 920 printf("\tlxlfw info <file>\n"); 921 printf("\n"); 922 printf("Extract image from Luxul firmware:\n"); 923 printf("\tlxlfw extract <file> [options]\n"); 924 printf("\t-O file\t\t\t\toutput file (- for stdout)\n"); 925 printf("\n"); 926 printf("Extract blobs from Luxul firmware:\n"); 927 printf("\tlxlfw blobs <file> [options]\n"); 928 printf("\t-c file\t\t\t\tcertificate output file\n"); 929 printf("\t-s file\t\t\t\tsignature output file\n"); 930 printf("\n"); 931 printf("Create new Luxul firmware:\n"); 932 printf("\tlxlfw create <file> [options]\n"); 933 printf("\t-i file\t\t\t\tinput file for Luxul's firmware container\n"); 934 printf("\t-l\t\t\t\tmark firmware as created by Luxul company (DON'T USE)\n"); 935 printf("\t-b board\t\t\tboard (device) name\n"); 936 printf("\t-r release\t\t\trelease number (e.g. 5.1.0, 7.1.0.2)\n"); 937 printf("\t-c file\t\t\t\tcertificate file\n"); 938 printf("\t-s file\t\t\t\tsignature file\n"); 939 printf("\n"); 940 printf("Insert blob to Luxul firmware:\n"); 941 printf("\tlxlfw insert <file> [options]\n"); 942 printf("\t-c file\t\t\t\tcertificate file\n"); 943 printf("\t-s file\t\t\t\tsignature file\n"); 944 945 } 946 947 int main(int argc, char **argv) { 948 if (argc > 1) { 949 if (!strcmp(argv[1], "info")) 950 return lxlfw_info(argc, argv); 951 else if (!strcmp(argv[1], "extract")) 952 return lxlfw_extract(argc, argv); 953 else if (!strcmp(argv[1], "blobs")) 954 return lxlfw_blobs(argc, argv); 955 else if (!strcmp(argv[1], "create")) 956 return lxlfw_create(argc, argv); 957 else if (!strcmp(argv[1], "insert")) 958 return lxlfw_insert(argc, argv); 959 } 960 961 usage(); 962 return 0; 963 } 964
This page was automatically generated by LXR 0.3.1. • OpenWrt