mktplinkfw2.c 23 KB

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