mktplinkfw-lib.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  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 <stdbool.h>
  22. #include <endian.h>
  23. #include <errno.h>
  24. #include <sys/stat.h>
  25. #include <arpa/inet.h>
  26. #include <netinet/in.h>
  27. #include "mktplinkfw-lib.h"
  28. #include "md5.h"
  29. extern char *ofname;
  30. extern char *progname;
  31. extern uint32_t kernel_len;
  32. extern struct file_info kernel_info;
  33. extern struct file_info rootfs_info;
  34. extern struct flash_layout *layout;
  35. extern uint32_t rootfs_ofs;
  36. extern uint32_t rootfs_align;
  37. extern int combined;
  38. extern int strip_padding;
  39. extern int add_jffs2_eof;
  40. static unsigned char jffs2_eof_mark[4] = {0xde, 0xad, 0xc0, 0xde};
  41. void fill_header(char *buf, int len);
  42. struct flash_layout *find_layout(struct flash_layout *layouts, const char *id)
  43. {
  44. struct flash_layout *ret;
  45. struct flash_layout *l;
  46. ret = NULL;
  47. for (l = layouts; l->id != NULL; l++){
  48. if (strcasecmp(id, l->id) == 0) {
  49. ret = l;
  50. break;
  51. }
  52. };
  53. return ret;
  54. }
  55. void get_md5(const char *data, int size, uint8_t *md5)
  56. {
  57. MD5_CTX ctx;
  58. MD5_Init(&ctx);
  59. MD5_Update(&ctx, data, size);
  60. MD5_Final(md5, &ctx);
  61. }
  62. int get_file_stat(struct file_info *fdata)
  63. {
  64. struct stat st;
  65. int res;
  66. if (fdata->file_name == NULL)
  67. return 0;
  68. res = stat(fdata->file_name, &st);
  69. if (res){
  70. ERRS("stat failed on %s", fdata->file_name);
  71. return res;
  72. }
  73. fdata->file_size = st.st_size;
  74. return 0;
  75. }
  76. int read_to_buf(const struct file_info *fdata, char *buf)
  77. {
  78. FILE *f;
  79. int ret = EXIT_FAILURE;
  80. f = fopen(fdata->file_name, "r");
  81. if (f == NULL) {
  82. ERRS("could not open \"%s\" for reading", fdata->file_name);
  83. goto out;
  84. }
  85. errno = 0;
  86. fread(buf, fdata->file_size, 1, f);
  87. if (errno != 0) {
  88. ERRS("unable to read from file \"%s\"", fdata->file_name);
  89. goto out_close;
  90. }
  91. ret = EXIT_SUCCESS;
  92. out_close:
  93. fclose(f);
  94. out:
  95. return ret;
  96. }
  97. static int pad_jffs2(char *buf, int currlen, int maxlen)
  98. {
  99. int len;
  100. uint32_t pad_mask;
  101. len = currlen;
  102. pad_mask = (4 * 1024) | (64 * 1024); /* EOF at 4KB and at 64KB */
  103. while ((len < maxlen) && (pad_mask != 0)) {
  104. uint32_t mask;
  105. int i;
  106. for (i = 10; i < 32; i++) {
  107. mask = 1 << i;
  108. if (pad_mask & mask)
  109. break;
  110. }
  111. len = ALIGN(len, mask);
  112. for (i = 10; i < 32; i++) {
  113. mask = 1 << i;
  114. if ((len & (mask - 1)) == 0)
  115. pad_mask &= ~mask;
  116. }
  117. for (i = 0; i < sizeof(jffs2_eof_mark); i++)
  118. buf[len + i] = jffs2_eof_mark[i];
  119. len += sizeof(jffs2_eof_mark);
  120. }
  121. return len;
  122. }
  123. int write_fw(const char *ofname, const char *data, int len)
  124. {
  125. FILE *f;
  126. int ret = EXIT_FAILURE;
  127. f = fopen(ofname, "w");
  128. if (f == NULL) {
  129. ERRS("could not open \"%s\" for writing", ofname);
  130. goto out;
  131. }
  132. errno = 0;
  133. fwrite(data, len, 1, f);
  134. if (errno) {
  135. ERRS("unable to write output file");
  136. goto out_flush;
  137. }
  138. DBG("firmware file \"%s\" completed", ofname);
  139. ret = EXIT_SUCCESS;
  140. out_flush:
  141. fflush(f);
  142. fclose(f);
  143. if (ret != EXIT_SUCCESS) {
  144. unlink(ofname);
  145. }
  146. out:
  147. return ret;
  148. }
  149. /* Helper functions to inspect_fw() representing different output formats */
  150. inline void inspect_fw_pstr(const char *label, const char *str)
  151. {
  152. printf("%-23s: %s\n", label, str);
  153. }
  154. inline void inspect_fw_phex(const char *label, uint32_t val)
  155. {
  156. printf("%-23s: 0x%08x\n", label, val);
  157. }
  158. inline void inspect_fw_phexdec(const char *label, uint32_t val)
  159. {
  160. printf("%-23s: 0x%08x / %8u bytes\n", label, val, val);
  161. }
  162. inline void inspect_fw_pmd5sum(const char *label, const uint8_t *val, const char *text)
  163. {
  164. int i;
  165. printf("%-23s:", label);
  166. for (i=0; i<MD5SUM_LEN; i++)
  167. printf(" %02x", val[i]);
  168. printf(" %s\n", text);
  169. }
  170. // header_size = sizeof(struct fw_header)
  171. int build_fw(size_t header_size)
  172. {
  173. int buflen;
  174. char *buf;
  175. char *p;
  176. int ret = EXIT_FAILURE;
  177. int writelen = 0;
  178. writelen = header_size + kernel_len;
  179. if (combined)
  180. buflen = writelen;
  181. else
  182. buflen = layout->fw_max_len;
  183. buf = malloc(buflen);
  184. if (!buf) {
  185. ERR("no memory for buffer\n");
  186. goto out;
  187. }
  188. memset(buf, 0xff, buflen);
  189. p = buf + header_size;
  190. ret = read_to_buf(&kernel_info, p);
  191. if (ret)
  192. goto out_free_buf;
  193. if (!combined) {
  194. p = buf + rootfs_ofs;
  195. ret = read_to_buf(&rootfs_info, p);
  196. if (ret)
  197. goto out_free_buf;
  198. writelen = rootfs_ofs + rootfs_info.file_size;
  199. if (add_jffs2_eof)
  200. writelen = pad_jffs2(buf, writelen, layout->fw_max_len);
  201. }
  202. if (!strip_padding)
  203. writelen = buflen;
  204. fill_header(buf, writelen);
  205. ret = write_fw(ofname, buf, writelen);
  206. if (ret)
  207. goto out_free_buf;
  208. ret = EXIT_SUCCESS;
  209. out_free_buf:
  210. free(buf);
  211. out:
  212. return ret;
  213. }