1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <errno.h>
5#include <getopt.h>
6#include <time.h>
7#include <stdint.h>
8#include <sys/stat.h>
9
10#define ROUNDUP(n, a)	((n + (a - 1)) & ~(a - 1))
11
12#define TRX_MAGIC		0x30524448
13#define TRX_MAX_OFFSET		4
14#define TRX_MAX_LEN		((64 * 1024 * 1024) - ((256 + 128) * 1024))		// 64MB - (256K cfe + 128K cfg)
15
16typedef struct {
17	uint32_t magic;
18	uint32_t length;
19	uint32_t crc32;
20	uint32_t flag_version;
21	uint32_t offsets[TRX_MAX_OFFSET];
22} trx_t;
23
24char trx_version = 1;
25int trx_max_offset = 3;
26
27uint32_t *crc_table = NULL;
28trx_t *trx = NULL;
29int trx_final = 0;
30time_t max_time = 0;
31
32inline size_t trx_header_size(void)
33{
34	return sizeof(*trx) - sizeof(trx->offsets) + (trx_max_offset * sizeof(trx->offsets[0]));
35}
36
37int crc_init(void)
38{
39	uint32_t c;
40	int i, j;
41
42	if (crc_table == NULL) {
43		if ((crc_table = malloc(sizeof(uint32_t) * 256)) == NULL) return 0;
44		for (i = 255; i >= 0; --i) {
45			c = i;
46			for (j = 8; j > 0; --j) {
47				if (c & 1) c = (c >> 1) ^ 0xEDB88320L;
48					else c >>= 1;
49			}
50			crc_table[i] = c;
51		}
52	}
53	return 1;
54}
55
56uint32_t crc_calc(uint32_t crc, uint8_t *buf, int len)
57{
58	while (len-- > 0) {
59		crc = crc_table[(crc ^ *buf) & 0xFF] ^ (crc >> 8);
60		++buf;
61	}
62	return crc;
63}
64
65void help(void)
66{
67	fprintf(stderr,
68		"Usage: -i <input> {output}\n"
69		"Output:\n"
70		" ASUS: 	  -r <id>,<v1>,<v2>,<v3>,<v4>,<output file>\n"
71		"\n"
72	);
73	exit(1);
74}
75
76void load_image(const char *fname)
77{
78	struct stat st;
79	FILE *f;
80	long rsize;
81
82	if (stat(fname, &st) != 0) {
83		perror(fname);
84		exit(1);
85	}
86	if (st.st_ctime > max_time) max_time = st.st_ctime;
87
88	rsize = ROUNDUP(st.st_size, 4);
89	if ((trx->length + rsize) > TRX_MAX_LEN) {
90		fprintf(stderr, "Total size %lu (%.1f KB) is too big. Maximum is %lu (%.1f KB).\n",
91			(trx->length + rsize), (trx->length + rsize) / 1024.0,
92			(long unsigned int) TRX_MAX_LEN, TRX_MAX_LEN / 1024.0);
93		exit(1);
94	}
95
96	if ((f = fopen(fname, "r")) == NULL) {
97		perror(fname);
98		exit(1);
99	}
100
101	if (fread((char *)trx, st.st_size, 1, f) != 1) {
102		perror(fname);
103		exit(1);
104	}
105	fclose(f);
106}
107
108void finalize_trx(void)
109{
110	uint32_t len;
111
112	if (trx_final) return;
113	trx_final = 1;
114
115	len = trx->length;
116
117	trx->magic = TRX_MAGIC;
118	trx->flag_version = trx_version << 16;
119	trx->crc32 = crc_calc(0xFFFFFFFF, (void *)&trx->flag_version,
120		trx->length - (sizeof(*trx) - (sizeof(trx->flag_version) + sizeof(trx->offsets))));
121}
122
123#define MAX_STRING 12
124#define MAX_VER 4
125
126typedef struct {
127	uint8_t major;
128	uint8_t minor;
129} version_t;
130
131typedef struct {
132	version_t kernel;
133	version_t fs;
134	char 	  productid[MAX_STRING];
135	version_t hw[MAX_VER*2];
136#ifdef BCMWL6A
137	uint16_t  sn;
138	uint16_t  en;
139	char	  pad[28];
140#else
141	char	  pad[32];
142#endif
143} TAIL;
144
145/* usage:
146 * -r <productid>,<version>,<output file>
147 *
148 */
149int create_asus(const char *optarg)
150{
151	FILE *f;
152	char value[320];
153	char *next, *pid, *ver, *fname, *p;
154	TAIL asus_tail;
155	uint32_t v1, v2, v3, v4;
156#ifdef BCMWL6A
157	char *sn, *en;
158	char tmp[10];
159#endif
160
161	memset(&asus_tail, 0, sizeof(TAIL));
162
163	strncpy(value, optarg, sizeof(value));
164	next = value;
165	pid = strsep(&next, ",");
166	if(!pid) return 0;
167
168	strncpy(&asus_tail.productid[0], pid, MAX_STRING);
169
170	ver = strsep(&next, ",");
171	if(!ver) return 0;
172
173	sscanf(ver, "%d.%d.%d.%d", &v1, &v2, &v3, &v4);
174	asus_tail.kernel.major = (uint8_t)v1;
175	asus_tail.kernel.minor = (uint8_t)v2;
176	asus_tail.fs.major = (uint8_t)v3;
177	asus_tail.fs.minor = (uint8_t)v4;
178
179#ifdef BCMWL6A
180	sn = strsep(&next, ",");
181	if(!sn) return 0;
182
183	en = strsep(&next, ",");
184	if(!en) return 0;
185
186	sscanf(sn, "%d", &v1);
187	asus_tail.sn = (uint16_t)v1;
188
189	sscanf(en, "%d-%s", &v1, tmp);
190	asus_tail.en = (uint16_t)v1;
191#endif
192
193	fname = strsep(&next, ",");
194	if(!fname) return 0;
195
196	// append version information into the latest offset
197	p = (char *)trx+trx->length-sizeof(TAIL);
198	memcpy(p, &asus_tail, sizeof(TAIL));
199
200	finalize_trx();
201
202	printf("Creating ASUS %s firmware to %s\n", asus_tail.productid, fname);
203
204	if (((f = fopen(fname, "w")) == NULL) ||
205		(fwrite(trx, trx->length, 1, f) != 1)) {
206		perror(fname);
207		exit(1);
208	}
209	fclose(f);
210
211	return 1;
212}
213
214int main(int argc, char **argv)
215{
216	int o;
217	unsigned l;
218
219	printf("\n");
220
221	if ((!crc_init()) || ((trx = calloc(1, TRX_MAX_LEN)) == NULL)) {
222		fprintf(stderr, "Not enough memory\n");
223		exit(1);
224	}
225	trx->length = trx_header_size();
226
227	while ((o = getopt(argc, argv, "v:i:a:t:l:m:r:")) != -1) {
228		switch (o) {
229		case 'i':
230			load_image(optarg);
231			break;
232		case 'r':
233			create_asus(optarg);
234			break;
235		default:
236			help();
237			return 1;
238		}
239	}
240
241	finalize_trx();
242	l = trx->length - trx_header_size();
243	printf("\nTRX Image:\n");
244	printf(" Total Size .... : %u (%.1f KB) (%.1f MB)\n", trx->length, trx->length / 1024.0, trx->length / 1024.0 / 1024.0);
245	printf(" CRC-32 ........ : %8X\n", trx->crc32);
246	printf("\n");
247
248	return 0;
249}
250