mkporayfw.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791
  1. /*
  2. * Builder/viewer/extractor utility for Poray firmware image files
  3. *
  4. * Copyright (C) 2013 Michel Stempin <michel.stempin@wanadoo.fr>
  5. * Copyright (C) 2013 Felix Kaechele <felix@fetzig.org>
  6. * Copyright (C) 2013 <admin@openschemes.com>
  7. *
  8. * This tool is based on:
  9. * TP-Link firmware upgrade tool.
  10. * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
  11. *
  12. * Itself based on:
  13. * TP-Link WR941 V2 firmware checksum fixing tool.
  14. * Copyright (C) 2008,2009 Wang Jian <lark@linux.net.cn>
  15. *
  16. * This program is free software; you can redistribute it and/or modify it
  17. * under the terms of the GNU General Public License version 2 as published
  18. * by the Free Software Foundation.
  19. *
  20. */
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <stdint.h>
  24. #include <string.h>
  25. #include <unistd.h>
  26. #include <libgen.h>
  27. #include <getopt.h>
  28. #include <stdarg.h>
  29. #include <errno.h>
  30. #include <sys/stat.h>
  31. #include <arpa/inet.h>
  32. #include <netinet/in.h>
  33. #if (__BYTE_ORDER == __BIG_ENDIAN)
  34. # define HOST_TO_BE32(x) (x)
  35. # define BE32_TO_HOST(x) (x)
  36. # define HOST_TO_LE32(x) bswap_32(x)
  37. # define LE32_TO_HOST(x) bswap_32(x)
  38. #else
  39. # define HOST_TO_BE32(x) bswap_32(x)
  40. # define BE32_TO_HOST(x) bswap_32(x)
  41. # define HOST_TO_LE32(x) (x)
  42. # define LE32_TO_HOST(x) (x)
  43. #endif
  44. /* Fixed header flags */
  45. #define HEADER_FLAGS 0x020e0000
  46. /* Recognized Hardware ID magic */
  47. #define HWID_HAME_MPR_A1_L8 0x32473352
  48. #define HWID_PORAY_R50B 0x31353033
  49. #define HWID_PORAY_R50D 0x33353033
  50. #define HWID_PORAY_R50E 0x34353033
  51. #define HWID_PORAY_M3 0x31353335
  52. #define HWID_PORAY_M4 0x32353335
  53. #define HWID_PORAY_Q3 0x33353335
  54. #define HWID_PORAY_X5_X6 0x35353335
  55. #define HWID_PORAY_X8 0x36353335
  56. #define HWID_PORAY_X1 0x38353335
  57. #define HWID_NEXX_WT1520 0x30353332
  58. #define HWID_NEXX_WT3020 0x30323033
  59. #define HWID_A5_V11 0x32473352
  60. /* Recognized XOR obfuscation keys */
  61. #define KEY_HAME 0
  62. #define KEY_PORAY_1 1
  63. #define KEY_PORAY_2 2
  64. #define KEY_PORAY_3 3
  65. #define KEY_PORAY_4 4
  66. #define KEY_NEXX_1 5
  67. #define KEY_NEXX_2 6
  68. #define KEY_A5_V11 7
  69. /* XOR key length */
  70. #define KEY_LEN 15
  71. struct file_info {
  72. char *file_name; /* Name of the file */
  73. uint32_t file_size; /* Length of the file */
  74. };
  75. struct fw_header {
  76. uint32_t hw_id; /* Hardware id */
  77. uint32_t firmware_len; /* Firmware data length */
  78. uint32_t flags; /* Header flags */
  79. uint8_t pad[16];
  80. } __attribute__ ((packed));
  81. struct flash_layout {
  82. char *id;
  83. uint32_t fw_max_len;
  84. };
  85. struct board_info {
  86. char *id;
  87. uint32_t hw_id;
  88. char *layout_id;
  89. uint32_t key;
  90. };
  91. /*
  92. * Globals
  93. */
  94. static char *ofname;
  95. static char *progname;
  96. static char *board_id;
  97. static struct board_info *board;
  98. static char *layout_id;
  99. static struct flash_layout *layout;
  100. static char *opt_hw_id;
  101. static uint32_t hw_id;
  102. static struct file_info firmware_info;
  103. static uint32_t firmware_len = 0;
  104. static int inspect = 0;
  105. static int extract = 0;
  106. static uint8_t key[][KEY_LEN] = {
  107. {0xC8, 0x3C, 0x3A, 0x93, 0xA2, 0x95, 0xC3, 0x63, 0x48, 0x45, 0x58, 0x09, 0x12, 0x03, 0x08},
  108. {0x89, 0x6B, 0x5A, 0x93, 0x92, 0x95, 0xC3, 0x63, 0xD0, 0xA3, 0x9C, 0x92, 0x2E, 0xE6, 0xC7},
  109. {0xC9, 0x1C, 0x3A, 0x93, 0x92, 0x95, 0xC3, 0x63, 0xD0, 0xA3, 0x9C, 0x92, 0x2E, 0xE6, 0xC7},
  110. {0x19, 0x1B, 0x3A, 0x93, 0x92, 0x95, 0xC3, 0x63, 0xD0, 0xA3, 0x9C, 0x92, 0x2E, 0xE6, 0xC7},
  111. {0x79, 0x7B, 0x7A, 0x93, 0x92, 0x95, 0xC3, 0x63, 0xD0, 0xA3, 0x9C, 0x92, 0x2E, 0xE6, 0xC7},
  112. {0x19, 0x1C, 0x4A, 0x93, 0x96, 0x95, 0xC3, 0x63, 0xD0, 0xA3, 0x9C, 0x92, 0x2E, 0x16, 0xC6},
  113. {0x39, 0x1C, 0x4A, 0x93, 0x96, 0x95, 0xC3, 0x63, 0xD0, 0xA3, 0x9C, 0x92, 0x2E, 0x16, 0xC6},
  114. {0xC8, 0x3C, 0x3A, 0x93, 0xA2, 0x95, 0xC3, 0x63, 0x48, 0x45, 0x58, 0x09, 0x20, 0x11, 0x08},
  115. };
  116. static struct flash_layout layouts[] = {
  117. {
  118. .id = "4M",
  119. .fw_max_len = 0x3c0000,
  120. }, {
  121. .id = "8M",
  122. .fw_max_len = 0x7c0000,
  123. }, {
  124. /* terminating entry */
  125. }
  126. };
  127. static struct board_info boards[] = {
  128. {
  129. .id = "A5-V11",
  130. .hw_id = HWID_A5_V11,
  131. .layout_id = "4M",
  132. .key = KEY_A5_V11,
  133. }, {
  134. .id = "MPR-A1",
  135. .hw_id = HWID_HAME_MPR_A1_L8,
  136. .layout_id = "4M",
  137. .key = KEY_HAME,
  138. }, {
  139. .id = "MPR-L8",
  140. .hw_id = HWID_HAME_MPR_A1_L8,
  141. .layout_id = "4M",
  142. .key = KEY_HAME,
  143. }, {
  144. .id = "R50B",
  145. .hw_id = HWID_PORAY_R50B,
  146. .layout_id = "4M",
  147. .key = KEY_PORAY_2,
  148. }, {
  149. .id = "R50D",
  150. .hw_id = HWID_PORAY_R50D,
  151. .layout_id = "4M",
  152. .key = KEY_PORAY_3,
  153. }, {
  154. .id = "R50E",
  155. .hw_id = HWID_PORAY_R50E,
  156. .layout_id = "4M",
  157. .key = KEY_PORAY_4,
  158. }, {
  159. .id = "M3",
  160. .hw_id = HWID_PORAY_M3,
  161. .layout_id = "4M",
  162. .key = KEY_PORAY_1,
  163. }, {
  164. .id = "M4",
  165. .hw_id = HWID_PORAY_M4,
  166. .layout_id = "4M",
  167. .key = KEY_PORAY_1,
  168. }, {
  169. .id = "Q3",
  170. .hw_id = HWID_PORAY_Q3,
  171. .layout_id = "4M",
  172. .key = KEY_PORAY_1,
  173. }, {
  174. .id = "X5 or X6",
  175. .hw_id = HWID_PORAY_X5_X6,
  176. .layout_id = "8M",
  177. .key = KEY_PORAY_1,
  178. }, {
  179. .id = "X5",
  180. .hw_id = HWID_PORAY_X5_X6,
  181. .layout_id = "8M",
  182. .key = KEY_PORAY_1,
  183. }, {
  184. .id = "X6",
  185. .hw_id = HWID_PORAY_X5_X6,
  186. .layout_id = "8M",
  187. .key = KEY_PORAY_1,
  188. }, {
  189. .id = "X8",
  190. .hw_id = HWID_PORAY_X8,
  191. .layout_id = "8M",
  192. .key = KEY_PORAY_1,
  193. }, {
  194. .id = "X1",
  195. .hw_id = HWID_PORAY_X1,
  196. .layout_id = "8M",
  197. .key = KEY_PORAY_1,
  198. }, {
  199. .id = "WT1520",
  200. .hw_id = HWID_NEXX_WT1520,
  201. .layout_id = "4M",
  202. .key = KEY_NEXX_1,
  203. }, {
  204. .id = "WT1520",
  205. .hw_id = HWID_NEXX_WT1520,
  206. .layout_id = "8M",
  207. .key = KEY_NEXX_1,
  208. }, {
  209. .id = "WT3020",
  210. .hw_id = HWID_NEXX_WT3020,
  211. .layout_id = "4M",
  212. .key = KEY_NEXX_2,
  213. }, {
  214. .id = "WT3020",
  215. .hw_id = HWID_NEXX_WT3020,
  216. .layout_id = "8M",
  217. .key = KEY_NEXX_2,
  218. }, {
  219. /* terminating entry */
  220. }
  221. };
  222. /*
  223. * Message macros
  224. */
  225. #define ERR(fmt, ...) do { \
  226. fflush(0); \
  227. fprintf(stderr, "[%s] *** error: " fmt "\n", \
  228. progname, ## __VA_ARGS__ ); \
  229. } while (0)
  230. #define ERRS(fmt, ...) do { \
  231. int save = errno; \
  232. fflush(0); \
  233. fprintf(stderr, "[%s] *** error: " fmt ":%s\n", \
  234. progname, ## __VA_ARGS__, strerror(save)); \
  235. } while (0)
  236. #define DBG(fmt, ...) do { \
  237. fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
  238. } while (0)
  239. /*
  240. * Find a board by its name
  241. */
  242. static struct board_info *find_board(char *id)
  243. {
  244. struct board_info *ret;
  245. struct board_info *board;
  246. ret = NULL;
  247. for (board = boards; board->id != NULL; board++){
  248. if (strcasecmp(id, board->id) == 0) {
  249. ret = board;
  250. break;
  251. }
  252. };
  253. return ret;
  254. }
  255. /*
  256. * Find a board by its hardware ID
  257. */
  258. static struct board_info *find_board_by_hwid(uint32_t hw_id)
  259. {
  260. struct board_info *board;
  261. for (board = boards; board->id != NULL; board++) {
  262. if (hw_id == board->hw_id)
  263. return board;
  264. };
  265. return NULL;
  266. }
  267. /*
  268. * Find a Flash memory layout by its name
  269. */
  270. static struct flash_layout *find_layout(char *id)
  271. {
  272. struct flash_layout *ret;
  273. struct flash_layout *l;
  274. ret = NULL;
  275. for (l = layouts; l->id != NULL; l++){
  276. if (strcasecmp(id, l->id) == 0) {
  277. ret = l;
  278. break;
  279. }
  280. };
  281. return ret;
  282. }
  283. /*
  284. * Display usage
  285. */
  286. static void usage(int status)
  287. {
  288. FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
  289. fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
  290. fprintf(stream,
  291. "\n"
  292. "Options:\n"
  293. " -B <board> create image for the board specified with <board>\n"
  294. " -H <hwid> use hardware id specified with <hwid>\n"
  295. " -F <id> use flash layout specified with <id>\n"
  296. " -f <file> read firmware image from the file <file>\n"
  297. " -o <file> write output to the file <file>\n"
  298. " -i inspect given firmware file (requires -f)\n"
  299. " -x extract combined kernel and rootfs while inspecting (implies -i)\n"
  300. " -h show this screen\n"
  301. );
  302. exit(status);
  303. }
  304. /*
  305. * Get file statistics
  306. */
  307. static int get_file_stat(struct file_info *fdata)
  308. {
  309. struct stat st;
  310. int res;
  311. if (fdata->file_name == NULL) {
  312. return 0;
  313. }
  314. res = stat(fdata->file_name, &st);
  315. if (res){
  316. ERRS("stat failed on %s", fdata->file_name);
  317. return res;
  318. }
  319. fdata->file_size = st.st_size;
  320. return 0;
  321. }
  322. /*
  323. * Read file into buffer
  324. */
  325. static int read_to_buf(struct file_info *fdata, uint8_t *buf)
  326. {
  327. FILE *f;
  328. int ret = EXIT_FAILURE;
  329. f = fopen(fdata->file_name, "rb");
  330. if (f == NULL) {
  331. ERRS("could not open \"%s\" for reading", fdata->file_name);
  332. goto out;
  333. }
  334. errno = 0;
  335. fread(buf, fdata->file_size, 1, f);
  336. if (errno != 0) {
  337. ERRS("unable to read from file \"%s\"", fdata->file_name);
  338. goto out_close;
  339. }
  340. ret = EXIT_SUCCESS;
  341. out_close:
  342. fclose(f);
  343. out:
  344. return ret;
  345. }
  346. /*
  347. * Check command line options
  348. */
  349. static int check_options(void)
  350. {
  351. int ret;
  352. if (firmware_info.file_name == NULL) {
  353. ERR("no firmware image specified");
  354. return -1;
  355. }
  356. ret = get_file_stat(&firmware_info);
  357. if (ret)
  358. return ret;
  359. if (inspect)
  360. return 0;
  361. if (board_id == NULL && opt_hw_id == NULL) {
  362. ERR("either board or hardware id must be specified");
  363. return -1;
  364. }
  365. if (board_id) {
  366. board = find_board(board_id);
  367. if (board == NULL) {
  368. ERR("unknown/unsupported board id \"%s\"", board_id);
  369. return -1;
  370. }
  371. if (layout_id == NULL) {
  372. layout_id = board->layout_id;
  373. }
  374. hw_id = board->hw_id;
  375. } else {
  376. hw_id = strtoul(opt_hw_id, NULL, 0);
  377. board = find_board_by_hwid(hw_id);
  378. if (layout_id == NULL) {
  379. layout_id = board->layout_id;
  380. }
  381. }
  382. layout = find_layout(layout_id);
  383. if (layout == NULL) {
  384. ERR("unknown flash layout \"%s\"", layout_id);
  385. return -1;
  386. }
  387. firmware_len = firmware_info.file_size;
  388. if (firmware_info.file_size >
  389. layout->fw_max_len - sizeof (struct fw_header)) {
  390. ERR("firmware image is too big");
  391. return -1;
  392. }
  393. if (ofname == NULL) {
  394. ERR("no output file specified");
  395. return -1;
  396. }
  397. return 0;
  398. }
  399. /*
  400. * Fill in firmware header
  401. */
  402. static void fill_header(uint8_t *buf)
  403. {
  404. struct fw_header *hdr = (struct fw_header *) buf;
  405. memset(hdr, 0, sizeof (struct fw_header));
  406. hdr->hw_id = HOST_TO_LE32(hw_id);
  407. hdr->firmware_len = HOST_TO_LE32(firmware_len);
  408. hdr->flags = HOST_TO_LE32(HEADER_FLAGS);
  409. }
  410. /*
  411. * Compute firmware checksum
  412. */
  413. static uint16_t checksum_fw(uint8_t *data, int len)
  414. {
  415. int i;
  416. int32_t checksum = 0;
  417. for (i = 0; i < len - 1; i += 2) {
  418. checksum += (data[i + 1] << 8) | data[i];
  419. }
  420. if (i < len) {
  421. checksum += data[i];
  422. }
  423. checksum = checksum + (checksum >> 16) + 0xffff;
  424. checksum = ~(checksum + (checksum >> 16)) & 0xffff;
  425. return (uint16_t) checksum;
  426. }
  427. /*
  428. * (De)obfuscate firmware using an XOR operation with a fixed length key
  429. */
  430. static void xor_fw(uint8_t *data, int len)
  431. {
  432. int i;
  433. for (i = 0; i <= len; i++) {
  434. data[i] ^= key[board->key][i % KEY_LEN];
  435. }
  436. }
  437. /*
  438. * Write firmware to file
  439. */
  440. static int write_fw(uint8_t *data, int len)
  441. {
  442. FILE *f;
  443. int ret = EXIT_FAILURE;
  444. f = fopen(ofname, "wb");
  445. if (f == NULL) {
  446. ERRS("could not open \"%s\" for writing", ofname);
  447. goto out;
  448. }
  449. errno = 0;
  450. fwrite(data, len, 1, f);
  451. if (errno) {
  452. ERRS("unable to write output file");
  453. goto out_flush;
  454. }
  455. DBG("firmware file \"%s\" completed", ofname);
  456. ret = EXIT_SUCCESS;
  457. out_flush:
  458. fflush(f);
  459. fclose(f);
  460. if (ret != EXIT_SUCCESS) {
  461. unlink(ofname);
  462. }
  463. out:
  464. return ret;
  465. }
  466. /*
  467. * Build firmware file
  468. */
  469. static int build_fw(void)
  470. {
  471. int buflen;
  472. uint8_t *buf, *p;
  473. int ret = EXIT_FAILURE;
  474. int writelen = 0;
  475. uint16_t checksum;
  476. buflen = layout->fw_max_len;
  477. buf = (uint8_t *) malloc(buflen);
  478. if (!buf) {
  479. ERR("no memory for buffer\n");
  480. goto out;
  481. }
  482. memset(buf, 0xff, buflen);
  483. p = buf + sizeof (struct fw_header);
  484. ret = read_to_buf(&firmware_info, p);
  485. if (ret) {
  486. goto out_free_buf;
  487. }
  488. writelen = sizeof (struct fw_header) + firmware_len + 2;
  489. /* Fill in header */
  490. fill_header(buf);
  491. /* Compute firmware checksum */
  492. checksum = checksum_fw(buf + sizeof (struct fw_header), firmware_len);
  493. /* Cannot use network order function because checksum is not word-aligned */
  494. buf[writelen - 1] = checksum >> 8;
  495. buf[writelen - 2] = checksum & 0xff;
  496. /* XOR obfuscate firmware */
  497. xor_fw(buf + sizeof (struct fw_header), firmware_len + 2);
  498. /* Write firmware file */
  499. ret = write_fw(buf, writelen);
  500. if (ret) {
  501. goto out_free_buf;
  502. }
  503. ret = EXIT_SUCCESS;
  504. out_free_buf:
  505. free(buf);
  506. out:
  507. return ret;
  508. }
  509. /* Helper functions to inspect_fw() representing different output formats */
  510. static inline void inspect_fw_pstr(char *label, char *str)
  511. {
  512. printf("%-23s: %s\n", label, str);
  513. }
  514. static inline void inspect_fw_phex(char *label, uint32_t val)
  515. {
  516. printf("%-23s: 0x%08x\n", label, val);
  517. }
  518. static inline void inspect_fw_phexpost(char *label,
  519. uint32_t val, char *post)
  520. {
  521. printf("%-23s: 0x%08x (%s)\n", label, val, post);
  522. }
  523. static inline void inspect_fw_phexdef(char *label,
  524. uint32_t val, uint32_t defval)
  525. {
  526. printf("%-23s: 0x%08x ", label, val);
  527. if (val == defval) {
  528. printf("(== OpenWrt default)\n");
  529. } else {
  530. printf("(OpenWrt default: 0x%08x)\n", defval);
  531. }
  532. }
  533. static inline void inspect_fw_phexexp(char *label,
  534. uint32_t val, uint32_t expval)
  535. {
  536. printf("%-23s: 0x%08x ", label, val);
  537. if (val == expval) {
  538. printf("(ok)\n");
  539. } else {
  540. printf("(expected: 0x%08x)\n", expval);
  541. }
  542. }
  543. static inline void inspect_fw_phexdec(char *label, uint32_t val)
  544. {
  545. printf("%-23s: 0x%08x / %8u bytes\n", label, val, val);
  546. }
  547. static inline void inspect_fw_pchecksum(char *label,
  548. uint16_t val, uint16_t expval)
  549. {
  550. printf("%-23s: 0x%04x ", label, val);
  551. if (val == expval) {
  552. printf("(ok)\n");
  553. } else {
  554. printf("(expected: 0x%04x)\n", expval);
  555. }
  556. }
  557. static int inspect_fw(void)
  558. {
  559. uint8_t *buf;
  560. struct fw_header *hdr;
  561. int ret = EXIT_FAILURE;
  562. uint16_t computed_checksum, file_checksum;
  563. buf = (uint8_t *) malloc(firmware_info.file_size);
  564. if (!buf) {
  565. ERR("no memory for buffer!\n");
  566. goto out;
  567. }
  568. ret = read_to_buf(&firmware_info, buf);
  569. if (ret) {
  570. goto out_free_buf;
  571. }
  572. hdr = (struct fw_header *)buf;
  573. inspect_fw_pstr("File name", firmware_info.file_name);
  574. inspect_fw_phexdec("File size", firmware_info.file_size);
  575. printf("\n");
  576. inspect_fw_phexdec("Header size", sizeof (struct fw_header));
  577. board = find_board_by_hwid(LE32_TO_HOST(hdr->hw_id));
  578. if (board) {
  579. layout = find_layout(board->layout_id);
  580. inspect_fw_phexpost("Hardware ID",
  581. LE32_TO_HOST( hdr->hw_id), board->id);
  582. } else {
  583. inspect_fw_phexpost("Hardware ID",
  584. LE32_TO_HOST(hdr->hw_id), "unknown");
  585. }
  586. inspect_fw_phexdec("Firmware data length",
  587. LE32_TO_HOST(hdr->firmware_len));
  588. inspect_fw_phexexp("Flags",
  589. LE32_TO_HOST(hdr->flags), HEADER_FLAGS);
  590. printf("\n");
  591. /* XOR unobfuscate firmware */
  592. xor_fw(buf + sizeof (struct fw_header), LE32_TO_HOST(hdr->firmware_len) + 2);
  593. /* Compute firmware checksum */
  594. computed_checksum = checksum_fw(buf + sizeof (struct fw_header), LE32_TO_HOST(hdr->firmware_len));
  595. /* Cannot use network order function because checksum is not word-aligned */
  596. file_checksum = (buf[firmware_info.file_size - 1] << 8) | buf[firmware_info.file_size - 2];
  597. inspect_fw_pchecksum("Firmware checksum", computed_checksum, file_checksum);
  598. /* Verify checksum */
  599. if (computed_checksum != file_checksum) {
  600. ret = -1;
  601. ERR("checksums do not match");
  602. goto out_free_buf;
  603. }
  604. printf("\n");
  605. if (extract) {
  606. FILE *fp;
  607. char *filename;
  608. if (ofname == NULL) {
  609. filename = malloc(strlen(firmware_info.file_name) + 10);
  610. sprintf(filename, "%s-firmware", firmware_info.file_name);
  611. } else {
  612. filename = ofname;
  613. }
  614. printf("Extracting firmware to \"%s\"...\n", filename);
  615. fp = fopen(filename, "wb");
  616. if (fp) {
  617. if (!fwrite(buf + sizeof (struct fw_header),
  618. LE32_TO_HOST(hdr->firmware_len), 1, fp)) {
  619. ERRS("error in fwrite(): %s", strerror(errno));
  620. }
  621. fclose(fp);
  622. } else {
  623. ERRS("error in fopen(): %s", strerror(errno));
  624. }
  625. if (ofname == NULL) {
  626. free(filename);
  627. }
  628. printf("\n");
  629. }
  630. out_free_buf:
  631. free(buf);
  632. out:
  633. return ret;
  634. }
  635. /*
  636. * Main entry point
  637. */
  638. int main(int argc, char *argv[])
  639. {
  640. int ret = EXIT_FAILURE;
  641. progname = basename(argv[0]);
  642. int c;
  643. while ((c = getopt(argc, argv, "B:H:F:f:o:ixh")) != -1) {
  644. switch (c) {
  645. case 'B':
  646. board_id = optarg;
  647. break;
  648. case 'H':
  649. opt_hw_id = optarg;
  650. break;
  651. case 'F':
  652. layout_id = optarg;
  653. break;
  654. case 'f':
  655. firmware_info.file_name = optarg;
  656. break;
  657. case 'o':
  658. ofname = optarg;
  659. break;
  660. case 'i':
  661. inspect = 1;
  662. break;
  663. case 'x':
  664. inspect = 1;
  665. extract = 1;
  666. break;
  667. case 'h':
  668. usage(EXIT_SUCCESS);
  669. break;
  670. default:
  671. usage(EXIT_FAILURE);
  672. break;
  673. }
  674. }
  675. ret = check_options();
  676. if (ret) {
  677. goto out;
  678. }
  679. if (!inspect) {
  680. ret = build_fw();
  681. } else {
  682. ret = inspect_fw();
  683. }
  684. out:
  685. return ret;
  686. }