firmware-utils: support checksum for AVM fritzbox wasp SOCs
[project/firmware-utils.git] / src / avm-wasp-checksum.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (C) 2020 Andreas Boehler <dev@aboehler.at>
4 *
5 * This tool was based on:
6 * firmware-crc.pl by Atheros Communications
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License version 2 as published
10 * by the Free Software Foundation.
11 *
12 */
13
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <stdint.h>
17 #include <string.h>
18 #include <getopt.h> /* for getopt() */
19 #include <byteswap.h>
20
21 char *infile;
22 char *outfile;
23 char *progname;
24 enum {
25 MODEL_3390,
26 MODEL_X490
27 } model;
28
29 #define CHUNK_SIZE 256
30
31 uint32_t crc32_for_byte(uint32_t r)
32 {
33 for (int j = 0; j < 8; ++j)
34 r = (r & 1 ? 0 : (uint32_t)0xEDB88320L) ^ r >> 1;
35 return r ^ (uint32_t)0xFF000000L;
36 }
37
38 void crc32(const void *data, size_t n_bytes, uint32_t *crc)
39 {
40 static uint32_t table[0x100];
41
42 if (!*table)
43 for (size_t i = 0; i < 0x100; ++i)
44 table[i] = crc32_for_byte(i);
45 for (size_t i = 0; i < n_bytes; ++i)
46 *crc = table[(uint8_t)*crc ^ ((uint8_t *)data)[i]] ^ *crc >> 8;
47 }
48
49 static void usage(int status)
50 {
51 fprintf(stderr, "Usage: %s [OPTIONS...]\n", progname);
52 fprintf(stderr,
53 "\n"
54 "Options:\n"
55 " -i input file name\n"
56 " -o output file name\n"
57 " -m model (3390, x490 for 3490/5490/7490)\n"
58 " -h show this screen\n"
59 );
60
61 exit(status);
62 }
63
64 int main(int argc, char *argv[])
65 {
66 uint32_t crc = 0;
67 FILE *in_fp;
68 FILE *out_fp;
69 uint32_t buf[CHUNK_SIZE];
70 size_t read;
71
72 progname = argv[0];
73
74 while (1) {
75 int c;
76
77 c = getopt(argc, argv, "i:o:m:h");
78 if (c == -1)
79 break;
80
81 switch (c) {
82 case 'i':
83 infile = optarg;
84 break;
85 case 'o':
86 outfile = optarg;
87 break;
88 case 'm':
89 if (strcmp(optarg, "3390") == 0)
90 model = MODEL_3390;
91 else if (strcmp(optarg, "x490") == 0)
92 model = MODEL_X490;
93 else
94 usage(EXIT_FAILURE);
95 break;
96 case 'h':
97 usage(EXIT_SUCCESS);
98 default:
99 usage(EXIT_FAILURE);
100 break;
101 }
102 }
103
104 if (!infile || !outfile)
105 usage(EXIT_FAILURE);
106
107 in_fp = fopen(infile, "r");
108 if (!in_fp) {
109 fprintf(stderr, "Error opening input file: %s\n", infile);
110 return EXIT_FAILURE;
111 }
112 out_fp = fopen(outfile, "w");
113 if (!out_fp) {
114 fprintf(stderr, "Error opening output file: %s\n", outfile);
115 fclose(in_fp);
116 return EXIT_FAILURE;
117 }
118
119 while (!feof(in_fp)) {
120 switch (model) {
121 case MODEL_3390:
122 read = fread(buf, sizeof(uint32_t), CHUNK_SIZE, in_fp);
123 if (ferror(in_fp)) {
124 fprintf(stderr, "Error reading input file: %s\n", infile);
125 fclose(in_fp);
126 fclose(out_fp);
127 return EXIT_FAILURE;
128 }
129 for (int i = 0; i < read; i++)
130 crc = crc ^ buf[i];
131 fwrite(buf, sizeof(uint32_t), read, out_fp);
132 if (ferror(out_fp)) {
133 fprintf(stderr, "Error writing output file: %s\n", outfile);
134 fclose(in_fp);
135 fclose(out_fp);
136 return EXIT_FAILURE;
137 }
138 break;
139 case MODEL_X490:
140 read = fread(buf, 1, sizeof(uint32_t) * CHUNK_SIZE, in_fp);
141 if (ferror(in_fp)) {
142 fprintf(stderr, "Error reading input file: %s\n", infile);
143 fclose(in_fp);
144 fclose(out_fp);
145 return EXIT_FAILURE;
146 }
147 crc32(buf, read, &crc);
148 fwrite(buf, 1, read, out_fp);
149 if (ferror(out_fp)) {
150 fprintf(stderr, "Error writing output file: %s\n", outfile);
151 fclose(in_fp);
152 fclose(out_fp);
153 return EXIT_FAILURE;
154 }
155 break;
156 }
157 }
158 if (model == MODEL_X490)
159 crc = __bswap_32(crc);
160 fwrite(&crc, sizeof(uint32_t), 1, out_fp);
161 if (ferror(out_fp)) {
162 fprintf(stderr, "Error writing checksum to output file: %s\n", outfile);
163 fclose(in_fp);
164 fclose(out_fp);
165 return EXIT_FAILURE;
166 }
167 fclose(in_fp);
168 fclose(out_fp);
169 printf("Done.\n");
170 return EXIT_SUCCESS;
171 }