1 // SPDX-License-Identifier: GPL-2.0-only 2 3 #include <stdio.h> 4 #include <string.h> 5 #include <stdlib.h> 6 #include <stdint.h> 7 #include <sys/types.h> 8 #include <unistd.h> 9 #include <byteswap.h> 10 #include <endian.h> 11 #include <getopt.h> 12 13 14 #if !defined(__BYTE_ORDER) 15 #error "Unknown byte order" 16 #endif 17 18 #if __BYTE_ORDER == __BIG_ENDIAN 19 #define cpu_to_be16(x) (x) 20 #define cpu_to_be32(x) (x) 21 #elif __BYTE_ORDER == __LITTLE_ENDIAN 22 #define cpu_to_be16(x) bswap_16(x) 23 #define cpu_to_be32(x) bswap_32(x) 24 #else 25 #error "Unsupported endianness" 26 #endif 27 28 29 #define IMAGE_VERSION 1 30 #define FILE_VERSION 1 31 #define FILE_DESCRIPTION "OpenWrt" 32 #define FILE_TYPE_MASK 0x1 33 34 35 #define PACKAGE_FLAG 2 36 37 #define FILE_TYPE_APPLICATION 0x04000000 38 39 #define VERSION_OFFSET_INVALID 0xffffffff 40 41 #define COMPRESSION_TYPE_NONE 0xffffffff 42 #define COMPRESSION_TYPE_7Z 0x00000002 43 44 45 struct file_header { 46 uint8_t res1[4]; 47 48 uint32_t header_crc; 49 50 uint32_t file_type; 51 uint32_t version; 52 uint32_t product_id; 53 uint32_t device_id; 54 55 uint32_t length_unpadded; 56 57 uint32_t version_offset; 58 59 uint16_t year; 60 uint8_t month; 61 uint8_t day; 62 uint8_t res2[1]; 63 uint8_t hour; 64 uint8_t minute; 65 uint8_t second; 66 67 uint8_t res3[64]; 68 69 char description[224]; 70 71 uint32_t length; 72 73 uint32_t file_crc; 74 75 uint32_t compression_type; 76 } __attribute__ ((packed)); 77 78 struct file_desc { 79 uint32_t file_type; 80 uint32_t offset; 81 uint32_t length; 82 uint32_t file_crc; 83 uint32_t version; 84 uint32_t type_mask; 85 } __attribute__ ((packed)); 86 87 struct image_header { 88 uint32_t version; 89 90 uint32_t file_count; 91 92 uint32_t product_id; 93 uint32_t device_id; 94 95 uint16_t year; 96 uint8_t month; 97 uint8_t day; 98 uint8_t res1[1]; 99 uint8_t hour; 100 uint8_t minute; 101 uint8_t second; 102 103 uint16_t package_crc; 104 uint16_t package_flag; 105 106 uint32_t length; 107 108 struct file_desc files[128]; 109 110 /* RSA signature, not required */ 111 uint8_t res2[3072]; 112 113 uint32_t header_crc; 114 } __attribute__ ((packed)); 115 116 117 static void *buf; 118 static size_t buflen; 119 120 static size_t length_unpadded; 121 static size_t length; 122 123 124 static uint32_t crc16_xmodem(char *buf, size_t len) { 125 uint32_t poly = 0x1021; 126 uint32_t crc = 0; 127 char b; 128 int i, j; 129 130 for (i = 0; i < len; i++) { 131 b = buf[i]; 132 crc = crc ^ (b << 8); 133 134 for (j = 0; j < 8; j++) { 135 crc = crc << 1; 136 if (crc & 0x10000) { 137 crc = (crc ^ poly) & 0xffff; 138 } 139 } 140 } 141 142 return crc; 143 } 144 145 static int create_buffer_and_read_file(char *filename) { 146 FILE *f; 147 148 f = fopen(filename, "r"); 149 if (f == NULL) { 150 fprintf(stderr, "failed to open input file\n"); 151 goto err; 152 } 153 154 fseek(f, 0L, SEEK_END); 155 length_unpadded = ftell(f); 156 rewind(f); 157 158 length = length_unpadded; 159 if (length_unpadded % 8 != 0) { 160 length += 8 - length_unpadded % 8; 161 } 162 163 buflen = sizeof(struct file_header) + sizeof(struct image_header) + length; 164 buf = malloc(buflen); 165 if (!buf) { 166 fprintf(stderr, "failed to allocate buffer\n"); 167 goto err_close; 168 } 169 170 memset(buf, 0, buflen); 171 172 if (fread(buf + sizeof(struct file_header) + sizeof(struct image_header), length_unpadded, 1, f) != 1) { 173 fprintf(stderr, "failed to read input file\n"); 174 goto err_free; 175 } 176 177 fclose(f); 178 return 0; 179 180 err_free: 181 free(buf); 182 err_close: 183 fclose(f); 184 err: 185 return -1; 186 } 187 188 static void build_file_header(uint32_t product_id, uint32_t device_id, uint32_t compression_type) { 189 struct file_header *header = buf + sizeof(struct image_header); 190 uint32_t crc; 191 192 header->file_type = cpu_to_be32(FILE_TYPE_APPLICATION); 193 194 header->version = cpu_to_be32(FILE_VERSION); 195 196 header->product_id = cpu_to_be32(product_id); 197 header->device_id = cpu_to_be32(device_id); 198 199 header->length_unpadded = cpu_to_be32(length_unpadded); 200 201 header->version_offset = cpu_to_be32(VERSION_OFFSET_INVALID); 202 203 header->year = cpu_to_be16(1970); 204 header->month = 1; 205 header->day = 1; 206 header->hour = 0; 207 header->minute = 0; 208 header->second = 0; 209 210 snprintf(header->description, sizeof(header->description), "%s", FILE_DESCRIPTION); 211 212 header->length = cpu_to_be32(length); 213 214 crc = crc16_xmodem(buf + sizeof(struct image_header) + sizeof(struct file_header), length); 215 header->file_crc = cpu_to_be32(crc); 216 217 header->compression_type = cpu_to_be32(compression_type); 218 219 crc = crc16_xmodem((char *)header + sizeof(header->res1) + sizeof(header->header_crc), 220 sizeof(struct file_header) - sizeof(header->res1) - sizeof(header->header_crc)); 221 header->header_crc = cpu_to_be32(crc); 222 } 223 224 static void build_image_header(uint32_t product_id, uint32_t device_id) { 225 struct image_header *header = buf; 226 struct file_header *file_header = buf + sizeof(struct image_header); 227 uint32_t crc; 228 229 header->version = cpu_to_be32(IMAGE_VERSION); 230 231 header->file_count = cpu_to_be32(1); 232 233 header->product_id = cpu_to_be32(product_id); 234 header->device_id = cpu_to_be32(device_id); 235 236 header->year = cpu_to_be16(1970); 237 header->month = 1; 238 header->day = 1; 239 header->hour = 0; 240 header->minute = 0; 241 header->second = 0; 242 243 crc = crc16_xmodem(buf + sizeof(struct file_header), buflen - sizeof(struct file_header)); 244 header->package_crc = cpu_to_be16(crc); 245 header->package_flag = cpu_to_be16(PACKAGE_FLAG); 246 247 header->length = cpu_to_be32(buflen - sizeof(struct image_header)); 248 249 header->files[0].file_type = file_header->file_type; 250 header->files[0].offset = cpu_to_be32(sizeof(struct image_header)); 251 header->files[0].length = cpu_to_be32(sizeof(struct file_header) + length); 252 header->files[0].file_crc = file_header->file_crc; 253 header->files[0].version = file_header->version; 254 header->files[0].type_mask = cpu_to_be32(FILE_TYPE_MASK); 255 256 crc = crc16_xmodem((char *)header, sizeof(struct image_header) - sizeof(header->header_crc)); 257 header->header_crc = cpu_to_be32(crc); 258 } 259 260 static int write_output_file(char *filename) { 261 int ret = 0; 262 FILE *f; 263 264 f = fopen(filename, "w"); 265 if (f == NULL) { 266 fprintf(stderr, "failed to open output file\n"); 267 ret = -1; 268 goto err; 269 } 270 271 if (fwrite(buf, buflen, 1, f) != 1) { 272 fprintf(stderr, "failed to write output file\n"); 273 ret = -1; 274 } 275 276 fclose(f); 277 278 err: 279 return ret; 280 } 281 282 static void usage(char* argv[]) { 283 printf("Usage: %s [OPTIONS...]\n" 284 "\n" 285 "Options:\n" 286 " -p <product id> product id (32-bit unsigned integer)\n" 287 " -d <device id> device id (32-bit unsigned integer)\n" 288 " -c <compression> compression type of the input file (7z or none)\n" 289 " (in case of 7z only LZMA compression is allowed)\n" 290 " -i <file> input filename\n" 291 " -o <file> output filename\n" 292 , argv[0]); 293 } 294 295 int main(int argc, char* argv[]) { 296 int ret = EXIT_FAILURE; 297 298 static uint32_t product_id = 0; 299 static uint32_t device_id = 0; 300 static uint32_t compression_type = COMPRESSION_TYPE_NONE; 301 static char *input_filename = NULL; 302 static char *output_filename = NULL; 303 304 while ( 1 ) { 305 int c; 306 307 c = getopt(argc, argv, "p:d:c:i:o:"); 308 if (c == -1) 309 break; 310 311 switch (c) { 312 case 'p': 313 product_id = strtoul(optarg, NULL, 0); 314 break; 315 case 'd': 316 device_id = strtoul(optarg, NULL, 0); 317 break; 318 case 'c': 319 if (strcmp(optarg, "none") == 0) { 320 compression_type = COMPRESSION_TYPE_NONE; 321 } else if (strcmp(optarg, "7z") == 0) { 322 compression_type = COMPRESSION_TYPE_7Z; 323 } else { 324 usage(argv); 325 return EXIT_FAILURE; 326 } 327 break; 328 case 'i': 329 input_filename = optarg; 330 break; 331 case 'o': 332 output_filename = optarg; 333 break; 334 default: 335 usage(argv); 336 goto err; 337 } 338 } 339 340 if (!product_id || !device_id || 341 !input_filename || strlen(input_filename) == 0 || 342 !output_filename || strlen(output_filename) == 0) { 343 344 usage(argv); 345 goto err; 346 } 347 348 if (create_buffer_and_read_file(input_filename)) { 349 goto err; 350 } 351 352 build_file_header(product_id, device_id, compression_type); 353 354 build_image_header(product_id, device_id); 355 356 if (write_output_file(output_filename)) { 357 goto err_free; 358 } 359 360 ret = EXIT_SUCCESS; 361 362 err_free: 363 free(buf); 364 err: 365 return ret; 366 } 367
This page was automatically generated by LXR 0.3.1. • OpenWrt