Advertisement
Twissel

fwsplit.c

Mar 9th, 2015
498
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 7.01 KB | None | 0 0
  1. /*
  2.  * Copyright (C) 2007 Ubiquiti Networks, Inc.
  3.  *
  4.  * This program is free software; you can redistribute it and/or
  5.  * modify it under the terms of the GNU General Public License as
  6.  * published by the Free Software Foundation; either version 2 of the
  7.  * License, or (at your option) any later version.
  8.  *
  9.  * This program is distributed in the hope that it will be useful, but
  10.  * WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12.  * General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  */
  18.  
  19. #define _GNU_SOURCE
  20. #include <string.h>
  21. #include <stdio.h>
  22. #include <netinet/in.h>
  23. #include <sys/types.h>
  24. #include <fcntl.h>
  25. #include <errno.h>
  26. #include <sys/stat.h>
  27. #include <sys/mman.h>
  28. #include <zlib.h>
  29. #include <limits.h>
  30. #include <unistd.h>
  31.  
  32.  
  33. #include "fw.h"
  34.  
  35. static int debug = 0;
  36. static char prefix[PATH_MAX];
  37.  
  38. #define MAX_PARTS 8
  39.  
  40. typedef struct fw_part {
  41.     part_t* header;
  42.     unsigned char* data;
  43.     u_int32_t data_size;
  44.     part_crc_t* signature;
  45. } fw_part_t;
  46.  
  47. typedef struct fw {
  48.     u_int32_t size;
  49.     char version[256];
  50.     fw_part_t parts[MAX_PARTS];
  51.     int part_count;
  52. } fw_t;
  53.  
  54. static int
  55. fw_check_header(const header_t* h) {
  56.         u_int32_t crc;
  57.         int len = sizeof(header_t) - 2 * sizeof(u_int32_t);
  58.  
  59.         crc = crc32(0L, (unsigned char*)h, len);
  60.     DEBUG("Calculated CRC: 0x%08X, expected: 0x%08X\n", htonl(crc), h->crc);
  61.         if (htonl(crc) != h->crc)
  62.                 return -1;
  63.  
  64.         return 0;
  65. }
  66.  
  67. static int
  68. fw_parse(const unsigned char* base, unsigned long size, fw_t* fw) {
  69.     const header_t* h = (const header_t*)base;
  70.     part_t* p;
  71.     signature_t* sig;
  72.     u_int32_t crc;
  73.     int i = 0;
  74.  
  75.     if (fw == NULL)
  76.         return -1;
  77.  
  78.     if (fw_check_header(h)) {
  79.         return -2;
  80.     }
  81.     memset(fw, 0, sizeof(fw_t));
  82.     fw->size = size;
  83.     memcpy(fw->version, h->version, sizeof(fw->version));
  84.     INFO("Firmware version: '%s'\n", fw->version);
  85.  
  86.     p = (part_t*)(base + sizeof(header_t));
  87.     i = 0;
  88.     while (strncmp(p->magic, MAGIC_END, MAGIC_LENGTH) != 0) {
  89.         DEBUG("Partition (%c%c%c%c): %s [%u]\n",
  90.                 p->magic[0], p->magic[1], p->magic[2], p->magic[3],
  91.                 p->name, ntohl(p->index));
  92.         DEBUG("  Partition size: 0x%X\n", ntohl(p->part_size));
  93.         DEBUG("  Data size: %u\n", ntohl(p->data_size));
  94.  
  95.         if ((strncmp(p->magic, MAGIC_PART, MAGIC_LENGTH) == 0) && (i < MAX_PARTS)) {
  96.             fw_part_t* fwp = &fw->parts[i];
  97.  
  98.             fwp->header = p;
  99.             fwp->data = (unsigned char*)p + sizeof(part_t);
  100.             fwp->data_size = ntohl(p->data_size);
  101.             fwp->signature =
  102.                 (part_crc_t*)(fwp->data + fwp->data_size);
  103.  
  104.             crc = htonl(crc32(0L, (unsigned char*)p,
  105.                       fwp->data_size + sizeof(part_t)));
  106.             if (crc != fwp->signature->crc) {
  107.                 WARN("Invalid '%s' CRC (claims: %u, but is %u)\n",
  108.                         fwp->header->name, fwp->signature->crc, crc);
  109.             }
  110.         }
  111.  
  112.         p = (part_t*)((unsigned char*)p + sizeof(part_t) +
  113.                   ntohl(p->data_size) + sizeof(part_crc_t));
  114.  
  115.         /* check bounds */
  116.         if (((unsigned char*)p - base) >= size) {
  117.             return -3;
  118.         }
  119.         ++i;
  120.     }
  121.     fw->part_count = i;
  122.  
  123.     sig = (signature_t*)p;
  124.     if (strncmp(sig->magic, MAGIC_END, MAGIC_LENGTH) != 0) {
  125.         ERROR("Bad firmware signature\n");
  126.         return -4;
  127.     }
  128.  
  129.     crc = htonl(crc32(0L, base, (unsigned char*)sig - base));
  130.     if (crc != sig->crc) {
  131.         WARN("Invalid signature CRC (claims: %u, but is %u)\n",
  132.              sig->crc, crc);
  133.     }
  134.  
  135.     return 0;
  136. }
  137.  
  138. static int
  139. fw_split(const fw_t* fw, const char* prefix) {
  140.     int i;
  141.     const fw_part_t* fwp;
  142.     FILE* f;
  143.     char filename[PATH_MAX];
  144.  
  145.     snprintf(filename, sizeof(filename), "%s.txt", prefix);
  146.  
  147.      INFO("Creating descriptor file:\n\t%s\n", filename);
  148.    
  149.     f = fopen(filename, "w");
  150.     if (f == NULL) {
  151.         ERROR("Couldn't open file '%s' for writing!\n", filename);
  152.         return -1;
  153.     }
  154.  
  155.     for (i = 0; i < fw->part_count; ++i) {
  156.         fwp = &fw->parts[i];
  157.  
  158.         fprintf(f, "%s\t\t0x%02X\t0x%08X\t0x%08X\t0x%08X\t0x%08X\t%s.%s\n",
  159.             fwp->header->name,
  160.             ntohl(fwp->header->index),
  161.             ntohl(fwp->header->baseaddr),
  162.             ntohl(fwp->header->part_size),
  163.             ntohl(fwp->header->memaddr),
  164.             ntohl(fwp->header->entryaddr),
  165.             prefix, fwp->header->name);
  166.  
  167.     }
  168.     fclose(f);
  169.  
  170.     INFO("Creating partition data files: \n");
  171.  
  172.     for (i = 0; i < fw->part_count; ++i) {
  173.         fwp = &fw->parts[i];
  174.  
  175.         snprintf(filename, sizeof(filename), "%s.%s",
  176.              prefix, fwp->header->name);
  177.         f = fopen(filename, "w");
  178.         if (f == NULL) {
  179.             ERROR("Failed opening file '%s' for writing: %s\n",
  180.                   filename, strerror(errno));
  181.             continue;
  182.         }
  183.        
  184.         INFO("\t%s\n", filename);
  185.  
  186.         if (fwrite(fwp->data, fwp->data_size, 1, f) != 1) {
  187.             ERROR("Failed writing to file '%s': %s\n",
  188.                   filename, strerror(errno));
  189.             fclose(f);
  190.             continue;
  191.         }
  192.         fclose(f);
  193.     }
  194.  
  195.     return 0;
  196. }
  197.  
  198. static void
  199. usage(const char* progname) {
  200.     INFO("Version %s\n"
  201.              "Usage: %s [options] <firmware file> [<fw file2> ... <fw fileN>]\n"
  202.          "\t-o <output file prefix>\t"
  203.                 " - output file prefix, default: firmware version\n"
  204.          "\t-d\t\t\t - turn debug output on\n"
  205.          "\t-h\t\t\t - this help\n", VERSION, progname);
  206. }
  207.  
  208.  
  209. static int
  210. do_fwsplit(const char* filename) {
  211.     int rc;
  212.     int fd;
  213.     struct stat st;
  214.     fw_t fw;
  215.     unsigned char* addr;
  216.  
  217.     INFO("Firmware file: '%s'\n", filename);
  218.  
  219.     rc = stat(filename, &st);
  220.     if (rc) {
  221.         ERROR("Couldn't stat() file '%s': %s\n",
  222.               filename, strerror(errno));
  223.         return -2;
  224.     }
  225.  
  226.     if (st.st_size < sizeof(header_t) + sizeof(signature_t)) {
  227.         ERROR("File '%s' is too short\n", filename);
  228.         return -3;
  229.     }
  230.  
  231.     fd = open(filename, O_RDONLY);
  232.     if (fd < 0) {
  233.         ERROR("Couldn't open file '%s': %s\n",
  234.               filename, strerror(errno));
  235.         return -4;
  236.     }
  237.  
  238.     addr=(unsigned char*)mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
  239.     if (addr == MAP_FAILED) {
  240.         ERROR("Failed mmaping memory for file '%s'\n", filename);
  241.         close(fd);
  242.         return -5;
  243.     }
  244.  
  245.     // parse & validate fw
  246.     rc = fw_parse(addr, st.st_size, &fw);
  247.     if (rc) {
  248.         ERROR("Invalid firmware file '%s'!\n", filename);
  249.         munmap(addr, st.st_size);
  250.         close(fd);
  251.         return -6;
  252.     }
  253.  
  254.     if (strlen(prefix) == 0) {
  255.         strncpy(prefix, fw.version, sizeof(prefix));
  256.     }
  257.     fw_split(&fw, prefix);
  258.    
  259.     munmap(addr, st.st_size);
  260.     close(fd);
  261.  
  262.     return 0;
  263. }
  264.  
  265. int
  266. main(int argc, char* argv[]) {
  267.     int o, i;
  268.  
  269.     memset(prefix, 0, sizeof(prefix));
  270.  
  271.     while ((o = getopt(argc, argv, "hdo:")) != -1) {
  272.         switch (o) {
  273.         case 'd':
  274.             debug++;
  275.             break;
  276.         case 'o':
  277.             if (optarg) {
  278.                 strncpy(prefix, optarg, sizeof(prefix));
  279.             }
  280.             break;
  281.         case 'h':
  282.             usage(argv[0]);
  283.             return -1;
  284.         }
  285.     }
  286.  
  287.     if (optind >= argc) {
  288.         usage(argv[0]);
  289.         return -1;
  290.     }
  291.  
  292.     if (strlen(prefix) != 0 && (optind + 1) < argc) {
  293.         WARN("Prefix overridden - will process only the first firmware file\n");
  294.         do_fwsplit(argv[optind]);
  295.     } else {
  296.         for (i = optind; i < argc; ++i) {
  297.             do_fwsplit(argv[i]);
  298.         }
  299.     }
  300.  
  301.     return 0;
  302. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement