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