Annotation of elwix/tools/mktplinkfw/mktplinkfw.c, revision 1.1.2.2
1.1.2.1 misho 1: /*
2: * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
3: *
4: * This tool was based on:
5: * TP-Link WR941 V2 firmware checksum fixing tool.
6: * Copyright (C) 2008,2009 Wang Jian <lark@linux.net.cn>
7: *
8: * This program is free software; you can redistribute it and/or modify it
9: * under the terms of the GNU General Public License version 2 as published
10: * by the Free Software Foundation.
11: *
12: */
13:
14: #include <stdio.h>
15: #include <stdlib.h>
16: #include <stdint.h>
17: #include <string.h>
18: #include <unistd.h> /* for unlink() */
19: #include <libgen.h>
20: #include <getopt.h> /* for getopt() */
21: #include <stdarg.h>
22: #include <errno.h>
23: #include <sys/stat.h>
24: #include <arpa/inet.h>
25:
26: #include <openssl/md5.h>
27:
28: #define HOST_TO_BE32(x) htonl(x)
29: #define BE32_TO_HOST(x) ntohl(x)
30:
31: /*
32: * This is linux specific; it completely fails to get the endianness
33: * correct when building on FreeBSD.
34: */
35: #if 0
36: #if (__BYTE_ORDER == __BIG_ENDIAN)
37: # define HOST_TO_BE32(x) (x)
38: # define BE32_TO_HOST(x) (x)
39: #else
40: # define HOST_TO_BE32(x) bswap_32(x)
41: # define BE32_TO_HOST(x) bswap_32(x)
42: #endif
43: #endif
44:
45: #define HEADER_VERSION_V1 0x01000000
1.1.2.2 ! misho 46: #define HWID_TL_MR3020_V1 0x30200001
1.1.2.1 misho 47: #define HWID_TL_MR3220_V1 0x32200001
48: #define HWID_TL_MR3420_V1 0x34200001
49: #define HWID_TL_WA901ND_V1 0x09010001
50: #define HWID_TL_WA901ND_V2 0x09010002
51: #define HWID_TL_WR703N_V1 0x07030101
52: #define HWID_TL_WR741ND_V1 0x07410001
53: #define HWID_TL_WR740N_V1 0x07400001
54: #define HWID_TL_WR740N_V3 0x07400300
55: #define HWID_TL_WR743ND_V1 0x07430001
56: #define HWID_TL_WR841N_V1_5 0x08410002
57: #define HWID_TL_WR841ND_V3 0x08410003
58: #define HWID_TL_WR841ND_V5 0x08410005
59: #define HWID_TL_WR841ND_V7 0x08410007
60: #define HWID_TL_WR941ND_V2 0x09410002
61: #define HWID_TL_WR941ND_V4 0x09410004
62: #define HWID_TL_WR1043ND_V1 0x10430001
63:
64: #define MD5SUM_LEN 16
65:
66: struct file_info {
67: char *file_name; /* name of the file */
68: uint32_t file_size; /* length of the file */
69: };
70:
71: struct fw_header {
72: uint32_t version; /* header version */
73: char vendor_name[24];
74: char fw_version[36];
75: uint32_t hw_id; /* hardware id */
76: uint32_t hw_rev; /* hardware revision */
77: uint32_t unk1;
78: uint8_t md5sum1[MD5SUM_LEN];
79: uint32_t unk2;
80: uint8_t md5sum2[MD5SUM_LEN];
81: uint32_t unk3;
82: uint32_t kernel_la; /* kernel load address */
83: uint32_t kernel_ep; /* kernel entry point */
84: uint32_t fw_length; /* total length of the firmware */
85: uint32_t kernel_ofs; /* kernel data offset */
86: uint32_t kernel_len; /* kernel data length */
87: uint32_t rootfs_ofs; /* rootfs data offset */
88: uint32_t rootfs_len; /* rootfs data length */
89: uint32_t boot_ofs; /* bootloader data offset */
90: uint32_t boot_len; /* bootloader data length */
91: uint8_t pad[360];
92: } __attribute__ ((packed));
93:
94: struct board_info {
95: char *id;
96: uint32_t hw_id;
97: uint32_t hw_rev;
98: uint32_t fw_max_len;
99: uint32_t kernel_la;
100: uint32_t kernel_ep;
101: uint32_t rootfs_ofs;
102: };
103:
104: /*
105: * Globals
106: */
107: static char *ofname;
108: static char *progname;
109: static char *vendor = "TP-LINK Technologies";
110: static char *version = "ver. 1.0";
111:
112: static char *board_id;
113: static struct board_info *board;
114: static struct file_info kernel_info;
115: static uint32_t kernel_la = 0;
116: static uint32_t kernel_ep = 0;
117: static struct file_info rootfs_info;
118: static uint32_t rootfs_ofs = 0;
119: static struct file_info boot_info;
120: static int combined;
121: static int strip_padding;
122:
123: static struct file_info inspect_info;
124: static int extract = 0;
125:
126: char md5salt_normal[MD5SUM_LEN] = {
127: 0xdc, 0xd7, 0x3a, 0xa5, 0xc3, 0x95, 0x98, 0xfb,
128: 0xdd, 0xf9, 0xe7, 0xf4, 0x0e, 0xae, 0x47, 0x38,
129: };
130:
131: char md5salt_boot[MD5SUM_LEN] = {
132: 0x8c, 0xef, 0x33, 0x5b, 0xd5, 0xc5, 0xce, 0xfa,
133: 0xa7, 0x9c, 0x28, 0xda, 0xb2, 0xe9, 0x0f, 0x42,
134: };
135:
136: static struct board_info boards[] = {
137: {
1.1.2.2 ! misho 138: .id = "TL-MR3020v1",
! 139: .hw_id = HWID_TL_MR3020_V1,
! 140: .hw_rev = 1,
! 141: /*
! 142: * Actual size of firmware is 3.8MB but for now, allow larger
! 143: * sizes until we work out a plan for this unit
! 144: * .fw_max_len = 0x3c0000,
! 145: */
! 146: .fw_max_len = 0x640000,
! 147: .kernel_la = 0x80060000,
! 148: .kernel_ep = 0x80060000,
! 149: .rootfs_ofs = 0x100000,
! 150: }, {
1.1.2.1 misho 151: .id = "TL-MR3220v1",
152: .hw_id = HWID_TL_MR3220_V1,
153: .hw_rev = 1,
154: .fw_max_len = 0x3c0000,
155: .kernel_la = 0x80060000,
156: .kernel_ep = 0x80060000,
157: .rootfs_ofs = 0x140000,
158: }, {
159: .id = "TL-MR3420v1",
160: .hw_id = HWID_TL_MR3420_V1,
161: .hw_rev = 1,
162: .fw_max_len = 0x3c0000,
163: .kernel_la = 0x80060000,
164: .kernel_ep = 0x80060000,
165: .rootfs_ofs = 0x140000,
166: }, {
167: .id = "TL-WA901NDv1",
168: .hw_id = HWID_TL_WA901ND_V1,
169: .hw_rev = 1,
170: .fw_max_len = 0x3c0000,
171: .kernel_la = 0x80060000,
172: .kernel_ep = 0x80060000,
173: .rootfs_ofs = 0x140000,
174: }, {
175: .id = "TL-WA901NDv2",
176: .hw_id = HWID_TL_WA901ND_V2,
177: .hw_rev = 1,
178: .fw_max_len = 0x3c0000,
179: .kernel_la = 0x80060000,
180: .kernel_ep = 0x80060000,
181: .rootfs_ofs = 0x140000,
182: }, {
183: .id = "TL-WR741NDv1",
184: .hw_id = HWID_TL_WR741ND_V1,
185: .hw_rev = 1,
186: .fw_max_len = 0x3c0000,
187: .kernel_la = 0x80060000,
188: .kernel_ep = 0x80060000,
189: .rootfs_ofs = 0x140000,
190: }, {
191: .id = "TL-WR740Nv1",
192: .hw_id = HWID_TL_WR740N_V1,
193: .hw_rev = 1,
194: .fw_max_len = 0x3c0000,
195: .kernel_la = 0x80060000,
196: .kernel_ep = 0x80060000,
197: .rootfs_ofs = 0x140000,
198: }, {
199: .id = "TL-WR740Nv3",
200: .hw_id = HWID_TL_WR740N_V3,
201: .hw_rev = 1,
202: .fw_max_len = 0x3c0000,
203: .kernel_la = 0x80060000,
204: .kernel_ep = 0x80060000,
205: .rootfs_ofs = 0x140000,
206: }, {
207: .id = "TL-WR743NDv1",
208: .hw_id = HWID_TL_WR743ND_V1,
209: .hw_rev = 1,
210: .fw_max_len = 0x3c0000,
211: .kernel_la = 0x80060000,
212: .kernel_ep = 0x80060000,
213: .rootfs_ofs = 0x140000,
214: }, {
215: .id = "TL-WR841Nv1.5",
216: .hw_id = HWID_TL_WR841N_V1_5,
217: .hw_rev = 2,
218: .fw_max_len = 0x3c0000,
219: .kernel_la = 0x80060000,
220: .kernel_ep = 0x80060000,
221: .rootfs_ofs = 0x140000,
222: }, {
223: .id = "TL-WR841NDv3",
224: .hw_id = HWID_TL_WR841ND_V3,
225: .hw_rev = 3,
226: .fw_max_len = 0x3c0000,
227: .kernel_la = 0x80060000,
228: .kernel_ep = 0x80060000,
229: .rootfs_ofs = 0x140000,
230: }, {
231: .id = "TL-WR841NDv5",
232: .hw_id = HWID_TL_WR841ND_V5,
233: .hw_rev = 1,
234: .fw_max_len = 0x3c0000,
235: .kernel_la = 0x80060000,
236: .kernel_ep = 0x80060000,
237: .rootfs_ofs = 0x140000,
238: }, {
239: .id = "TL-WR841NDv7",
240: .hw_id = HWID_TL_WR841ND_V7,
241: .hw_rev = 1,
242: .fw_max_len = 0x3c0000,
243: .kernel_la = 0x80060000,
244: .kernel_ep = 0x80060000,
245: .rootfs_ofs = 0x140000,
246: }, {
247: .id = "TL-WR941NDv2",
248: .hw_id = HWID_TL_WR941ND_V2,
249: .hw_rev = 2,
250: .fw_max_len = 0x3c0000,
251: .kernel_la = 0x80060000,
252: .kernel_ep = 0x80060000,
253: .rootfs_ofs = 0x140000,
254: }, {
255: .id = "TL-WR941NDv4",
256: .hw_id = HWID_TL_WR941ND_V4,
257: .hw_rev = 1,
258: .fw_max_len = 0x3c0000,
259: .kernel_la = 0x80060000,
260: .kernel_ep = 0x80060000,
261: .rootfs_ofs = 0x140000,
262: }, {
263: .id = "TL-WR1043NDv1",
264: .hw_id = HWID_TL_WR1043ND_V1,
265: .hw_rev = 1,
266: .fw_max_len = 0x7c0000,
267: .kernel_la = 0x80060000,
268: .kernel_ep = 0x80060000,
269: .rootfs_ofs = 0x140000,
270: }, {
271: .id = "TL-WR703Nv1",
272: .hw_id = HWID_TL_WR703N_V1,
273: .hw_rev = 1,
274: .fw_max_len = 0x3c0000,
275: .kernel_la = 0x80060000,
276: .kernel_ep = 0x80060000,
277: .rootfs_ofs = 0x100000,
278: }, {
279: /* terminating entry */
280: }
281: };
282:
283: /*
284: * Message macros
285: */
286: #define ERR(fmt, ...) do { \
287: fflush(0); \
288: fprintf(stderr, "[%s] *** error: " fmt "\n", \
289: progname, ## __VA_ARGS__ ); \
290: } while (0)
291:
292: #define ERRS(fmt, ...) do { \
293: int save = errno; \
294: fflush(0); \
1.1.2.2 ! misho 295: fprintf(stderr, "[%s] *** error: " fmt " error:%s\n", \
1.1.2.1 misho 296: progname, ## __VA_ARGS__, strerror(save)); \
297: } while (0)
298:
299: #define DBG(fmt, ...) do { \
300: fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
301: } while (0)
302:
303: static struct board_info *find_board(char *id)
304: {
305: struct board_info *ret;
306: struct board_info *board;
307:
308: ret = NULL;
309: for (board = boards; board->id != NULL; board++){
310: if (strcasecmp(id, board->id) == 0) {
311: ret = board;
312: break;
313: }
314: };
315:
316: return ret;
317: }
318:
319: static struct board_info *find_board_by_hwid(uint32_t hw_id)
320: {
321: struct board_info *board;
322:
323: for (board = boards; board->id != NULL; board++) {
324: if (hw_id == board->hw_id)
325: return board;
326: };
327:
328: return NULL;
329: }
330:
331:
332: static void usage(int status)
333: {
334: FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
335: struct board_info *board;
336:
337: fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
338: fprintf(stream,
339: "\n"
340: "Options:\n"
341: " -B <board> create image for the board specified with <board>\n"
342: " -c use combined kernel image\n"
343: " -E <ep> overwrite kernel entry point with <ep> (hexval prefixed with 0x)\n"
344: " -L <la> overwrite kernel load address with <la> (hexval prefixed with 0x)\n"
345: " -k <file> read kernel image from the file <file>\n"
346: " -r <file> read rootfs image from the file <file>\n"
347: " -R <offset> overwrite rootfs offset with <offset> (hexval prefixed with 0x)\n"
348: " -o <file> write output to the file <file>\n"
349: " -s strip padding from the end of the image\n"
350: " -N <vendor> set image vendor to <vendor>\n"
351: " -V <version> set image version to <version>\n"
352: " -i <file> inspect given firmware file <file>\n"
353: " -x extract kernel and rootfs while inspecting (requires -i)\n"
354: " -h show this screen\n"
355: );
356:
357: exit(status);
358: }
359:
1.1.2.2 ! misho 360: static void get_md5(char *data, int size, uint8_t *md5)
1.1.2.1 misho 361: {
362: MD5_CTX ctx;
363:
364: MD5_Init(&ctx);
365: MD5_Update(&ctx, data, size);
1.1.2.2 ! misho 366: MD5_Final(md5, &ctx);
1.1.2.1 misho 367: }
368:
369: static int get_file_stat(struct file_info *fdata)
370: {
371: struct stat st;
372: int res;
373:
374: if (fdata->file_name == NULL)
375: return 0;
376:
377: res = stat(fdata->file_name, &st);
378: if (res){
379: ERRS("stat failed on %s", fdata->file_name);
380: return res;
381: }
382:
383: fdata->file_size = st.st_size;
384: return 0;
385: }
386:
387: static int read_to_buf(struct file_info *fdata, char *buf)
388: {
389: FILE *f;
390: int ret = EXIT_FAILURE;
391:
392: f = fopen(fdata->file_name, "r");
393: if (f == NULL) {
394: ERRS("could not open \"%s\" for reading", fdata->file_name);
395: goto out;
396: }
397:
398: errno = 0;
399: fread(buf, fdata->file_size, 1, f);
400: if (errno != 0) {
401: ERRS("unable to read from file \"%s\"", fdata->file_name);
402: goto out_close;
403: }
404:
405: ret = EXIT_SUCCESS;
406:
407: out_close:
408: fclose(f);
409: out:
410: return ret;
411: }
412:
413: static int check_options(void)
414: {
415: int ret;
416:
417: if (inspect_info.file_name) {
418: ret = get_file_stat(&inspect_info);
419: if (ret)
420: return ret;
421:
422: return 0;
423: } else if (extract) {
424: ERR("no firmware for inspection specified");
425: return -1;
426: }
427:
428: if (board_id == NULL) {
429: ERR("no board specified");
430: return -1;
431: }
432:
433: board = find_board(board_id);
434: if (board == NULL) {
435: ERR("unknown/unsupported board id \"%s\"", board_id);
436: return -1;
437: }
438: if (!kernel_la)
439: kernel_la = board->kernel_la;
440: if (!kernel_ep)
441: kernel_ep = board->kernel_ep;
442: if (!rootfs_ofs)
443: rootfs_ofs = board->rootfs_ofs;
444:
445: if (kernel_info.file_name == NULL) {
446: ERR("no kernel image specified");
447: return -1;
448: }
449:
450: ret = get_file_stat(&kernel_info);
451: if (ret)
452: return ret;
453:
454: if (combined) {
455: if (kernel_info.file_size >
456: board->fw_max_len - sizeof(struct fw_header)) {
1.1.2.2 ! misho 457: ERR("Combined kernel image is too big. Max[%lu] kernel img [%d]",
! 458: board->fw_max_len - sizeof(struct fw_header), kernel_info.file_size);
1.1.2.1 misho 459: return -1;
460: }
461: } else {
462: if (kernel_info.file_size >
1.1.2.2 ! misho 463: (rootfs_ofs - sizeof(struct fw_header))) {
! 464: ERR("kernel image is too big. Max[%lu] kernel img [%d]",
! 465: rootfs_ofs - sizeof(struct fw_header), kernel_info.file_size);
1.1.2.1 misho 466: return -1;
467: }
468: if (rootfs_info.file_name == NULL) {
469: ERR("no rootfs image specified");
470: return -1;
471: }
472:
473: ret = get_file_stat(&rootfs_info);
474: if (ret)
475: return ret;
476:
477: if (rootfs_info.file_size >
478: (board->fw_max_len - rootfs_ofs)) {
1.1.2.2 ! misho 479: ERR("rootfs image is too big. Max[%d] fs img [%d]",
! 480: board->fw_max_len - rootfs_ofs, rootfs_info.file_size);
1.1.2.1 misho 481: return -1;
482: }
483: }
484:
485: if (ofname == NULL) {
486: ERR("no output file specified");
487: return -1;
488: }
489:
490: return 0;
491: }
492:
493: static void fill_header(char *buf, int len)
494: {
495: struct fw_header *hdr = (struct fw_header *)buf;
496:
497: memset(hdr, 0, sizeof(struct fw_header));
498:
499: hdr->version = HOST_TO_BE32(HEADER_VERSION_V1);
500: strncpy(hdr->vendor_name, vendor, sizeof(hdr->vendor_name));
501: strncpy(hdr->fw_version, version, sizeof(hdr->fw_version));
502: hdr->hw_id = HOST_TO_BE32(board->hw_id);
503: hdr->hw_rev = HOST_TO_BE32(board->hw_rev);
504:
505: if (boot_info.file_size == 0)
506: memcpy(hdr->md5sum1, md5salt_normal, sizeof(hdr->md5sum1));
507: else
508: memcpy(hdr->md5sum1, md5salt_boot, sizeof(hdr->md5sum1));
509:
510: hdr->kernel_la = HOST_TO_BE32(kernel_la);
511: hdr->kernel_ep = HOST_TO_BE32(kernel_ep);
512: hdr->fw_length = HOST_TO_BE32(board->fw_max_len);
513: hdr->kernel_ofs = HOST_TO_BE32(sizeof(struct fw_header));
514: hdr->kernel_len = HOST_TO_BE32(kernel_info.file_size);
515: if (!combined) {
516: hdr->rootfs_ofs = HOST_TO_BE32(rootfs_ofs);
517: hdr->rootfs_len = HOST_TO_BE32(rootfs_info.file_size);
518: }
519:
1.1.2.2 ! misho 520: get_md5(buf, len, hdr->md5sum1);
1.1.2.1 misho 521: }
522:
523: static int write_fw(char *data, int len)
524: {
525: FILE *f;
526: int ret = EXIT_FAILURE;
527:
528: f = fopen(ofname, "w");
529: if (f == NULL) {
530: ERRS("could not open \"%s\" for writing", ofname);
531: goto out;
532: }
533:
534: errno = 0;
535: fwrite(data, len, 1, f);
536: if (errno) {
1.1.2.2 ! misho 537: ERRS("unable to write output file \"%s\"", ofname);
1.1.2.1 misho 538: goto out_flush;
539: }
540:
541: DBG("firmware file \"%s\" completed", ofname);
542:
543: ret = EXIT_SUCCESS;
544:
545: out_flush:
546: fflush(f);
547: fclose(f);
548: if (ret != EXIT_SUCCESS) {
549: unlink(ofname);
550: }
551: out:
552: return ret;
553: }
554:
555: static int build_fw(void)
556: {
557: int buflen;
558: char *buf;
559: char *p;
560: int ret = EXIT_FAILURE;
561: int writelen = 0;
562:
563: buflen = board->fw_max_len;
564:
565: buf = malloc(buflen);
566: if (!buf) {
567: ERR("no memory for buffer\n");
568: goto out;
569: }
570:
571: memset(buf, 0xff, buflen);
572: p = buf + sizeof(struct fw_header);
573: ret = read_to_buf(&kernel_info, p);
574: if (ret)
575: goto out_free_buf;
576:
577: writelen = kernel_info.file_size;
578:
579: if (!combined) {
580: p = buf + rootfs_ofs;
581: ret = read_to_buf(&rootfs_info, p);
582: if (ret)
583: goto out_free_buf;
584:
585: writelen = rootfs_ofs + rootfs_info.file_size;
586: }
587:
588: if (!strip_padding)
589: writelen = buflen;
590:
591: fill_header(buf, writelen);
592: ret = write_fw(buf, writelen);
593: if (ret)
594: goto out_free_buf;
595:
596: ret = EXIT_SUCCESS;
597:
598: out_free_buf:
599: free(buf);
600: out:
601: return ret;
602: }
603:
604: /* Helper functions to inspect_fw() representing different output formats */
605: static inline void inspect_fw_pstr(char *label, char *str)
606: {
607: printf("%-23s: %s\n", label, str);
608: }
609:
610: static inline void inspect_fw_phex(char *label, uint32_t val)
611: {
612: printf("%-23s: 0x%08x\n", label, val);
613: }
614:
615: static inline void inspect_fw_phexpost(char *label,
616: uint32_t val, char *post)
617: {
618: printf("%-23s: 0x%08x (%s)\n", label, val, post);
619: }
620:
621: static inline void inspect_fw_phexdef(char *label,
622: uint32_t val, uint32_t defval)
623: {
624: printf("%-23s: 0x%08x ", label, val);
625:
626: if (val == defval)
627: printf("(== OpenWrt default)\n");
628: else
629: printf("(OpenWrt default: 0x%08x)\n", defval);
630: }
631:
632: static inline void inspect_fw_phexexp(char *label,
633: uint32_t val, uint32_t expval)
634: {
635: printf("%-23s: 0x%08x ", label, val);
636:
637: if (val == expval)
638: printf("(ok)\n");
639: else
640: printf("(expected: 0x%08x)\n", expval);
641: }
642:
643: static inline void inspect_fw_phexdec(char *label, uint32_t val)
644: {
645: printf("%-23s: 0x%08x / %8u bytes\n", label, val, val);
646: }
647:
648: static inline void inspect_fw_phexdecdef(char *label,
649: uint32_t val, uint32_t defval)
650: {
651: printf("%-23s: 0x%08x / %8u bytes ", label, val, val);
652:
653: if (val == defval)
654: printf("(== OpenWrt default)\n");
655: else
656: printf("(OpenWrt default: 0x%08x)\n", defval);
657: }
658:
659: static inline void inspect_fw_pmd5sum(char *label, uint8_t *val, char *text)
660: {
661: int i;
662:
663: printf("%-23s:", label);
664: for (i=0; i<MD5SUM_LEN; i++)
665: printf(" %02x", val[i]);
666: printf(" %s\n", text);
667: }
668:
669: static int inspect_fw(void)
670: {
671: char *buf;
672: struct fw_header *hdr;
673: uint8_t md5sum[MD5SUM_LEN];
674: struct board_info *board;
675: int ret = EXIT_FAILURE;
676:
677: buf = malloc(inspect_info.file_size);
678: if (!buf) {
679: ERR("no memory for buffer!\n");
680: goto out;
681: }
682:
683: ret = read_to_buf(&inspect_info, buf);
684: if (ret)
685: goto out_free_buf;
686: hdr = (struct fw_header *)buf;
687:
688: inspect_fw_pstr("File name", inspect_info.file_name);
689: inspect_fw_phexdec("File size", inspect_info.file_size);
690:
691: if (BE32_TO_HOST(hdr->version) != HEADER_VERSION_V1) {
692: ERR("file does not seem to have V1 header!\n");
693: goto out_free_buf;
694: }
695:
696: inspect_fw_phexdec("Version 1 Header size", sizeof(struct fw_header));
697:
698: if (BE32_TO_HOST(hdr->unk1) != 0)
699: inspect_fw_phexdec("Unknown value 1", hdr->unk1);
700:
701: memcpy(md5sum, hdr->md5sum1, sizeof(md5sum));
702: if (BE32_TO_HOST(hdr->boot_len) == 0)
703: memcpy(hdr->md5sum1, md5salt_normal, sizeof(md5sum));
704: else
705: memcpy(hdr->md5sum1, md5salt_boot, sizeof(md5sum));
1.1.2.2 ! misho 706: get_md5(buf, inspect_info.file_size, hdr->md5sum1);
1.1.2.1 misho 707:
708: if (memcmp(md5sum, hdr->md5sum1, sizeof(md5sum))) {
709: inspect_fw_pmd5sum("Header MD5Sum1", md5sum, "(*ERROR*)");
710: inspect_fw_pmd5sum(" --> expected", hdr->md5sum1, "");
711: } else {
712: inspect_fw_pmd5sum("Header MD5Sum1", md5sum, "(ok)");
713: }
714: if (BE32_TO_HOST(hdr->unk2) != 0)
715: inspect_fw_phexdec("Unknown value 2", hdr->unk2);
716: inspect_fw_pmd5sum("Header MD5Sum2", hdr->md5sum2,
717: "(purpose yet unknown, unchecked here)");
718: if (BE32_TO_HOST(hdr->unk3) != 0)
719: inspect_fw_phexdec("Unknown value 3", hdr->unk3);
720:
721: printf("\n");
722:
723: inspect_fw_pstr("Vendor name", hdr->vendor_name);
724: inspect_fw_pstr("Firmware version", hdr->fw_version);
725: board = find_board_by_hwid(BE32_TO_HOST(hdr->hw_id));
726: if (board) {
727: inspect_fw_phexpost("Hardware ID",
728: BE32_TO_HOST(hdr->hw_id), board->id);
729: inspect_fw_phexexp("Hardware Revision",
730: BE32_TO_HOST(hdr->hw_rev), board->hw_rev);
731: } else {
732: inspect_fw_phexpost("Hardware ID",
733: BE32_TO_HOST(hdr->hw_id), "unknown");
734: inspect_fw_phex("Hardware Revision",
735: BE32_TO_HOST(hdr->hw_rev));
736: }
737:
738: printf("\n");
739:
740: inspect_fw_phexdec("Kernel data offset",
741: BE32_TO_HOST(hdr->kernel_ofs));
742: inspect_fw_phexdec("Kernel data length",
743: BE32_TO_HOST(hdr->kernel_len));
744: if (board) {
745: inspect_fw_phexdef("Kernel load address",
746: BE32_TO_HOST(hdr->kernel_la),
747: board->kernel_la);
748: inspect_fw_phexdef("Kernel entry point",
749: BE32_TO_HOST(hdr->kernel_ep),
750: board->kernel_ep);
751: inspect_fw_phexdecdef("Rootfs data offset",
752: BE32_TO_HOST(hdr->rootfs_ofs),
753: board->rootfs_ofs);
754: } else {
755: inspect_fw_phex("Kernel load address",
756: BE32_TO_HOST(hdr->kernel_la));
757: inspect_fw_phex("Kernel entry point",
758: BE32_TO_HOST(hdr->kernel_ep));
759: inspect_fw_phexdec("Rootfs data offset",
760: BE32_TO_HOST(hdr->rootfs_ofs));
761: }
762: inspect_fw_phexdec("Rootfs data length",
763: BE32_TO_HOST(hdr->rootfs_len));
764: inspect_fw_phexdec("Boot loader data offset",
765: BE32_TO_HOST(hdr->boot_ofs));
766: inspect_fw_phexdec("Boot loader data length",
767: BE32_TO_HOST(hdr->boot_len));
768: inspect_fw_phexdec("Total firmware length",
769: BE32_TO_HOST(hdr->fw_length));
770:
771: if (extract) {
772: FILE *fp;
773: char *filename;
774:
775: printf("\n");
776:
777: filename = malloc(strlen(inspect_info.file_name) + 8);
778: sprintf(filename, "%s-kernel", inspect_info.file_name);
779: printf("Extracting kernel to \"%s\"...\n", filename);
780: fp = fopen(filename, "w");
781: if (fp) {
782: if (!fwrite(buf + BE32_TO_HOST(hdr->kernel_ofs),
783: BE32_TO_HOST(hdr->kernel_len), 1, fp)) {
784: ERR("error in fwrite(): %s", strerror(errno));
785: }
786: fclose(fp);
787: } else {
788: ERR("error in fopen(): %s", strerror(errno));
789: }
790: free(filename);
791:
792: filename = malloc(strlen(inspect_info.file_name) + 8);
793: sprintf(filename, "%s-rootfs", inspect_info.file_name);
794: printf("Extracting rootfs to \"%s\"...\n", filename);
795: fp = fopen(filename, "w");
796: if (fp) {
797: if (!fwrite(buf + BE32_TO_HOST(hdr->rootfs_ofs),
798: BE32_TO_HOST(hdr->rootfs_len), 1, fp)) {
799: ERR("error in fwrite(): %s", strerror(errno));
800: }
801: fclose(fp);
802: } else {
803: ERR("error in fopen(): %s", strerror(errno));
804: }
805: free(filename);
806: }
807:
808: out_free_buf:
809: free(buf);
810: out:
811: return ret;
812: }
813:
814: int main(int argc, char *argv[])
815: {
816: int ret = EXIT_FAILURE;
817: int err;
818:
819: FILE *outfile;
820:
821: progname = basename(argv[0]);
822:
823: while ( 1 ) {
824: int c;
825:
826: c = getopt(argc, argv, "B:E:L:V:N:ci:k:r:R:o:xhs");
827: if (c == -1)
828: break;
829:
830: switch (c) {
831: case 'B':
832: board_id = optarg;
833: break;
834: case 'E':
835: sscanf(optarg, "0x%x", &kernel_ep);
836: break;
837: case 'L':
838: sscanf(optarg, "0x%x", &kernel_la);
839: break;
840: case 'V':
841: version = optarg;
842: break;
843: case 'N':
844: vendor = optarg;
845: break;
846: case 'c':
847: combined++;
848: break;
849: case 'k':
850: kernel_info.file_name = optarg;
851: break;
852: case 'r':
853: rootfs_info.file_name = optarg;
854: break;
855: case 'R':
856: sscanf(optarg, "0x%x", &rootfs_ofs);
857: break;
858: case 'o':
859: ofname = optarg;
860: break;
861: case 's':
862: strip_padding = 1;
863: break;
864: case 'i':
865: inspect_info.file_name = optarg;
866: break;
867: case 'x':
868: extract = 1;
869: break;
870: case 'h':
871: usage(EXIT_SUCCESS);
872: break;
873: default:
874: usage(EXIT_FAILURE);
875: break;
876: }
877: }
878:
879: ret = check_options();
880: if (ret)
881: goto out;
882:
883: if (!inspect_info.file_name)
884: ret = build_fw();
885: else
886: ret = inspect_fw();
887:
888: out:
889: return ret;
890: }
891:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>