firmware-utils: honor env SOURCE_DATE_EPOCH
[oweals/openwrt.git] / tools / firmware-utils / src / spw303v.c
1 /*
2  * spw303v.c - partially based on OpenWrt's imagetag.c and addpattern.c
3  *
4  * Copyright (C) 2011  Jonas Gorski <jonas.gorski@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 <unistd.h>
27 #include <sys/stat.h>
28
29 #define IMAGE_LEN 10                   /* Length of Length Field */
30 #define ADDRESS_LEN 12                 /* Length of Address field */
31 #define TAGID_LEN  6                   /* Length of tag ID */
32 #define TAGINFO_LEN 20                 /* Length of vendor information field in tag */
33 #define TAGVER_LEN 4                   /* Length of Tag Version */
34 #define TAGLAYOUT_LEN 4                /* Length of FlashLayoutVer */
35
36
37 struct spw303v_tag
38 {
39     unsigned char tagVersion[4];       // tag version.  Will be 2 here.
40     unsigned char signiture_1[20];                       // text line for company info
41     unsigned char signiture_2[14];                      // additional info (can be version number)
42     unsigned char chipId[6];                                    // chip id
43     unsigned char boardId[16];                          // board id
44     unsigned char bigEndian[2];                         // if = 1 - big, = 0 - little endia of the host
45     unsigned char totalImageLen[IMAGE_LEN];      // the sum of all the following length
46     unsigned char cfeAddress[ADDRESS_LEN];       // if non zero, cfe starting address
47     unsigned char cfeLen[IMAGE_LEN];             // if non zero, cfe size in clear ASCII text.
48     unsigned char rootfsAddress[ADDRESS_LEN];    // if non zero, filesystem starting address
49     unsigned char rootfsLen[IMAGE_LEN];          // if non zero, filesystem size in clear ASCII text.
50     unsigned char kernelAddress[ADDRESS_LEN];    // if non zero, kernel starting address
51     unsigned char kernelLen[IMAGE_LEN];          // if non zero, kernel size in clear ASCII text.
52
53         unsigned char certf1Address[ADDRESS_LEN];
54         unsigned char certf1Len[6];
55         unsigned char certf2Address[ADDRESS_LEN];
56         unsigned char certf2Len[6];
57         unsigned char certf3Address[ADDRESS_LEN];
58         unsigned char certf3Len[6];
59         unsigned char httpsFileSize[4];
60         unsigned char tr64FileSize[4];
61         unsigned char tr69FileSize[4];
62         unsigned char filesmap[4];
63
64     unsigned char imageSequence[4];                             // incrments everytime an image is flashed
65     unsigned char reserved[4];                                      // reserved for later use
66     unsigned char imageCRC[4];                      // 216-219: CRC32 of images
67     unsigned char reserved2[16];                    // 220-235: Unused at present
68     unsigned char headerCRC[4];                     // 236-239: CRC32 of header excluding tagVersion
69     unsigned char reserved3[16];                    // 240-255: Unused at present
70 };
71
72 static uint32_t crc32tab[256] = {
73         0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
74         0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
75         0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
76         0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
77         0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
78         0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
79         0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
80         0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
81         0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
82         0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
83         0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
84         0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
85         0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
86         0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
87         0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
88         0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
89         0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
90         0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
91         0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
92         0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
93         0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
94         0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
95         0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
96         0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
97         0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
98         0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
99         0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
100         0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
101         0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
102         0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
103         0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
104         0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
105 };
106 #define IMAGETAG_CRC_START                      0xFFFFFFFF
107
108 #define IMAGETAG_MAGIC1_TCOM            "AAAAAAAA Corporatio"
109
110 static char fake_data[] = {
111         0x18, 0x21, 0x21, 0x18, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21 ,0x18,
112         0x21, 0x24, 0x21, 0x1b, 0x18, 0x18, 0x24, 0x24, 0x18, 0x21, 0x21, 0x21,
113         0x21, 0x21, 0x21, 0x21, 0x1b, 0x18, 0x18, 0x24, 0x24, 0x21, 0x21, 0x21,
114         0x21, 0x21, 0x21, 0x21, 0x18, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x18,
115         0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x18, 0x21, 0x21,
116         0x21, 0x21, 0x21, 0x21,
117 };
118
119
120 uint32_t crc32(uint32_t crc, uint8_t *data, size_t len)
121 {
122         while (len--)
123                 crc = (crc >> 8) ^ crc32tab[(crc ^ *data++) & 0xFF];
124
125         return crc;
126 }
127
128 void fix_header(void *buf)
129 {
130         struct spw303v_tag *tag = buf;
131         uint32_t crc;
132         /* Replace signature with custom t-com one */
133         memset(tag->signiture_1, 0, 20);
134         memcpy(tag->signiture_1, IMAGETAG_MAGIC1_TCOM, strlen(IMAGETAG_MAGIC1_TCOM));
135
136         /* Clear cert fields to remove information_* data */
137         memset(tag->certf1Address, 0, 74);
138
139         /* replace image crc with modified one */
140         crc = ntohl(*((uint32_t *)&tag->imageCRC));
141
142         crc = htonl(crc32(crc, fake_data, 64));
143
144         memcpy(tag->imageCRC, &crc, 4);
145
146         /* Update tag crc */
147         crc = htonl(crc32(IMAGETAG_CRC_START, buf, 236));
148         memcpy(tag->headerCRC, &crc, 4);
149 }
150
151
152
153 void usage(void) __attribute__ (( __noreturn__ ));
154
155 void usage(void)
156 {
157         fprintf(stderr, "Usage: spw303v [-i <inputfile>] [-o <outputfile>]\n");
158         exit(EXIT_FAILURE);
159 }
160
161
162 int main(int argc, char **argv)
163 {
164         char buf[1024]; /* keep this at 1k or adjust garbage calc below */
165         FILE *in = stdin;
166         FILE *out = stdout;
167         char *ifn = NULL;
168         char *ofn = NULL;
169         int c;
170         int v0, v1, v2;
171         size_t n;
172         int first_block = 1;
173
174         uint32_t image_crc = IMAGETAG_CRC_START;
175
176         while ((c = getopt(argc, argv, "i:o:h")) != -1) {
177                 switch (c) {
178                         case 'i':
179                                 ifn = optarg;
180                                 break;
181                         case 'o':
182                                 ofn = optarg;
183                                 break;
184                         case 'h':
185                         default:
186                                 usage();
187                 }
188         }
189
190         if (optind != argc || optind == 1) {
191                 fprintf(stderr, "illegal arg \"%s\"\n", argv[optind]);
192                 usage();
193         }
194
195         if (ifn && !(in = fopen(ifn, "r"))) {
196                 fprintf(stderr, "can not open \"%s\" for reading\n", ifn);
197                 usage();
198         }
199
200         if (ofn && !(out = fopen(ofn, "w"))) {
201                 fprintf(stderr, "can not open \"%s\" for writing\n", ofn);
202                 usage();
203         }
204
205
206
207         while ((n = fread(buf, 1, sizeof(buf), in)) > 0) {
208                 if (n < sizeof(buf)) {
209                         if (ferror(in)) {
210                         FREAD_ERROR:
211                                 fprintf(stderr, "fread error\n");
212                                 return EXIT_FAILURE;
213                         }
214                 }
215
216                 if (first_block && n >= 256) {
217                         fix_header(buf);
218                         first_block = 0;
219                 }
220
221                 image_crc = crc32(image_crc, buf, n);
222
223                 if (!fwrite(buf, n, 1, out)) {
224                 FWRITE_ERROR:
225                         fprintf(stderr, "fwrite error\n");
226                         return EXIT_FAILURE;
227                 }
228         }
229
230         if (ferror(in)) {
231                 goto FREAD_ERROR;
232         }
233
234         if (fflush(out)) {
235                 goto FWRITE_ERROR;
236         }
237
238         fclose(in);
239         fclose(out);
240
241         return EXIT_SUCCESS;
242 }