mktplinkfw.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158
  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_V1 0x01000000
  28. #define HWID_GL_INET_V1 0x08000001
  29. #define HWID_GS_OOLITE_V1 0x3C000101
  30. #define HWID_TL_MR10U_V1 0x00100101
  31. #define HWID_TL_MR13U_V1 0x00130101
  32. #define HWID_TL_MR3020_V1 0x30200001
  33. #define HWID_TL_MR3220_V1 0x32200001
  34. #define HWID_TL_MR3220_V2 0x32200002
  35. #define HWID_TL_MR3420_V1 0x34200001
  36. #define HWID_TL_MR3420_V2 0x34200002
  37. #define HWID_TL_WA701N_V1 0x07010001
  38. #define HWID_TL_WA7510N_V1 0x75100001
  39. #define HWID_TL_WA801ND_V1 0x08010001
  40. #define HWID_TL_WA830RE_V1 0x08300010
  41. #define HWID_TL_WA830RE_V2 0x08300002
  42. #define HWID_TL_WA801ND_V2 0x08010002
  43. #define HWID_TL_WA901ND_V1 0x09010001
  44. #define HWID_TL_WA901ND_V2 0x09010002
  45. #define HWID_TL_WDR4300_V1_IL 0x43008001
  46. #define HWID_TL_WDR4900_V1 0x49000001
  47. #define HWID_TL_WR703N_V1 0x07030101
  48. #define HWID_TL_WR720N_V3 0x07200103
  49. #define HWID_TL_WR741ND_V1 0x07410001
  50. #define HWID_TL_WR741ND_V4 0x07410004
  51. #define HWID_TL_WR740N_V1 0x07400001
  52. #define HWID_TL_WR740N_V3 0x07400003
  53. #define HWID_TL_WR743ND_V1 0x07430001
  54. #define HWID_TL_WR743ND_V2 0x07430002
  55. #define HWID_TL_WR841N_V1_5 0x08410002
  56. #define HWID_TL_WR841ND_V3 0x08410003
  57. #define HWID_TL_WR841ND_V5 0x08410005
  58. #define HWID_TL_WR841ND_V7 0x08410007
  59. #define HWID_TL_WR941ND_V2 0x09410002
  60. #define HWID_TL_WR941ND_V4 0x09410004
  61. #define HWID_TL_WR1043ND_V1 0x10430001
  62. #define HWID_TL_WR1043ND_V2 0x10430002
  63. #define HWID_TL_WR1041N_V2 0x10410002
  64. #define HWID_TL_WR2543N_V1 0x25430001
  65. #define MD5SUM_LEN 16
  66. struct file_info {
  67. char *file_name; /* name of the file */
  68. uint32_t file_size; /* length of the file */
  69. };
  70. struct fw_header {
  71. uint32_t version; /* header version */
  72. char vendor_name[24];
  73. char fw_version[36];
  74. uint32_t hw_id; /* hardware id */
  75. uint32_t hw_rev; /* hardware revision */
  76. uint32_t unk1;
  77. uint8_t md5sum1[MD5SUM_LEN];
  78. uint32_t unk2;
  79. uint8_t md5sum2[MD5SUM_LEN];
  80. uint32_t unk3;
  81. uint32_t kernel_la; /* kernel load address */
  82. uint32_t kernel_ep; /* kernel entry point */
  83. uint32_t fw_length; /* total length of the firmware */
  84. uint32_t kernel_ofs; /* kernel data offset */
  85. uint32_t kernel_len; /* kernel data length */
  86. uint32_t rootfs_ofs; /* rootfs data offset */
  87. uint32_t rootfs_len; /* rootfs data length */
  88. uint32_t boot_ofs; /* bootloader data offset */
  89. uint32_t boot_len; /* bootloader data length */
  90. uint16_t ver_hi;
  91. uint16_t ver_mid;
  92. uint16_t ver_lo;
  93. uint8_t pad[354];
  94. } __attribute__ ((packed));
  95. struct flash_layout {
  96. char *id;
  97. uint32_t fw_max_len;
  98. uint32_t kernel_la;
  99. uint32_t kernel_ep;
  100. uint32_t rootfs_ofs;
  101. };
  102. struct board_info {
  103. char *id;
  104. uint32_t hw_id;
  105. uint32_t hw_rev;
  106. char *layout_id;
  107. };
  108. /*
  109. * Globals
  110. */
  111. static char *ofname;
  112. static char *progname;
  113. static char *vendor = "TP-LINK Technologies";
  114. static char *version = "ver. 1.0";
  115. static char *fw_ver = "0.0.0";
  116. static char *board_id;
  117. static struct board_info *board;
  118. static char *layout_id;
  119. static struct flash_layout *layout;
  120. static char *opt_hw_id;
  121. static uint32_t hw_id;
  122. static char *opt_hw_rev;
  123. static uint32_t hw_rev;
  124. static int fw_ver_lo;
  125. static int fw_ver_mid;
  126. static int fw_ver_hi;
  127. static struct file_info kernel_info;
  128. static uint32_t kernel_la = 0;
  129. static uint32_t kernel_ep = 0;
  130. static uint32_t kernel_len = 0;
  131. static struct file_info rootfs_info;
  132. static uint32_t rootfs_ofs = 0;
  133. static uint32_t rootfs_align;
  134. static struct file_info boot_info;
  135. static int combined;
  136. static int strip_padding;
  137. static int add_jffs2_eof;
  138. static unsigned char jffs2_eof_mark[4] = {0xde, 0xad, 0xc0, 0xde};
  139. static uint32_t fw_max_len;
  140. static uint32_t reserved_space;
  141. static struct file_info inspect_info;
  142. static int extract = 0;
  143. char md5salt_normal[MD5SUM_LEN] = {
  144. 0xdc, 0xd7, 0x3a, 0xa5, 0xc3, 0x95, 0x98, 0xfb,
  145. 0xdd, 0xf9, 0xe7, 0xf4, 0x0e, 0xae, 0x47, 0x38,
  146. };
  147. char md5salt_boot[MD5SUM_LEN] = {
  148. 0x8c, 0xef, 0x33, 0x5b, 0xd5, 0xc5, 0xce, 0xfa,
  149. 0xa7, 0x9c, 0x28, 0xda, 0xb2, 0xe9, 0x0f, 0x42,
  150. };
  151. static struct flash_layout layouts[] = {
  152. {
  153. .id = "4M",
  154. .fw_max_len = 0x3c0000,
  155. .kernel_la = 0x80060000,
  156. .kernel_ep = 0x80060000,
  157. .rootfs_ofs = 0x140000,
  158. }, {
  159. .id = "4Mlzma",
  160. .fw_max_len = 0x3c0000,
  161. .kernel_la = 0x80060000,
  162. .kernel_ep = 0x80060000,
  163. .rootfs_ofs = 0x100000,
  164. }, {
  165. .id = "8M",
  166. .fw_max_len = 0x7c0000,
  167. .kernel_la = 0x80060000,
  168. .kernel_ep = 0x80060000,
  169. .rootfs_ofs = 0x140000,
  170. }, {
  171. .id = "8Mlzma",
  172. .fw_max_len = 0x7c0000,
  173. .kernel_la = 0x80060000,
  174. .kernel_ep = 0x80060000,
  175. .rootfs_ofs = 0x100000,
  176. }, {
  177. .id = "16M",
  178. .fw_max_len = 0xf80000,
  179. .kernel_la = 0x80060000,
  180. .kernel_ep = 0x80060000,
  181. .rootfs_ofs = 0x140000,
  182. }, {
  183. .id = "16Mlzma",
  184. .fw_max_len = 0xf80000,
  185. .kernel_la = 0x80060000,
  186. .kernel_ep = 0x80060000,
  187. .rootfs_ofs = 0x100000,
  188. }, {
  189. .id = "16Mppc",
  190. .fw_max_len = 0xf80000,
  191. .kernel_la = 0x00000000,
  192. .kernel_ep = 0xc0000000,
  193. .rootfs_ofs = 0x2a0000,
  194. }, {
  195. /* terminating entry */
  196. }
  197. };
  198. static struct board_info boards[] = {
  199. {
  200. .id = "TL-MR10Uv1",
  201. .hw_id = HWID_TL_MR10U_V1,
  202. .hw_rev = 1,
  203. .layout_id = "4Mlzma",
  204. }, {
  205. .id = "TL-MR13Uv1",
  206. .hw_id = HWID_TL_MR13U_V1,
  207. .hw_rev = 1,
  208. .layout_id = "4Mlzma",
  209. }, {
  210. .id = "TL-MR3020v1",
  211. .hw_id = HWID_TL_MR3020_V1,
  212. .hw_rev = 1,
  213. .layout_id = "4Mlzma",
  214. }, {
  215. .id = "TL-MR3220v1",
  216. .hw_id = HWID_TL_MR3220_V1,
  217. .hw_rev = 1,
  218. .layout_id = "4M",
  219. }, {
  220. .id = "TL-MR3220v2",
  221. .hw_id = HWID_TL_MR3220_V2,
  222. .hw_rev = 1,
  223. .layout_id = "4Mlzma",
  224. }, {
  225. .id = "TL-MR3420v1",
  226. .hw_id = HWID_TL_MR3420_V1,
  227. .hw_rev = 1,
  228. .layout_id = "4M",
  229. }, {
  230. .id = "TL-MR3420v2",
  231. .hw_id = HWID_TL_MR3420_V2,
  232. .hw_rev = 1,
  233. .layout_id = "4Mlzma",
  234. }, {
  235. .id = "TL-WA701Nv1",
  236. .hw_id = HWID_TL_WA701N_V1,
  237. .hw_rev = 1,
  238. .layout_id = "4M",
  239. }, {
  240. .id = "TL-WA7510N",
  241. .hw_id = HWID_TL_WA7510N_V1,
  242. .hw_rev = 1,
  243. .layout_id = "4M",
  244. }, {
  245. .id = "TL-WA801NDv1",
  246. .hw_id = HWID_TL_WA801ND_V1,
  247. .hw_rev = 1,
  248. .layout_id = "4M",
  249. }, {
  250. .id = "TL-WA830REv1",
  251. .hw_id = HWID_TL_WA830RE_V1,
  252. .hw_rev = 1,
  253. .layout_id = "4M",
  254. }, {
  255. .id = "TL-WA830REv2",
  256. .hw_id = HWID_TL_WA830RE_V2,
  257. .hw_rev = 1,
  258. .layout_id = "4M",
  259. }, {
  260. .id = "TL-WA801NDv2",
  261. .hw_id = HWID_TL_WA801ND_V2,
  262. .hw_rev = 1,
  263. .layout_id = "4Mlzma",
  264. }, {
  265. .id = "TL-WA901NDv1",
  266. .hw_id = HWID_TL_WA901ND_V1,
  267. .hw_rev = 1,
  268. .layout_id = "4M",
  269. }, {
  270. .id = "TL-WA901NDv2",
  271. .hw_id = HWID_TL_WA901ND_V2,
  272. .hw_rev = 1,
  273. .layout_id = "4M",
  274. }, {
  275. .id = "TL-WDR4300v1",
  276. .hw_id = HWID_TL_WDR4300_V1_IL,
  277. .hw_rev = 1,
  278. .layout_id = "8Mlzma",
  279. }, {
  280. .id = "TL-WDR4900v1",
  281. .hw_id = HWID_TL_WDR4900_V1,
  282. .hw_rev = 1,
  283. .layout_id = "16Mppc",
  284. }, {
  285. .id = "TL-WR741NDv1",
  286. .hw_id = HWID_TL_WR741ND_V1,
  287. .hw_rev = 1,
  288. .layout_id = "4M",
  289. }, {
  290. .id = "TL-WR741NDv4",
  291. .hw_id = HWID_TL_WR741ND_V4,
  292. .hw_rev = 1,
  293. .layout_id = "4Mlzma",
  294. }, {
  295. .id = "TL-WR740Nv1",
  296. .hw_id = HWID_TL_WR740N_V1,
  297. .hw_rev = 1,
  298. .layout_id = "4M",
  299. }, {
  300. .id = "TL-WR740Nv3",
  301. .hw_id = HWID_TL_WR740N_V3,
  302. .hw_rev = 1,
  303. .layout_id = "4M",
  304. }, {
  305. .id = "TL-WR743NDv1",
  306. .hw_id = HWID_TL_WR743ND_V1,
  307. .hw_rev = 1,
  308. .layout_id = "4M",
  309. }, {
  310. .id = "TL-WR743NDv2",
  311. .hw_id = HWID_TL_WR743ND_V2,
  312. .hw_rev = 1,
  313. .layout_id = "4Mlzma",
  314. }, {
  315. .id = "TL-WR841Nv1.5",
  316. .hw_id = HWID_TL_WR841N_V1_5,
  317. .hw_rev = 2,
  318. .layout_id = "4M",
  319. }, {
  320. .id = "TL-WR841NDv3",
  321. .hw_id = HWID_TL_WR841ND_V3,
  322. .hw_rev = 3,
  323. .layout_id = "4M",
  324. }, {
  325. .id = "TL-WR841NDv5",
  326. .hw_id = HWID_TL_WR841ND_V5,
  327. .hw_rev = 1,
  328. .layout_id = "4M",
  329. }, {
  330. .id = "TL-WR841NDv7",
  331. .hw_id = HWID_TL_WR841ND_V7,
  332. .hw_rev = 1,
  333. .layout_id = "4M",
  334. }, {
  335. .id = "TL-WR941NDv2",
  336. .hw_id = HWID_TL_WR941ND_V2,
  337. .hw_rev = 2,
  338. .layout_id = "4M",
  339. }, {
  340. .id = "TL-WR941NDv4",
  341. .hw_id = HWID_TL_WR941ND_V4,
  342. .hw_rev = 1,
  343. .layout_id = "4M",
  344. }, {
  345. .id = "TL-WR1041Nv2",
  346. .hw_id = HWID_TL_WR1041N_V2,
  347. .hw_rev = 1,
  348. .layout_id = "4Mlzma",
  349. }, {
  350. .id = "TL-WR1043NDv1",
  351. .hw_id = HWID_TL_WR1043ND_V1,
  352. .hw_rev = 1,
  353. .layout_id = "8M",
  354. }, {
  355. .id = "TL-WR1043NDv2",
  356. .hw_id = HWID_TL_WR1043ND_V2,
  357. .hw_rev = 1,
  358. .layout_id = "8Mlzma",
  359. }, {
  360. .id = "TL-WR2543Nv1",
  361. .hw_id = HWID_TL_WR2543N_V1,
  362. .hw_rev = 1,
  363. .layout_id = "8Mlzma",
  364. }, {
  365. .id = "TL-WR703Nv1",
  366. .hw_id = HWID_TL_WR703N_V1,
  367. .hw_rev = 1,
  368. .layout_id = "4Mlzma",
  369. }, {
  370. .id = "TL-WR720Nv3",
  371. .hw_id = HWID_TL_WR720N_V3,
  372. .hw_rev = 1,
  373. .layout_id = "4Mlzma",
  374. }, {
  375. .id = "GL-INETv1",
  376. .hw_id = HWID_GL_INET_V1,
  377. .hw_rev = 1,
  378. .layout_id = "8Mlzma",
  379. }, {
  380. .id = "GS-OOLITEv1",
  381. .hw_id = HWID_GS_OOLITE_V1,
  382. .hw_rev = 1,
  383. .layout_id = "16Mlzma",
  384. }, {
  385. /* terminating entry */
  386. }
  387. };
  388. /*
  389. * Message macros
  390. */
  391. #define ERR(fmt, ...) do { \
  392. fflush(0); \
  393. fprintf(stderr, "[%s] *** error: " fmt "\n", \
  394. progname, ## __VA_ARGS__ ); \
  395. } while (0)
  396. #define ERRS(fmt, ...) do { \
  397. int save = errno; \
  398. fflush(0); \
  399. fprintf(stderr, "[%s] *** error: " fmt "\n", \
  400. progname, ## __VA_ARGS__, strerror(save)); \
  401. } while (0)
  402. #define DBG(fmt, ...) do { \
  403. fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
  404. } while (0)
  405. static struct board_info *find_board(char *id)
  406. {
  407. struct board_info *ret;
  408. struct board_info *board;
  409. ret = NULL;
  410. for (board = boards; board->id != NULL; board++){
  411. if (strcasecmp(id, board->id) == 0) {
  412. ret = board;
  413. break;
  414. }
  415. };
  416. return ret;
  417. }
  418. static struct board_info *find_board_by_hwid(uint32_t hw_id)
  419. {
  420. struct board_info *board;
  421. for (board = boards; board->id != NULL; board++) {
  422. if (hw_id == board->hw_id)
  423. return board;
  424. };
  425. return NULL;
  426. }
  427. static struct flash_layout *find_layout(char *id)
  428. {
  429. struct flash_layout *ret;
  430. struct flash_layout *l;
  431. ret = NULL;
  432. for (l = layouts; l->id != NULL; l++){
  433. if (strcasecmp(id, l->id) == 0) {
  434. ret = l;
  435. break;
  436. }
  437. };
  438. return ret;
  439. }
  440. static void usage(int status)
  441. {
  442. FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
  443. struct board_info *board;
  444. fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
  445. fprintf(stream,
  446. "\n"
  447. "Options:\n"
  448. " -B <board> create image for the board specified with <board>\n"
  449. " -c use combined kernel image\n"
  450. " -E <ep> overwrite kernel entry point with <ep> (hexval prefixed with 0x)\n"
  451. " -L <la> overwrite kernel load address with <la> (hexval prefixed with 0x)\n"
  452. " -H <hwid> use hardware id specified with <hwid>\n"
  453. " -W <hwrev> use hardware revision specified with <hwrev>\n"
  454. " -F <id> use flash layout specified with <id>\n"
  455. " -k <file> read kernel image from the file <file>\n"
  456. " -r <file> read rootfs image from the file <file>\n"
  457. " -a <align> align the rootfs start on an <align> bytes boundary\n"
  458. " -R <offset> overwrite rootfs offset with <offset> (hexval prefixed with 0x)\n"
  459. " -o <file> write output to the file <file>\n"
  460. " -s strip padding from the end of the image\n"
  461. " -j add jffs2 end-of-filesystem markers\n"
  462. " -N <vendor> set image vendor to <vendor>\n"
  463. " -V <version> set image version to <version>\n"
  464. " -v <version> set firmware version to <version>\n"
  465. " -i <file> inspect given firmware file <file>\n"
  466. " -x extract kernel and rootfs while inspecting (requires -i)\n"
  467. " -X <size> reserve <size> bytes in the firmware image (hexval prefixed with 0x)\n"
  468. " -h show this screen\n"
  469. );
  470. exit(status);
  471. }
  472. static int get_md5(char *data, int size, char *md5)
  473. {
  474. MD5_CTX ctx;
  475. MD5_Init(&ctx);
  476. MD5_Update(&ctx, data, size);
  477. MD5_Final(md5, &ctx);
  478. }
  479. static int get_file_stat(struct file_info *fdata)
  480. {
  481. struct stat st;
  482. int res;
  483. if (fdata->file_name == NULL)
  484. return 0;
  485. res = stat(fdata->file_name, &st);
  486. if (res){
  487. ERRS("stat failed on %s", fdata->file_name);
  488. return res;
  489. }
  490. fdata->file_size = st.st_size;
  491. return 0;
  492. }
  493. static int read_to_buf(struct file_info *fdata, char *buf)
  494. {
  495. FILE *f;
  496. int ret = EXIT_FAILURE;
  497. f = fopen(fdata->file_name, "r");
  498. if (f == NULL) {
  499. ERRS("could not open \"%s\" for reading", fdata->file_name);
  500. goto out;
  501. }
  502. errno = 0;
  503. fread(buf, fdata->file_size, 1, f);
  504. if (errno != 0) {
  505. ERRS("unable to read from file \"%s\"", fdata->file_name);
  506. goto out_close;
  507. }
  508. ret = EXIT_SUCCESS;
  509. out_close:
  510. fclose(f);
  511. out:
  512. return ret;
  513. }
  514. static int check_options(void)
  515. {
  516. int ret;
  517. if (inspect_info.file_name) {
  518. ret = get_file_stat(&inspect_info);
  519. if (ret)
  520. return ret;
  521. return 0;
  522. } else if (extract) {
  523. ERR("no firmware for inspection specified");
  524. return -1;
  525. }
  526. if (board_id == NULL && opt_hw_id == NULL) {
  527. ERR("either board or hardware id must be specified");
  528. return -1;
  529. }
  530. if (board_id) {
  531. board = find_board(board_id);
  532. if (board == NULL) {
  533. ERR("unknown/unsupported board id \"%s\"", board_id);
  534. return -1;
  535. }
  536. if (layout_id == NULL)
  537. layout_id = board->layout_id;
  538. hw_id = board->hw_id;
  539. hw_rev = board->hw_rev;
  540. } else {
  541. if (layout_id == NULL) {
  542. ERR("flash layout is not specified");
  543. return -1;
  544. }
  545. hw_id = strtoul(opt_hw_id, NULL, 0);
  546. if (opt_hw_rev)
  547. hw_rev = strtoul(opt_hw_rev, NULL, 0);
  548. else
  549. hw_rev = 1;
  550. }
  551. layout = find_layout(layout_id);
  552. if (layout == NULL) {
  553. ERR("unknown flash layout \"%s\"", layout_id);
  554. return -1;
  555. }
  556. if (!kernel_la)
  557. kernel_la = layout->kernel_la;
  558. if (!kernel_ep)
  559. kernel_ep = layout->kernel_ep;
  560. if (!rootfs_ofs)
  561. rootfs_ofs = layout->rootfs_ofs;
  562. if (reserved_space > layout->fw_max_len) {
  563. ERR("reserved space is not valid");
  564. return -1;
  565. }
  566. fw_max_len = layout->fw_max_len - reserved_space;
  567. if (kernel_info.file_name == NULL) {
  568. ERR("no kernel image specified");
  569. return -1;
  570. }
  571. ret = get_file_stat(&kernel_info);
  572. if (ret)
  573. return ret;
  574. kernel_len = kernel_info.file_size;
  575. if (combined) {
  576. if (kernel_info.file_size >
  577. fw_max_len - sizeof(struct fw_header)) {
  578. ERR("kernel image is too big");
  579. return -1;
  580. }
  581. } else {
  582. if (rootfs_info.file_name == NULL) {
  583. ERR("no rootfs image specified");
  584. return -1;
  585. }
  586. ret = get_file_stat(&rootfs_info);
  587. if (ret)
  588. return ret;
  589. if (rootfs_align) {
  590. kernel_len += sizeof(struct fw_header);
  591. kernel_len = ALIGN(kernel_len, rootfs_align);
  592. kernel_len -= sizeof(struct fw_header);
  593. DBG("kernel length aligned to %u", kernel_len);
  594. if (kernel_len + rootfs_info.file_size >
  595. fw_max_len - sizeof(struct fw_header)) {
  596. ERR("images are too big");
  597. return -1;
  598. }
  599. } else {
  600. if (kernel_info.file_size >
  601. rootfs_ofs - sizeof(struct fw_header)) {
  602. ERR("kernel image is too big");
  603. return -1;
  604. }
  605. if (rootfs_info.file_size >
  606. (fw_max_len - rootfs_ofs)) {
  607. ERR("rootfs image is too big");
  608. return -1;
  609. }
  610. }
  611. }
  612. if (ofname == NULL) {
  613. ERR("no output file specified");
  614. return -1;
  615. }
  616. ret = sscanf(fw_ver, "%d.%d.%d", &fw_ver_hi, &fw_ver_mid, &fw_ver_lo);
  617. if (ret != 3) {
  618. ERR("invalid firmware version '%s'", fw_ver);
  619. return -1;
  620. }
  621. return 0;
  622. }
  623. static void fill_header(char *buf, int len)
  624. {
  625. struct fw_header *hdr = (struct fw_header *)buf;
  626. memset(hdr, 0, sizeof(struct fw_header));
  627. hdr->version = htonl(HEADER_VERSION_V1);
  628. strncpy(hdr->vendor_name, vendor, sizeof(hdr->vendor_name));
  629. strncpy(hdr->fw_version, version, sizeof(hdr->fw_version));
  630. hdr->hw_id = htonl(hw_id);
  631. hdr->hw_rev = htonl(hw_rev);
  632. if (boot_info.file_size == 0)
  633. memcpy(hdr->md5sum1, md5salt_normal, sizeof(hdr->md5sum1));
  634. else
  635. memcpy(hdr->md5sum1, md5salt_boot, sizeof(hdr->md5sum1));
  636. hdr->kernel_la = htonl(kernel_la);
  637. hdr->kernel_ep = htonl(kernel_ep);
  638. hdr->fw_length = htonl(layout->fw_max_len);
  639. hdr->kernel_ofs = htonl(sizeof(struct fw_header));
  640. hdr->kernel_len = htonl(kernel_len);
  641. if (!combined) {
  642. hdr->rootfs_ofs = htonl(rootfs_ofs);
  643. hdr->rootfs_len = htonl(rootfs_info.file_size);
  644. }
  645. hdr->ver_hi = htons(fw_ver_hi);
  646. hdr->ver_mid = htons(fw_ver_mid);
  647. hdr->ver_lo = htons(fw_ver_lo);
  648. get_md5(buf, len, hdr->md5sum1);
  649. }
  650. static int pad_jffs2(char *buf, int currlen)
  651. {
  652. int len;
  653. uint32_t pad_mask;
  654. len = currlen;
  655. pad_mask = (64 * 1024);
  656. while ((len < layout->fw_max_len) && (pad_mask != 0)) {
  657. uint32_t mask;
  658. int i;
  659. for (i = 10; i < 32; i++) {
  660. mask = 1 << i;
  661. if (pad_mask & mask)
  662. break;
  663. }
  664. len = ALIGN(len, mask);
  665. for (i = 10; i < 32; i++) {
  666. mask = 1 << i;
  667. if ((len & (mask - 1)) == 0)
  668. pad_mask &= ~mask;
  669. }
  670. for (i = 0; i < sizeof(jffs2_eof_mark); i++)
  671. buf[len + i] = jffs2_eof_mark[i];
  672. len += sizeof(jffs2_eof_mark);
  673. }
  674. return len;
  675. }
  676. static int write_fw(char *data, int len)
  677. {
  678. FILE *f;
  679. int ret = EXIT_FAILURE;
  680. f = fopen(ofname, "w");
  681. if (f == NULL) {
  682. ERRS("could not open \"%s\" for writing", ofname);
  683. goto out;
  684. }
  685. errno = 0;
  686. fwrite(data, len, 1, f);
  687. if (errno) {
  688. ERRS("unable to write output file");
  689. goto out_flush;
  690. }
  691. DBG("firmware file \"%s\" completed", ofname);
  692. ret = EXIT_SUCCESS;
  693. out_flush:
  694. fflush(f);
  695. fclose(f);
  696. if (ret != EXIT_SUCCESS) {
  697. unlink(ofname);
  698. }
  699. out:
  700. return ret;
  701. }
  702. static int build_fw(void)
  703. {
  704. int buflen;
  705. char *buf;
  706. char *p;
  707. int ret = EXIT_FAILURE;
  708. int writelen = 0;
  709. buflen = layout->fw_max_len;
  710. buf = malloc(buflen);
  711. if (!buf) {
  712. ERR("no memory for buffer\n");
  713. goto out;
  714. }
  715. memset(buf, 0xff, buflen);
  716. p = buf + sizeof(struct fw_header);
  717. ret = read_to_buf(&kernel_info, p);
  718. if (ret)
  719. goto out_free_buf;
  720. writelen = sizeof(struct fw_header) + kernel_len;
  721. if (!combined) {
  722. if (rootfs_align)
  723. p = buf + writelen;
  724. else
  725. p = buf + rootfs_ofs;
  726. ret = read_to_buf(&rootfs_info, p);
  727. if (ret)
  728. goto out_free_buf;
  729. if (rootfs_align)
  730. writelen += rootfs_info.file_size;
  731. else
  732. writelen = rootfs_ofs + rootfs_info.file_size;
  733. if (add_jffs2_eof)
  734. writelen = pad_jffs2(buf, writelen);
  735. }
  736. if (!strip_padding)
  737. writelen = buflen;
  738. fill_header(buf, writelen);
  739. ret = write_fw(buf, writelen);
  740. if (ret)
  741. goto out_free_buf;
  742. ret = EXIT_SUCCESS;
  743. out_free_buf:
  744. free(buf);
  745. out:
  746. return ret;
  747. }
  748. /* Helper functions to inspect_fw() representing different output formats */
  749. static inline void inspect_fw_pstr(char *label, char *str)
  750. {
  751. printf("%-23s: %s\n", label, str);
  752. }
  753. static inline void inspect_fw_phex(char *label, uint32_t val)
  754. {
  755. printf("%-23s: 0x%08x\n", label, val);
  756. }
  757. static inline void inspect_fw_phexpost(char *label,
  758. uint32_t val, char *post)
  759. {
  760. printf("%-23s: 0x%08x (%s)\n", label, val, post);
  761. }
  762. static inline void inspect_fw_phexdef(char *label,
  763. uint32_t val, uint32_t defval)
  764. {
  765. printf("%-23s: 0x%08x ", label, val);
  766. if (val == defval)
  767. printf("(== OpenWrt default)\n");
  768. else
  769. printf("(OpenWrt default: 0x%08x)\n", defval);
  770. }
  771. static inline void inspect_fw_phexexp(char *label,
  772. uint32_t val, uint32_t expval)
  773. {
  774. printf("%-23s: 0x%08x ", label, val);
  775. if (val == expval)
  776. printf("(ok)\n");
  777. else
  778. printf("(expected: 0x%08x)\n", expval);
  779. }
  780. static inline void inspect_fw_phexdec(char *label, uint32_t val)
  781. {
  782. printf("%-23s: 0x%08x / %8u bytes\n", label, val, val);
  783. }
  784. static inline void inspect_fw_phexdecdef(char *label,
  785. uint32_t val, uint32_t defval)
  786. {
  787. printf("%-23s: 0x%08x / %8u bytes ", label, val, val);
  788. if (val == defval)
  789. printf("(== OpenWrt default)\n");
  790. else
  791. printf("(OpenWrt default: 0x%08x)\n", defval);
  792. }
  793. static inline void inspect_fw_pmd5sum(char *label, uint8_t *val, char *text)
  794. {
  795. int i;
  796. printf("%-23s:", label);
  797. for (i=0; i<MD5SUM_LEN; i++)
  798. printf(" %02x", val[i]);
  799. printf(" %s\n", text);
  800. }
  801. static int inspect_fw(void)
  802. {
  803. char *buf;
  804. struct fw_header *hdr;
  805. uint8_t md5sum[MD5SUM_LEN];
  806. struct board_info *board;
  807. int ret = EXIT_FAILURE;
  808. buf = malloc(inspect_info.file_size);
  809. if (!buf) {
  810. ERR("no memory for buffer!\n");
  811. goto out;
  812. }
  813. ret = read_to_buf(&inspect_info, buf);
  814. if (ret)
  815. goto out_free_buf;
  816. hdr = (struct fw_header *)buf;
  817. inspect_fw_pstr("File name", inspect_info.file_name);
  818. inspect_fw_phexdec("File size", inspect_info.file_size);
  819. if (ntohl(hdr->version) != HEADER_VERSION_V1) {
  820. ERR("file does not seem to have V1 header!\n");
  821. goto out_free_buf;
  822. }
  823. inspect_fw_phexdec("Version 1 Header size", sizeof(struct fw_header));
  824. if (ntohl(hdr->unk1) != 0)
  825. inspect_fw_phexdec("Unknown value 1", hdr->unk1);
  826. memcpy(md5sum, hdr->md5sum1, sizeof(md5sum));
  827. if (ntohl(hdr->boot_len) == 0)
  828. memcpy(hdr->md5sum1, md5salt_normal, sizeof(md5sum));
  829. else
  830. memcpy(hdr->md5sum1, md5salt_boot, sizeof(md5sum));
  831. get_md5(buf, inspect_info.file_size, hdr->md5sum1);
  832. if (memcmp(md5sum, hdr->md5sum1, sizeof(md5sum))) {
  833. inspect_fw_pmd5sum("Header MD5Sum1", md5sum, "(*ERROR*)");
  834. inspect_fw_pmd5sum(" --> expected", hdr->md5sum1, "");
  835. } else {
  836. inspect_fw_pmd5sum("Header MD5Sum1", md5sum, "(ok)");
  837. }
  838. if (ntohl(hdr->unk2) != 0)
  839. inspect_fw_phexdec("Unknown value 2", hdr->unk2);
  840. inspect_fw_pmd5sum("Header MD5Sum2", hdr->md5sum2,
  841. "(purpose yet unknown, unchecked here)");
  842. if (ntohl(hdr->unk3) != 0)
  843. inspect_fw_phexdec("Unknown value 3", hdr->unk3);
  844. printf("\n");
  845. inspect_fw_pstr("Vendor name", hdr->vendor_name);
  846. inspect_fw_pstr("Firmware version", hdr->fw_version);
  847. board = find_board_by_hwid(ntohl(hdr->hw_id));
  848. if (board) {
  849. layout = find_layout(board->layout_id);
  850. inspect_fw_phexpost("Hardware ID",
  851. ntohl(hdr->hw_id), board->id);
  852. inspect_fw_phexexp("Hardware Revision",
  853. ntohl(hdr->hw_rev), board->hw_rev);
  854. } else {
  855. inspect_fw_phexpost("Hardware ID",
  856. ntohl(hdr->hw_id), "unknown");
  857. inspect_fw_phex("Hardware Revision",
  858. ntohl(hdr->hw_rev));
  859. }
  860. printf("\n");
  861. inspect_fw_phexdec("Kernel data offset",
  862. ntohl(hdr->kernel_ofs));
  863. inspect_fw_phexdec("Kernel data length",
  864. ntohl(hdr->kernel_len));
  865. if (board) {
  866. inspect_fw_phexdef("Kernel load address",
  867. ntohl(hdr->kernel_la),
  868. layout ? layout->kernel_la : 0xffffffff);
  869. inspect_fw_phexdef("Kernel entry point",
  870. ntohl(hdr->kernel_ep),
  871. layout ? layout->kernel_ep : 0xffffffff);
  872. inspect_fw_phexdecdef("Rootfs data offset",
  873. ntohl(hdr->rootfs_ofs),
  874. layout ? layout->rootfs_ofs : 0xffffffff);
  875. } else {
  876. inspect_fw_phex("Kernel load address",
  877. ntohl(hdr->kernel_la));
  878. inspect_fw_phex("Kernel entry point",
  879. ntohl(hdr->kernel_ep));
  880. inspect_fw_phexdec("Rootfs data offset",
  881. ntohl(hdr->rootfs_ofs));
  882. }
  883. inspect_fw_phexdec("Rootfs data length",
  884. ntohl(hdr->rootfs_len));
  885. inspect_fw_phexdec("Boot loader data offset",
  886. ntohl(hdr->boot_ofs));
  887. inspect_fw_phexdec("Boot loader data length",
  888. ntohl(hdr->boot_len));
  889. inspect_fw_phexdec("Total firmware length",
  890. ntohl(hdr->fw_length));
  891. if (extract) {
  892. FILE *fp;
  893. char *filename;
  894. printf("\n");
  895. filename = malloc(strlen(inspect_info.file_name) + 8);
  896. sprintf(filename, "%s-kernel", inspect_info.file_name);
  897. printf("Extracting kernel to \"%s\"...\n", filename);
  898. fp = fopen(filename, "w");
  899. if (fp) {
  900. if (!fwrite(buf + ntohl(hdr->kernel_ofs),
  901. ntohl(hdr->kernel_len), 1, fp)) {
  902. ERR("error in fwrite(): %s", strerror(errno));
  903. }
  904. fclose(fp);
  905. } else {
  906. ERR("error in fopen(): %s", strerror(errno));
  907. }
  908. free(filename);
  909. filename = malloc(strlen(inspect_info.file_name) + 8);
  910. sprintf(filename, "%s-rootfs", inspect_info.file_name);
  911. printf("Extracting rootfs to \"%s\"...\n", filename);
  912. fp = fopen(filename, "w");
  913. if (fp) {
  914. if (!fwrite(buf + ntohl(hdr->rootfs_ofs),
  915. ntohl(hdr->rootfs_len), 1, fp)) {
  916. ERR("error in fwrite(): %s", strerror(errno));
  917. }
  918. fclose(fp);
  919. } else {
  920. ERR("error in fopen(): %s", strerror(errno));
  921. }
  922. free(filename);
  923. }
  924. out_free_buf:
  925. free(buf);
  926. out:
  927. return ret;
  928. }
  929. int main(int argc, char *argv[])
  930. {
  931. int ret = EXIT_FAILURE;
  932. int err;
  933. FILE *outfile;
  934. progname = basename(argv[0]);
  935. while ( 1 ) {
  936. int c;
  937. c = getopt(argc, argv, "a:B:H:E:F:L:V:N:W:ci:k:r:R:o:xX:hsjv:");
  938. if (c == -1)
  939. break;
  940. switch (c) {
  941. case 'a':
  942. sscanf(optarg, "0x%x", &rootfs_align);
  943. break;
  944. case 'B':
  945. board_id = optarg;
  946. break;
  947. case 'H':
  948. opt_hw_id = optarg;
  949. break;
  950. case 'E':
  951. sscanf(optarg, "0x%x", &kernel_ep);
  952. break;
  953. case 'F':
  954. layout_id = optarg;
  955. break;
  956. case 'W':
  957. opt_hw_rev = optarg;
  958. break;
  959. case 'L':
  960. sscanf(optarg, "0x%x", &kernel_la);
  961. break;
  962. case 'V':
  963. version = optarg;
  964. break;
  965. case 'v':
  966. fw_ver = optarg;
  967. break;
  968. case 'N':
  969. vendor = optarg;
  970. break;
  971. case 'c':
  972. combined++;
  973. break;
  974. case 'k':
  975. kernel_info.file_name = optarg;
  976. break;
  977. case 'r':
  978. rootfs_info.file_name = optarg;
  979. break;
  980. case 'R':
  981. sscanf(optarg, "0x%x", &rootfs_ofs);
  982. break;
  983. case 'o':
  984. ofname = optarg;
  985. break;
  986. case 's':
  987. strip_padding = 1;
  988. break;
  989. case 'i':
  990. inspect_info.file_name = optarg;
  991. break;
  992. case 'j':
  993. add_jffs2_eof = 1;
  994. break;
  995. case 'x':
  996. extract = 1;
  997. break;
  998. case 'h':
  999. usage(EXIT_SUCCESS);
  1000. break;
  1001. case 'X':
  1002. sscanf(optarg, "0x%x", &reserved_space);
  1003. break;
  1004. default:
  1005. usage(EXIT_FAILURE);
  1006. break;
  1007. }
  1008. }
  1009. ret = check_options();
  1010. if (ret)
  1011. goto out;
  1012. if (!inspect_info.file_name)
  1013. ret = build_fw();
  1014. else
  1015. ret = inspect_fw();
  1016. out:
  1017. return ret;
  1018. }