Broadcom Consumer Router Firmware Header Dump
[firmware_header_dump.git] / firmware_header_dump.c
1 static const char *title =\
2 "Broadcom Consumer Router Firmware Header Dump"
3 ;
4 static const float VERSION = 1.0f;
5
6 static const char *copyright = \
7 "Copyright 2015-2016 TJ <hacker@iam.tj>\n"
8 "Licensed on the terms of the GNU General Public License version 3\n"
9 ;
10
11 static const char *help = \
12 "For routers using the Broadcom CFE ((Customer Premises Equipment) CPE Firmware Environment) and firmware update files.\n\n"
13
14 "Displays the fields of the firmware update file header structure.\n\n"
15 ;
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <stdarg.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <fcntl.h>
24 #include <unistd.h>
25 #include <arpa/inet.h>
26 #include <stdint.h>
27 #include <stddef.h>
28
29 #define BCMTAG_EXE_USE 1
30
31 #include "heap_reap.h"
32 #include "bcmTag.h"
33
34 static unsigned int MESSAGE_SIZE = 1024;
35
36 static void
37 pr_usage(int verbose)
38 {
39   fprintf(stderr,
40     "Usage:\n"
41     "  -h  show additional help\n"
42     "\n"
43     "%s",
44     verbose ? help : ""
45   );
46 }
47
48 static void
49 pr_error_exit(unsigned int usage, const char *error, ...)
50 {
51  va_list args;
52  char error_message[MESSAGE_SIZE + 1];
53
54  if (!error) return;
55
56  va_start(args, error);
57  (void) vsnprintf(error_message, MESSAGE_SIZE + 1, error, args);
58  va_end(args);
59  fprintf(stderr, "Error: %s\n", error_message);
60
61  if (usage) pr_usage(usage);
62
63  heap_and_reap(NULL-1, 0, 0);
64  exit(EXIT_FAILURE);
65 }
66
67 /* calculate standard CRC32
68  *
69  * @param data pointer to start of input data
70  * @param len  length in bytes of data to be checksummed
71  * @param crc32 seed value (Broadcom use 0xffffffff)
72  */
73 unsigned int crc32(const unsigned char *data, ssize_t len, unsigned int crc)
74 {
75    for ( ; len > 0; --len ) {
76      crc = (crc >> 8) ^ Crc32_table[ (crc ^ *data++) & 0xff ];
77    }
78    return crc;
79 }
80
81
82 int
83 main(int argc, char **argv)
84 {
85   unsigned int arg, crc;
86   char *filename = NULL;
87   int fd, fd_mode;
88   unsigned char *buffer = NULL;
89   unsigned long header_len = sizeof(FILE_TAG);
90   char *format_spec_user = "%-12s Manufacturer: %s Model: %s CRC32: %08x Length: %ld File: %s\n";
91   char *format_spec_test = "%-12s %s %s %08x %ld\n";
92   char *format_spec = format_spec_user; // default output format
93
94   unsigned int opt_quiet;
95   
96   opt_quiet = 0;
97
98   fprintf(stderr, "%s\nVersion: %0.2f\n%s\n", title, VERSION, copyright);
99
100   for (arg = 1; arg < (unsigned) argc; ++arg) {
101     char *p = argv[arg];
102     size_t arg_len = strlen(p);
103
104     if (p[0] == '-') {
105       if(p[1] != 0) {
106         switch (p[1]) {
107           case 'h': // help
108             pr_usage(1);
109             goto end;
110         }
111       } else {
112         pr_error_exit(0, "cannot read data from stdin; provide a filename");
113       }
114       continue;
115     }
116     else if (!filename) { // remaining non-option must be the filename
117       filename = p;
118     } else {
119       if (!opt_quiet)
120         fprintf(stderr, "Can only process one file; ignoring '%s'\n", p);
121     }
122   }
123
124
125   fd_mode = O_RDONLY;
126
127   if (filename) {
128    if ((fd = open(filename, fd_mode)) > 0) {
129      if ( (buffer = heap_and_reap(NULL, header_len, 1)) != NULL) {
130        ssize_t qty;
131        if ( (qty = read(fd, buffer, header_len)) < header_len) {
132          if (!opt_quiet)
133            fprintf(stderr, "warning: only able to read %ld of %ld bytes\n", qty, header_len);
134          header_len = qty;
135        }
136      } else {
137        close(fd);
138        pr_error_exit(0, "unable to allocate memory (%ld bytes)\n", header_len);
139      }
140
141      PFILE_TAG header = (PFILE_TAG) buffer;
142      printf("%04lx Tag Version: %s\n"
143             "%04lx Signature 1: %s\n"
144             "%04lx Signature 2: %s\n"
145             "%04lx Chip ID: %s\n"
146             "%04lx Board ID: %s\n"
147             "%04lx Big Endian: %s\n"
148             "%04lx Image Len: %s (0x%08lx)\n"
149             "%04lx CFE Address: %s (0x%08lx)\n"
150             "%04lx CFE Len: %s (0x%08lx)\n"
151             "%04lx Root FS Address: %s (0x%08lx)\n"
152             "%04lx Root FS Len: %s (0x%08lx)\n"
153             "%04lx Kernel Address: %s (0x%08lx)\n"
154             "%04lx Kernel Len: %s (0x%08lx)\n"
155             "%04lx Image Sequence: %s (0x%08x)\n"
156             "%04lx External Version: %s\n"
157             "%04lx Internal Version: %s\n"
158             "%04lx Image Next: %u\n"
159             "%04lx Image Validation Token: 0x%0x\n"
160             "%04lx Tag Validation Token: 0x%0x\n"
161             "",
162             offsetof(struct _FILE_TAG, tagVersion), header->tagVersion,
163             offsetof(struct _FILE_TAG, signiture_1), header->signiture_1,
164             offsetof(struct _FILE_TAG, signiture_2), header->signiture_2,
165             offsetof(struct _FILE_TAG, chipId), header->chipId,
166             offsetof(struct _FILE_TAG, boardId), header->boardId,
167             offsetof(struct _FILE_TAG, bigEndian), *header->bigEndian == '1' ? "Yes" : "No",
168             offsetof(struct _FILE_TAG, totalImageLen), header->totalImageLen, atol(header->totalImageLen),
169             offsetof(struct _FILE_TAG, cfeAddress), header->cfeAddress, atol(header->cfeAddress),
170             offsetof(struct _FILE_TAG, cfeLen), header->cfeLen, atol(header->cfeLen),
171             offsetof(struct _FILE_TAG, rootfsAddress), header->rootfsAddress, atol(header->rootfsAddress),
172             offsetof(struct _FILE_TAG, rootfsLen), header->rootfsLen, atol(header->rootfsLen),
173             offsetof(struct _FILE_TAG, kernelAddress), header->kernelAddress, atol(header->kernelAddress),
174             offsetof(struct _FILE_TAG, kernelLen), header->kernelLen, atol(header->kernelLen),
175             offsetof(struct _FILE_TAG, imageSequence), header->imageSequence, atoi(header->imageSequence),
176             offsetof(struct _FILE_TAG, externalversion), header->externalversion,
177             offsetof(struct _FILE_TAG, internalversion), header->internalversion,
178             offsetof(struct _FILE_TAG, imageNext), (unsigned int)*(unsigned char *)(header->imageNext),
179             offsetof(struct _FILE_TAG, imageValidationToken), ntohl( *((unsigned int *)(header->imageValidationToken)) ),
180             offsetof(struct _FILE_TAG, tagValidationToken), ntohl( *((unsigned int *)(header->tagValidationToken)) )
181      );
182
183      heap_and_reap(buffer, 0, 0);
184      close(fd);
185     } else {
186       fprintf(stderr, "Unable to open for %s (%s)\n", "reading" , filename );
187     }
188   } else {
189     pr_usage(0);
190   }
191
192 end:
193   heap_and_reap(NULL-1, 0, 0);
194   return 0;
195 }
196