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