1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org> 4 * 5 * This tool was based on: 6 * TP-Link WR941 V2 firmware checksum fixing tool. 7 * Copyright (C) 2008,2009 Wang Jian <lark@linux.net.cn> 8 */ 9 10 #include <stdio.h> 11 #include <stdlib.h> 12 #include <stdint.h> 13 #include <string.h> 14 #include <unistd.h> /* for unlink() */ 15 #include <libgen.h> 16 #include <getopt.h> /* for getopt() */ 17 #include <stdarg.h> 18 #include <stdbool.h> 19 #include <endian.h> 20 #include <errno.h> 21 #include <sys/stat.h> 22 23 #include <arpa/inet.h> 24 #include <netinet/in.h> 25 26 #include "mktplinkfw-lib.h" 27 #include "md5.h" 28 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 41 static unsigned char jffs2_eof_mark[4] = {0xde, 0xad, 0xc0, 0xde}; 42 43 void fill_header(char *buf, int len); 44 45 struct flash_layout *find_layout(struct flash_layout *layouts, const char *id) 46 { 47 struct flash_layout *ret; 48 struct flash_layout *l; 49 50 ret = NULL; 51 for (l = layouts; l->id != NULL; l++){ 52 if (strcasecmp(id, l->id) == 0) { 53 ret = l; 54 break; 55 } 56 }; 57 58 return ret; 59 } 60 61 void get_md5(const char *data, int size, uint8_t *md5) 62 { 63 MD5_CTX ctx; 64 65 MD5_Init(&ctx); 66 MD5_Update(&ctx, data, size); 67 MD5_Final(md5, &ctx); 68 } 69 70 int get_file_stat(struct file_info *fdata) 71 { 72 struct stat st; 73 int res; 74 75 if (fdata->file_name == NULL) 76 return 0; 77 78 res = stat(fdata->file_name, &st); 79 if (res){ 80 ERRS("stat failed on %s", fdata->file_name); 81 return res; 82 } 83 84 fdata->file_size = st.st_size; 85 return 0; 86 } 87 88 int read_to_buf(const struct file_info *fdata, char *buf) 89 { 90 FILE *f; 91 int ret = EXIT_FAILURE; 92 93 f = fopen(fdata->file_name, "r"); 94 if (f == NULL) { 95 ERRS("could not open \"%s\" for reading", fdata->file_name); 96 goto out; 97 } 98 99 errno = 0; 100 fread(buf, fdata->file_size, 1, f); 101 if (errno != 0) { 102 ERRS("unable to read from file \"%s\"", fdata->file_name); 103 goto out_close; 104 } 105 106 ret = EXIT_SUCCESS; 107 108 out_close: 109 fclose(f); 110 out: 111 return ret; 112 } 113 114 static int pad_jffs2(char *buf, int currlen, int maxlen) 115 { 116 int len; 117 uint32_t pad_mask; 118 119 len = currlen; 120 pad_mask = (4 * 1024) | (64 * 1024); /* EOF at 4KB and at 64KB */ 121 while ((len < maxlen) && (pad_mask != 0)) { 122 uint32_t mask; 123 int i; 124 125 for (i = 10; i < 32; i++) { 126 mask = 1 << i; 127 if (pad_mask & mask) 128 break; 129 } 130 131 len = ALIGN(len, mask); 132 133 for (i = 10; i < 32; i++) { 134 mask = 1 << i; 135 if ((len & (mask - 1)) == 0) 136 pad_mask &= ~mask; 137 } 138 139 for (i = 0; i < sizeof(jffs2_eof_mark); i++) 140 buf[len + i] = jffs2_eof_mark[i]; 141 142 len += sizeof(jffs2_eof_mark); 143 } 144 145 return len; 146 } 147 148 int write_fw(const char *ofname, const char *data, int len) 149 { 150 FILE *f; 151 int ret = EXIT_FAILURE; 152 153 f = fopen(ofname, "w"); 154 if (f == NULL) { 155 ERRS("could not open \"%s\" for writing", ofname); 156 goto out; 157 } 158 159 errno = 0; 160 fwrite(data, len, 1, f); 161 if (errno) { 162 ERRS("unable to write output file"); 163 goto out_flush; 164 } 165 166 DBG("firmware file \"%s\" completed", ofname); 167 168 ret = EXIT_SUCCESS; 169 170 out_flush: 171 fflush(f); 172 fclose(f); 173 if (ret != EXIT_SUCCESS) { 174 unlink(ofname); 175 } 176 out: 177 return ret; 178 } 179 180 /* Helper functions to inspect_fw() representing different output formats */ 181 inline void inspect_fw_pstr(const char *label, const char *str) 182 { 183 printf("%-23s: %s\n", label, str); 184 } 185 186 inline void inspect_fw_phex(const char *label, uint32_t val) 187 { 188 printf("%-23s: 0x%08x\n", label, val); 189 } 190 191 inline void inspect_fw_phexdec(const char *label, uint32_t val) 192 { 193 printf("%-23s: 0x%08x / %8u bytes\n", label, val, val); 194 } 195 196 inline void inspect_fw_pmd5sum(const char *label, const uint8_t *val, const char *text) 197 { 198 int i; 199 200 printf("%-23s:", label); 201 for (i=0; i<MD5SUM_LEN; i++) 202 printf(" %02x", val[i]); 203 printf(" %s\n", text); 204 } 205 206 // header_size = sizeof(struct fw_header) 207 int build_fw(size_t header_size) 208 { 209 int buflen; 210 char *buf; 211 char *p; 212 int ret = EXIT_FAILURE; 213 int writelen = 0; 214 215 writelen = header_size + kernel_len; 216 217 if (combined) 218 buflen = writelen; 219 else 220 buflen = layout->fw_max_len; 221 222 buf = malloc(buflen); 223 if (!buf) { 224 ERR("no memory for buffer\n"); 225 goto out; 226 } 227 228 memset(buf, 0xff, buflen); 229 p = buf + header_size; 230 ret = read_to_buf(&kernel_info, p); 231 if (ret) 232 goto out_free_buf; 233 234 if (!combined) { 235 p = buf + rootfs_ofs; 236 237 ret = read_to_buf(&rootfs_info, p); 238 if (ret) 239 goto out_free_buf; 240 241 writelen = rootfs_ofs + rootfs_info.file_size; 242 243 if (add_jffs2_eof) 244 writelen = pad_jffs2(buf, writelen, layout->fw_max_len); 245 } 246 247 if (!strip_padding) 248 writelen = buflen; 249 250 fill_header(buf, writelen); 251 ret = write_fw(ofname, buf, writelen); 252 if (ret) 253 goto out_free_buf; 254 255 ret = EXIT_SUCCESS; 256 257 out_free_buf: 258 free(buf); 259 out: 260 return ret; 261 } 262
This page was automatically generated by LXR 0.3.1. • OpenWrt