1#include <stdio.h> 2#include <stdint.h> 3#include <stdlib.h> 4#include <unistd.h> 5#include <libgen.h> 6#include <stdarg.h> 7#include <getopt.h> 8#include <string.h> 9#include <errno.h> 10 11#include <netinet/in.h> // htonl 12 13// Usage: mkdapimg [-p] [-m <model>] -s <sig> -i <input> -o <output> 14// 15// e.g.: mkdapimg -s RT3052-AP-DAP1350-3 -i sysupgarde.bin -o factory.bin 16// 17// If the model string <model> is not given, we will assume that 18// the leading characters upto the first "-" is the model. 19// 20// The "-p" (patch) option is used to patch the exisiting image with the 21// specified model and signature. 22// The "-x" (fix) option will recalculate the payload size and checksum 23// during the patch mode operation. 24 25// The img_hdr_struct was taken from the D-Link SDK: 26// DAP-1350_A1_FW1.11NA_GPL/GPL_Source_Code/Uboot/DAP-1350/httpd/header.h 27 28#define MAX_MODEL_NAME_LEN 20 29#define MAX_SIG_LEN 30 30#define MAX_REGION_LEN 4 31#define MAX_VERSION_LEN 12 32 33struct img_hdr_struct { 34 uint32_t checksum; 35 char model[MAX_MODEL_NAME_LEN]; 36 char sig[MAX_SIG_LEN]; 37 uint8_t partition; 38 uint8_t hdr_len; 39 uint8_t rsv1; 40 uint8_t rsv2; 41 uint32_t flash_byte_cnt; 42} imghdr ; 43 44char *progname; 45 46void 47perrexit(int code, char *msg) 48{ 49 fprintf(stderr, "%s: %s: %s\n", progname, msg, strerror(errno)); 50 exit(code); 51} 52 53void 54usage() 55{ 56 fprintf(stderr, "usage: %s [-p] [-m model] [-r region] [-v version] -s signature -i input -o output\n", progname); 57 exit(1); 58} 59 60int 61main(int ac, char *av[]) 62{ 63 char model[MAX_MODEL_NAME_LEN+1]; 64 char signature[MAX_SIG_LEN+1]; 65 char region[MAX_REGION_LEN+1]; 66 char version[MAX_VERSION_LEN+1]; 67 int patchmode = 0; 68 int fixmode = 0; 69 int have_regionversion = 0; 70 71 FILE *ifile, *ofile; 72 int c; 73 uint32_t cksum; 74 uint32_t bcnt; 75 76 progname = basename(av[0]); 77 memset(model, 0, sizeof(model)); 78 memset(signature, 0, sizeof(signature)); 79 memset(region, 0, sizeof(region)); 80 memset(version, 0, sizeof(version)); 81 82 while ( 1 ) { 83 int c; 84 85 c = getopt(ac, av, "pxm:r:v:s:i:o:"); 86 if (c == -1) 87 break; 88 89 switch (c) { 90 case 'p': 91 patchmode = 1; 92 break; 93 case 'x': 94 fixmode = 1; 95 break; 96 case 'm': 97 if (strlen(optarg) > MAX_MODEL_NAME_LEN) { 98 fprintf(stderr, "%s: model name exceeds %d chars\n", 99 progname, MAX_MODEL_NAME_LEN); 100 exit(1); 101 } 102 strcpy(model, optarg); 103 break; 104 case 'r': 105 if (strlen(optarg) > MAX_REGION_LEN) { 106 fprintf(stderr, "%s: region exceeds %d chars\n", 107 progname, MAX_REGION_LEN); 108 exit(1); 109 } 110 have_regionversion = 1; 111 strcpy(region, optarg); 112 break; 113 case 'v': 114 if (strlen(optarg) > MAX_VERSION_LEN) { 115 fprintf(stderr, "%s: version exceeds %d chars\n", 116 progname, MAX_VERSION_LEN); 117 exit(1); 118 } 119 have_regionversion = 1; 120 strcpy(version, optarg); 121 break; 122 case 's': 123 if (strlen(optarg) > MAX_SIG_LEN) { 124 fprintf(stderr, "%s: signature exceeds %d chars\n", 125 progname, MAX_SIG_LEN); 126 exit(1); 127 } 128 strcpy(signature, optarg); 129 break; 130 case 'i': 131 if ((ifile = fopen(optarg, "r")) == NULL) 132 perrexit(1, optarg); 133 break; 134 case 'o': 135 if ((ofile = fopen(optarg, "w")) == NULL) 136 perrexit(1, optarg); 137 break; 138 default: 139 usage(); 140 } 141 } 142 143 if (signature[0] == 0 || ifile == NULL || ofile == NULL) { 144 usage(); 145 } 146 147 if (model[0] == 0) { 148 char *p = strchr(signature, '-'); 149 if (p == NULL) { 150 fprintf(stderr, "%s: model name unknown\n", progname); 151 exit(1); 152 } 153 if (p - signature > MAX_MODEL_NAME_LEN) { 154 *p = 0; 155 fprintf(stderr, "%s: auto model name failed, string %s too long\n", progname, signature); 156 exit(1); 157 } 158 strncpy(model, signature, p - signature); 159 } 160 161 if (patchmode) { 162 if (fread(&imghdr, sizeof(imghdr), 1, ifile) < 0) 163 perrexit(2, "fread on input"); 164 } 165 166 for (bcnt = 0, cksum = 0 ; (c = fgetc(ifile)) != EOF ; bcnt++) 167 cksum += c & 0xff; 168 169 if (fseek(ifile, patchmode ? sizeof(imghdr) : 0, SEEK_SET) < 0) 170 perrexit(2, "fseek on input"); 171 172 if (patchmode == 0) { 173 // Fill in the header 174 memset(&imghdr, 0, sizeof(imghdr)); 175 imghdr.checksum = htonl(cksum); 176 imghdr.partition = 0 ; // don't care? 177 imghdr.hdr_len = sizeof(imghdr); 178 if (have_regionversion) { 179 imghdr.hdr_len += MAX_REGION_LEN; 180 imghdr.hdr_len += MAX_VERSION_LEN; 181 } 182 imghdr.flash_byte_cnt = htonl(bcnt); 183 } else { 184 if (ntohl(imghdr.checksum) != cksum) { 185 fprintf(stderr, "%s: patch mode, checksum mismatch\n", 186 progname); 187 if (fixmode) { 188 fprintf(stderr, "%s: fixing\n", progname); 189 imghdr.checksum = htonl(cksum); 190 } else 191 exit(3); 192 } else if (ntohl(imghdr.flash_byte_cnt) != bcnt) { 193 fprintf(stderr, "%s: patch mode, size mismatch\n", 194 progname); 195 if (fixmode) { 196 fprintf(stderr, "%s: fixing\n", progname); 197 imghdr.flash_byte_cnt = htonl(bcnt); 198 } else 199 exit(3); 200 } 201 } 202 203 strncpy(imghdr.model, model, MAX_MODEL_NAME_LEN); 204 strncpy(imghdr.sig, signature, MAX_SIG_LEN); 205 206 if (fwrite(&imghdr, sizeof(imghdr), 1, ofile) < 0) 207 perrexit(2, "fwrite header on output"); 208 if (have_regionversion) { 209 if (fwrite(®ion, MAX_REGION_LEN, 1, ofile) < 0) 210 perrexit(2, "fwrite header on output"); 211 if (fwrite(&version, MAX_VERSION_LEN, 1, ofile) < 0) 212 perrexit(2, "fwrite header on output"); 213 } 214 215 while ((c = fgetc(ifile)) != EOF) { 216 if (fputc(c, ofile) == EOF) 217 perrexit(2, "fputc on output"); 218 } 219 220 if (ferror(ifile)) 221 perrexit(2, "fgetc on input"); 222 223 224 fclose(ofile); 225 fclose(ifile); 226} 227