ce3a039e7ed6e9c76d4fa445f4e11612e2f2a8a8
[openwrt/staging/wigyori.git] / tools / firmware-utils / src / tplink-safeloader.c
1 /*
2 Copyright (c) 2014, Matthias Schiffer <mschiffer@universe-factory.net>
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7
8 1. Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright notice,
11 this list of conditions and the following disclaimer in the documentation
12 and/or other materials provided with the distribution.
13
14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26
27 /*
28 tplink-safeloader
29
30 Image generation tool for the TP-LINK SafeLoader as seen on
31 TP-LINK Pharos devices (CPE210/220/510/520)
32 */
33
34
35 #include <assert.h>
36 #include <errno.h>
37 #include <stdbool.h>
38 #include <stdio.h>
39 #include <stdint.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <time.h>
43 #include <unistd.h>
44
45 #include <arpa/inet.h>
46
47 #include <sys/types.h>
48 #include <sys/stat.h>
49 #include <limits.h>
50
51 #include "md5.h"
52
53
54 #define ALIGN(x,a) ({ typeof(a) __a = (a); (((x) + __a - 1) & ~(__a - 1)); })
55
56
57 #define MAX_PARTITIONS 32
58
59 /** An image partition table entry */
60 struct image_partition_entry {
61 const char *name;
62 size_t size;
63 uint8_t *data;
64 };
65
66 /** A flash partition table entry */
67 struct flash_partition_entry {
68 char *name;
69 uint32_t base;
70 uint32_t size;
71 };
72
73 /** Firmware layout description */
74 struct device_info {
75 const char *id;
76 const char *vendor;
77 const char *support_list;
78 char support_trail;
79 const char *soft_ver;
80 struct flash_partition_entry partitions[MAX_PARTITIONS+1];
81 const char *first_sysupgrade_partition;
82 const char *last_sysupgrade_partition;
83 };
84
85 /** The content of the soft-version structure */
86 struct __attribute__((__packed__)) soft_version {
87 uint32_t magic;
88 uint32_t zero;
89 uint8_t pad1;
90 uint8_t version_major;
91 uint8_t version_minor;
92 uint8_t version_patch;
93 uint8_t year_hi;
94 uint8_t year_lo;
95 uint8_t month;
96 uint8_t day;
97 uint32_t rev;
98 uint8_t pad2;
99 };
100
101
102 static const uint8_t jffs2_eof_mark[4] = {0xde, 0xad, 0xc0, 0xde};
103
104
105 /**
106 Salt for the MD5 hash
107
108 Fortunately, TP-LINK seems to use the same salt for most devices which use
109 the new image format.
110 */
111 static const uint8_t md5_salt[16] = {
112 0x7a, 0x2b, 0x15, 0xed,
113 0x9b, 0x98, 0x59, 0x6d,
114 0xe5, 0x04, 0xab, 0x44,
115 0xac, 0x2a, 0x9f, 0x4e,
116 };
117
118
119 /** Firmware layout table */
120 static struct device_info boards[] = {
121 /** Firmware layout for the CPE210/220 V1 */
122 {
123 .id = "CPE210",
124 .vendor = "CPE510(TP-LINK|UN|N300-5):1.0\r\n",
125 .support_list =
126 "SupportList:\r\n"
127 "CPE210(TP-LINK|UN|N300-2):1.0\r\n"
128 "CPE210(TP-LINK|UN|N300-2):1.1\r\n"
129 "CPE210(TP-LINK|US|N300-2):1.1\r\n"
130 "CPE210(TP-LINK|EU|N300-2):1.1\r\n"
131 "CPE220(TP-LINK|UN|N300-2):1.1\r\n"
132 "CPE220(TP-LINK|US|N300-2):1.1\r\n"
133 "CPE220(TP-LINK|EU|N300-2):1.1\r\n",
134 .support_trail = '\xff',
135 .soft_ver = NULL,
136
137 .partitions = {
138 {"fs-uboot", 0x00000, 0x20000},
139 {"partition-table", 0x20000, 0x02000},
140 {"default-mac", 0x30000, 0x00020},
141 {"product-info", 0x31100, 0x00100},
142 {"signature", 0x32000, 0x00400},
143 {"os-image", 0x40000, 0x200000},
144 {"file-system", 0x240000, 0x570000},
145 {"soft-version", 0x7b0000, 0x00100},
146 {"support-list", 0x7b1000, 0x00400},
147 {"user-config", 0x7c0000, 0x10000},
148 {"default-config", 0x7d0000, 0x10000},
149 {"log", 0x7e0000, 0x10000},
150 {"radio", 0x7f0000, 0x10000},
151 {NULL, 0, 0}
152 },
153
154 .first_sysupgrade_partition = "os-image",
155 .last_sysupgrade_partition = "support-list",
156 },
157
158 /** Firmware layout for the CPE210 V2 */
159 {
160 .id = "CPE210V2",
161 .vendor = "CPE210(TP-LINK|UN|N300-2|00000000):2.0\r\n",
162 .support_list =
163 "SupportList:\r\n"
164 "CPE210(TP-LINK|EU|N300-2|00000000):2.0\r\n"
165 "CPE210(TP-LINK|EU|N300-2|45550000):2.0\r\n"
166 "CPE210(TP-LINK|EU|N300-2|55530000):2.0\r\n"
167 "CPE210(TP-LINK|UN|N300-2|00000000):2.0\r\n"
168 "CPE210(TP-LINK|UN|N300-2|45550000):2.0\r\n"
169 "CPE210(TP-LINK|UN|N300-2|55530000):2.0\r\n"
170 "CPE210(TP-LINK|US|N300-2|55530000):2.0\r\n"
171 "CPE210(TP-LINK|UN|N300-2):2.0\r\n"
172 "CPE210(TP-LINK|EU|N300-2):2.0\r\n"
173 "CPE210(TP-LINK|US|N300-2):2.0\r\n",
174 .support_trail = '\xff',
175 .soft_ver = NULL,
176
177 .partitions = {
178 {"fs-uboot", 0x00000, 0x20000},
179 {"partition-table", 0x20000, 0x02000},
180 {"default-mac", 0x30000, 0x00020},
181 {"product-info", 0x31100, 0x00100},
182 {"device-info", 0x31400, 0x00400},
183 {"signature", 0x32000, 0x00400},
184 {"device-id", 0x33000, 0x00100},
185 {"firmware", 0x40000, 0x770000},
186 {"soft-version", 0x7b0000, 0x00100},
187 {"support-list", 0x7b1000, 0x01000},
188 {"user-config", 0x7c0000, 0x10000},
189 {"default-config", 0x7d0000, 0x10000},
190 {"log", 0x7e0000, 0x10000},
191 {"radio", 0x7f0000, 0x10000},
192 {NULL, 0, 0}
193 },
194
195 .first_sysupgrade_partition = "os-image",
196 .last_sysupgrade_partition = "support-list",
197 },
198
199 /** Firmware layout for the CPE210 V3 */
200 {
201 .id = "CPE210V3",
202 .vendor = "CPE210(TP-LINK|UN|N300-2|00000000):3.0\r\n",
203 .support_list =
204 "SupportList:\r\n"
205 "CPE210(TP-LINK|EU|N300-2|45550000):3.0\r\n"
206 "CPE210(TP-LINK|UN|N300-2|00000000):3.0\r\n"
207 "CPE210(TP-LINK|UN|N300-2):3.0\r\n"
208 "CPE210(TP-LINK|EU|N300-2):3.0\r\n",
209 .support_trail = '\xff',
210 .soft_ver = NULL,
211
212 .partitions = {
213 {"fs-uboot", 0x00000, 0x20000},
214 {"partition-table", 0x20000, 0x01000},
215 {"default-mac", 0x30000, 0x00020},
216 {"product-info", 0x31100, 0x00100},
217 {"device-info", 0x31400, 0x00400},
218 {"signature", 0x32000, 0x00400},
219 {"device-id", 0x33000, 0x00100},
220 {"firmware", 0x40000, 0x770000},
221 {"soft-version", 0x7b0000, 0x00100},
222 {"support-list", 0x7b1000, 0x01000},
223 {"user-config", 0x7c0000, 0x10000},
224 {"default-config", 0x7d0000, 0x10000},
225 {"log", 0x7e0000, 0x10000},
226 {"radio", 0x7f0000, 0x10000},
227 {NULL, 0, 0}
228 },
229
230 .first_sysupgrade_partition = "os-image",
231 .last_sysupgrade_partition = "support-list",
232 },
233
234 /** Firmware layout for the CPE220 V2 */
235 {
236 .id = "CPE220V2",
237 .vendor = "CPE510(TP-LINK|UN|N300-5):1.0\r\n",
238 .support_list =
239 "SupportList:\r\n"
240 "CPE220(TP-LINK|EU|N300-2|00000000):2.0\r\n"
241 "CPE220(TP-LINK|EU|N300-2|45550000):2.0\r\n"
242 "CPE220(TP-LINK|EU|N300-2|55530000):2.0\r\n"
243 "CPE220(TP-LINK|UN|N300-2|00000000):2.0\r\n"
244 "CPE220(TP-LINK|UN|N300-2|45550000):2.0\r\n"
245 "CPE220(TP-LINK|UN|N300-2|55530000):2.0\r\n"
246 "CPE220(TP-LINK|US|N300-2|55530000):2.0\r\n"
247 "CPE220(TP-LINK|UN|N300-2):2.0\r\n"
248 "CPE220(TP-LINK|EU|N300-2):2.0\r\n"
249 "CPE220(TP-LINK|US|N300-2):2.0\r\n",
250 .support_trail = '\xff',
251 .soft_ver = NULL,
252
253 .partitions = {
254 {"fs-uboot", 0x00000, 0x20000},
255 {"partition-table", 0x20000, 0x02000},
256 {"default-mac", 0x30000, 0x00020},
257 {"product-info", 0x31100, 0x00100},
258 {"signature", 0x32000, 0x00400},
259 {"os-image", 0x40000, 0x200000},
260 {"file-system", 0x240000, 0x570000},
261 {"soft-version", 0x7b0000, 0x00100},
262 {"support-list", 0x7b1000, 0x00400},
263 {"user-config", 0x7c0000, 0x10000},
264 {"default-config", 0x7d0000, 0x10000},
265 {"log", 0x7e0000, 0x10000},
266 {"radio", 0x7f0000, 0x10000},
267 {NULL, 0, 0}
268 },
269
270 .first_sysupgrade_partition = "os-image",
271 .last_sysupgrade_partition = "support-list",
272 },
273
274 /** Firmware layout for the CPE510/520 V1 */
275 {
276 .id = "CPE510",
277 .vendor = "CPE510(TP-LINK|UN|N300-5):1.0\r\n",
278 .support_list =
279 "SupportList:\r\n"
280 "CPE510(TP-LINK|UN|N300-5):1.0\r\n"
281 "CPE510(TP-LINK|UN|N300-5):1.1\r\n"
282 "CPE510(TP-LINK|UN|N300-5):1.1\r\n"
283 "CPE510(TP-LINK|US|N300-5):1.1\r\n"
284 "CPE510(TP-LINK|EU|N300-5):1.1\r\n"
285 "CPE520(TP-LINK|UN|N300-5):1.1\r\n"
286 "CPE520(TP-LINK|US|N300-5):1.1\r\n"
287 "CPE520(TP-LINK|EU|N300-5):1.1\r\n",
288 .support_trail = '\xff',
289 .soft_ver = NULL,
290
291 .partitions = {
292 {"fs-uboot", 0x00000, 0x20000},
293 {"partition-table", 0x20000, 0x02000},
294 {"default-mac", 0x30000, 0x00020},
295 {"product-info", 0x31100, 0x00100},
296 {"signature", 0x32000, 0x00400},
297 {"os-image", 0x40000, 0x200000},
298 {"file-system", 0x240000, 0x570000},
299 {"soft-version", 0x7b0000, 0x00100},
300 {"support-list", 0x7b1000, 0x00400},
301 {"user-config", 0x7c0000, 0x10000},
302 {"default-config", 0x7d0000, 0x10000},
303 {"log", 0x7e0000, 0x10000},
304 {"radio", 0x7f0000, 0x10000},
305 {NULL, 0, 0}
306 },
307
308 .first_sysupgrade_partition = "os-image",
309 .last_sysupgrade_partition = "support-list",
310 },
311
312 /** Firmware layout for the CPE510 V2 */
313 {
314 .id = "CPE510V2",
315 .vendor = "CPE510(TP-LINK|UN|N300-5):2.0\r\n",
316 .support_list =
317 "SupportList:\r\n"
318 "CPE510(TP-LINK|EU|N300-5|00000000):2.0\r\n"
319 "CPE510(TP-LINK|EU|N300-5|45550000):2.0\r\n"
320 "CPE510(TP-LINK|EU|N300-5|55530000):2.0\r\n"
321 "CPE510(TP-LINK|UN|N300-5|00000000):2.0\r\n"
322 "CPE510(TP-LINK|UN|N300-5|45550000):2.0\r\n"
323 "CPE510(TP-LINK|UN|N300-5|55530000):2.0\r\n"
324 "CPE510(TP-LINK|US|N300-5|00000000):2.0\r\n"
325 "CPE510(TP-LINK|US|N300-5|45550000):2.0\r\n"
326 "CPE510(TP-LINK|US|N300-5|55530000):2.0\r\n"
327 "CPE510(TP-LINK|UN|N300-5):2.0\r\n"
328 "CPE510(TP-LINK|EU|N300-5):2.0\r\n"
329 "CPE510(TP-LINK|US|N300-5):2.0\r\n",
330 .support_trail = '\xff',
331 .soft_ver = NULL,
332
333 .partitions = {
334 {"fs-uboot", 0x00000, 0x20000},
335 {"partition-table", 0x20000, 0x02000},
336 {"default-mac", 0x30000, 0x00020},
337 {"product-info", 0x31100, 0x00100},
338 {"signature", 0x32000, 0x00400},
339 {"os-image", 0x40000, 0x200000},
340 {"file-system", 0x240000, 0x570000},
341 {"soft-version", 0x7b0000, 0x00100},
342 {"support-list", 0x7b1000, 0x00400},
343 {"user-config", 0x7c0000, 0x10000},
344 {"default-config", 0x7d0000, 0x10000},
345 {"log", 0x7e0000, 0x10000},
346 {"radio", 0x7f0000, 0x10000},
347 {NULL, 0, 0}
348 },
349
350 .first_sysupgrade_partition = "os-image",
351 .last_sysupgrade_partition = "support-list",
352 },
353
354 /** Firmware layout for the CPE510 V3 */
355 {
356 .id = "CPE510V3",
357 .vendor = "CPE510(TP-LINK|UN|N300-5):3.0\r\n",
358 .support_list =
359 "SupportList:\r\n"
360 "CPE510(TP-LINK|EU|N300-5|00000000):3.0\r\n"
361 "CPE510(TP-LINK|EU|N300-5|45550000):3.0\r\n"
362 "CPE510(TP-LINK|EU|N300-5|55530000):3.0\r\n"
363 "CPE510(TP-LINK|UN|N300-5|00000000):3.0\r\n"
364 "CPE510(TP-LINK|UN|N300-5|45550000):3.0\r\n"
365 "CPE510(TP-LINK|UN|N300-5|55530000):3.0\r\n"
366 "CPE510(TP-LINK|US|N300-5|00000000):3.0\r\n"
367 "CPE510(TP-LINK|US|N300-5|45550000):3.0\r\n"
368 "CPE510(TP-LINK|US|N300-5|55530000):3.0\r\n"
369 "CPE510(TP-LINK|UN|N300-5):3.0\r\n"
370 "CPE510(TP-LINK|EU|N300-5):3.0\r\n"
371 "CPE510(TP-LINK|US|N300-5):3.0\r\n",
372 .support_trail = '\xff',
373 .soft_ver = NULL,
374
375 .partitions = {
376 {"fs-uboot", 0x00000, 0x20000},
377 {"partition-table", 0x20000, 0x02000},
378 {"default-mac", 0x30000, 0x00020},
379 {"product-info", 0x31100, 0x00100},
380 {"signature", 0x32000, 0x00400},
381 {"os-image", 0x40000, 0x200000},
382 {"file-system", 0x240000, 0x570000},
383 {"soft-version", 0x7b0000, 0x00100},
384 {"support-list", 0x7b1000, 0x00400},
385 {"user-config", 0x7c0000, 0x10000},
386 {"default-config", 0x7d0000, 0x10000},
387 {"log", 0x7e0000, 0x10000},
388 {"radio", 0x7f0000, 0x10000},
389 {NULL, 0, 0}
390 },
391
392 .first_sysupgrade_partition = "os-image",
393 .last_sysupgrade_partition = "support-list",
394 },
395
396 /** Firmware layout for the CPE610V1 */
397 {
398 .id = "CPE610V1",
399 .vendor = "CPE610(TP-LINK|UN|N300-5|00000000):1.0\r\n",
400 .support_list =
401 "SupportList:\r\n"
402 "CPE610(TP-LINK|EU|N300-5|00000000):1.0\r\n"
403 "CPE610(TP-LINK|EU|N300-5|45550000):1.0\r\n"
404 "CPE610(TP-LINK|EU|N300-5|55530000):1.0\r\n"
405 "CPE610(TP-LINK|UN|N300-5|00000000):1.0\r\n"
406 "CPE610(TP-LINK|UN|N300-5|45550000):1.0\r\n"
407 "CPE610(TP-LINK|UN|N300-5|55530000):1.0\r\n"
408 "CPE610(TP-LINK|US|N300-5|55530000):1.0\r\n"
409 "CPE610(TP-LINK|UN|N300-5):1.0\r\n"
410 "CPE610(TP-LINK|EU|N300-5):1.0\r\n"
411 "CPE610(TP-LINK|US|N300-5):1.0\r\n",
412 .support_trail = '\xff',
413 .soft_ver = NULL,
414
415 .partitions = {
416 {"fs-uboot", 0x00000, 0x20000},
417 {"partition-table", 0x20000, 0x02000},
418 {"default-mac", 0x30000, 0x00020},
419 {"product-info", 0x31100, 0x00100},
420 {"signature", 0x32000, 0x00400},
421 {"os-image", 0x40000, 0x200000},
422 {"file-system", 0x240000, 0x570000},
423 {"soft-version", 0x7b0000, 0x00100},
424 {"support-list", 0x7b1000, 0x00400},
425 {"user-config", 0x7c0000, 0x10000},
426 {"default-config", 0x7d0000, 0x10000},
427 {"log", 0x7e0000, 0x10000},
428 {"radio", 0x7f0000, 0x10000},
429 {NULL, 0, 0}
430 },
431
432 .first_sysupgrade_partition = "os-image",
433 .last_sysupgrade_partition = "support-list",
434 },
435
436 {
437 .id = "WBS210",
438 .vendor = "CPE510(TP-LINK|UN|N300-5):1.0\r\n",
439 .support_list =
440 "SupportList:\r\n"
441 "WBS210(TP-LINK|UN|N300-2):1.20\r\n"
442 "WBS210(TP-LINK|US|N300-2):1.20\r\n"
443 "WBS210(TP-LINK|EU|N300-2):1.20\r\n",
444 .support_trail = '\xff',
445 .soft_ver = NULL,
446
447 .partitions = {
448 {"fs-uboot", 0x00000, 0x20000},
449 {"partition-table", 0x20000, 0x02000},
450 {"default-mac", 0x30000, 0x00020},
451 {"product-info", 0x31100, 0x00100},
452 {"signature", 0x32000, 0x00400},
453 {"os-image", 0x40000, 0x200000},
454 {"file-system", 0x240000, 0x570000},
455 {"soft-version", 0x7b0000, 0x00100},
456 {"support-list", 0x7b1000, 0x00400},
457 {"user-config", 0x7c0000, 0x10000},
458 {"default-config", 0x7d0000, 0x10000},
459 {"log", 0x7e0000, 0x10000},
460 {"radio", 0x7f0000, 0x10000},
461 {NULL, 0, 0}
462 },
463
464 .first_sysupgrade_partition = "os-image",
465 .last_sysupgrade_partition = "support-list",
466 },
467
468 {
469 .id = "WBS510",
470 .vendor = "CPE510(TP-LINK|UN|N300-5):1.0\r\n",
471 .support_list =
472 "SupportList:\r\n"
473 "WBS510(TP-LINK|UN|N300-5):1.20\r\n"
474 "WBS510(TP-LINK|US|N300-5):1.20\r\n"
475 "WBS510(TP-LINK|EU|N300-5):1.20\r\n",
476 .support_trail = '\xff',
477 .soft_ver = NULL,
478
479 .partitions = {
480 {"fs-uboot", 0x00000, 0x20000},
481 {"partition-table", 0x20000, 0x02000},
482 {"default-mac", 0x30000, 0x00020},
483 {"product-info", 0x31100, 0x00100},
484 {"signature", 0x32000, 0x00400},
485 {"os-image", 0x40000, 0x200000},
486 {"file-system", 0x240000, 0x570000},
487 {"soft-version", 0x7b0000, 0x00100},
488 {"support-list", 0x7b1000, 0x00400},
489 {"user-config", 0x7c0000, 0x10000},
490 {"default-config", 0x7d0000, 0x10000},
491 {"log", 0x7e0000, 0x10000},
492 {"radio", 0x7f0000, 0x10000},
493 {NULL, 0, 0}
494 },
495
496 .first_sysupgrade_partition = "os-image",
497 .last_sysupgrade_partition = "support-list",
498 },
499
500 /** Firmware layout for the C2600 */
501 {
502 .id = "C2600",
503 .vendor = "",
504 .support_list =
505 "SupportList:\r\n"
506 "{product_name:Archer C2600,product_ver:1.0.0,special_id:00000000}\r\n",
507 .support_trail = '\x00',
508 .soft_ver = NULL,
509
510 /**
511 We use a bigger os-image partition than the stock images (and thus
512 smaller file-system), as our kernel doesn't fit in the stock firmware's
513 2 MB os-image since kernel 4.14.
514 */
515 .partitions = {
516 {"SBL1", 0x00000, 0x20000},
517 {"MIBIB", 0x20000, 0x20000},
518 {"SBL2", 0x40000, 0x20000},
519 {"SBL3", 0x60000, 0x30000},
520 {"DDRCONFIG", 0x90000, 0x10000},
521 {"SSD", 0xa0000, 0x10000},
522 {"TZ", 0xb0000, 0x30000},
523 {"RPM", 0xe0000, 0x20000},
524 {"fs-uboot", 0x100000, 0x70000},
525 {"uboot-env", 0x170000, 0x40000},
526 {"radio", 0x1b0000, 0x40000},
527 {"os-image", 0x1f0000, 0x400000}, /* Stock: base 0x1f0000 size 0x200000 */
528 {"file-system", 0x5f0000, 0x1900000}, /* Stock: base 0x3f0000 size 0x1b00000 */
529 {"default-mac", 0x1ef0000, 0x00200},
530 {"pin", 0x1ef0200, 0x00200},
531 {"product-info", 0x1ef0400, 0x0fc00},
532 {"partition-table", 0x1f00000, 0x10000},
533 {"soft-version", 0x1f10000, 0x10000},
534 {"support-list", 0x1f20000, 0x10000},
535 {"profile", 0x1f30000, 0x10000},
536 {"default-config", 0x1f40000, 0x10000},
537 {"user-config", 0x1f50000, 0x40000},
538 {"qos-db", 0x1f90000, 0x40000},
539 {"usb-config", 0x1fd0000, 0x10000},
540 {"log", 0x1fe0000, 0x20000},
541 {NULL, 0, 0}
542 },
543
544 .first_sysupgrade_partition = "os-image",
545 .last_sysupgrade_partition = "file-system"
546 },
547
548 /** Firmware layout for the A7-V5 */
549 {
550 .id = "ARCHER-A7-V5",
551 .support_list =
552 "SupportList:\n"
553 "{product_name:Archer A7,product_ver:5.0.0,special_id:45550000}\n"
554 "{product_name:Archer A7,product_ver:5.0.0,special_id:55530000}\n"
555 "{product_name:Archer A7,product_ver:5.0.0,special_id:43410000}\n"
556 "{product_name:Archer A7,product_ver:5.0.0,special_id:4A500000}\n"
557 "{product_name:Archer A7,product_ver:5.0.0,special_id:54570000}\n",
558 .support_trail = '\x00',
559 .soft_ver = "soft_ver:1.0.0\n",
560
561 /* We're using a dynamic kernel/rootfs split here */
562 .partitions = {
563 {"factory-boot", 0x00000, 0x20000},
564 {"fs-uboot", 0x20000, 0x20000},
565 {"firmware", 0x40000, 0xec0000}, /* Stock: name os-image base 0x40000 size 0x120000 */
566 /* Stock: name file-system base 0x160000 size 0xda0000 */
567 {"default-mac", 0xf40000, 0x00200},
568 {"pin", 0xf40200, 0x00200},
569 {"device-id", 0xf40400, 0x00100},
570 {"product-info", 0xf40500, 0x0fb00},
571 {"soft-version", 0xf50000, 0x00100},
572 {"extra-para", 0xf51000, 0x01000},
573 {"support-list", 0xf52000, 0x0a000},
574 {"profile", 0xf5c000, 0x04000},
575 {"default-config", 0xf60000, 0x10000},
576 {"user-config", 0xf70000, 0x40000},
577 {"certificate", 0xfb0000, 0x10000},
578 {"partition-table", 0xfc0000, 0x10000},
579 {"log", 0xfd0000, 0x20000},
580 {"radio", 0xff0000, 0x10000},
581 {NULL, 0, 0}
582 },
583
584 .first_sysupgrade_partition = "os-image",
585 .last_sysupgrade_partition = "file-system",
586 },
587
588 /** Firmware layout for the C2v3 */
589 {
590 .id = "ARCHER-C2-V3",
591 .support_list =
592 "SupportList:\n"
593 "{product_name:ArcherC2,product_ver:3.0.0,special_id:00000000}\n"
594 "{product_name:ArcherC2,product_ver:3.0.0,special_id:55530000}\n"
595 "{product_name:ArcherC2,product_ver:3.0.0,special_id:45550000}\n",
596 .support_trail = '\x00',
597 .soft_ver = "soft_ver:3.0.1\n",
598
599 /** We're using a dynamic kernel/rootfs split here */
600
601 .partitions = {
602 {"factory-boot", 0x00000, 0x20000},
603 {"fs-uboot", 0x20000, 0x10000},
604 {"firmware", 0x30000, 0x7a0000},
605 {"user-config", 0x7d0000, 0x04000},
606 {"default-mac", 0x7e0000, 0x00100},
607 {"device-id", 0x7e0100, 0x00100},
608 {"extra-para", 0x7e0200, 0x00100},
609 {"pin", 0x7e0300, 0x00100},
610 {"support-list", 0x7e0400, 0x00400},
611 {"soft-version", 0x7e0800, 0x00400},
612 {"product-info", 0x7e0c00, 0x01400},
613 {"partition-table", 0x7e2000, 0x01000},
614 {"profile", 0x7e3000, 0x01000},
615 {"default-config", 0x7e4000, 0x04000},
616 {"merge-config", 0x7ec000, 0x02000},
617 {"qos-db", 0x7ee000, 0x02000},
618 {"radio", 0x7f0000, 0x10000},
619 {NULL, 0, 0}
620 },
621
622 .first_sysupgrade_partition = "os-image",
623 .last_sysupgrade_partition = "file-system",
624 },
625
626 /** Firmware layout for the C25v1 */
627 {
628 .id = "ARCHER-C25-V1",
629 .support_list =
630 "SupportList:\n"
631 "{product_name:ArcherC25,product_ver:1.0.0,special_id:00000000}\n"
632 "{product_name:ArcherC25,product_ver:1.0.0,special_id:55530000}\n"
633 "{product_name:ArcherC25,product_ver:1.0.0,special_id:45550000}\n",
634 .support_trail = '\x00',
635 .soft_ver = "soft_ver:1.0.0\n",
636
637 /* We're using a dynamic kernel/rootfs split here */
638 .partitions = {
639 {"factory-boot", 0x00000, 0x20000},
640 {"fs-uboot", 0x20000, 0x10000},
641 {"firmware", 0x30000, 0x7a0000}, /* Stock: name os-image base 0x30000 size 0x100000 */
642 /* Stock: name file-system base 0x130000 size 0x6a0000 */
643 {"user-config", 0x7d0000, 0x04000},
644 {"default-mac", 0x7e0000, 0x00100},
645 {"device-id", 0x7e0100, 0x00100},
646 {"extra-para", 0x7e0200, 0x00100},
647 {"pin", 0x7e0300, 0x00100},
648 {"support-list", 0x7e0400, 0x00400},
649 {"soft-version", 0x7e0800, 0x00400},
650 {"product-info", 0x7e0c00, 0x01400},
651 {"partition-table", 0x7e2000, 0x01000},
652 {"profile", 0x7e3000, 0x01000},
653 {"default-config", 0x7e4000, 0x04000},
654 {"merge-config", 0x7ec000, 0x02000},
655 {"qos-db", 0x7ee000, 0x02000},
656 {"radio", 0x7f0000, 0x10000},
657 {NULL, 0, 0}
658 },
659
660 .first_sysupgrade_partition = "os-image",
661 .last_sysupgrade_partition = "file-system",
662 },
663
664 /** Firmware layout for the C58v1 */
665 {
666 .id = "ARCHER-C58-V1",
667 .vendor = "",
668 .support_list =
669 "SupportList:\r\n"
670 "{product_name:Archer C58,product_ver:1.0.0,special_id:00000000}\r\n"
671 "{product_name:Archer C58,product_ver:1.0.0,special_id:45550000}\r\n"
672 "{product_name:Archer C58,product_ver:1.0.0,special_id:55530000}\r\n",
673 .support_trail = '\x00',
674 .soft_ver = "soft_ver:1.0.0\n",
675
676 .partitions = {
677 {"fs-uboot", 0x00000, 0x10000},
678 {"default-mac", 0x10000, 0x00200},
679 {"pin", 0x10200, 0x00200},
680 {"product-info", 0x10400, 0x00100},
681 {"partition-table", 0x10500, 0x00800},
682 {"soft-version", 0x11300, 0x00200},
683 {"support-list", 0x11500, 0x00100},
684 {"device-id", 0x11600, 0x00100},
685 {"profile", 0x11700, 0x03900},
686 {"default-config", 0x15000, 0x04000},
687 {"user-config", 0x19000, 0x04000},
688 {"firmware", 0x20000, 0x7c8000},
689 {"certyficate", 0x7e8000, 0x08000},
690 {"radio", 0x7f0000, 0x10000},
691 {NULL, 0, 0}
692 },
693
694 .first_sysupgrade_partition = "os-image",
695 .last_sysupgrade_partition = "file-system",
696 },
697
698 /** Firmware layout for the C59v1 */
699 {
700 .id = "ARCHER-C59-V1",
701 .vendor = "",
702 .support_list =
703 "SupportList:\r\n"
704 "{product_name:Archer C59,product_ver:1.0.0,special_id:00000000}\r\n"
705 "{product_name:Archer C59,product_ver:1.0.0,special_id:45550000}\r\n"
706 "{product_name:Archer C59,product_ver:1.0.0,special_id:52550000}\r\n"
707 "{product_name:Archer C59,product_ver:1.0.0,special_id:55530000}\r\n",
708 .support_trail = '\x00',
709 .soft_ver = "soft_ver:1.0.0\n",
710
711 /* We're using a dynamic kernel/rootfs split here */
712 .partitions = {
713 {"fs-uboot", 0x00000, 0x10000},
714 {"default-mac", 0x10000, 0x00200},
715 {"pin", 0x10200, 0x00200},
716 {"device-id", 0x10400, 0x00100},
717 {"product-info", 0x10500, 0x0fb00},
718 {"firmware", 0x20000, 0xe30000},
719 {"partition-table", 0xe50000, 0x10000},
720 {"soft-version", 0xe60000, 0x10000},
721 {"support-list", 0xe70000, 0x10000},
722 {"profile", 0xe80000, 0x10000},
723 {"default-config", 0xe90000, 0x10000},
724 {"user-config", 0xea0000, 0x40000},
725 {"usb-config", 0xee0000, 0x10000},
726 {"certificate", 0xef0000, 0x10000},
727 {"qos-db", 0xf00000, 0x40000},
728 {"log", 0xfe0000, 0x10000},
729 {"radio", 0xff0000, 0x10000},
730 {NULL, 0, 0}
731 },
732
733 .first_sysupgrade_partition = "os-image",
734 .last_sysupgrade_partition = "file-system",
735 },
736
737 /** Firmware layout for the C59v2 */
738 {
739 .id = "ARCHER-C59-V2",
740 .vendor = "",
741 .support_list =
742 "SupportList:\r\n"
743 "{product_name:Archer C59,product_ver:2.0.0,special_id:00000000}\r\n"
744 "{product_name:Archer C59,product_ver:2.0.0,special_id:45550000}\r\n"
745 "{product_name:Archer C59,product_ver:2.0.0,special_id:55530000}\r\n",
746 .support_trail = '\x00',
747 .soft_ver = "soft_ver:2.0.0 Build 20161206 rel.7303\n",
748
749 /** We're using a dynamic kernel/rootfs split here */
750 .partitions = {
751 {"factory-boot", 0x00000, 0x20000},
752 {"fs-uboot", 0x20000, 0x10000},
753 {"default-mac", 0x30000, 0x00200},
754 {"pin", 0x30200, 0x00200},
755 {"device-id", 0x30400, 0x00100},
756 {"product-info", 0x30500, 0x0fb00},
757 {"firmware", 0x40000, 0xe10000},
758 {"partition-table", 0xe50000, 0x10000},
759 {"soft-version", 0xe60000, 0x10000},
760 {"support-list", 0xe70000, 0x10000},
761 {"profile", 0xe80000, 0x10000},
762 {"default-config", 0xe90000, 0x10000},
763 {"user-config", 0xea0000, 0x40000},
764 {"usb-config", 0xee0000, 0x10000},
765 {"certificate", 0xef0000, 0x10000},
766 {"extra-para", 0xf00000, 0x10000},
767 {"qos-db", 0xf10000, 0x30000},
768 {"log", 0xfe0000, 0x10000},
769 {"radio", 0xff0000, 0x10000},
770 {NULL, 0, 0}
771 },
772
773 .first_sysupgrade_partition = "os-image",
774 .last_sysupgrade_partition = "file-system",
775 },
776
777 /** Firmware layout for the C6v2 */
778 {
779 .id = "ARCHER-C6-V2",
780 .vendor = "",
781 .support_list =
782 "SupportList:\r\n"
783 "{product_name:Archer C6,product_ver:2.0.0,special_id:45550000}\r\n"
784 "{product_name:Archer C6,product_ver:2.0.0,special_id:52550000}\r\n"
785 "{product_name:Archer C6,product_ver:2.0.0,special_id:4A500000}\r\n",
786 .support_trail = '\x00',
787 .soft_ver = "soft_ver:1.0.0\n",
788
789 .partitions = {
790 {"fs-uboot", 0x00000, 0x20000},
791 {"default-mac", 0x20000, 0x00200},
792 {"pin", 0x20200, 0x00100},
793 {"product-info", 0x20300, 0x00200},
794 {"device-id", 0x20500, 0x0fb00},
795 {"firmware", 0x30000, 0x7a9400},
796 {"soft-version", 0x7d9400, 0x00100},
797 {"extra-para", 0x7d9500, 0x00100},
798 {"support-list", 0x7d9600, 0x00200},
799 {"profile", 0x7d9800, 0x03000},
800 {"default-config", 0x7dc800, 0x03000},
801 {"partition-table", 0x7df800, 0x00800},
802 {"user-config", 0x7e0000, 0x0c000},
803 {"certificate", 0x7ec000, 0x04000},
804 {"radio", 0x7f0000, 0x10000},
805 {NULL, 0, 0}
806 },
807
808 .first_sysupgrade_partition = "os-image",
809 .last_sysupgrade_partition = "file-system",
810 },
811
812
813 /** Firmware layout for the C60v1 */
814 {
815 .id = "ARCHER-C60-V1",
816 .vendor = "",
817 .support_list =
818 "SupportList:\r\n"
819 "{product_name:Archer C60,product_ver:1.0.0,special_id:00000000}\r\n"
820 "{product_name:Archer C60,product_ver:1.0.0,special_id:45550000}\r\n"
821 "{product_name:Archer C60,product_ver:1.0.0,special_id:55530000}\r\n",
822 .support_trail = '\x00',
823 .soft_ver = "soft_ver:1.0.0\n",
824
825 .partitions = {
826 {"fs-uboot", 0x00000, 0x10000},
827 {"default-mac", 0x10000, 0x00200},
828 {"pin", 0x10200, 0x00200},
829 {"product-info", 0x10400, 0x00100},
830 {"partition-table", 0x10500, 0x00800},
831 {"soft-version", 0x11300, 0x00200},
832 {"support-list", 0x11500, 0x00100},
833 {"device-id", 0x11600, 0x00100},
834 {"profile", 0x11700, 0x03900},
835 {"default-config", 0x15000, 0x04000},
836 {"user-config", 0x19000, 0x04000},
837 {"firmware", 0x20000, 0x7c8000},
838 {"certyficate", 0x7e8000, 0x08000},
839 {"radio", 0x7f0000, 0x10000},
840 {NULL, 0, 0}
841 },
842
843 .first_sysupgrade_partition = "os-image",
844 .last_sysupgrade_partition = "file-system",
845 },
846
847 /** Firmware layout for the C60v2 */
848 {
849 .id = "ARCHER-C60-V2",
850 .vendor = "",
851 .support_list =
852 "SupportList:\r\n"
853 "{product_name:Archer C60,product_ver:2.0.0,special_id:42520000}\r\n"
854 "{product_name:Archer C60,product_ver:2.0.0,special_id:45550000}\r\n"
855 "{product_name:Archer C60,product_ver:2.0.0,special_id:55530000}\r\n",
856 .support_trail = '\x00',
857 .soft_ver = "soft_ver:2.0.0\n",
858
859 .partitions = {
860 {"factory-boot", 0x00000, 0x1fb00},
861 {"default-mac", 0x1fb00, 0x00200},
862 {"pin", 0x1fd00, 0x00100},
863 {"product-info", 0x1fe00, 0x00100},
864 {"device-id", 0x1ff00, 0x00100},
865 {"fs-uboot", 0x20000, 0x10000},
866 {"firmware", 0x30000, 0x7a0000},
867 {"soft-version", 0x7d9500, 0x00100},
868 {"support-list", 0x7d9600, 0x00100},
869 {"extra-para", 0x7d9700, 0x00100},
870 {"profile", 0x7d9800, 0x03000},
871 {"default-config", 0x7dc800, 0x03000},
872 {"partition-table", 0x7df800, 0x00800},
873 {"user-config", 0x7e0000, 0x0c000},
874 {"certificate", 0x7ec000, 0x04000},
875 {"radio", 0x7f0000, 0x10000},
876 {NULL, 0, 0}
877 },
878
879 .first_sysupgrade_partition = "os-image",
880 .last_sysupgrade_partition = "file-system",
881 },
882
883 /** Firmware layout for the C5 */
884 {
885 .id = "ARCHER-C5-V2",
886 .vendor = "",
887 .support_list =
888 "SupportList:\r\n"
889 "{product_name:ArcherC5,product_ver:2.0.0,special_id:00000000}\r\n"
890 "{product_name:ArcherC5,product_ver:2.0.0,special_id:55530000}\r\n"
891 "{product_name:ArcherC5,product_ver:2.0.0,special_id:4A500000}\r\n", /* JP version */
892 .support_trail = '\x00',
893 .soft_ver = NULL,
894
895 .partitions = {
896 {"fs-uboot", 0x00000, 0x40000},
897 {"os-image", 0x40000, 0x200000},
898 {"file-system", 0x240000, 0xc00000},
899 {"default-mac", 0xe40000, 0x00200},
900 {"pin", 0xe40200, 0x00200},
901 {"product-info", 0xe40400, 0x00200},
902 {"partition-table", 0xe50000, 0x10000},
903 {"soft-version", 0xe60000, 0x00200},
904 {"support-list", 0xe61000, 0x0f000},
905 {"profile", 0xe70000, 0x10000},
906 {"default-config", 0xe80000, 0x10000},
907 {"user-config", 0xe90000, 0x50000},
908 {"log", 0xee0000, 0x100000},
909 {"radio_bk", 0xfe0000, 0x10000},
910 {"radio", 0xff0000, 0x10000},
911 {NULL, 0, 0}
912 },
913
914 .first_sysupgrade_partition = "os-image",
915 .last_sysupgrade_partition = "file-system"
916 },
917
918 /** Firmware layout for the C7 */
919 {
920 .id = "ARCHER-C7-V4",
921 .support_list =
922 "SupportList:\n"
923 "{product_name:Archer C7,product_ver:4.0.0,special_id:00000000}\n"
924 "{product_name:Archer C7,product_ver:4.0.0,special_id:41550000}\n"
925 "{product_name:Archer C7,product_ver:4.0.0,special_id:45550000}\n"
926 "{product_name:Archer C7,product_ver:4.0.0,special_id:4B520000}\n"
927 "{product_name:Archer C7,product_ver:4.0.0,special_id:42520000}\n"
928 "{product_name:Archer C7,product_ver:4.0.0,special_id:4A500000}\n"
929 "{product_name:Archer C7,product_ver:4.0.0,special_id:52550000}\n"
930 "{product_name:Archer C7,product_ver:4.0.0,special_id:54570000}\n"
931 "{product_name:Archer C7,product_ver:4.0.0,special_id:55530000}\n"
932 "{product_name:Archer C7,product_ver:4.0.0,special_id:43410000}\n",
933 .support_trail = '\x00',
934 .soft_ver = "soft_ver:1.0.0\n",
935
936 /* We're using a dynamic kernel/rootfs split here */
937 .partitions = {
938 {"factory-boot", 0x00000, 0x20000},
939 {"fs-uboot", 0x20000, 0x20000},
940 {"firmware", 0x40000, 0xEC0000}, /* Stock: name os-image base 0x40000 size 0x120000 */
941 /* Stock: name file-system base 0x160000 size 0xda0000 */
942 {"default-mac", 0xf00000, 0x00200},
943 {"pin", 0xf00200, 0x00200},
944 {"device-id", 0xf00400, 0x00100},
945 {"product-info", 0xf00500, 0x0fb00},
946 {"soft-version", 0xf10000, 0x00100},
947 {"extra-para", 0xf11000, 0x01000},
948 {"support-list", 0xf12000, 0x0a000},
949 {"profile", 0xf1c000, 0x04000},
950 {"default-config", 0xf20000, 0x10000},
951 {"user-config", 0xf30000, 0x40000},
952 {"qos-db", 0xf70000, 0x40000},
953 {"certificate", 0xfb0000, 0x10000},
954 {"partition-table", 0xfc0000, 0x10000},
955 {"log", 0xfd0000, 0x20000},
956 {"radio", 0xff0000, 0x10000},
957 {NULL, 0, 0}
958 },
959
960 .first_sysupgrade_partition = "os-image",
961 .last_sysupgrade_partition = "file-system",
962 },
963
964 /** Firmware layout for the C7 v5*/
965 {
966 .id = "ARCHER-C7-V5",
967 .support_list =
968 "SupportList:\n"
969 "{product_name:Archer C7,product_ver:5.0.0,special_id:00000000}\n"
970 "{product_name:Archer C7,product_ver:5.0.0,special_id:45550000}\n"
971 "{product_name:Archer C7,product_ver:5.0.0,special_id:55530000}\n"
972 "{product_name:Archer C7,product_ver:5.0.0,special_id:43410000}\n"
973 "{product_name:Archer C7,product_ver:5.0.0,special_id:4A500000}\n"
974 "{product_name:Archer C7,product_ver:5.0.0,special_id:54570000}\n"
975 "{product_name:Archer C7,product_ver:5.0.0,special_id:52550000}\n"
976 "{product_name:Archer C7,product_ver:5.0.0,special_id:4B520000}\n",
977
978 .support_trail = '\x00',
979 .soft_ver = "soft_ver:1.0.0\n",
980
981 /* We're using a dynamic kernel/rootfs split here */
982 .partitions = {
983 {"factory-boot", 0x00000, 0x20000},
984 {"fs-uboot", 0x20000, 0x20000},
985 {"partition-table", 0x40000, 0x10000},
986 {"radio", 0x50000, 0x10000},
987 {"default-mac", 0x60000, 0x00200},
988 {"pin", 0x60200, 0x00200},
989 {"device-id", 0x60400, 0x00100},
990 {"product-info", 0x60500, 0x0fb00},
991 {"soft-version", 0x70000, 0x01000},
992 {"extra-para", 0x71000, 0x01000},
993 {"support-list", 0x72000, 0x0a000},
994 {"profile", 0x7c000, 0x04000},
995 {"user-config", 0x80000, 0x40000},
996
997
998 {"firmware", 0xc0000, 0xf00000}, /* Stock: name os-image base 0xc0000 size 0x120000 */
999 /* Stock: name file-system base 0x1e0000 size 0xde0000 */
1000
1001 {"log", 0xfc0000, 0x20000},
1002 {"certificate", 0xfe0000, 0x10000},
1003 {"default-config", 0xff0000, 0x10000},
1004 {NULL, 0, 0}
1005
1006 },
1007
1008 .first_sysupgrade_partition = "os-image",
1009 .last_sysupgrade_partition = "file-system",
1010 },
1011
1012 /** Firmware layout for the C9 */
1013 {
1014 .id = "ARCHERC9",
1015 .vendor = "",
1016 .support_list =
1017 "SupportList:\n"
1018 "{product_name:ArcherC9,"
1019 "product_ver:1.0.0,"
1020 "special_id:00000000}\n",
1021 .support_trail = '\x00',
1022 .soft_ver = NULL,
1023
1024 .partitions = {
1025 {"fs-uboot", 0x00000, 0x40000},
1026 {"os-image", 0x40000, 0x200000},
1027 {"file-system", 0x240000, 0xc00000},
1028 {"default-mac", 0xe40000, 0x00200},
1029 {"pin", 0xe40200, 0x00200},
1030 {"product-info", 0xe40400, 0x00200},
1031 {"partition-table", 0xe50000, 0x10000},
1032 {"soft-version", 0xe60000, 0x00200},
1033 {"support-list", 0xe61000, 0x0f000},
1034 {"profile", 0xe70000, 0x10000},
1035 {"default-config", 0xe80000, 0x10000},
1036 {"user-config", 0xe90000, 0x50000},
1037 {"log", 0xee0000, 0x100000},
1038 {"radio_bk", 0xfe0000, 0x10000},
1039 {"radio", 0xff0000, 0x10000},
1040 {NULL, 0, 0}
1041 },
1042
1043 .first_sysupgrade_partition = "os-image",
1044 .last_sysupgrade_partition = "file-system"
1045 },
1046
1047 /** Firmware layout for the EAP120 */
1048 {
1049 .id = "EAP120",
1050 .vendor = "EAP120(TP-LINK|UN|N300-2):1.0\r\n",
1051 .support_list =
1052 "SupportList:\r\n"
1053 "EAP120(TP-LINK|UN|N300-2):1.0\r\n",
1054 .support_trail = '\xff',
1055 .soft_ver = NULL,
1056
1057 .partitions = {
1058 {"fs-uboot", 0x00000, 0x20000},
1059 {"partition-table", 0x20000, 0x02000},
1060 {"default-mac", 0x30000, 0x00020},
1061 {"support-list", 0x31000, 0x00100},
1062 {"product-info", 0x31100, 0x00100},
1063 {"soft-version", 0x32000, 0x00100},
1064 {"os-image", 0x40000, 0x180000},
1065 {"file-system", 0x1c0000, 0x600000},
1066 {"user-config", 0x7c0000, 0x10000},
1067 {"backup-config", 0x7d0000, 0x10000},
1068 {"log", 0x7e0000, 0x10000},
1069 {"radio", 0x7f0000, 0x10000},
1070 {NULL, 0, 0}
1071 },
1072
1073 .first_sysupgrade_partition = "os-image",
1074 .last_sysupgrade_partition = "file-system"
1075 },
1076
1077 /** Firmware layout for the TL-WA850RE v2 */
1078 {
1079 .id = "TLWA850REV2",
1080 .vendor = "",
1081 .support_list =
1082 "SupportList:\n"
1083 "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:55530000}\n"
1084 "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:00000000}\n"
1085 "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:55534100}\n"
1086 "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:45550000}\n"
1087 "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:4B520000}\n"
1088 "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:42520000}\n"
1089 "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:4A500000}\n"
1090 "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:43410000}\n"
1091 "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:41550000}\n"
1092 "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:52550000}\n",
1093 .support_trail = '\x00',
1094 .soft_ver = NULL,
1095
1096 /**
1097 576KB were moved from file-system to os-image
1098 in comparison to the stock image
1099 */
1100 .partitions = {
1101 {"fs-uboot", 0x00000, 0x20000},
1102 {"os-image", 0x20000, 0x150000},
1103 {"file-system", 0x170000, 0x240000},
1104 {"partition-table", 0x3b0000, 0x02000},
1105 {"default-mac", 0x3c0000, 0x00020},
1106 {"pin", 0x3c0100, 0x00020},
1107 {"product-info", 0x3c1000, 0x01000},
1108 {"soft-version", 0x3c2000, 0x00100},
1109 {"support-list", 0x3c3000, 0x01000},
1110 {"profile", 0x3c4000, 0x08000},
1111 {"user-config", 0x3d0000, 0x10000},
1112 {"default-config", 0x3e0000, 0x10000},
1113 {"radio", 0x3f0000, 0x10000},
1114 {NULL, 0, 0}
1115 },
1116
1117 .first_sysupgrade_partition = "os-image",
1118 .last_sysupgrade_partition = "file-system"
1119 },
1120
1121 /** Firmware layout for the TL-WA855RE v1 */
1122 {
1123 .id = "TLWA855REV1",
1124 .vendor = "",
1125 .support_list =
1126 "SupportList:\n"
1127 "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:00000000}\n"
1128 "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:55530000}\n"
1129 "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:45550000}\n"
1130 "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:4B520000}\n"
1131 "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:42520000}\n"
1132 "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:4A500000}\n"
1133 "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:43410000}\n"
1134 "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:41550000}\n"
1135 "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:52550000}\n",
1136 .support_trail = '\x00',
1137 .soft_ver = NULL,
1138
1139 .partitions = {
1140 {"fs-uboot", 0x00000, 0x20000},
1141 {"os-image", 0x20000, 0x150000},
1142 {"file-system", 0x170000, 0x240000},
1143 {"partition-table", 0x3b0000, 0x02000},
1144 {"default-mac", 0x3c0000, 0x00020},
1145 {"pin", 0x3c0100, 0x00020},
1146 {"product-info", 0x3c1000, 0x01000},
1147 {"soft-version", 0x3c2000, 0x00100},
1148 {"support-list", 0x3c3000, 0x01000},
1149 {"profile", 0x3c4000, 0x08000},
1150 {"user-config", 0x3d0000, 0x10000},
1151 {"default-config", 0x3e0000, 0x10000},
1152 {"radio", 0x3f0000, 0x10000},
1153 {NULL, 0, 0}
1154 },
1155
1156 .first_sysupgrade_partition = "os-image",
1157 .last_sysupgrade_partition = "file-system"
1158 },
1159
1160 /** Firmware layout for the TL-WR1043 v5 */
1161 {
1162 .id = "TLWR1043NV5",
1163 .vendor = "",
1164 .support_list =
1165 "SupportList:\n"
1166 "{product_name:TL-WR1043N,product_ver:5.0.0,special_id:45550000}\n"
1167 "{product_name:TL-WR1043N,product_ver:5.0.0,special_id:55530000}\n",
1168 .support_trail = '\x00',
1169 .soft_ver = "soft_ver:1.0.0\n",
1170 .partitions = {
1171 {"factory-boot", 0x00000, 0x20000},
1172 {"fs-uboot", 0x20000, 0x20000},
1173 {"firmware", 0x40000, 0xec0000},
1174 {"default-mac", 0xf00000, 0x00200},
1175 {"pin", 0xf00200, 0x00200},
1176 {"device-id", 0xf00400, 0x00100},
1177 {"product-info", 0xf00500, 0x0fb00},
1178 {"soft-version", 0xf10000, 0x01000},
1179 {"extra-para", 0xf11000, 0x01000},
1180 {"support-list", 0xf12000, 0x0a000},
1181 {"profile", 0xf1c000, 0x04000},
1182 {"default-config", 0xf20000, 0x10000},
1183 {"user-config", 0xf30000, 0x40000},
1184 {"qos-db", 0xf70000, 0x40000},
1185 {"certificate", 0xfb0000, 0x10000},
1186 {"partition-table", 0xfc0000, 0x10000},
1187 {"log", 0xfd0000, 0x20000},
1188 {"radio", 0xff0000, 0x10000},
1189 {NULL, 0, 0}
1190 },
1191 .first_sysupgrade_partition = "os-image",
1192 .last_sysupgrade_partition = "file-system"
1193 },
1194
1195 /** Firmware layout for the TL-WR1043 v4 */
1196 {
1197 .id = "TLWR1043NDV4",
1198 .vendor = "",
1199 .support_list =
1200 "SupportList:\n"
1201 "{product_name:TL-WR1043ND,product_ver:4.0.0,special_id:45550000}\n",
1202 .support_trail = '\x00',
1203 .soft_ver = NULL,
1204
1205 /* We're using a dynamic kernel/rootfs split here */
1206 .partitions = {
1207 {"fs-uboot", 0x00000, 0x20000},
1208 {"firmware", 0x20000, 0xf30000},
1209 {"default-mac", 0xf50000, 0x00200},
1210 {"pin", 0xf50200, 0x00200},
1211 {"product-info", 0xf50400, 0x0fc00},
1212 {"soft-version", 0xf60000, 0x0b000},
1213 {"support-list", 0xf6b000, 0x04000},
1214 {"profile", 0xf70000, 0x04000},
1215 {"default-config", 0xf74000, 0x0b000},
1216 {"user-config", 0xf80000, 0x40000},
1217 {"partition-table", 0xfc0000, 0x10000},
1218 {"log", 0xfd0000, 0x20000},
1219 {"radio", 0xff0000, 0x10000},
1220 {NULL, 0, 0}
1221 },
1222
1223 .first_sysupgrade_partition = "os-image",
1224 .last_sysupgrade_partition = "file-system"
1225 },
1226
1227 /** Firmware layout for the TL-WR902AC v1 */
1228 {
1229 .id = "TL-WR902AC-V1",
1230 .vendor = "",
1231 .support_list =
1232 "SupportList:\n"
1233 "{product_name:TL-WR902AC,product_ver:1.0.0,special_id:45550000}\n"
1234 "{product_name:TL-WR902AC,product_ver:1.0.0,special_id:55530000}\n",
1235 .support_trail = '\x00',
1236 .soft_ver = NULL,
1237
1238 /**
1239 384KB were moved from file-system to os-image
1240 in comparison to the stock image
1241 */
1242 .partitions = {
1243 {"fs-uboot", 0x00000, 0x20000},
1244 {"firmware", 0x20000, 0x730000},
1245 {"default-mac", 0x750000, 0x00200},
1246 {"pin", 0x750200, 0x00200},
1247 {"product-info", 0x750400, 0x0fc00},
1248 {"soft-version", 0x760000, 0x0b000},
1249 {"support-list", 0x76b000, 0x04000},
1250 {"profile", 0x770000, 0x04000},
1251 {"default-config", 0x774000, 0x0b000},
1252 {"user-config", 0x780000, 0x40000},
1253 {"partition-table", 0x7c0000, 0x10000},
1254 {"log", 0x7d0000, 0x20000},
1255 {"radio", 0x7f0000, 0x10000},
1256 {NULL, 0, 0}
1257 },
1258
1259 .first_sysupgrade_partition = "os-image",
1260 .last_sysupgrade_partition = "file-system",
1261 },
1262
1263 /** Firmware layout for the TL-WR942N V1 */
1264 {
1265 .id = "TLWR942NV1",
1266 .vendor = "",
1267 .support_list =
1268 "SupportList:\r\n"
1269 "{product_name:TL-WR942N,product_ver:1.0.0,special_id:00000000}\r\n"
1270 "{product_name:TL-WR942N,product_ver:1.0.0,special_id:52550000}\r\n",
1271 .support_trail = '\x00',
1272 .soft_ver = NULL,
1273
1274 .partitions = {
1275 {"fs-uboot", 0x00000, 0x20000},
1276 {"firmware", 0x20000, 0xe20000},
1277 {"default-mac", 0xe40000, 0x00200},
1278 {"pin", 0xe40200, 0x00200},
1279 {"product-info", 0xe40400, 0x0fc00},
1280 {"partition-table", 0xe50000, 0x10000},
1281 {"soft-version", 0xe60000, 0x10000},
1282 {"support-list", 0xe70000, 0x10000},
1283 {"profile", 0xe80000, 0x10000},
1284 {"default-config", 0xe90000, 0x10000},
1285 {"user-config", 0xea0000, 0x40000},
1286 {"qos-db", 0xee0000, 0x40000},
1287 {"certificate", 0xf20000, 0x10000},
1288 {"usb-config", 0xfb0000, 0x10000},
1289 {"log", 0xfc0000, 0x20000},
1290 {"radio-bk", 0xfe0000, 0x10000},
1291 {"radio", 0xff0000, 0x10000},
1292 {NULL, 0, 0}
1293 },
1294
1295 .first_sysupgrade_partition = "os-image",
1296 .last_sysupgrade_partition = "file-system",
1297 },
1298
1299 /** Firmware layout for the RE350 v1 */
1300 {
1301 .id = "RE350-V1",
1302 .vendor = "",
1303 .support_list =
1304 "SupportList:\n"
1305 "{product_name:RE350,product_ver:1.0.0,special_id:45550000}\n"
1306 "{product_name:RE350,product_ver:1.0.0,special_id:00000000}\n"
1307 "{product_name:RE350,product_ver:1.0.0,special_id:41550000}\n"
1308 "{product_name:RE350,product_ver:1.0.0,special_id:55530000}\n"
1309 "{product_name:RE350,product_ver:1.0.0,special_id:43410000}\n"
1310 "{product_name:RE350,product_ver:1.0.0,special_id:4b520000}\n"
1311 "{product_name:RE350,product_ver:1.0.0,special_id:4a500000}\n",
1312 .support_trail = '\x00',
1313 .soft_ver = NULL,
1314
1315 /** We're using a dynamic kernel/rootfs split here */
1316 .partitions = {
1317 {"fs-uboot", 0x00000, 0x20000},
1318 {"firmware", 0x20000, 0x5e0000},
1319 {"partition-table", 0x600000, 0x02000},
1320 {"default-mac", 0x610000, 0x00020},
1321 {"pin", 0x610100, 0x00020},
1322 {"product-info", 0x611100, 0x01000},
1323 {"soft-version", 0x620000, 0x01000},
1324 {"support-list", 0x621000, 0x01000},
1325 {"profile", 0x622000, 0x08000},
1326 {"user-config", 0x630000, 0x10000},
1327 {"default-config", 0x640000, 0x10000},
1328 {"radio", 0x7f0000, 0x10000},
1329 {NULL, 0, 0}
1330 },
1331
1332 .first_sysupgrade_partition = "os-image",
1333 .last_sysupgrade_partition = "file-system"
1334 },
1335
1336 /** Firmware layout for the RE350K v1 */
1337 {
1338 .id = "RE350K-V1",
1339 .vendor = "",
1340 .support_list =
1341 "SupportList:\n"
1342 "{product_name:RE350K,product_ver:1.0.0,special_id:00000000,product_region:US}\n",
1343 .support_trail = '\x00',
1344 .soft_ver = NULL,
1345
1346 /** We're using a dynamic kernel/rootfs split here */
1347 .partitions = {
1348 {"fs-uboot", 0x00000, 0x20000},
1349 {"firmware", 0x20000, 0xd70000},
1350 {"partition-table", 0xd90000, 0x02000},
1351 {"default-mac", 0xda0000, 0x00020},
1352 {"pin", 0xda0100, 0x00020},
1353 {"product-info", 0xda1100, 0x01000},
1354 {"soft-version", 0xdb0000, 0x01000},
1355 {"support-list", 0xdb1000, 0x01000},
1356 {"profile", 0xdb2000, 0x08000},
1357 {"user-config", 0xdc0000, 0x10000},
1358 {"default-config", 0xdd0000, 0x10000},
1359 {"device-id", 0xde0000, 0x00108},
1360 {"radio", 0xff0000, 0x10000},
1361 {NULL, 0, 0}
1362 },
1363
1364 .first_sysupgrade_partition = "os-image",
1365 .last_sysupgrade_partition = "file-system"
1366 },
1367
1368 /** Firmware layout for the RE355 */
1369 {
1370 .id = "RE355",
1371 .vendor = "",
1372 .support_list =
1373 "SupportList:\r\n"
1374 "{product_name:RE355,product_ver:1.0.0,special_id:00000000}\r\n"
1375 "{product_name:RE355,product_ver:1.0.0,special_id:55530000}\r\n"
1376 "{product_name:RE355,product_ver:1.0.0,special_id:45550000}\r\n"
1377 "{product_name:RE355,product_ver:1.0.0,special_id:4A500000}\r\n"
1378 "{product_name:RE355,product_ver:1.0.0,special_id:43410000}\r\n"
1379 "{product_name:RE355,product_ver:1.0.0,special_id:41550000}\r\n"
1380 "{product_name:RE355,product_ver:1.0.0,special_id:4B520000}\r\n"
1381 "{product_name:RE355,product_ver:1.0.0,special_id:55534100}\r\n",
1382 .support_trail = '\x00',
1383 .soft_ver = NULL,
1384
1385 /* We're using a dynamic kernel/rootfs split here */
1386 .partitions = {
1387 {"fs-uboot", 0x00000, 0x20000},
1388 {"firmware", 0x20000, 0x5e0000},
1389 {"partition-table", 0x600000, 0x02000},
1390 {"default-mac", 0x610000, 0x00020},
1391 {"pin", 0x610100, 0x00020},
1392 {"product-info", 0x611100, 0x01000},
1393 {"soft-version", 0x620000, 0x01000},
1394 {"support-list", 0x621000, 0x01000},
1395 {"profile", 0x622000, 0x08000},
1396 {"user-config", 0x630000, 0x10000},
1397 {"default-config", 0x640000, 0x10000},
1398 {"radio", 0x7f0000, 0x10000},
1399 {NULL, 0, 0}
1400 },
1401
1402 .first_sysupgrade_partition = "os-image",
1403 .last_sysupgrade_partition = "file-system"
1404 },
1405
1406 /** Firmware layout for the RE450 */
1407 {
1408 .id = "RE450",
1409 .vendor = "",
1410 .support_list =
1411 "SupportList:\r\n"
1412 "{product_name:RE450,product_ver:1.0.0,special_id:00000000}\r\n"
1413 "{product_name:RE450,product_ver:1.0.0,special_id:55530000}\r\n"
1414 "{product_name:RE450,product_ver:1.0.0,special_id:45550000}\r\n"
1415 "{product_name:RE450,product_ver:1.0.0,special_id:4A500000}\r\n"
1416 "{product_name:RE450,product_ver:1.0.0,special_id:43410000}\r\n"
1417 "{product_name:RE450,product_ver:1.0.0,special_id:41550000}\r\n"
1418 "{product_name:RE450,product_ver:1.0.0,special_id:4B520000}\r\n"
1419 "{product_name:RE450,product_ver:1.0.0,special_id:55534100}\r\n",
1420 .support_trail = '\x00',
1421 .soft_ver = NULL,
1422
1423 /** We're using a dynamic kernel/rootfs split here */
1424 .partitions = {
1425 {"fs-uboot", 0x00000, 0x20000},
1426 {"firmware", 0x20000, 0x5e0000},
1427 {"partition-table", 0x600000, 0x02000},
1428 {"default-mac", 0x610000, 0x00020},
1429 {"pin", 0x610100, 0x00020},
1430 {"product-info", 0x611100, 0x01000},
1431 {"soft-version", 0x620000, 0x01000},
1432 {"support-list", 0x621000, 0x01000},
1433 {"profile", 0x622000, 0x08000},
1434 {"user-config", 0x630000, 0x10000},
1435 {"default-config", 0x640000, 0x10000},
1436 {"radio", 0x7f0000, 0x10000},
1437 {NULL, 0, 0}
1438 },
1439
1440 .first_sysupgrade_partition = "os-image",
1441 .last_sysupgrade_partition = "file-system"
1442 },
1443
1444 /** Firmware layout for the RE450 v2 */
1445 {
1446 .id = "RE450-V2",
1447 .vendor = "",
1448 .support_list =
1449 "SupportList:\r\n"
1450 "{product_name:RE450,product_ver:2.0.0,special_id:00000000}\r\n"
1451 "{product_name:RE450,product_ver:2.0.0,special_id:55530000}\r\n"
1452 "{product_name:RE450,product_ver:2.0.0,special_id:45550000}\r\n"
1453 "{product_name:RE450,product_ver:2.0.0,special_id:4A500000}\r\n"
1454 "{product_name:RE450,product_ver:2.0.0,special_id:43410000}\r\n"
1455 "{product_name:RE450,product_ver:2.0.0,special_id:41550000}\r\n"
1456 "{product_name:RE450,product_ver:2.0.0,special_id:41530000}\r\n"
1457 "{product_name:RE450,product_ver:2.0.0,special_id:4B520000}\r\n"
1458 "{product_name:RE450,product_ver:2.0.0,special_id:42520000}\r\n",
1459 .support_trail = '\x00',
1460 .soft_ver = NULL,
1461
1462 /* We're using a dynamic kernel/rootfs split here */
1463 .partitions = {
1464 {"fs-uboot", 0x00000, 0x20000},
1465 {"firmware", 0x20000, 0x5e0000},
1466 {"partition-table", 0x600000, 0x02000},
1467 {"default-mac", 0x610000, 0x00020},
1468 {"pin", 0x610100, 0x00020},
1469 {"product-info", 0x611100, 0x01000},
1470 {"soft-version", 0x620000, 0x01000},
1471 {"support-list", 0x621000, 0x01000},
1472 {"profile", 0x622000, 0x08000},
1473 {"user-config", 0x630000, 0x10000},
1474 {"default-config", 0x640000, 0x10000},
1475 {"radio", 0x7f0000, 0x10000},
1476
1477 {NULL, 0, 0}
1478 },
1479
1480 .first_sysupgrade_partition = "os-image",
1481 .last_sysupgrade_partition = "file-system"
1482 },
1483
1484 /** Firmware layout for the RE650 */
1485 {
1486 .id = "RE650-V1",
1487 .vendor = "",
1488 .support_list =
1489 "SupportList:\r\n"
1490 "{product_name:RE650,product_ver:1.0.0,special_id:00000000}\r\n"
1491 "{product_name:RE650,product_ver:1.0.0,special_id:55530000}\r\n"
1492 "{product_name:RE650,product_ver:1.0.0,special_id:45550000}\r\n"
1493 "{product_name:RE650,product_ver:1.0.0,special_id:4A500000}\r\n"
1494 "{product_name:RE650,product_ver:1.0.0,special_id:43410000}\r\n"
1495 "{product_name:RE650,product_ver:1.0.0,special_id:41550000}\r\n"
1496 "{product_name:RE650,product_ver:1.0.0,special_id:41530000}\r\n",
1497 .support_trail = '\x00',
1498 .soft_ver = NULL,
1499
1500 /* We're using a dynamic kernel/rootfs split here */
1501 .partitions = {
1502 {"fs-uboot", 0x00000, 0x20000},
1503 {"firmware", 0x20000, 0xde0000},
1504 {"partition-table", 0xe00000, 0x02000},
1505 {"default-mac", 0xe10000, 0x00020},
1506 {"pin", 0xe10100, 0x00020},
1507 {"product-info", 0xe11100, 0x01000},
1508 {"soft-version", 0xe20000, 0x01000},
1509 {"support-list", 0xe21000, 0x01000},
1510 {"profile", 0xe22000, 0x08000},
1511 {"user-config", 0xe30000, 0x10000},
1512 {"default-config", 0xe40000, 0x10000},
1513 {"radio", 0xff0000, 0x10000},
1514 {NULL, 0, 0}
1515 },
1516
1517 .first_sysupgrade_partition = "os-image",
1518 .last_sysupgrade_partition = "file-system"
1519 },
1520
1521 {}
1522 };
1523
1524 #define error(_ret, _errno, _str, ...) \
1525 do { \
1526 fprintf(stderr, _str ": %s\n", ## __VA_ARGS__, \
1527 strerror(_errno)); \
1528 if (_ret) \
1529 exit(_ret); \
1530 } while (0)
1531
1532
1533 /** Stores a uint32 as big endian */
1534 static inline void put32(uint8_t *buf, uint32_t val) {
1535 buf[0] = val >> 24;
1536 buf[1] = val >> 16;
1537 buf[2] = val >> 8;
1538 buf[3] = val;
1539 }
1540
1541 /** Allocates a new image partition */
1542 static struct image_partition_entry alloc_image_partition(const char *name, size_t len) {
1543 struct image_partition_entry entry = {name, len, malloc(len)};
1544 if (!entry.data)
1545 error(1, errno, "malloc");
1546
1547 return entry;
1548 }
1549
1550 /** Frees an image partition */
1551 static void free_image_partition(struct image_partition_entry entry) {
1552 free(entry.data);
1553 }
1554
1555 static time_t source_date_epoch = -1;
1556 static void set_source_date_epoch() {
1557 char *env = getenv("SOURCE_DATE_EPOCH");
1558 char *endptr = env;
1559 errno = 0;
1560 if (env && *env) {
1561 source_date_epoch = strtoull(env, &endptr, 10);
1562 if (errno || (endptr && *endptr != '\0')) {
1563 fprintf(stderr, "Invalid SOURCE_DATE_EPOCH");
1564 exit(1);
1565 }
1566 }
1567 }
1568
1569 /** Generates the partition-table partition */
1570 static struct image_partition_entry make_partition_table(const struct flash_partition_entry *p) {
1571 struct image_partition_entry entry = alloc_image_partition("partition-table", 0x800);
1572
1573 char *s = (char *)entry.data, *end = (char *)(s+entry.size);
1574
1575 *(s++) = 0x00;
1576 *(s++) = 0x04;
1577 *(s++) = 0x00;
1578 *(s++) = 0x00;
1579
1580 size_t i;
1581 for (i = 0; p[i].name; i++) {
1582 size_t len = end-s;
1583 size_t w = snprintf(s, len, "partition %s base 0x%05x size 0x%05x\n", p[i].name, p[i].base, p[i].size);
1584
1585 if (w > len-1)
1586 error(1, 0, "flash partition table overflow?");
1587
1588 s += w;
1589 }
1590
1591 s++;
1592
1593 memset(s, 0xff, end-s);
1594
1595 return entry;
1596 }
1597
1598
1599 /** Generates a binary-coded decimal representation of an integer in the range [0, 99] */
1600 static inline uint8_t bcd(uint8_t v) {
1601 return 0x10 * (v/10) + v%10;
1602 }
1603
1604
1605 /** Generates the soft-version partition */
1606 static struct image_partition_entry make_soft_version(uint32_t rev) {
1607 struct image_partition_entry entry = alloc_image_partition("soft-version", sizeof(struct soft_version));
1608 struct soft_version *s = (struct soft_version *)entry.data;
1609
1610 time_t t;
1611
1612 if (source_date_epoch != -1)
1613 t = source_date_epoch;
1614 else if (time(&t) == (time_t)(-1))
1615 error(1, errno, "time");
1616
1617 struct tm *tm = localtime(&t);
1618
1619 s->magic = htonl(0x0000000c);
1620 s->zero = 0;
1621 s->pad1 = 0xff;
1622
1623 s->version_major = 0;
1624 s->version_minor = 0;
1625 s->version_patch = 0;
1626
1627 s->year_hi = bcd((1900+tm->tm_year)/100);
1628 s->year_lo = bcd(tm->tm_year%100);
1629 s->month = bcd(tm->tm_mon+1);
1630 s->day = bcd(tm->tm_mday);
1631 s->rev = htonl(rev);
1632
1633 s->pad2 = 0xff;
1634
1635 return entry;
1636 }
1637
1638 static struct image_partition_entry make_soft_version_from_string(const char *soft_ver) {
1639 /** String length _including_ the terminating zero byte */
1640 uint32_t ver_len = strlen(soft_ver) + 1;
1641 /** Partition contains 64 bit header, the version string, and one additional null byte */
1642 size_t partition_len = 2*sizeof(uint32_t) + ver_len + 1;
1643 struct image_partition_entry entry = alloc_image_partition("soft-version", partition_len);
1644
1645 uint32_t *len = (uint32_t *)entry.data;
1646 len[0] = htonl(ver_len);
1647 len[1] = 0;
1648 memcpy(&len[2], soft_ver, ver_len);
1649
1650 entry.data[partition_len - 1] = 0;
1651
1652 return entry;
1653 }
1654
1655 /** Generates the support-list partition */
1656 static struct image_partition_entry make_support_list(struct device_info *info) {
1657 size_t len = strlen(info->support_list);
1658 struct image_partition_entry entry = alloc_image_partition("support-list", len + 9);
1659
1660 put32(entry.data, len);
1661 memset(entry.data+4, 0, 4);
1662 memcpy(entry.data+8, info->support_list, len);
1663 entry.data[len+8] = info->support_trail;
1664
1665 return entry;
1666 }
1667
1668 /** Creates a new image partition with an arbitrary name from a file */
1669 static struct image_partition_entry read_file(const char *part_name, const char *filename, bool add_jffs2_eof, struct flash_partition_entry *file_system_partition) {
1670 struct stat statbuf;
1671
1672 if (stat(filename, &statbuf) < 0)
1673 error(1, errno, "unable to stat file `%s'", filename);
1674
1675 size_t len = statbuf.st_size;
1676
1677 if (add_jffs2_eof) {
1678 if (file_system_partition)
1679 len = ALIGN(len + file_system_partition->base, 0x10000) + sizeof(jffs2_eof_mark) - file_system_partition->base;
1680 else
1681 len = ALIGN(len, 0x10000) + sizeof(jffs2_eof_mark);
1682 }
1683
1684 struct image_partition_entry entry = alloc_image_partition(part_name, len);
1685
1686 FILE *file = fopen(filename, "rb");
1687 if (!file)
1688 error(1, errno, "unable to open file `%s'", filename);
1689
1690 if (fread(entry.data, statbuf.st_size, 1, file) != 1)
1691 error(1, errno, "unable to read file `%s'", filename);
1692
1693 if (add_jffs2_eof) {
1694 uint8_t *eof = entry.data + statbuf.st_size, *end = entry.data+entry.size;
1695
1696 memset(eof, 0xff, end - eof - sizeof(jffs2_eof_mark));
1697 memcpy(end - sizeof(jffs2_eof_mark), jffs2_eof_mark, sizeof(jffs2_eof_mark));
1698 }
1699
1700 fclose(file);
1701
1702 return entry;
1703 }
1704
1705 /** Creates a new image partition from arbitrary data */
1706 static struct image_partition_entry put_data(const char *part_name, const char *datain, size_t len) {
1707
1708 struct image_partition_entry entry = alloc_image_partition(part_name, len);
1709
1710 memcpy(entry.data, datain, len);
1711
1712 return entry;
1713 }
1714
1715 /**
1716 Copies a list of image partitions into an image buffer and generates the image partition table while doing so
1717
1718 Example image partition table:
1719
1720 fwup-ptn partition-table base 0x00800 size 0x00800
1721 fwup-ptn os-image base 0x01000 size 0x113b45
1722 fwup-ptn file-system base 0x114b45 size 0x1d0004
1723 fwup-ptn support-list base 0x2e4b49 size 0x000d1
1724
1725 Each line of the partition table is terminated with the bytes 09 0d 0a ("\t\r\n"),
1726 the end of the partition table is marked with a zero byte.
1727
1728 The firmware image must contain at least the partition-table and support-list partitions
1729 to be accepted. There aren't any alignment constraints for the image partitions.
1730
1731 The partition-table partition contains the actual flash layout; partitions
1732 from the image partition table are mapped to the corresponding flash partitions during
1733 the firmware upgrade. The support-list partition contains a list of devices supported by
1734 the firmware image.
1735
1736 The base offsets in the firmware partition table are relative to the end
1737 of the vendor information block, so the partition-table partition will
1738 actually start at offset 0x1814 of the image.
1739
1740 I think partition-table must be the first partition in the firmware image.
1741 */
1742 static void put_partitions(uint8_t *buffer, const struct flash_partition_entry *flash_parts, const struct image_partition_entry *parts) {
1743 size_t i, j;
1744 char *image_pt = (char *)buffer, *end = image_pt + 0x800;
1745
1746 size_t base = 0x800;
1747 for (i = 0; parts[i].name; i++) {
1748 for (j = 0; flash_parts[j].name; j++) {
1749 if (!strcmp(flash_parts[j].name, parts[i].name)) {
1750 if (parts[i].size > flash_parts[j].size)
1751 error(1, 0, "%s partition too big (more than %u bytes)", flash_parts[j].name, (unsigned)flash_parts[j].size);
1752 break;
1753 }
1754 }
1755
1756 assert(flash_parts[j].name);
1757
1758 memcpy(buffer + base, parts[i].data, parts[i].size);
1759
1760 size_t len = end-image_pt;
1761 size_t w = snprintf(image_pt, len, "fwup-ptn %s base 0x%05x size 0x%05x\t\r\n", parts[i].name, (unsigned)base, (unsigned)parts[i].size);
1762
1763 if (w > len-1)
1764 error(1, 0, "image partition table overflow?");
1765
1766 image_pt += w;
1767
1768 base += parts[i].size;
1769 }
1770 }
1771
1772 /** Generates and writes the image MD5 checksum */
1773 static void put_md5(uint8_t *md5, uint8_t *buffer, unsigned int len) {
1774 MD5_CTX ctx;
1775
1776 MD5_Init(&ctx);
1777 MD5_Update(&ctx, md5_salt, (unsigned int)sizeof(md5_salt));
1778 MD5_Update(&ctx, buffer, len);
1779 MD5_Final(md5, &ctx);
1780 }
1781
1782
1783 /**
1784 Generates the firmware image in factory format
1785
1786 Image format:
1787
1788 Bytes (hex) Usage
1789 ----------- -----
1790 0000-0003 Image size (4 bytes, big endian)
1791 0004-0013 MD5 hash (hash of a 16 byte salt and the image data starting with byte 0x14)
1792 0014-0017 Vendor information length (without padding) (4 bytes, big endian)
1793 0018-1013 Vendor information (4092 bytes, padded with 0xff; there seem to be older
1794 (VxWorks-based) TP-LINK devices which use a smaller vendor information block)
1795 1014-1813 Image partition table (2048 bytes, padded with 0xff)
1796 1814-xxxx Firmware partitions
1797 */
1798 static void * generate_factory_image(struct device_info *info, const struct image_partition_entry *parts, size_t *len) {
1799 *len = 0x1814;
1800
1801 size_t i;
1802 for (i = 0; parts[i].name; i++)
1803 *len += parts[i].size;
1804
1805 uint8_t *image = malloc(*len);
1806 if (!image)
1807 error(1, errno, "malloc");
1808
1809 memset(image, 0xff, *len);
1810 put32(image, *len);
1811
1812 if (info->vendor) {
1813 size_t vendor_len = strlen(info->vendor);
1814 put32(image+0x14, vendor_len);
1815 memcpy(image+0x18, info->vendor, vendor_len);
1816 }
1817
1818 put_partitions(image + 0x1014, info->partitions, parts);
1819 put_md5(image+0x04, image+0x14, *len-0x14);
1820
1821 return image;
1822 }
1823
1824 /**
1825 Generates the firmware image in sysupgrade format
1826
1827 This makes some assumptions about the provided flash and image partition tables and
1828 should be generalized when TP-LINK starts building its safeloader into hardware with
1829 different flash layouts.
1830 */
1831 static void * generate_sysupgrade_image(struct device_info *info, const struct image_partition_entry *image_parts, size_t *len) {
1832 size_t i, j;
1833 size_t flash_first_partition_index = 0;
1834 size_t flash_last_partition_index = 0;
1835 const struct flash_partition_entry *flash_first_partition = NULL;
1836 const struct flash_partition_entry *flash_last_partition = NULL;
1837 const struct image_partition_entry *image_last_partition = NULL;
1838
1839 /** Find first and last partitions */
1840 for (i = 0; info->partitions[i].name; i++) {
1841 if (!strcmp(info->partitions[i].name, info->first_sysupgrade_partition)) {
1842 flash_first_partition = &info->partitions[i];
1843 flash_first_partition_index = i;
1844 } else if (!strcmp(info->partitions[i].name, info->last_sysupgrade_partition)) {
1845 flash_last_partition = &info->partitions[i];
1846 flash_last_partition_index = i;
1847 }
1848 }
1849
1850 assert(flash_first_partition && flash_last_partition);
1851 assert(flash_first_partition_index < flash_last_partition_index);
1852
1853 /** Find last partition from image to calculate needed size */
1854 for (i = 0; image_parts[i].name; i++) {
1855 if (!strcmp(image_parts[i].name, info->last_sysupgrade_partition)) {
1856 image_last_partition = &image_parts[i];
1857 break;
1858 }
1859 }
1860
1861 assert(image_last_partition);
1862
1863 *len = flash_last_partition->base - flash_first_partition->base + image_last_partition->size;
1864
1865 uint8_t *image = malloc(*len);
1866 if (!image)
1867 error(1, errno, "malloc");
1868
1869 memset(image, 0xff, *len);
1870
1871 for (i = flash_first_partition_index; i <= flash_last_partition_index; i++) {
1872 for (j = 0; image_parts[j].name; j++) {
1873 if (!strcmp(info->partitions[i].name, image_parts[j].name)) {
1874 if (image_parts[j].size > info->partitions[i].size)
1875 error(1, 0, "%s partition too big (more than %u bytes)", info->partitions[i].name, (unsigned)info->partitions[i].size);
1876 memcpy(image + info->partitions[i].base - flash_first_partition->base, image_parts[j].data, image_parts[j].size);
1877 break;
1878 }
1879
1880 assert(image_parts[j].name);
1881 }
1882 }
1883
1884 return image;
1885 }
1886
1887 /** Generates an image according to a given layout and writes it to a file */
1888 static void build_image(const char *output,
1889 const char *kernel_image,
1890 const char *rootfs_image,
1891 uint32_t rev,
1892 bool add_jffs2_eof,
1893 bool sysupgrade,
1894 struct device_info *info) {
1895
1896 size_t i;
1897
1898 struct image_partition_entry parts[7] = {};
1899
1900 struct flash_partition_entry *firmware_partition = NULL;
1901 struct flash_partition_entry *os_image_partition = NULL;
1902 struct flash_partition_entry *file_system_partition = NULL;
1903 size_t firmware_partition_index = 0;
1904
1905 for (i = 0; info->partitions[i].name; i++) {
1906 if (!strcmp(info->partitions[i].name, "firmware"))
1907 {
1908 firmware_partition = &info->partitions[i];
1909 firmware_partition_index = i;
1910 }
1911 }
1912
1913 if (firmware_partition)
1914 {
1915 os_image_partition = &info->partitions[firmware_partition_index];
1916 file_system_partition = &info->partitions[firmware_partition_index + 1];
1917
1918 struct stat kernel;
1919 if (stat(kernel_image, &kernel) < 0)
1920 error(1, errno, "unable to stat file `%s'", kernel_image);
1921
1922 if (kernel.st_size > firmware_partition->size)
1923 error(1, 0, "kernel overflowed firmware partition\n");
1924
1925 for (i = MAX_PARTITIONS-1; i >= firmware_partition_index + 1; i--)
1926 info->partitions[i+1] = info->partitions[i];
1927
1928 file_system_partition->name = "file-system";
1929 file_system_partition->base = firmware_partition->base + kernel.st_size;
1930
1931 /* Align partition start to erase blocks for factory images only */
1932 if (!sysupgrade)
1933 file_system_partition->base = ALIGN(firmware_partition->base + kernel.st_size, 0x10000);
1934
1935 file_system_partition->size = firmware_partition->size - file_system_partition->base;
1936
1937 os_image_partition->name = "os-image";
1938 os_image_partition->size = kernel.st_size;
1939 }
1940
1941 parts[0] = make_partition_table(info->partitions);
1942 if (info->soft_ver)
1943 parts[1] = make_soft_version_from_string(info->soft_ver);
1944 else
1945 parts[1] = make_soft_version(rev);
1946
1947 parts[2] = make_support_list(info);
1948 parts[3] = read_file("os-image", kernel_image, false, NULL);
1949 parts[4] = read_file("file-system", rootfs_image, add_jffs2_eof, file_system_partition);
1950
1951 /* Some devices need the extra-para partition to accept the firmware */
1952 if (strcasecmp(info->id, "ARCHER-C2-V3") == 0 ||
1953 strcasecmp(info->id, "ARCHER-C25-V1") == 0 ||
1954 strcasecmp(info->id, "ARCHER-C59-V2") == 0 ||
1955 strcasecmp(info->id, "ARCHER-C60-V2") == 0 ||
1956 strcasecmp(info->id, "TLWR1043NV5") == 0) {
1957 const char mdat[11] = {0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00};
1958 parts[5] = put_data("extra-para", mdat, 11);
1959 } else if (strcasecmp(info->id, "ARCHER-A7-V5") == 0 || strcasecmp(info->id, "ARCHER-C7-V4") == 0 || strcasecmp(info->id, "ARCHER-C7-V5") == 0) {
1960 const char mdat[11] = {0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0xca, 0x00, 0x01, 0x00, 0x00};
1961 parts[5] = put_data("extra-para", mdat, 11);
1962 } else if (strcasecmp(info->id, "ARCHER-C6-V2") == 0) {
1963 const char mdat[11] = {0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00};
1964 parts[5] = put_data("extra-para", mdat, 11);
1965 }
1966
1967 size_t len;
1968 void *image;
1969 if (sysupgrade)
1970 image = generate_sysupgrade_image(info, parts, &len);
1971 else
1972 image = generate_factory_image(info, parts, &len);
1973
1974 FILE *file = fopen(output, "wb");
1975 if (!file)
1976 error(1, errno, "unable to open output file");
1977
1978 if (fwrite(image, len, 1, file) != 1)
1979 error(1, 0, "unable to write output file");
1980
1981 fclose(file);
1982
1983 free(image);
1984
1985 for (i = 0; parts[i].name; i++)
1986 free_image_partition(parts[i]);
1987 }
1988
1989 /** Usage output */
1990 static void usage(const char *argv0) {
1991 fprintf(stderr,
1992 "Usage: %s [OPTIONS...]\n"
1993 "\n"
1994 "Options:\n"
1995 " -h show this help\n"
1996 "\n"
1997 "Create a new image:\n"
1998 " -B <board> create image for the board specified with <board>\n"
1999 " -k <file> read kernel image from the file <file>\n"
2000 " -r <file> read rootfs image from the file <file>\n"
2001 " -o <file> write output to the file <file>\n"
2002 " -V <rev> sets the revision number to <rev>\n"
2003 " -j add jffs2 end-of-filesystem markers\n"
2004 " -S create sysupgrade instead of factory image\n"
2005 "Extract an old image:\n"
2006 " -x <file> extract all oem firmware partition\n"
2007 " -d <dir> destination to extract the firmware partition\n"
2008 " -z <file> convert an oem firmware into a sysupgade file. Use -o for output file\n",
2009 argv0
2010 );
2011 };
2012
2013
2014 static struct device_info *find_board(const char *id)
2015 {
2016 struct device_info *board = NULL;
2017
2018 for (board = boards; board->id != NULL; board++)
2019 if (strcasecmp(id, board->id) == 0)
2020 return board;
2021
2022 return NULL;
2023 }
2024
2025 static int add_flash_partition(
2026 struct flash_partition_entry *part_list,
2027 size_t max_entries,
2028 const char *name,
2029 unsigned long base,
2030 unsigned long size)
2031 {
2032 size_t ptr;
2033 /* check if the list has a free entry */
2034 for (ptr = 0; ptr < max_entries; ptr++, part_list++) {
2035 if (part_list->name == NULL &&
2036 part_list->base == 0 &&
2037 part_list->size == 0)
2038 break;
2039 }
2040
2041 if (ptr == max_entries) {
2042 error(1, 0, "No free flash part entry available.");
2043 }
2044
2045 part_list->name = calloc(1, strlen(name) + 1);
2046 if (!part_list->name) {
2047 error(1, 0, "Unable to allocate memory");
2048 }
2049
2050 memcpy((char *)part_list->name, name, strlen(name));
2051 part_list->base = base;
2052 part_list->size = size;
2053
2054 return 0;
2055 }
2056
2057 /** read the partition table into struct flash_partition_entry */
2058 static int read_partition_table(
2059 FILE *file, long offset,
2060 struct flash_partition_entry *entries, size_t max_entries,
2061 int type)
2062 {
2063 char buf[2048];
2064 char *ptr, *end;
2065 const char *parthdr = NULL;
2066 const char *fwuphdr = "fwup-ptn";
2067 const char *flashhdr = "partition";
2068
2069 /* TODO: search for the partition table */
2070
2071 switch(type) {
2072 case 0:
2073 parthdr = fwuphdr;
2074 break;
2075 case 1:
2076 parthdr = flashhdr;
2077 break;
2078 default:
2079 error(1, 0, "Invalid partition table");
2080 }
2081
2082 if (fseek(file, offset, SEEK_SET) < 0)
2083 error(1, errno, "Can not seek in the firmware");
2084
2085 if (fread(buf, 2048, 1, file) != 1)
2086 error(1, errno, "Can not read fwup-ptn from the firmware");
2087
2088 buf[2047] = '\0';
2089
2090 /* look for the partition header */
2091 if (memcmp(buf, parthdr, strlen(parthdr)) != 0) {
2092 fprintf(stderr, "DEBUG: can not find fwuphdr\n");
2093 return 1;
2094 }
2095
2096 ptr = buf;
2097 end = buf + sizeof(buf);
2098 while ((ptr + strlen(parthdr)) < end &&
2099 memcmp(ptr, parthdr, strlen(parthdr)) == 0) {
2100 char *end_part;
2101 char *end_element;
2102
2103 char name[32] = { 0 };
2104 int name_len = 0;
2105 unsigned long base = 0;
2106 unsigned long size = 0;
2107
2108 end_part = memchr(ptr, '\n', (end - ptr));
2109 if (end_part == NULL) {
2110 /* in theory this should never happen, because a partition always ends with 0x09, 0x0D, 0x0A */
2111 break;
2112 }
2113
2114 for (int i = 0; i <= 4; i++) {
2115 if (end_part <= ptr)
2116 break;
2117
2118 end_element = memchr(ptr, 0x20, (end_part - ptr));
2119 if (end_element == NULL) {
2120 error(1, errno, "Ignoring the rest of the partition entries.");
2121 break;
2122 }
2123
2124 switch (i) {
2125 /* partition header */
2126 case 0:
2127 ptr = end_element + 1;
2128 continue;
2129 /* name */
2130 case 1:
2131 name_len = (end_element - ptr) > 31 ? 31 : (end_element - ptr);
2132 strncpy(name, ptr, name_len);
2133 name[name_len] = '\0';
2134 ptr = end_element + 1;
2135 continue;
2136
2137 /* string "base" */
2138 case 2:
2139 ptr = end_element + 1;
2140 continue;
2141
2142 /* actual base */
2143 case 3:
2144 base = strtoul(ptr, NULL, 16);
2145 ptr = end_element + 1;
2146 continue;
2147
2148 /* string "size" */
2149 case 4:
2150 ptr = end_element + 1;
2151 /* actual size. The last element doesn't have a sepeartor */
2152 size = strtoul(ptr, NULL, 16);
2153 /* the part ends with 0x09, 0x0d, 0x0a */
2154 ptr = end_part + 1;
2155 add_flash_partition(entries, max_entries, name, base, size);
2156 continue;
2157 }
2158 }
2159 }
2160
2161 return 0;
2162 }
2163
2164 static void write_partition(
2165 FILE *input_file,
2166 size_t firmware_offset,
2167 struct flash_partition_entry *entry,
2168 FILE *output_file)
2169 {
2170 char buf[4096];
2171 size_t offset;
2172
2173 fseek(input_file, entry->base + firmware_offset, SEEK_SET);
2174
2175 for (offset = 0; sizeof(buf) + offset <= entry->size; offset += sizeof(buf)) {
2176 if (fread(buf, sizeof(buf), 1, input_file) != 1)
2177 error(1, errno, "Can not read partition from input_file");
2178
2179 if (fwrite(buf, sizeof(buf), 1, output_file) != 1)
2180 error(1, errno, "Can not write partition to output_file");
2181 }
2182 /* write last chunk smaller than buffer */
2183 if (offset < entry->size) {
2184 offset = entry->size - offset;
2185 if (fread(buf, offset, 1, input_file) != 1)
2186 error(1, errno, "Can not read partition from input_file");
2187 if (fwrite(buf, offset, 1, output_file) != 1)
2188 error(1, errno, "Can not write partition to output_file");
2189 }
2190 }
2191
2192 static int extract_firmware_partition(FILE *input_file, size_t firmware_offset, struct flash_partition_entry *entry, const char *output_directory)
2193 {
2194 FILE *output_file;
2195 char output[PATH_MAX];
2196
2197 snprintf(output, PATH_MAX, "%s/%s", output_directory, entry->name);
2198 output_file = fopen(output, "wb+");
2199 if (output_file == NULL) {
2200 error(1, errno, "Can not open output file %s", output);
2201 }
2202
2203 write_partition(input_file, firmware_offset, entry, output_file);
2204
2205 fclose(output_file);
2206
2207 return 0;
2208 }
2209
2210 /** extract all partitions from the firmware file */
2211 static int extract_firmware(const char *input, const char *output_directory)
2212 {
2213 struct flash_partition_entry entries[16] = { 0 };
2214 size_t max_entries = 16;
2215 size_t firmware_offset = 0x1014;
2216 FILE *input_file;
2217
2218 struct stat statbuf;
2219
2220 /* check input file */
2221 if (stat(input, &statbuf)) {
2222 error(1, errno, "Can not read input firmware %s", input);
2223 }
2224
2225 /* check if output directory exists */
2226 if (stat(output_directory, &statbuf)) {
2227 error(1, errno, "Failed to stat output directory %s", output_directory);
2228 }
2229
2230 if ((statbuf.st_mode & S_IFMT) != S_IFDIR) {
2231 error(1, errno, "Given output directory is not a directory %s", output_directory);
2232 }
2233
2234 input_file = fopen(input, "rb");
2235
2236 if (read_partition_table(input_file, firmware_offset, entries, 16, 0) != 0) {
2237 error(1, 0, "Error can not read the partition table (fwup-ptn)");
2238 }
2239
2240 for (size_t i = 0; i < max_entries; i++) {
2241 if (entries[i].name == NULL &&
2242 entries[i].base == 0 &&
2243 entries[i].size == 0)
2244 continue;
2245
2246 extract_firmware_partition(input_file, firmware_offset, &entries[i], output_directory);
2247 }
2248
2249 return 0;
2250 }
2251
2252 static struct flash_partition_entry *find_partition(
2253 struct flash_partition_entry *entries, size_t max_entries,
2254 const char *name, const char *error_msg)
2255 {
2256 for (size_t i = 0; i < max_entries; i++, entries++) {
2257 if (strcmp(entries->name, name) == 0)
2258 return entries;
2259 }
2260
2261 error(1, 0, "%s", error_msg);
2262 return NULL;
2263 }
2264
2265 static void write_ff(FILE *output_file, size_t size)
2266 {
2267 char buf[4096];
2268 size_t offset;
2269
2270 memset(buf, 0xff, sizeof(buf));
2271
2272 for (offset = 0; offset + sizeof(buf) < size ; offset += sizeof(buf)) {
2273 if (fwrite(buf, sizeof(buf), 1, output_file) != 1)
2274 error(1, errno, "Can not write 0xff to output_file");
2275 }
2276
2277 /* write last chunk smaller than buffer */
2278 if (offset < size) {
2279 offset = size - offset;
2280 if (fwrite(buf, offset, 1, output_file) != 1)
2281 error(1, errno, "Can not write partition to output_file");
2282 }
2283 }
2284
2285 static void convert_firmware(const char *input, const char *output)
2286 {
2287 struct flash_partition_entry fwup[MAX_PARTITIONS] = { 0 };
2288 struct flash_partition_entry flash[MAX_PARTITIONS] = { 0 };
2289 struct flash_partition_entry *fwup_os_image = NULL, *fwup_file_system = NULL;
2290 struct flash_partition_entry *flash_os_image = NULL, *flash_file_system = NULL;
2291 struct flash_partition_entry *fwup_partition_table = NULL;
2292 size_t firmware_offset = 0x1014;
2293 FILE *input_file, *output_file;
2294
2295 struct stat statbuf;
2296
2297 /* check input file */
2298 if (stat(input, &statbuf)) {
2299 error(1, errno, "Can not read input firmware %s", input);
2300 }
2301
2302 input_file = fopen(input, "rb");
2303 if (!input_file)
2304 error(1, 0, "Can not open input firmware %s", input);
2305
2306 output_file = fopen(output, "wb");
2307 if (!output_file)
2308 error(1, 0, "Can not open output firmware %s", output);
2309
2310 if (read_partition_table(input_file, firmware_offset, fwup, MAX_PARTITIONS, 0) != 0) {
2311 error(1, 0, "Error can not read the partition table (fwup-ptn)");
2312 }
2313
2314 fwup_os_image = find_partition(fwup, MAX_PARTITIONS,
2315 "os-image", "Error can not find os-image partition (fwup)");
2316 fwup_file_system = find_partition(fwup, MAX_PARTITIONS,
2317 "file-system", "Error can not find file-system partition (fwup)");
2318 fwup_partition_table = find_partition(fwup, MAX_PARTITIONS,
2319 "partition-table", "Error can not find partition-table partition");
2320
2321 /* the flash partition table has a 0x00000004 magic haeder */
2322 if (read_partition_table(input_file, firmware_offset + fwup_partition_table->base + 4, flash, MAX_PARTITIONS, 1) != 0)
2323 error(1, 0, "Error can not read the partition table (flash)");
2324
2325 flash_os_image = find_partition(flash, MAX_PARTITIONS,
2326 "os-image", "Error can not find os-image partition (flash)");
2327 flash_file_system = find_partition(flash, MAX_PARTITIONS,
2328 "file-system", "Error can not find file-system partition (flash)");
2329
2330 /* write os_image to 0x0 */
2331 write_partition(input_file, firmware_offset, fwup_os_image, output_file);
2332 write_ff(output_file, flash_os_image->size - fwup_os_image->size);
2333
2334 /* write file-system behind os_image */
2335 fseek(output_file, flash_file_system->base - flash_os_image->base, SEEK_SET);
2336 write_partition(input_file, firmware_offset, fwup_file_system, output_file);
2337 write_ff(output_file, flash_file_system->size - fwup_file_system->size);
2338
2339 fclose(output_file);
2340 fclose(input_file);
2341 }
2342
2343 int main(int argc, char *argv[]) {
2344 const char *board = NULL, *kernel_image = NULL, *rootfs_image = NULL, *output = NULL;
2345 const char *extract_image = NULL, *output_directory = NULL, *convert_image = NULL;
2346 bool add_jffs2_eof = false, sysupgrade = false;
2347 unsigned rev = 0;
2348 struct device_info *info;
2349 set_source_date_epoch();
2350
2351 while (true) {
2352 int c;
2353
2354 c = getopt(argc, argv, "B:k:r:o:V:jSh:x:d:z:");
2355 if (c == -1)
2356 break;
2357
2358 switch (c) {
2359 case 'B':
2360 board = optarg;
2361 break;
2362
2363 case 'k':
2364 kernel_image = optarg;
2365 break;
2366
2367 case 'r':
2368 rootfs_image = optarg;
2369 break;
2370
2371 case 'o':
2372 output = optarg;
2373 break;
2374
2375 case 'V':
2376 sscanf(optarg, "r%u", &rev);
2377 break;
2378
2379 case 'j':
2380 add_jffs2_eof = true;
2381 break;
2382
2383 case 'S':
2384 sysupgrade = true;
2385 break;
2386
2387 case 'h':
2388 usage(argv[0]);
2389 return 0;
2390
2391 case 'd':
2392 output_directory = optarg;
2393 break;
2394
2395 case 'x':
2396 extract_image = optarg;
2397 break;
2398
2399 case 'z':
2400 convert_image = optarg;
2401 break;
2402
2403 default:
2404 usage(argv[0]);
2405 return 1;
2406 }
2407 }
2408
2409 if (extract_image || output_directory) {
2410 if (!extract_image)
2411 error(1, 0, "No factory/oem image given via -x <file>. Output directory is only valid with -x");
2412 if (!output_directory)
2413 error(1, 0, "Can not extract an image without output directory. Use -d <dir>");
2414 extract_firmware(extract_image, output_directory);
2415 } else if (convert_image) {
2416 if (!output)
2417 error(1, 0, "Can not convert a factory/oem image into sysupgrade image without output file. Use -o <file>");
2418 convert_firmware(convert_image, output);
2419 } else {
2420 if (!board)
2421 error(1, 0, "no board has been specified");
2422 if (!kernel_image)
2423 error(1, 0, "no kernel image has been specified");
2424 if (!rootfs_image)
2425 error(1, 0, "no rootfs image has been specified");
2426 if (!output)
2427 error(1, 0, "no output filename has been specified");
2428
2429 info = find_board(board);
2430
2431 if (info == NULL)
2432 error(1, 0, "unsupported board %s", board);
2433
2434 build_image(output, kernel_image, rootfs_image, rev, add_jffs2_eof, sysupgrade, info);
2435 }
2436
2437 return 0;
2438 }