1/*
2 * zyxbcm.c - based on Jonas Gorski's spw303v.c
3 *
4 * Copyright (C) 2014 ��lvaro Fern��ndez Rojas <noltari@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 <arpa/inet.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <stdint.h>
26#include <time.h>
27#include <unistd.h>
28#include <sys/stat.h>
29
30#define TAGVER_LEN 4			/* Length of Tag Version */
31#define SIG1_LEN 20			/* Company Signature 1 Length */
32#define SIG2_LEN 14			/* Company Signature 2 Lenght */
33#define BOARDID_LEN 16			/* Length of BoardId */
34#define ENDIANFLAG_LEN 2		/* Endian Flag Length */
35#define CHIPID_LEN 6			/* Chip Id Length */
36#define IMAGE_LEN 10			/* Length of Length Field */
37#define ADDRESS_LEN 12			/* Length of Address field */
38#define DUALFLAG_LEN 2			/* Dual Image flag Length */
39#define INACTIVEFLAG_LEN 2		/* Inactie Flag Length */
40#define RSASIG_LEN 20			/* Length of RSA Signature in tag */
41#define TAGINFO1_LEN 30			/* Length of vendor information field1 in tag */
42#define ZYX_TAGINFO1_LEN 20		/* Length of vendor information field1 in tag */
43#define FLASHLAYOUTVER_LEN 4		/* Length of Flash Layout Version String tag */
44#define TAGINFO2_LEN 16			/* Length of vendor information field2 in tag */
45#define CRC_LEN 4			/* Length of CRC in bytes */
46
47#define IMAGETAG_CRC_START 0xFFFFFFFF
48
49struct bcm_tag {
50	char tagVersion[TAGVER_LEN];			// 0-3: Version of the image tag
51	char sig_1[SIG1_LEN];				// 4-23: Company Line 1
52	char sig_2[SIG2_LEN];				// 24-37: Company Line 2
53	char chipid[CHIPID_LEN];			// 38-43: Chip this image is for
54	char boardid[BOARDID_LEN];			// 44-59: Board name
55	char big_endian[ENDIANFLAG_LEN];		// 60-61: Map endianness -- 1 BE 0 LE
56	char totalLength[IMAGE_LEN];			// 62-71: Total length of image
57	char cfeAddress[ADDRESS_LEN];			// 72-83: Address in memory of CFE
58	char cfeLength[IMAGE_LEN];			// 84-93: Size of CFE
59	char flashImageStart[ADDRESS_LEN];		// 94-105: Address in memory of image start (kernel for OpenWRT, rootfs for stock firmware)
60	char flashRootLength[IMAGE_LEN];		// 106-115: Size of rootfs for flashing
61	char kernelAddress[ADDRESS_LEN];		// 116-127: Address in memory of kernel
62	char kernelLength[IMAGE_LEN];			// 128-137: Size of kernel
63	char dualImage[DUALFLAG_LEN];			// 138-139: Unused at present
64	char inactiveFlag[INACTIVEFLAG_LEN];		// 140-141: Unused at present
65	char rsa_signature[RSASIG_LEN];			// 142-161: RSA Signature (unused at present; some vendors may use this)
66	char information1[TAGINFO1_LEN];		// 162-191: Compilation and related information (not generated/used by OpenWRT)
67	char flashLayoutVer[FLASHLAYOUTVER_LEN];	// 192-195: Version flash layout
68	char fskernelCRC[CRC_LEN];			// 196-199: kernel+rootfs CRC32
69	char information2[TAGINFO2_LEN];		// 200-215: Unused at present except Alice Gate where is is information
70	char imageCRC[CRC_LEN];				// 216-219: CRC32 of image less imagetag (kernel for Alice Gate)
71	char rootfsCRC[CRC_LEN];			// 220-223: CRC32 of rootfs partition
72	char kernelCRC[CRC_LEN];			// 224-227: CRC32 of kernel partition
73	char imageSequence[4];				// 228-231: Image sequence number
74	char rootLength[4];				// 232-235: steal from reserved1 to keep the real root length so we can use in the flash map even after we have change the rootLength to 0 to satisfy devices that check CRC on every boot
75	char headerCRC[CRC_LEN];			// 236-239: CRC32 of header excluding tagVersion
76	char reserved2[16];				// 240-255: Unused at present
77};
78
79struct zyxbcm_tag {
80	char tagVersion[TAGVER_LEN];			// 0-3: Version of the image tag
81	char sig_1[SIG1_LEN];				// 4-23: Company Line 1
82	char sig_2[SIG2_LEN];				// 24-37: Company Line 2
83	char chipid[CHIPID_LEN];			// 38-43: Chip this image is for
84	char boardid[BOARDID_LEN];			// 44-59: Board name
85	char big_endian[ENDIANFLAG_LEN];		// 60-61: Map endianness -- 1 BE 0 LE
86	char totalLength[IMAGE_LEN];			// 62-71: Total length of image
87	char cfeAddress[ADDRESS_LEN];			// 72-83: Address in memory of CFE
88	char cfeLength[IMAGE_LEN];			// 84-93: Size of CFE
89	char flashImageStart[ADDRESS_LEN];		// 94-105: Address in memory of image start (kernel for OpenWRT, rootfs for stock firmware)
90	char flashRootLength[IMAGE_LEN];		// 106-115: Size of rootfs for flashing
91	char kernelAddress[ADDRESS_LEN];		// 116-127: Address in memory of kernel
92	char kernelLength[IMAGE_LEN];			// 128-137: Size of kernel
93	char dualImage[DUALFLAG_LEN];			// 138-139: Unused at present
94	char inactiveFlag[INACTIVEFLAG_LEN];		// 140-141: Unused at present
95	char rsa_signature[RSASIG_LEN];			// 142-161: RSA Signature (unused at present; some vendors may use this)
96	char information1[ZYX_TAGINFO1_LEN];		// 162-181: Compilation and related information (not generated/used by OpenWRT)
97	char flashImageEnd[ADDRESS_LEN];		// 182-193: Address in memory of image end
98	char fskernelCRC[CRC_LEN];			// 194-197: kernel+rootfs CRC32
99	char reserved1[2];				// 198-199: Unused at present
100	char information2[TAGINFO2_LEN];		// 200-215: Unused at present except Alice Gate where is is information
101	char imageCRC[CRC_LEN];				// 216-219: CRC32 of image less imagetag (kernel for Alice Gate)
102	char rootfsCRC[CRC_LEN];			// 220-223: CRC32 of rootfs partition
103	char kernelCRC[CRC_LEN];			// 224-227: CRC32 of kernel partition
104	char imageSequence[4];				// 228-231: Image sequence number
105	char rootLength[4];				// 232-235: steal from reserved1 to keep the real root length so we can use in the flash map even after we have change the rootLength to 0 to satisfy devices that check CRC on every boot
106	char headerCRC[CRC_LEN];			// 236-239: CRC32 of header excluding tagVersion
107	char reserved2[16];				// 240-255: Unused at present
108};
109
110static uint32_t crc32tab[256] = {
111	0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
112	0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
113	0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
114	0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
115	0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
116	0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
117	0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
118	0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
119	0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
120	0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
121	0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
122	0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
123	0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
124	0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
125	0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
126	0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
127	0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
128	0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
129	0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
130	0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
131	0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
132	0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
133	0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
134	0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
135	0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
136	0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
137	0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
138	0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
139	0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
140	0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
141	0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
142	0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
143};
144
145uint32_t crc32(uint32_t crc, uint8_t *data, size_t len)
146{
147	while (len--)
148		crc = (crc >> 8) ^ crc32tab[(crc ^ *data++) & 0xFF];
149
150	return crc;
151}
152
153void fix_header(void *buf)
154{
155	struct bcm_tag *bcmtag = buf;
156	struct zyxbcm_tag *zyxtag = buf;
157	uint8_t fskernel_crc[CRC_LEN];
158	uint32_t crc;
159	uint64_t flash_start, rootfs_len, kernel_len;
160
161	/* Backup values */
162	flash_start = strtoul(bcmtag->flashImageStart, NULL, 10);
163	rootfs_len = strtoul(bcmtag->flashRootLength, NULL, 10);
164	kernel_len = strtoul(bcmtag->kernelLength, NULL, 10);
165	memcpy(fskernel_crc, bcmtag->fskernelCRC, CRC_LEN);
166
167	/* Clear values */
168	zyxtag->information1[ZYX_TAGINFO1_LEN - 1] = 0;
169	memset(zyxtag->flashImageEnd, 0, ADDRESS_LEN);
170	memset(zyxtag->fskernelCRC, 0, CRC_LEN);
171	memset(zyxtag->reserved1, 0, 2);
172
173	/* Replace values */
174	sprintf(zyxtag->flashImageEnd, "%lu", flash_start + rootfs_len + kernel_len);
175	memcpy(zyxtag->fskernelCRC, fskernel_crc, CRC_LEN);
176
177	/* Update tag crc */
178	crc = htonl(crc32(IMAGETAG_CRC_START, buf, 236));
179	memcpy(zyxtag->headerCRC, &crc, 4);
180}
181
182void usage(void) __attribute__ (( __noreturn__ ));
183
184void usage(void)
185{
186	fprintf(stderr, "Usage: zyxbcm [-i <inputfile>] [-o <outputfile>]\n");
187	exit(EXIT_FAILURE);
188}
189
190int main(int argc, char **argv)
191{
192	char buf[1024];	/* keep this at 1k or adjust garbage calc below */
193	FILE *in = stdin, *out = stdout;
194	char *ifn = NULL, *ofn = NULL;
195	size_t n;
196	int c, first_block = 1;
197
198	while ((c = getopt(argc, argv, "i:o:h")) != -1) {
199		switch (c) {
200			case 'i':
201				ifn = optarg;
202				break;
203			case 'o':
204				ofn = optarg;
205				break;
206			case 'h':
207			default:
208				usage();
209		}
210	}
211
212	if (optind != argc || optind == 1) {
213		fprintf(stderr, "illegal arg \"%s\"\n", argv[optind]);
214		usage();
215	}
216
217	if (ifn && !(in = fopen(ifn, "r"))) {
218		fprintf(stderr, "can not open \"%s\" for reading\n", ifn);
219		usage();
220	}
221
222	if (ofn && !(out = fopen(ofn, "w"))) {
223		fprintf(stderr, "can not open \"%s\" for writing\n", ofn);
224		usage();
225	}
226
227	while ((n = fread(buf, 1, sizeof(buf), in)) > 0) {
228		if (n < sizeof(buf)) {
229			if (ferror(in)) {
230			FREAD_ERROR:
231				fprintf(stderr, "fread error\n");
232				return EXIT_FAILURE;
233			}
234		}
235
236		if (first_block && n >= 256) {
237			fix_header(buf);
238			first_block = 0;
239		}
240
241		if (!fwrite(buf, n, 1, out)) {
242		FWRITE_ERROR:
243			fprintf(stderr, "fwrite error\n");
244			return EXIT_FAILURE;
245		}
246	}
247
248	if (ferror(in)) {
249		goto FREAD_ERROR;
250	}
251
252	if (fflush(out)) {
253		goto FWRITE_ERROR;
254	}
255
256	fclose(in);
257	fclose(out);
258
259	return EXIT_SUCCESS;
260}
261