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