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