rpcd: iwinfo plugin fixes
[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 uint8_t version[4] = { };
52
53 static const uint32_t crc32_tbl[] = {
54         0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
55         0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
56         0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
57         0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
58         0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
59         0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
60         0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
61         0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
62         0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
63         0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
64         0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
65         0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
66         0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
67         0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
68         0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
69         0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
70         0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
71         0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
72         0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
73         0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
74         0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
75         0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
76         0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
77         0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
78         0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
79         0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
80         0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
81         0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
82         0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
83         0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
84         0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
85         0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
86         0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
87         0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
88         0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
89         0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
90         0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
91         0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
92         0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
93         0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
94         0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
95         0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
96         0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
97         0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
98         0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
99         0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
100         0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
101         0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
102         0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
103         0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
104         0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
105         0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
106         0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
107         0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
108         0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
109         0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
110         0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
111         0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
112         0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
113         0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
114         0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
115         0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
116         0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
117         0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
118 };
119
120 static void parse_options(int argc, char **argv) {
121         int c;
122
123         while ((c = getopt(argc, argv, "i:o:p:v:")) != -1) {
124                 switch (c) {
125                 case 'i':
126                         in_path = optarg;
127                         break;
128                 case 'o':
129                         out_path = optarg;
130                         break;
131                 case 'p':
132                         productid = optarg;
133                         break;
134                 case 'v':
135                         if (sscanf(optarg, "%hu.%hu.%hu.%hu", &version[0], &version[1], &version[2], &version[3]) != 4)
136                                 fprintf(stderr, "Version %s doesn't match suppored 4-digits format\n", optarg);
137                         break;
138                 }
139         }
140 }
141
142 static void usage() {
143         printf("Usage:\n");
144         printf("\t-i file\t\t\t\tinput TRX file\n");
145         printf("\t-o file\t\t\t\toutput Asus TRX file\n");
146         printf("\t-p productid\t\t\tproduct (device) ID\n");
147         printf("\t-v version\t\t\tfirmware version formatted with 4 digits like: 1.2.3.4\n");
148 }
149
150 int main(int argc, char **argv) {
151         struct trx_header hdr;
152         struct asustrx_tail tail = { };
153         FILE *in, *out;
154         uint8_t buf[1024];
155         size_t bytes;
156         size_t length = 0;
157         uint32_t crc32 = 0xffffffff;
158         int i;
159         int err = 0;
160
161         /* Parse & validate arguments */
162         parse_options(argc, argv);
163         if (!in_path || !out_path || !productid) {
164                 usage();
165                 err = -EINVAL;
166                 goto err;
167         }
168
169         /* Fill Asus tail */
170         tail.version[0] = version[0];
171         tail.version[1] = version[1];
172         tail.version[2] = version[2];
173         tail.version[3] = version[3];
174         strncpy(tail.productid, productid, sizeof(tail.productid));
175
176         /* Open files */
177         in = fopen(in_path, "r");
178         if (!in) {
179                 fprintf(stderr, "Couldn't open %s\n", in_path);
180                 err = -EIO;
181                 goto err;
182         }
183         out = fopen(out_path, "w+");
184         if (!out) {
185                 fprintf(stderr, "Couldn't open %s\n", out_path);
186                 err = -EIO;
187                 goto err;
188         }
189
190         /* Check is there is empty place for Asus tail */
191         bytes = sizeof(struct asustrx_tail);
192         fseek(in, -bytes, SEEK_END);
193         if (fread(buf, 1, bytes, in) != bytes) {
194                 fprintf(stderr, "Couldn't read %zu B from %s\n", bytes, in_path);
195                 err = -EIO;
196                 goto err;
197         }
198         for (i = 0; i < bytes; i++) {
199                 if (buf[i]) {
200                         fprintf(stderr, "Input TRX doesn't have last 64 B empty %s\n", out_path);
201                         err = -ENOSPC;
202                         goto err;
203                 }
204         }
205
206         /* Copy whole TRX */
207         rewind(in);
208         while ((bytes = fread(buf, 1, sizeof(buf), in)) > 0) {
209                 if (fwrite(buf, 1, bytes, out) != bytes) {
210                         fprintf(stderr, "Couldn't write %zu B to %s\n", bytes, out_path);
211                         err = -EIO;
212                         goto err;
213                 }
214         }
215
216         /* Overwrite last 64 B with Asus tail */
217         bytes = sizeof(tail);
218         fseek(out, -bytes, SEEK_CUR);
219         if (fwrite(&tail, 1, bytes, out) != bytes) {
220                 fprintf(stderr, "Couldn't write %zu B to %s\n", bytes, out_path);
221                 err = -EIO;
222                 goto err;
223         }
224
225         /* Calculate crc32 */
226         fseek(out, TRX_FLAGS_OFFSET, SEEK_SET);
227         length = TRX_FLAGS_OFFSET;
228         while ((bytes = fread(buf, 1, sizeof(buf), out )) > 0) {
229                 length += bytes;
230                 for (i = 0; i < bytes; i++)
231                         crc32 = crc32_tbl[(crc32 ^ buf[i]) & 0xff] ^ (crc32 >> 8);
232         }
233
234         /* Update header */
235         bytes = sizeof(hdr);
236         rewind(out);
237         if (fread(&hdr, 1, sizeof(hdr), out) != bytes) {
238                 fprintf(stderr, "Couldn't read %zu B from %s\n", bytes, in_path);
239                 err = -EIO;
240                 goto err;
241         }
242         hdr.crc32 = cpu_to_le32(crc32);
243         rewind(out);
244         if (fwrite(&hdr, 1, bytes, out) != bytes) {
245                 fprintf(stderr, "Couldn't write %zu B to %s\n", bytes, out_path);
246                 err = -EIO;
247                 goto err;
248         }
249
250 err:
251         if (out)
252                 fclose(out);
253         if (in)
254                 fclose(in);
255         return err;
256 }