20fd1ed520a8eea7b6e7f585b0acf58910d8efc1
[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 }