tplink-safeloader: support Archer C6v3.0 (BR)
[project/firmware-utils.git] / src / spw303v.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * spw303v.c - partially based on OpenWrt's imagetag.c and addpattern.c
4 *
5 * Copyright (C) 2011 Jonas Gorski <jonas.gorski@gmail.com>
6 */
7
8 #include <arpa/inet.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <stdint.h>
13 #include <unistd.h>
14 #include <sys/stat.h>
15
16 #define IMAGE_LEN 10 /* Length of Length Field */
17 #define ADDRESS_LEN 12 /* Length of Address field */
18 #define TAGID_LEN 6 /* Length of tag ID */
19 #define TAGINFO_LEN 20 /* Length of vendor information field in tag */
20 #define TAGVER_LEN 4 /* Length of Tag Version */
21 #define TAGLAYOUT_LEN 4 /* Length of FlashLayoutVer */
22
23
24 struct spw303v_tag
25 {
26 unsigned char tagVersion[4]; // tag version. Will be 2 here.
27 unsigned char signiture_1[20]; // text line for company info
28 unsigned char signiture_2[14]; // additional info (can be version number)
29 unsigned char chipId[6]; // chip id
30 unsigned char boardId[16]; // board id
31 unsigned char bigEndian[2]; // if = 1 - big, = 0 - little endia of the host
32 unsigned char totalImageLen[IMAGE_LEN]; // the sum of all the following length
33 unsigned char cfeAddress[ADDRESS_LEN]; // if non zero, cfe starting address
34 unsigned char cfeLen[IMAGE_LEN]; // if non zero, cfe size in clear ASCII text.
35 unsigned char rootfsAddress[ADDRESS_LEN]; // if non zero, filesystem starting address
36 unsigned char rootfsLen[IMAGE_LEN]; // if non zero, filesystem size in clear ASCII text.
37 unsigned char kernelAddress[ADDRESS_LEN]; // if non zero, kernel starting address
38 unsigned char kernelLen[IMAGE_LEN]; // if non zero, kernel size in clear ASCII text.
39
40 unsigned char certf1Address[ADDRESS_LEN];
41 unsigned char certf1Len[6];
42 unsigned char certf2Address[ADDRESS_LEN];
43 unsigned char certf2Len[6];
44 unsigned char certf3Address[ADDRESS_LEN];
45 unsigned char certf3Len[6];
46 unsigned char httpsFileSize[4];
47 unsigned char tr64FileSize[4];
48 unsigned char tr69FileSize[4];
49 unsigned char filesmap[4];
50
51 unsigned char imageSequence[4]; // incrments everytime an image is flashed
52 unsigned char reserved[4]; // reserved for later use
53 unsigned char imageCRC[4]; // 216-219: CRC32 of images
54 unsigned char reserved2[16]; // 220-235: Unused at present
55 unsigned char headerCRC[4]; // 236-239: CRC32 of header excluding tagVersion
56 unsigned char reserved3[16]; // 240-255: Unused at present
57 };
58
59 static uint32_t crc32tab[256] = {
60 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
61 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
62 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
63 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
64 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
65 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
66 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
67 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
68 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
69 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
70 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
71 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
72 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
73 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
74 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
75 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
76 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
77 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
78 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
79 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
80 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
81 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
82 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
83 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
84 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
85 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
86 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
87 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
88 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
89 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
90 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
91 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
92 };
93 #define IMAGETAG_CRC_START 0xFFFFFFFF
94
95 #define IMAGETAG_MAGIC1_TCOM "AAAAAAAA Corporatio"
96
97 static char fake_data[] = {
98 0x18, 0x21, 0x21, 0x18, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21 ,0x18,
99 0x21, 0x24, 0x21, 0x1b, 0x18, 0x18, 0x24, 0x24, 0x18, 0x21, 0x21, 0x21,
100 0x21, 0x21, 0x21, 0x21, 0x1b, 0x18, 0x18, 0x24, 0x24, 0x21, 0x21, 0x21,
101 0x21, 0x21, 0x21, 0x21, 0x18, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x18,
102 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x18, 0x21, 0x21,
103 0x21, 0x21, 0x21, 0x21,
104 };
105
106
107 uint32_t crc32(uint32_t crc, const void *data, size_t len)
108 {
109 const uint8_t *in = data;
110
111 while (len--)
112 crc = (crc >> 8) ^ crc32tab[(crc ^ *in++) & 0xFF];
113
114 return crc;
115 }
116
117 void fix_header(void *buf)
118 {
119 struct spw303v_tag *tag = buf;
120 uint32_t crc;
121 /* Replace signature with custom t-com one */
122 memset(tag->signiture_1, 0, 20);
123 memcpy(tag->signiture_1, IMAGETAG_MAGIC1_TCOM, strlen(IMAGETAG_MAGIC1_TCOM));
124
125 /* Clear cert fields to remove information_* data */
126 memset(tag->certf1Address, 0, 74);
127
128 /* replace image crc with modified one */
129 crc = ntohl(*((uint32_t *)&tag->imageCRC));
130
131 crc = htonl(crc32(crc, fake_data, 64));
132
133 memcpy(tag->imageCRC, &crc, 4);
134
135 /* Update tag crc */
136 crc = htonl(crc32(IMAGETAG_CRC_START, buf, 236));
137 memcpy(tag->headerCRC, &crc, 4);
138 }
139
140
141
142 void usage(void) __attribute__ (( __noreturn__ ));
143
144 void usage(void)
145 {
146 fprintf(stderr, "Usage: spw303v [-i <inputfile>] [-o <outputfile>]\n");
147 exit(EXIT_FAILURE);
148 }
149
150
151 int main(int argc, char **argv)
152 {
153 char buf[1024]; /* keep this at 1k or adjust garbage calc below */
154 FILE *in = stdin;
155 FILE *out = stdout;
156 char *ifn = NULL;
157 char *ofn = NULL;
158 int c;
159 size_t n;
160 int first_block = 1;
161
162 uint32_t image_crc = IMAGETAG_CRC_START;
163
164 while ((c = getopt(argc, argv, "i:o:h")) != -1) {
165 switch (c) {
166 case 'i':
167 ifn = optarg;
168 break;
169 case 'o':
170 ofn = optarg;
171 break;
172 case 'h':
173 default:
174 usage();
175 }
176 }
177
178 if (optind != argc || optind == 1) {
179 fprintf(stderr, "illegal arg \"%s\"\n", argv[optind]);
180 usage();
181 }
182
183 if (ifn && !(in = fopen(ifn, "r"))) {
184 fprintf(stderr, "can not open \"%s\" for reading\n", ifn);
185 usage();
186 }
187
188 if (ofn && !(out = fopen(ofn, "w"))) {
189 fprintf(stderr, "can not open \"%s\" for writing\n", ofn);
190 usage();
191 }
192
193
194
195 while ((n = fread(buf, 1, sizeof(buf), in)) > 0) {
196 if (n < sizeof(buf)) {
197 if (ferror(in)) {
198 FREAD_ERROR:
199 fprintf(stderr, "fread error\n");
200 return EXIT_FAILURE;
201 }
202 }
203
204 if (first_block && n >= 256) {
205 fix_header(buf);
206 first_block = 0;
207 }
208
209 image_crc = crc32(image_crc, buf, n);
210
211 if (!fwrite(buf, n, 1, out)) {
212 FWRITE_ERROR:
213 fprintf(stderr, "fwrite error\n");
214 return EXIT_FAILURE;
215 }
216 }
217
218 if (ferror(in)) {
219 goto FREAD_ERROR;
220 }
221
222 if (fflush(out)) {
223 goto FWRITE_ERROR;
224 }
225
226 fclose(in);
227 fclose(out);
228
229 return EXIT_SUCCESS;
230 }