firmware-utils: asustrx: new tool for TRX format with Asus tail
[openwrt/openwrt.git] / tools / firmware-utils / src / asustrx.c
1 /*
2 * asustrx
3 *
4 * Copyright (C) 2015 Rafał Miłecki <zajec5@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
9 * any later version.
10 */
11
12 #include <byteswap.h>
13 #include <errno.h>
14 #include <stdint.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <unistd.h>
19
20 #if __BYTE_ORDER == __BIG_ENDIAN
21 #define cpu_to_le32(x) bswap_32(x)
22 #define le32_to_cpu(x) bswap_32(x)
23 #elif __BYTE_ORDER == __LITTLE_ENDIAN
24 #define cpu_to_le32(x) (x)
25 #define le32_to_cpu(x) (x)
26 #else
27 #error "Unsupported endianness"
28 #endif
29
30 #define TRX_MAGIC 0x30524448
31 #define TRX_FLAGS_OFFSET 12
32
33 struct trx_header {
34 uint32_t magic;
35 uint32_t length;
36 uint32_t crc32;
37 uint16_t flags;
38 uint16_t version;
39 uint32_t offset[3];
40 };
41
42 struct asustrx_tail {
43 uint8_t version[4];
44 char productid[12];
45 uint8_t unused[48];
46 };
47
48 char *in_path = NULL;
49 char *out_path = NULL;
50 char *productid = NULL;
51
52 static const uint32_t crc32_tbl[] = {
53 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
54 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
55 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
56 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
57 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
58 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
59 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
60 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
61 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
62 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
63 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
64 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
65 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
66 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
67 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
68 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
69 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
70 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
71 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
72 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
73 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
74 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
75 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
76 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
77 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
78 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
79 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
80 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
81 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
82 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
83 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
84 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
85 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
86 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
87 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
88 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
89 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
90 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
91 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
92 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
93 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
94 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
95 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
96 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
97 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
98 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
99 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
100 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
101 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
102 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
103 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
104 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
105 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
106 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
107 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
108 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
109 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
110 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
111 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
112 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
113 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
114 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
115 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
116 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
117 };
118
119 static void parse_options(int argc, char **argv) {
120 int c;
121
122 while ((c = getopt(argc, argv, "i:o:p:")) != -1) {
123 switch (c) {
124 case 'i':
125 in_path = optarg;
126 break;
127 case 'o':
128 out_path = optarg;
129 break;
130 case 'p':
131 productid = optarg;
132 break;
133 }
134 }
135 }
136
137 static void usage() {
138 printf("Usage:\n");
139 printf("\t-i file\t\t\t\tinput TRX file\n");
140 printf("\t-o offset\t\t\toutput Asus TRX file\n");
141 printf("\t-p productid\t\t\tproduct (device) ID\n");
142 }
143
144 int main(int argc, char **argv) {
145 struct trx_header hdr;
146 struct asustrx_tail tail = { };
147 FILE *in, *out;
148 uint8_t buf[1024];
149 size_t bytes;
150 size_t length = 0;
151 uint32_t crc32 = 0xffffffff;
152 int i;
153 int err = 0;
154
155 /* Parse & validate arguments */
156 parse_options(argc, argv);
157 if (!in_path || !out_path || !productid) {
158 usage();
159 err = -EINVAL;
160 goto err;
161 }
162
163 /* Fill Asus tail */
164 strncpy(tail.productid, productid, sizeof(tail.productid));
165
166 /* Open files */
167 in = fopen(in_path, "r");
168 if (!in) {
169 fprintf(stderr, "Couldn't open %s\n", in_path);
170 err = -EIO;
171 goto err;
172 }
173 out = fopen(out_path, "w+");
174 if (!out) {
175 fprintf(stderr, "Couldn't open %s\n", out_path);
176 err = -EIO;
177 goto err;
178 }
179
180 /* Check is there is empty place for Asus tail */
181 bytes = sizeof(struct asustrx_tail);
182 fseek(in, -bytes, SEEK_END);
183 if (fread(buf, 1, bytes, in) != bytes) {
184 fprintf(stderr, "Couldn't read %zu B from %s\n", bytes, in_path);
185 err = -EIO;
186 goto err;
187 }
188 for (i = 0; i < bytes; i++) {
189 if (buf[i]) {
190 fprintf(stderr, "Input TRX doesn't have last 64 B empty %s\n");
191 err = -ENOSPC;
192 goto err;
193 }
194 }
195
196 /* Copy whole TRX */
197 rewind(in);
198 while ((bytes = fread(buf, 1, sizeof(buf), in)) > 0) {
199 if (fwrite(buf, 1, bytes, out) != bytes) {
200 fprintf(stderr, "Couldn't write %zu B to %s\n", bytes, out_path);
201 err = -EIO;
202 goto err;
203 }
204 }
205
206 /* Overwrite last 64 B with Asus tail */
207 bytes = sizeof(tail);
208 fseek(out, -bytes, SEEK_CUR);
209 if (fwrite(&tail, 1, bytes, out) != bytes) {
210 fprintf(stderr, "Couldn't write %zu B to %s\n", bytes);
211 err = -EIO;
212 goto err;
213 }
214
215 /* Calculate crc32 */
216 fseek(out, TRX_FLAGS_OFFSET, SEEK_SET);
217 length = TRX_FLAGS_OFFSET;
218 while ((bytes = fread(buf, 1, sizeof(buf), out )) > 0) {
219 length += bytes;
220 for (i = 0; i < bytes; i++)
221 crc32 = crc32_tbl[(crc32 ^ buf[i]) & 0xff] ^ (crc32 >> 8);
222 }
223
224 /* Update header */
225 bytes = sizeof(hdr);
226 rewind(out);
227 if (fread(&hdr, 1, sizeof(hdr), out) != bytes) {
228 fprintf(stderr, "Couldn't read %zu B from %s\n", bytes, in_path);
229 err = -EIO;
230 goto err;
231 }
232 hdr.crc32 = cpu_to_le32(crc32);
233 rewind(out);
234 if (fwrite(&hdr, 1, bytes, out) != bytes) {
235 fprintf(stderr, "Couldn't write %zu B to %s\n", bytes);
236 err = -EIO;
237 goto err;
238 }
239
240 err:
241 if (out)
242 fclose(out);
243 if (in)
244 fclose(in);
245 return err;
246 }