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