1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Make CHK Image 4 * 5 * This utility creates Netgear .chk files. 6 * 7 * Copyright (C) 2008 Dave C. Reeve <Dave.Reeve@dreeve.org> 8 */ 9 #include <stdio.h> 10 #include <stdlib.h> 11 #include <string.h> 12 #include <stdarg.h> 13 #include <errno.h> 14 #include <arpa/inet.h> 15 #include <unistd.h> 16 17 #define BUF_LEN (2048) 18 19 #define MAX_BOARD_ID_LEN (64) 20 21 /* 22 * Note on the reserved field of the chk_header: 23 * OFW naming scheme is typically: DEVICENAME-VA.B.C.D_E.F.G.chk, with A-G 24 * between 0 and 255. For instance: EX3700_EX3800-V1.0.0.58_1.0.38.chk 25 * The reserved field works like this: 26 * reserved[0]: region code. 1 for WW (WorldWide) and 2 for NA (North America) 27 * reserved[1]: A 28 * reserved[2]: B 29 * reserved[3]: C 30 * reserved[4]: D 31 * reserved[5]: E 32 * reserved[6]: F 33 * reserved[7]: G 34 */ 35 struct chk_header { 36 uint32_t magic; 37 uint32_t header_len; 38 uint8_t reserved[8]; 39 uint32_t kernel_chksum; 40 uint32_t rootfs_chksum; 41 uint32_t kernel_len; 42 uint32_t rootfs_len; 43 uint32_t image_chksum; 44 uint32_t header_chksum; 45 /* char board_id[] - upto MAX_BOARD_ID_LEN */ 46 }; 47 48 static void __attribute__ ((format (printf, 2, 3))) 49 fatal_error (int maybe_errno, const char * format, ...) 50 { 51 va_list ap; 52 53 fprintf (stderr, "mkchkimg: "); 54 va_start (ap, format); 55 vfprintf (stderr, format, ap); 56 va_end (ap); 57 58 if (maybe_errno) { 59 fprintf (stderr, ": %s\n", strerror (maybe_errno)); 60 } else { 61 fprintf (stderr, "\n"); 62 } 63 64 exit (EXIT_FAILURE); 65 } 66 67 static void __attribute__ ((format (printf, 1, 2))) 68 message (const char * format, ...) 69 { 70 va_list ap; 71 72 fprintf (stderr, "mkchkimg: "); 73 va_start (ap, format); 74 vfprintf (stderr, format, ap); 75 va_end (ap); 76 fprintf (stderr, "\n"); 77 } 78 79 struct ngr_checksum { 80 uint32_t c0; 81 uint32_t c1; 82 }; 83 84 static inline void 85 netgear_checksum_init (struct ngr_checksum * c) 86 { 87 c->c0 = c->c1 = 0; 88 } 89 90 static inline void 91 netgear_checksum_add (struct ngr_checksum * c, unsigned char * buf, size_t len) 92 { 93 size_t i; 94 95 for (i=0; i<len; i++) { 96 c->c0 += buf[i] & 0xff; 97 c->c1 += c->c0; 98 } 99 } 100 101 static inline unsigned long 102 netgear_checksum_fini (struct ngr_checksum * c) 103 { 104 uint32_t b, checksum; 105 106 b = (c->c0 & 65535) + ((c->c0 >> 16) & 65535); 107 c->c0 = ((b >> 16) + b) & 65535; 108 b = (c->c1 & 65535) + ((c->c1 >> 16) & 65535); 109 c->c1 = ((b >> 16) + b) & 65535; 110 checksum = ((c->c1 << 16) | c->c0); 111 return checksum; 112 } 113 114 static void 115 print_help (void) 116 { 117 fprintf (stderr, "Usage: mkchkimg -o output -k kernel [-f filesys] [-b board_id] [-r region]\n"); 118 } 119 120 int 121 main (int argc, char * argv[]) 122 { 123 int opt; 124 char * ptr; 125 size_t len; 126 size_t header_len; 127 struct chk_header * hdr; 128 struct ngr_checksum chk_part, chk_whole; 129 char buf[BUF_LEN]; 130 char * output_file, * kern_file, * fs_file; 131 FILE * out_fp, * kern_fp, * fs_fp; 132 char * board_id; 133 unsigned long region; 134 135 /* Default values */ 136 board_id = "U12H072T00_NETGEAR"; 137 region = 1; /* 1=WW, 2=NA */ 138 output_file = NULL; 139 kern_file = NULL; 140 fs_file = NULL; 141 fs_fp = NULL; 142 143 while ((opt = getopt (argc, argv, ":b:r:k:f:o:h")) != -1) { 144 switch (opt) { 145 case 'b': 146 /* Board Identity */ 147 if (strlen (optarg) > MAX_BOARD_ID_LEN) { 148 fatal_error (0, "Board lenght exceeds %d", 149 MAX_BOARD_ID_LEN); 150 } 151 board_id = optarg; 152 break; 153 154 case 'r': 155 /* Region */ 156 errno = 0; 157 region = strtoul (optarg, &ptr, 0); 158 if (errno || ptr==optarg || *ptr!='\0') { 159 fatal_error (0, "Cannot parse region %s", optarg); 160 } 161 if (region > 0xff) { 162 fatal_error (0, "Region cannot exceed 0xff"); 163 } 164 break; 165 166 case 'k': 167 /* Kernel */ 168 kern_file = optarg; 169 break; 170 171 case 'f': 172 /* Filing System */ 173 fs_file = optarg; 174 break; 175 176 case 'o': 177 /* Output file */ 178 output_file = optarg; 179 break; 180 181 case 'h': 182 print_help (); 183 return EXIT_SUCCESS; 184 185 case ':': 186 print_help (); 187 fatal_error (0, "Option -%c missing argument", optopt); 188 break; 189 190 case '?': 191 print_help (); 192 fatal_error (0, "Unknown argument -%c", optopt); 193 break; 194 195 default: 196 break; 197 } 198 } 199 200 /* Check we have all the options expected */ 201 if (!kern_file) { 202 print_help (); 203 fatal_error (0, "Kernel file expected"); 204 } 205 if (!output_file) { 206 print_help (); 207 fatal_error (0, "Output file required"); 208 } 209 message ("Netgear CHK writer - v0.1"); 210 211 /* Open the input file */ 212 kern_fp = fopen (kern_file, "r"); 213 if (!kern_fp) { 214 fatal_error (errno, "Cannot open %s", kern_file); 215 } 216 217 /* Open the fs file, if specified */ 218 if (fs_file) { 219 fs_fp = fopen (fs_file, "r"); 220 if (!fs_fp) { 221 fclose(kern_fp); 222 fatal_error (errno, "Cannot open %s", fs_file); 223 } 224 } 225 226 /* Open the output file */ 227 out_fp = fopen (output_file, "w+"); 228 if (!out_fp) { 229 fclose(kern_fp); 230 if (fs_fp) { 231 fclose(fs_fp); 232 } 233 fatal_error (errno, "Cannot open %s", output_file); 234 } 235 236 /* Write zeros when the chk header will be */ 237 buf[0] = '\0'; 238 header_len = sizeof (struct chk_header) + strlen (board_id); 239 if (fwrite (buf, 1, header_len, out_fp) != header_len) { 240 fatal_error (errno, "Cannot write header"); 241 } 242 243 /* Allocate storage for header, we fill in as we go */ 244 hdr = malloc (sizeof (struct chk_header)); 245 if (!hdr) { 246 fatal_error (0, "malloc failed"); 247 } 248 bzero (hdr, sizeof (struct chk_header)); 249 250 /* Fill in known values */ 251 hdr->magic = htonl (0x2a23245e); 252 hdr->header_len = htonl(header_len); 253 hdr->reserved[0] = (unsigned char)(region & 0xff); 254 memset(&hdr->reserved[1], 99, sizeof(hdr->reserved) - 1); 255 256 message (" Board Id: %s", board_id); 257 message (" Region: %s", region == 1 ? "World Wide (WW)" 258 : (region == 2 ? "North America (NA)" : "Unknown")); 259 260 /* Copy the trx file, calculating the checksum as we go */ 261 netgear_checksum_init (&chk_part); 262 netgear_checksum_init (&chk_whole); 263 while (!feof (kern_fp)) { 264 len = fread (buf, 1, BUF_LEN, kern_fp); 265 if (len < 1) { 266 break; 267 } 268 if (fwrite (buf, len, 1, out_fp) != 1) { 269 fatal_error (errno, "Write error"); 270 } 271 hdr->kernel_len += len; 272 netgear_checksum_add (&chk_part, (unsigned char *)buf, len); 273 netgear_checksum_add (&chk_whole, (unsigned char *)buf, len); 274 } 275 fclose(kern_fp); 276 hdr->kernel_chksum = netgear_checksum_fini (&chk_part); 277 message (" Kernel Len: %u", hdr->kernel_len); 278 message ("Kernel Checksum: 0x%08x", hdr->kernel_chksum); 279 hdr->kernel_len = htonl (hdr->kernel_len); 280 hdr->kernel_chksum = htonl (hdr->kernel_chksum); 281 282 /* Now copy the root fs, calculating the checksum as we go */ 283 if (fs_fp) { 284 netgear_checksum_init (&chk_part); 285 while (!feof (fs_fp)) { 286 len = fread (buf, 1, BUF_LEN, fs_fp); 287 if (len < 1) { 288 break; 289 } 290 if (fwrite (buf, len, 1, out_fp) != 1) { 291 fatal_error (errno, "Write error"); 292 } 293 hdr->rootfs_len += len; 294 netgear_checksum_add (&chk_part, (unsigned char *)buf, len); 295 netgear_checksum_add (&chk_whole, (unsigned char *)buf, len); 296 } 297 fclose(fs_fp); 298 hdr->rootfs_chksum = (netgear_checksum_fini (&chk_part)); 299 message (" Rootfs Len: %u", hdr->rootfs_len); 300 message ("Rootfs Checksum: 0x%08x", hdr->rootfs_chksum); 301 hdr->rootfs_len = htonl (hdr->rootfs_len); 302 hdr->rootfs_chksum = htonl (hdr->rootfs_chksum); 303 } 304 305 /* Calcautate the image checksum */ 306 hdr->image_chksum = netgear_checksum_fini (&chk_whole); 307 message (" Image Checksum: 0x%08x", hdr->image_chksum); 308 hdr->image_chksum = htonl (hdr->image_chksum); 309 310 /* Calculate the header checksum */ 311 netgear_checksum_init (&chk_part); 312 netgear_checksum_add (&chk_part, (unsigned char *)hdr, 313 sizeof (struct chk_header)); 314 netgear_checksum_add (&chk_part, (unsigned char *)board_id, 315 strlen (board_id)); 316 hdr->header_chksum = htonl (netgear_checksum_fini (&chk_part)); 317 318 /* Finally rewind the output and write headers */ 319 rewind (out_fp); 320 if (fwrite (hdr, sizeof (struct chk_header), 1, out_fp) != 1) { 321 fatal_error (errno, "Cannot write header"); 322 } 323 if (fwrite (board_id, strlen (board_id), 1, out_fp) != 1) { 324 fatal_error (errno, "Cannot write board id"); 325 } 326 327 /* Success */ 328 fclose(out_fp); 329 return EXIT_SUCCESS; 330 } 331 332
This page was automatically generated by LXR 0.3.1. • OpenWrt