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