1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2014 Gabor Juhos <juhosg@openwrt.org> 4 */ 5 6 #include <stdio.h> 7 #include <stdlib.h> 8 #include <stdint.h> 9 #include <string.h> 10 #include <unistd.h> /* for unlink() */ 11 #include <libgen.h> 12 #include <getopt.h> /* for getopt() */ 13 #include <stdarg.h> 14 #include <errno.h> 15 #include <sys/stat.h> 16 17 #include <arpa/inet.h> 18 #include <netinet/in.h> 19 20 #define MAX_MAGIC_LEN 16 21 #define MAX_MODEL_LEN 32 22 #define MAX_VERSION_LEN 14 23 #define MAX_MTD_NAME_LEN 16 24 25 #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f)) 26 27 struct edimax_header { 28 char magic[MAX_MAGIC_LEN]; 29 char model[MAX_MODEL_LEN]; 30 unsigned char force; 31 unsigned char header_csum; 32 unsigned char data_csum; 33 uint32_t data_size; 34 uint32_t start_addr; 35 uint32_t end_addr; 36 char fw_version[MAX_VERSION_LEN]; 37 unsigned char type; 38 char mtd_name[MAX_MTD_NAME_LEN]; 39 } __attribute__ ((packed)); 40 41 /* 42 * Globals 43 */ 44 static char *ofname; 45 static char *ifname; 46 static char *progname; 47 48 static char *model; 49 static char *magic = "eDiMaX"; 50 static char *fw_version = ""; 51 static char *mtd_name; 52 static int force; 53 static uint32_t start_addr; 54 static uint32_t end_addr; 55 static uint8_t image_type; 56 static int data_size; 57 58 /* 59 * Message macros 60 */ 61 #define ERR(fmt, ...) do { \ 62 fflush(0); \ 63 fprintf(stderr, "[%s] *** error: " fmt "\n", \ 64 progname, ## __VA_ARGS__ ); \ 65 } while (0) 66 67 #define ERRS(fmt, ...) do { \ 68 int save = errno; \ 69 fflush(0); \ 70 fprintf(stderr, "[%s] *** error: " fmt " (%s)\n", \ 71 progname, ## __VA_ARGS__, strerror(save)); \ 72 } while (0) 73 74 #define DBG(fmt, ...) do { \ 75 fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \ 76 } while (0) 77 78 static void usage(int status) 79 { 80 FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout; 81 82 fprintf(stream, "Usage: %s [OPTIONS...]\n", progname); 83 fprintf(stream, 84 "\n" 85 "Options:\n" 86 " -e <addr> set end addr to <addr>\n" 87 " -f set force flag\n" 88 " -h show this screen\n" 89 " -i <file> read input data from the file <file>\n" 90 " -o <file> write output to the file <file>\n" 91 " -m <model> set model to <model>\n" 92 " -M <magic> set image magic to <magic>\n" 93 " -n <name> set MTD device name to <name>\n" 94 " -s <addr> set start address to <addr>\n" 95 " -t <type> set image type to <type>\n" 96 " -v <version> set firmware version to <version>\n" 97 ); 98 99 exit(status); 100 } 101 102 int 103 str2u32(char *arg, uint32_t *val) 104 { 105 char *err = NULL; 106 uint32_t t; 107 108 errno=0; 109 t = strtoul(arg, &err, 0); 110 if (errno || (err==arg) || ((err != NULL) && *err)) { 111 return -1; 112 } 113 114 *val = t; 115 return 0; 116 } 117 118 int 119 str2u8(char *arg, uint8_t *val) 120 { 121 char *err = NULL; 122 uint32_t t; 123 124 errno=0; 125 t = strtoul(arg, &err, 0); 126 if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x100)) { 127 return -1; 128 } 129 130 *val = t & 0xFF; 131 return 0; 132 } 133 134 static int get_file_size(char *name) 135 { 136 struct stat st; 137 int res; 138 139 res = stat(name, &st); 140 if (res){ 141 ERRS("stat failed on %s", name); 142 return -1; 143 } 144 145 return st.st_size; 146 } 147 148 static int read_to_buf(char *name, char *buf, int buflen) 149 { 150 FILE *f; 151 int ret = EXIT_FAILURE; 152 153 f = fopen(name, "r"); 154 if (f == NULL) { 155 ERRS("could not open \"%s\" for reading", name); 156 goto out; 157 } 158 159 errno = 0; 160 fread(buf, buflen, 1, f); 161 if (errno != 0) { 162 ERRS("unable to read from file \"%s\"", name); 163 goto out_close; 164 } 165 166 ret = EXIT_SUCCESS; 167 168 out_close: 169 fclose(f); 170 out: 171 return ret; 172 } 173 174 static int check_options(void) 175 { 176 #define CHKSTR(_name, _msg) \ 177 do { \ 178 if (_name == NULL) { \ 179 ERR("no %s specified", _msg); \ 180 return -1; \ 181 } \ 182 } while (0) 183 184 #define CHKSTRLEN(_name, _msg) \ 185 do { \ 186 int field_len; \ 187 CHKSTR(_name, _msg); \ 188 field_len = FIELD_SIZEOF(struct edimax_header, _name) - 1; \ 189 if (strlen(_name) > field_len) { \ 190 ERR("'%s' is too long, max %s length is %d", \ 191 _name, _msg, field_len); \ 192 return -1; \ 193 } \ 194 } while (0) 195 196 CHKSTR(ofname, "output file"); 197 CHKSTR(ifname, "input file"); 198 199 CHKSTRLEN(magic, "magic"); 200 CHKSTRLEN(model, "model"); 201 CHKSTRLEN(mtd_name, "MTD device name"); 202 CHKSTRLEN(fw_version, "firware version"); 203 204 data_size = get_file_size(ifname); 205 if (data_size < 0) 206 return -1; 207 208 return 0; 209 } 210 211 static int write_fw(char *data, int len) 212 { 213 FILE *f; 214 int ret = EXIT_FAILURE; 215 216 f = fopen(ofname, "w"); 217 if (f == NULL) { 218 ERRS("could not open \"%s\" for writing", ofname); 219 goto out; 220 } 221 222 errno = 0; 223 fwrite(data, len, 1, f); 224 if (errno) { 225 ERRS("unable to write output file"); 226 goto out_flush; 227 } 228 229 DBG("firmware file \"%s\" completed", ofname); 230 231 ret = EXIT_SUCCESS; 232 233 out_flush: 234 fflush(f); 235 fclose(f); 236 if (ret != EXIT_SUCCESS) { 237 unlink(ofname); 238 } 239 out: 240 return ret; 241 } 242 243 static unsigned char checksum(unsigned char *p, unsigned len) 244 { 245 unsigned char csum = 0; 246 247 while (len--) 248 csum += *p++; 249 250 csum ^= 0xb9; 251 252 return csum; 253 } 254 255 static int build_fw(void) 256 { 257 int buflen; 258 char *buf; 259 char *data; 260 struct edimax_header *hdr; 261 int ret = EXIT_FAILURE; 262 263 buflen = sizeof(struct edimax_header) + data_size; 264 265 buf = malloc(buflen); 266 if (!buf) { 267 ERR("no memory for buffer\n"); 268 goto out; 269 } 270 271 data = buf + sizeof(struct edimax_header); 272 273 /* read input file */ 274 ret = read_to_buf(ifname, data, data_size); 275 if (ret) 276 goto out_free_buf; 277 278 /* fill firmware header */ 279 hdr = (struct edimax_header *)buf; 280 memset(hdr, 0, sizeof(struct edimax_header)); 281 282 strncpy(hdr->model, model, sizeof(hdr->model)); 283 strncpy(hdr->magic, magic, sizeof(hdr->magic)); 284 strncpy(hdr->fw_version, fw_version, sizeof(hdr->fw_version)); 285 strncpy(hdr->mtd_name, mtd_name, sizeof(hdr->mtd_name)); 286 287 hdr->force = force; 288 hdr->start_addr = htonl(start_addr); 289 hdr->end_addr = htonl(end_addr); 290 hdr->data_size = htonl(data_size); 291 hdr->type = image_type; 292 293 hdr->data_csum = checksum((unsigned char *)data, data_size); 294 hdr->header_csum = checksum((unsigned char *)hdr, 295 sizeof(struct edimax_header)); 296 297 ret = write_fw(buf, buflen); 298 if (ret) 299 goto out_free_buf; 300 301 ret = EXIT_SUCCESS; 302 303 out_free_buf: 304 free(buf); 305 out: 306 return ret; 307 } 308 309 int main(int argc, char *argv[]) 310 { 311 int ret = EXIT_FAILURE; 312 313 progname = basename(argv[0]); 314 315 while (1) { 316 int c; 317 318 c = getopt(argc, argv, "e:fhi:o:m:M:n:s:t:v:"); 319 if (c == -1) 320 break; 321 322 switch (c) { 323 case 'e': 324 if (str2u32(optarg, &end_addr)) { 325 ERR("%s is invalid '%s'", 326 "end address", optarg); 327 goto out; 328 } 329 break; 330 case 'f': 331 force = 1; 332 break; 333 case 'i': 334 ifname = optarg; 335 break; 336 case 'h': 337 usage(EXIT_SUCCESS); 338 break; 339 case 'o': 340 ofname = optarg; 341 break; 342 case 'm': 343 model = optarg; 344 break; 345 case 'M': 346 magic = optarg; 347 break; 348 case 'n': 349 mtd_name = optarg; 350 break; 351 case 's': 352 if (str2u32(optarg, &start_addr)) { 353 ERR("%s is invalid '%s'", 354 "start address", optarg); 355 goto out; 356 } 357 break; 358 case 't': 359 if (str2u8(optarg, &image_type)) { 360 ERR("%s is invalid '%s'", 361 "image type", optarg); 362 goto out; 363 } 364 break; 365 case 'v': 366 fw_version = optarg; 367 break; 368 default: 369 usage(EXIT_FAILURE); 370 break; 371 } 372 } 373 374 ret = check_options(); 375 if (ret) 376 goto out; 377 378 ret = build_fw(); 379 380 out: 381 return ret; 382 } 383
This page was automatically generated by LXR 0.3.1. • OpenWrt