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