• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/firmware-utils/src/mkchkimg.c

  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