mktplinkfw2.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944
  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. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <stdint.h>
  16. #include <string.h>
  17. #include <unistd.h> /* for unlink() */
  18. #include <libgen.h>
  19. #include <getopt.h> /* for getopt() */
  20. #include <stdarg.h>
  21. #include <errno.h>
  22. #include <sys/stat.h>
  23. #include <arpa/inet.h>
  24. #include <netinet/in.h>
  25. #include "md5.h"
  26. #define ALIGN(x,a) ({ typeof(a) __a = (a); (((x) + __a - 1) & ~(__a - 1)); })
  27. #define HEADER_VERSION_V2 0x02000000
  28. #define HWID_TD_W8970_V1 0x89700001
  29. #define MD5SUM_LEN 16
  30. struct file_info {
  31. char *file_name; /* name of the file */
  32. uint32_t file_size; /* length of the file */
  33. };
  34. struct fw_header {
  35. uint32_t version; /* 0x00: header version */
  36. char fw_version[48]; /* 0x04: fw version string */
  37. uint32_t hw_id; /* 0x34: hardware id */
  38. uint32_t hw_rev; /* 0x38: FIXME: hardware revision? */
  39. uint32_t unk1; /* 0x3c: 0x00000000 */
  40. uint8_t md5sum1[MD5SUM_LEN]; /* 0x40 */
  41. uint32_t unk2; /* 0x50: 0x00000000 */
  42. uint8_t md5sum2[MD5SUM_LEN]; /* 0x54 */
  43. uint32_t unk3; /* 0x64: 0xffffffff */
  44. uint32_t kernel_la; /* 0x68: kernel load address */
  45. uint32_t kernel_ep; /* 0x6c: kernel entry point */
  46. uint32_t fw_length; /* 0x70: total length of the image */
  47. uint32_t kernel_ofs; /* 0x74: kernel data offset */
  48. uint32_t kernel_len; /* 0x78: kernel data length */
  49. uint32_t rootfs_ofs; /* 0x7c: rootfs data offset */
  50. uint32_t rootfs_len; /* 0x80: rootfs data length */
  51. uint32_t boot_ofs; /* 0x84: FIXME: seems to be unused */
  52. uint32_t boot_len; /* 0x88: FIXME: seems to be unused */
  53. uint16_t unk4; /* 0x8c: 0x55aa */
  54. uint8_t sver_hi; /* 0x8e */
  55. uint8_t sver_lo; /* 0x8f */
  56. uint8_t unk5; /* 0x90: magic: 0xa5 */
  57. uint8_t ver_hi; /* 0x91 */
  58. uint8_t ver_mid; /* 0x92 */
  59. uint8_t ver_lo; /* 0x93 */
  60. uint8_t pad[364];
  61. } __attribute__ ((packed));
  62. struct flash_layout {
  63. char *id;
  64. uint32_t fw_max_len;
  65. uint32_t kernel_la;
  66. uint32_t kernel_ep;
  67. uint32_t rootfs_ofs;
  68. };
  69. struct board_info {
  70. char *id;
  71. uint32_t hw_id;
  72. uint32_t hw_rev;
  73. char *layout_id;
  74. };
  75. /*
  76. * Globals
  77. */
  78. static char *ofname;
  79. static char *progname;
  80. static char *vendor = "TP-LINK Technologies";
  81. static char *version = "ver. 1.0";
  82. static char *fw_ver = "0.0.0";
  83. static char *sver = "1.0";
  84. static char *board_id;
  85. static struct board_info *board;
  86. static char *layout_id;
  87. static struct flash_layout *layout;
  88. static char *opt_hw_id;
  89. static uint32_t hw_id;
  90. static char *opt_hw_rev;
  91. static uint32_t hw_rev;
  92. static int fw_ver_lo;
  93. static int fw_ver_mid;
  94. static int fw_ver_hi;
  95. static int sver_lo;
  96. static int sver_hi;
  97. static struct file_info kernel_info;
  98. static uint32_t kernel_la = 0;
  99. static uint32_t kernel_ep = 0;
  100. static uint32_t kernel_len = 0;
  101. static struct file_info rootfs_info;
  102. static uint32_t rootfs_ofs = 0;
  103. static uint32_t rootfs_align;
  104. static struct file_info boot_info;
  105. static int combined;
  106. static int strip_padding;
  107. static int add_jffs2_eof;
  108. static unsigned char jffs2_eof_mark[4] = {0xde, 0xad, 0xc0, 0xde};
  109. static struct file_info inspect_info;
  110. static int extract = 0;
  111. char md5salt_normal[MD5SUM_LEN] = {
  112. 0xdc, 0xd7, 0x3a, 0xa5, 0xc3, 0x95, 0x98, 0xfb,
  113. 0xdc, 0xf9, 0xe7, 0xf4, 0x0e, 0xae, 0x47, 0x37,
  114. };
  115. char md5salt_boot[MD5SUM_LEN] = {
  116. 0x8c, 0xef, 0x33, 0x5b, 0xd5, 0xc5, 0xce, 0xfa,
  117. 0xa7, 0x9c, 0x28, 0xda, 0xb2, 0xe9, 0x0f, 0x42,
  118. };
  119. static struct flash_layout layouts[] = {
  120. {
  121. .id = "8Mltq",
  122. .fw_max_len = 0x7a0000,
  123. .kernel_la = 0x80002000,
  124. .kernel_ep = 0x80002000,
  125. .rootfs_ofs = 0x140000,
  126. }, {
  127. /* terminating entry */
  128. }
  129. };
  130. static struct board_info boards[] = {
  131. {
  132. .id = "TD-W8970v1",
  133. .hw_id = HWID_TD_W8970_V1,
  134. .hw_rev = 1,
  135. .layout_id = "8Mltq",
  136. }, {
  137. /* terminating entry */
  138. }
  139. };
  140. /*
  141. * Message macros
  142. */
  143. #define ERR(fmt, ...) do { \
  144. fflush(0); \
  145. fprintf(stderr, "[%s] *** error: " fmt "\n", \
  146. progname, ## __VA_ARGS__ ); \
  147. } while (0)
  148. #define ERRS(fmt, ...) do { \
  149. int save = errno; \
  150. fflush(0); \
  151. fprintf(stderr, "[%s] *** error: " fmt "\n", \
  152. progname, ## __VA_ARGS__, strerror(save)); \
  153. } while (0)
  154. #define DBG(fmt, ...) do { \
  155. fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
  156. } while (0)
  157. static struct board_info *find_board(char *id)
  158. {
  159. struct board_info *ret;
  160. struct board_info *board;
  161. ret = NULL;
  162. for (board = boards; board->id != NULL; board++){
  163. if (strcasecmp(id, board->id) == 0) {
  164. ret = board;
  165. break;
  166. }
  167. };
  168. return ret;
  169. }
  170. static struct board_info *find_board_by_hwid(uint32_t hw_id)
  171. {
  172. struct board_info *board;
  173. for (board = boards; board->id != NULL; board++) {
  174. if (hw_id == board->hw_id)
  175. return board;
  176. };
  177. return NULL;
  178. }
  179. static struct flash_layout *find_layout(char *id)
  180. {
  181. struct flash_layout *ret;
  182. struct flash_layout *l;
  183. ret = NULL;
  184. for (l = layouts; l->id != NULL; l++){
  185. if (strcasecmp(id, l->id) == 0) {
  186. ret = l;
  187. break;
  188. }
  189. };
  190. return ret;
  191. }
  192. static void usage(int status)
  193. {
  194. FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
  195. struct board_info *board;
  196. fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
  197. fprintf(stream,
  198. "\n"
  199. "Options:\n"
  200. " -B <board> create image for the board specified with <board>\n"
  201. " -c use combined kernel image\n"
  202. " -E <ep> overwrite kernel entry point with <ep> (hexval prefixed with 0x)\n"
  203. " -L <la> overwrite kernel load address with <la> (hexval prefixed with 0x)\n"
  204. " -H <hwid> use hardware id specified with <hwid>\n"
  205. " -W <hwrev> use hardware revision specified with <hwrev>\n"
  206. " -F <id> use flash layout specified with <id>\n"
  207. " -k <file> read kernel image from the file <file>\n"
  208. " -r <file> read rootfs image from the file <file>\n"
  209. " -a <align> align the rootfs start on an <align> bytes boundary\n"
  210. " -R <offset> overwrite rootfs offset with <offset> (hexval prefixed with 0x)\n"
  211. " -o <file> write output to the file <file>\n"
  212. " -s strip padding from the end of the image\n"
  213. " -j add jffs2 end-of-filesystem markers\n"
  214. " -V <version> set image version to <version>\n"
  215. " -v <version> set firmware version to <version>\n"
  216. " -y <version> set secondary version to <version>\n"
  217. " -i <file> inspect given firmware file <file>\n"
  218. " -x extract kernel and rootfs while inspecting (requires -i)\n"
  219. " -h show this screen\n"
  220. );
  221. exit(status);
  222. }
  223. static int get_md5(char *data, int size, char *md5)
  224. {
  225. MD5_CTX ctx;
  226. MD5_Init(&ctx);
  227. MD5_Update(&ctx, data, size);
  228. MD5_Final(md5, &ctx);
  229. }
  230. static int get_file_stat(struct file_info *fdata)
  231. {
  232. struct stat st;
  233. int res;
  234. if (fdata->file_name == NULL)
  235. return 0;
  236. res = stat(fdata->file_name, &st);
  237. if (res){
  238. ERRS("stat failed on %s", fdata->file_name);
  239. return res;
  240. }
  241. fdata->file_size = st.st_size;
  242. return 0;
  243. }
  244. static int read_to_buf(struct file_info *fdata, char *buf)
  245. {
  246. FILE *f;
  247. int ret = EXIT_FAILURE;
  248. f = fopen(fdata->file_name, "r");
  249. if (f == NULL) {
  250. ERRS("could not open \"%s\" for reading", fdata->file_name);
  251. goto out;
  252. }
  253. errno = 0;
  254. fread(buf, fdata->file_size, 1, f);
  255. if (errno != 0) {
  256. ERRS("unable to read from file \"%s\"", fdata->file_name);
  257. goto out_close;
  258. }
  259. ret = EXIT_SUCCESS;
  260. out_close:
  261. fclose(f);
  262. out:
  263. return ret;
  264. }
  265. static int check_options(void)
  266. {
  267. int ret;
  268. if (inspect_info.file_name) {
  269. ret = get_file_stat(&inspect_info);
  270. if (ret)
  271. return ret;
  272. return 0;
  273. } else if (extract) {
  274. ERR("no firmware for inspection specified");
  275. return -1;
  276. }
  277. if (board_id == NULL && opt_hw_id == NULL) {
  278. ERR("either board or hardware id must be specified");
  279. return -1;
  280. }
  281. if (board_id) {
  282. board = find_board(board_id);
  283. if (board == NULL) {
  284. ERR("unknown/unsupported board id \"%s\"", board_id);
  285. return -1;
  286. }
  287. if (layout_id == NULL)
  288. layout_id = board->layout_id;
  289. hw_id = board->hw_id;
  290. hw_rev = board->hw_rev;
  291. } else {
  292. if (layout_id == NULL) {
  293. ERR("flash layout is not specified");
  294. return -1;
  295. }
  296. hw_id = strtoul(opt_hw_id, NULL, 0);
  297. if (opt_hw_rev)
  298. hw_rev = strtoul(opt_hw_rev, NULL, 0);
  299. else
  300. hw_rev = 1;
  301. }
  302. layout = find_layout(layout_id);
  303. if (layout == NULL) {
  304. ERR("unknown flash layout \"%s\"", layout_id);
  305. return -1;
  306. }
  307. if (!kernel_la)
  308. kernel_la = layout->kernel_la;
  309. if (!kernel_ep)
  310. kernel_ep = layout->kernel_ep;
  311. if (!rootfs_ofs)
  312. rootfs_ofs = layout->rootfs_ofs;
  313. if (kernel_info.file_name == NULL) {
  314. ERR("no kernel image specified");
  315. return -1;
  316. }
  317. ret = get_file_stat(&kernel_info);
  318. if (ret)
  319. return ret;
  320. kernel_len = kernel_info.file_size;
  321. if (combined) {
  322. if (kernel_info.file_size >
  323. layout->fw_max_len - sizeof(struct fw_header)) {
  324. ERR("kernel image is too big");
  325. return -1;
  326. }
  327. } else {
  328. if (rootfs_info.file_name == NULL) {
  329. ERR("no rootfs image specified");
  330. return -1;
  331. }
  332. ret = get_file_stat(&rootfs_info);
  333. if (ret)
  334. return ret;
  335. if (rootfs_align) {
  336. kernel_len += sizeof(struct fw_header);
  337. kernel_len = ALIGN(kernel_len, rootfs_align);
  338. kernel_len -= sizeof(struct fw_header);
  339. DBG("kernel length aligned to %u", kernel_len);
  340. if (kernel_len + rootfs_info.file_size >
  341. layout->fw_max_len - sizeof(struct fw_header)) {
  342. ERR("images are too big");
  343. return -1;
  344. }
  345. } else {
  346. if (kernel_info.file_size >
  347. rootfs_ofs - sizeof(struct fw_header)) {
  348. ERR("kernel image is too big");
  349. return -1;
  350. }
  351. if (rootfs_info.file_size >
  352. (layout->fw_max_len - rootfs_ofs)) {
  353. ERR("rootfs image is too big");
  354. return -1;
  355. }
  356. }
  357. }
  358. if (ofname == NULL) {
  359. ERR("no output file specified");
  360. return -1;
  361. }
  362. ret = sscanf(fw_ver, "%d.%d.%d", &fw_ver_hi, &fw_ver_mid, &fw_ver_lo);
  363. if (ret != 3) {
  364. ERR("invalid firmware version '%s'", fw_ver);
  365. return -1;
  366. }
  367. ret = sscanf(sver, "%d.%d", &sver_hi, &sver_lo);
  368. if (ret != 2) {
  369. ERR("invalid secondary version '%s'", sver);
  370. return -1;
  371. }
  372. return 0;
  373. }
  374. static void fill_header(char *buf, int len)
  375. {
  376. struct fw_header *hdr = (struct fw_header *)buf;
  377. unsigned ver_len;
  378. memset(hdr, '\xff', sizeof(struct fw_header));
  379. hdr->version = htonl(HEADER_VERSION_V2);
  380. ver_len = strlen(version);
  381. if (ver_len > (sizeof(hdr->fw_version) - 1))
  382. ver_len = sizeof(hdr->fw_version) - 1;
  383. memcpy(hdr->fw_version, version, ver_len);
  384. hdr->fw_version[ver_len] = 0;
  385. hdr->hw_id = htonl(hw_id);
  386. hdr->hw_rev = htonl(hw_rev);
  387. if (boot_info.file_size == 0) {
  388. memcpy(hdr->md5sum1, md5salt_normal, sizeof(hdr->md5sum1));
  389. hdr->boot_ofs = htonl(0);
  390. hdr->boot_len = htonl(0);
  391. } else {
  392. memcpy(hdr->md5sum1, md5salt_boot, sizeof(hdr->md5sum1));
  393. hdr->boot_ofs = htonl(rootfs_ofs + rootfs_info.file_size);
  394. hdr->boot_len = htonl(rootfs_info.file_size);
  395. }
  396. hdr->kernel_la = htonl(kernel_la);
  397. hdr->kernel_ep = htonl(kernel_ep);
  398. hdr->fw_length = htonl(layout->fw_max_len);
  399. hdr->kernel_ofs = htonl(sizeof(struct fw_header));
  400. hdr->kernel_len = htonl(kernel_len);
  401. if (!combined) {
  402. hdr->rootfs_ofs = htonl(rootfs_ofs);
  403. hdr->rootfs_len = htonl(rootfs_info.file_size);
  404. }
  405. hdr->boot_ofs = htonl(0);
  406. hdr->boot_len = htonl(boot_info.file_size);
  407. hdr->unk1 = htonl(0);
  408. hdr->unk2 = htonl(0);
  409. hdr->unk3 = htonl(0xffffffff);
  410. hdr->unk4 = htons(0x55aa);
  411. hdr->unk5 = 0xa5;
  412. hdr->sver_hi = sver_hi;
  413. hdr->sver_lo = sver_lo;
  414. hdr->ver_hi = fw_ver_hi;
  415. hdr->ver_mid = fw_ver_mid;
  416. hdr->ver_lo = fw_ver_lo;
  417. get_md5(buf, len, hdr->md5sum1);
  418. }
  419. static int pad_jffs2(char *buf, int currlen)
  420. {
  421. int len;
  422. uint32_t pad_mask;
  423. len = currlen;
  424. pad_mask = (64 * 1024);
  425. while ((len < layout->fw_max_len) && (pad_mask != 0)) {
  426. uint32_t mask;
  427. int i;
  428. for (i = 10; i < 32; i++) {
  429. mask = 1 << i;
  430. if (pad_mask & mask)
  431. break;
  432. }
  433. len = ALIGN(len, mask);
  434. for (i = 10; i < 32; i++) {
  435. mask = 1 << i;
  436. if ((len & (mask - 1)) == 0)
  437. pad_mask &= ~mask;
  438. }
  439. for (i = 0; i < sizeof(jffs2_eof_mark); i++)
  440. buf[len + i] = jffs2_eof_mark[i];
  441. len += sizeof(jffs2_eof_mark);
  442. }
  443. return len;
  444. }
  445. static int write_fw(char *data, int len)
  446. {
  447. FILE *f;
  448. int ret = EXIT_FAILURE;
  449. f = fopen(ofname, "w");
  450. if (f == NULL) {
  451. ERRS("could not open \"%s\" for writing", ofname);
  452. goto out;
  453. }
  454. errno = 0;
  455. fwrite(data, len, 1, f);
  456. if (errno) {
  457. ERRS("unable to write output file");
  458. goto out_flush;
  459. }
  460. DBG("firmware file \"%s\" completed", ofname);
  461. ret = EXIT_SUCCESS;
  462. out_flush:
  463. fflush(f);
  464. fclose(f);
  465. if (ret != EXIT_SUCCESS) {
  466. unlink(ofname);
  467. }
  468. out:
  469. return ret;
  470. }
  471. static int build_fw(void)
  472. {
  473. int buflen;
  474. char *buf;
  475. char *p;
  476. int ret = EXIT_FAILURE;
  477. int writelen = 0;
  478. buflen = layout->fw_max_len;
  479. buf = malloc(buflen);
  480. if (!buf) {
  481. ERR("no memory for buffer\n");
  482. goto out;
  483. }
  484. memset(buf, 0xff, buflen);
  485. p = buf + sizeof(struct fw_header);
  486. ret = read_to_buf(&kernel_info, p);
  487. if (ret)
  488. goto out_free_buf;
  489. writelen = sizeof(struct fw_header) + kernel_len;
  490. if (!combined) {
  491. if (rootfs_align)
  492. p = buf + writelen;
  493. else
  494. p = buf + rootfs_ofs;
  495. ret = read_to_buf(&rootfs_info, p);
  496. if (ret)
  497. goto out_free_buf;
  498. if (rootfs_align)
  499. writelen += rootfs_info.file_size;
  500. else
  501. writelen = rootfs_ofs + rootfs_info.file_size;
  502. if (add_jffs2_eof)
  503. writelen = pad_jffs2(buf, writelen);
  504. }
  505. if (!strip_padding)
  506. writelen = buflen;
  507. fill_header(buf, writelen);
  508. ret = write_fw(buf, writelen);
  509. if (ret)
  510. goto out_free_buf;
  511. ret = EXIT_SUCCESS;
  512. out_free_buf:
  513. free(buf);
  514. out:
  515. return ret;
  516. }
  517. /* Helper functions to inspect_fw() representing different output formats */
  518. static inline void inspect_fw_pstr(char *label, char *str)
  519. {
  520. printf("%-23s: %s\n", label, str);
  521. }
  522. static inline void inspect_fw_phex(char *label, uint32_t val)
  523. {
  524. printf("%-23s: 0x%08x\n", label, val);
  525. }
  526. static inline void inspect_fw_phexpost(char *label,
  527. uint32_t val, char *post)
  528. {
  529. printf("%-23s: 0x%08x (%s)\n", label, val, post);
  530. }
  531. static inline void inspect_fw_phexdef(char *label,
  532. uint32_t val, uint32_t defval)
  533. {
  534. printf("%-23s: 0x%08x ", label, val);
  535. if (val == defval)
  536. printf("(== OpenWrt default)\n");
  537. else
  538. printf("(OpenWrt default: 0x%08x)\n", defval);
  539. }
  540. static inline void inspect_fw_phexexp(char *label,
  541. uint32_t val, uint32_t expval)
  542. {
  543. printf("%-23s: 0x%08x ", label, val);
  544. if (val == expval)
  545. printf("(ok)\n");
  546. else
  547. printf("(expected: 0x%08x)\n", expval);
  548. }
  549. static inline void inspect_fw_phexdec(char *label, uint32_t val)
  550. {
  551. printf("%-23s: 0x%08x / %8u bytes\n", label, val, val);
  552. }
  553. static inline void inspect_fw_phexdecdef(char *label,
  554. uint32_t val, uint32_t defval)
  555. {
  556. printf("%-23s: 0x%08x / %8u bytes ", label, val, val);
  557. if (val == defval)
  558. printf("(== OpenWrt default)\n");
  559. else
  560. printf("(OpenWrt default: 0x%08x)\n", defval);
  561. }
  562. static inline void inspect_fw_pmd5sum(char *label, uint8_t *val, char *text)
  563. {
  564. int i;
  565. printf("%-23s:", label);
  566. for (i=0; i<MD5SUM_LEN; i++)
  567. printf(" %02x", val[i]);
  568. printf(" %s\n", text);
  569. }
  570. static int inspect_fw(void)
  571. {
  572. char *buf;
  573. struct fw_header *hdr;
  574. uint8_t md5sum[MD5SUM_LEN];
  575. struct board_info *board;
  576. int ret = EXIT_FAILURE;
  577. buf = malloc(inspect_info.file_size);
  578. if (!buf) {
  579. ERR("no memory for buffer!\n");
  580. goto out;
  581. }
  582. ret = read_to_buf(&inspect_info, buf);
  583. if (ret)
  584. goto out_free_buf;
  585. hdr = (struct fw_header *)buf;
  586. inspect_fw_pstr("File name", inspect_info.file_name);
  587. inspect_fw_phexdec("File size", inspect_info.file_size);
  588. if (ntohl(hdr->version) != HEADER_VERSION_V2) {
  589. ERR("file does not seem to have V2 header!\n");
  590. goto out_free_buf;
  591. }
  592. inspect_fw_phexdec("Version 2 Header size", sizeof(struct fw_header));
  593. if (ntohl(hdr->unk1) != 0)
  594. inspect_fw_phexdec("Unknown value 1", hdr->unk1);
  595. memcpy(md5sum, hdr->md5sum1, sizeof(md5sum));
  596. if (ntohl(hdr->boot_len) == 0)
  597. memcpy(hdr->md5sum1, md5salt_normal, sizeof(md5sum));
  598. else
  599. memcpy(hdr->md5sum1, md5salt_boot, sizeof(md5sum));
  600. get_md5(buf, inspect_info.file_size, hdr->md5sum1);
  601. if (memcmp(md5sum, hdr->md5sum1, sizeof(md5sum))) {
  602. inspect_fw_pmd5sum("Header MD5Sum1", md5sum, "(*ERROR*)");
  603. inspect_fw_pmd5sum(" --> expected", hdr->md5sum1, "");
  604. } else {
  605. inspect_fw_pmd5sum("Header MD5Sum1", md5sum, "(ok)");
  606. }
  607. if (ntohl(hdr->unk2) != 0)
  608. inspect_fw_phexdec("Unknown value 2", hdr->unk2);
  609. inspect_fw_pmd5sum("Header MD5Sum2", hdr->md5sum2,
  610. "(purpose yet unknown, unchecked here)");
  611. if (ntohl(hdr->unk3) != 0xffffffff)
  612. inspect_fw_phexdec("Unknown value 3", hdr->unk3);
  613. if (ntohs(hdr->unk4) != 0x55aa)
  614. inspect_fw_phexdec("Unknown value 4", hdr->unk4);
  615. if (hdr->unk5 != 0xa5)
  616. inspect_fw_phexdec("Unknown value 5", hdr->unk5);
  617. printf("\n");
  618. inspect_fw_pstr("Firmware version", hdr->fw_version);
  619. board = find_board_by_hwid(ntohl(hdr->hw_id));
  620. if (board) {
  621. layout = find_layout(board->layout_id);
  622. inspect_fw_phexpost("Hardware ID",
  623. ntohl(hdr->hw_id), board->id);
  624. inspect_fw_phexexp("Hardware Revision",
  625. ntohl(hdr->hw_rev), board->hw_rev);
  626. } else {
  627. inspect_fw_phexpost("Hardware ID",
  628. ntohl(hdr->hw_id), "unknown");
  629. inspect_fw_phex("Hardware Revision",
  630. ntohl(hdr->hw_rev));
  631. }
  632. printf("%-23s: %d.%d.%d-%d.%d\n", "Software version",
  633. hdr->ver_hi, hdr->ver_mid, hdr->ver_lo,
  634. hdr->sver_hi, hdr->sver_lo);
  635. printf("\n");
  636. inspect_fw_phexdec("Kernel data offset",
  637. ntohl(hdr->kernel_ofs));
  638. inspect_fw_phexdec("Kernel data length",
  639. ntohl(hdr->kernel_len));
  640. if (board) {
  641. inspect_fw_phexdef("Kernel load address",
  642. ntohl(hdr->kernel_la),
  643. layout ? layout->kernel_la : 0xffffffff);
  644. inspect_fw_phexdef("Kernel entry point",
  645. ntohl(hdr->kernel_ep),
  646. layout ? layout->kernel_ep : 0xffffffff);
  647. inspect_fw_phexdecdef("Rootfs data offset",
  648. ntohl(hdr->rootfs_ofs),
  649. layout ? layout->rootfs_ofs : 0xffffffff);
  650. } else {
  651. inspect_fw_phex("Kernel load address",
  652. ntohl(hdr->kernel_la));
  653. inspect_fw_phex("Kernel entry point",
  654. ntohl(hdr->kernel_ep));
  655. inspect_fw_phexdec("Rootfs data offset",
  656. ntohl(hdr->rootfs_ofs));
  657. }
  658. inspect_fw_phexdec("Rootfs data length",
  659. ntohl(hdr->rootfs_len));
  660. inspect_fw_phexdec("Boot loader data offset",
  661. ntohl(hdr->boot_ofs));
  662. inspect_fw_phexdec("Boot loader data length",
  663. ntohl(hdr->boot_len));
  664. inspect_fw_phexdec("Total firmware length",
  665. ntohl(hdr->fw_length));
  666. if (extract) {
  667. FILE *fp;
  668. char *filename;
  669. printf("\n");
  670. filename = malloc(strlen(inspect_info.file_name) + 8);
  671. sprintf(filename, "%s-kernel", inspect_info.file_name);
  672. printf("Extracting kernel to \"%s\"...\n", filename);
  673. fp = fopen(filename, "w");
  674. if (fp) {
  675. if (!fwrite(buf + ntohl(hdr->kernel_ofs),
  676. ntohl(hdr->kernel_len), 1, fp)) {
  677. ERR("error in fwrite(): %s", strerror(errno));
  678. }
  679. fclose(fp);
  680. } else {
  681. ERR("error in fopen(): %s", strerror(errno));
  682. }
  683. free(filename);
  684. filename = malloc(strlen(inspect_info.file_name) + 8);
  685. sprintf(filename, "%s-rootfs", inspect_info.file_name);
  686. printf("Extracting rootfs to \"%s\"...\n", filename);
  687. fp = fopen(filename, "w");
  688. if (fp) {
  689. if (!fwrite(buf + ntohl(hdr->rootfs_ofs),
  690. ntohl(hdr->rootfs_len), 1, fp)) {
  691. ERR("error in fwrite(): %s", strerror(errno));
  692. }
  693. fclose(fp);
  694. } else {
  695. ERR("error in fopen(): %s", strerror(errno));
  696. }
  697. free(filename);
  698. }
  699. out_free_buf:
  700. free(buf);
  701. out:
  702. return ret;
  703. }
  704. int main(int argc, char *argv[])
  705. {
  706. int ret = EXIT_FAILURE;
  707. int err;
  708. FILE *outfile;
  709. progname = basename(argv[0]);
  710. while ( 1 ) {
  711. int c;
  712. c = getopt(argc, argv, "a:B:H:E:F:L:V:N:W:ci:k:r:R:o:xhsjv:y:");
  713. if (c == -1)
  714. break;
  715. switch (c) {
  716. case 'a':
  717. sscanf(optarg, "0x%x", &rootfs_align);
  718. break;
  719. case 'B':
  720. board_id = optarg;
  721. break;
  722. case 'H':
  723. opt_hw_id = optarg;
  724. break;
  725. case 'E':
  726. sscanf(optarg, "0x%x", &kernel_ep);
  727. break;
  728. case 'F':
  729. layout_id = optarg;
  730. break;
  731. case 'W':
  732. opt_hw_rev = optarg;
  733. break;
  734. case 'L':
  735. sscanf(optarg, "0x%x", &kernel_la);
  736. break;
  737. case 'V':
  738. version = optarg;
  739. break;
  740. case 'v':
  741. fw_ver = optarg;
  742. break;
  743. case 'y':
  744. sver = optarg;
  745. break;
  746. case 'N':
  747. vendor = optarg;
  748. break;
  749. case 'c':
  750. combined++;
  751. break;
  752. case 'k':
  753. kernel_info.file_name = optarg;
  754. break;
  755. case 'r':
  756. rootfs_info.file_name = optarg;
  757. break;
  758. case 'R':
  759. sscanf(optarg, "0x%x", &rootfs_ofs);
  760. break;
  761. case 'o':
  762. ofname = optarg;
  763. break;
  764. case 's':
  765. strip_padding = 1;
  766. break;
  767. case 'i':
  768. inspect_info.file_name = optarg;
  769. break;
  770. case 'j':
  771. add_jffs2_eof = 1;
  772. break;
  773. case 'x':
  774. extract = 1;
  775. break;
  776. case 'h':
  777. usage(EXIT_SUCCESS);
  778. break;
  779. default:
  780. usage(EXIT_FAILURE);
  781. break;
  782. }
  783. }
  784. ret = check_options();
  785. if (ret)
  786. goto out;
  787. if (!inspect_info.file_name)
  788. ret = build_fw();
  789. else
  790. ret = inspect_fw();
  791. out:
  792. return ret;
  793. }