OpenWrt – Blame information for rev 4
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
4 | office | 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 | const 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 | const struct flash_partition_entry partitions[MAX_PARTITIONS+1]; |
||
81 | const char *first_sysupgrade_partition; |
||
82 | const char *last_sysupgrade_partition; |
||
83 | }; |
||
84 | |||
85 | /** The content of the soft-version structure */ |
||
86 | struct __attribute__((__packed__)) soft_version { |
||
87 | uint32_t magic; |
||
88 | uint32_t zero; |
||
89 | uint8_t pad1; |
||
90 | uint8_t version_major; |
||
91 | uint8_t version_minor; |
||
92 | uint8_t version_patch; |
||
93 | uint8_t year_hi; |
||
94 | uint8_t year_lo; |
||
95 | uint8_t month; |
||
96 | uint8_t day; |
||
97 | uint32_t rev; |
||
98 | uint8_t pad2; |
||
99 | }; |
||
100 | |||
101 | |||
102 | static const uint8_t jffs2_eof_mark[4] = {0xde, 0xad, 0xc0, 0xde}; |
||
103 | |||
104 | |||
105 | /** |
||
106 | Salt for the MD5 hash |
||
107 | |||
108 | Fortunately, TP-LINK seems to use the same salt for most devices which use |
||
109 | the new image format. |
||
110 | */ |
||
111 | static const uint8_t md5_salt[16] = { |
||
112 | 0x7a, 0x2b, 0x15, 0xed, |
||
113 | 0x9b, 0x98, 0x59, 0x6d, |
||
114 | 0xe5, 0x04, 0xab, 0x44, |
||
115 | 0xac, 0x2a, 0x9f, 0x4e, |
||
116 | }; |
||
117 | |||
118 | |||
119 | /** Firmware layout table */ |
||
120 | static struct device_info boards[] = { |
||
121 | /** Firmware layout for the CPE210/220 */ |
||
122 | { |
||
123 | .id = "CPE210", |
||
124 | .vendor = "CPE510(TP-LINK|UN|N300-5):1.0\r\n", |
||
125 | .support_list = |
||
126 | "SupportList:\r\n" |
||
127 | "CPE210(TP-LINK|UN|N300-2):1.0\r\n" |
||
128 | "CPE210(TP-LINK|UN|N300-2):1.1\r\n" |
||
129 | "CPE210(TP-LINK|US|N300-2):1.1\r\n" |
||
130 | "CPE210(TP-LINK|EU|N300-2):1.1\r\n" |
||
131 | "CPE220(TP-LINK|UN|N300-2):1.1\r\n" |
||
132 | "CPE220(TP-LINK|US|N300-2):1.1\r\n" |
||
133 | "CPE220(TP-LINK|EU|N300-2):1.1\r\n", |
||
134 | .support_trail = '\xff', |
||
135 | .soft_ver = NULL, |
||
136 | |||
137 | .partitions = { |
||
138 | {"fs-uboot", 0x00000, 0x20000}, |
||
139 | {"partition-table", 0x20000, 0x02000}, |
||
140 | {"default-mac", 0x30000, 0x00020}, |
||
141 | {"product-info", 0x31100, 0x00100}, |
||
142 | {"signature", 0x32000, 0x00400}, |
||
143 | {"os-image", 0x40000, 0x1c0000}, |
||
144 | {"file-system", 0x200000, 0x5b0000}, |
||
145 | {"soft-version", 0x7b0000, 0x00100}, |
||
146 | {"support-list", 0x7b1000, 0x00400}, |
||
147 | {"user-config", 0x7c0000, 0x10000}, |
||
148 | {"default-config", 0x7d0000, 0x10000}, |
||
149 | {"log", 0x7e0000, 0x10000}, |
||
150 | {"radio", 0x7f0000, 0x10000}, |
||
151 | {NULL, 0, 0} |
||
152 | }, |
||
153 | |||
154 | .first_sysupgrade_partition = "os-image", |
||
155 | .last_sysupgrade_partition = "support-list", |
||
156 | }, |
||
157 | |||
158 | /** Firmware layout for the CPE210 V2 */ |
||
159 | { |
||
160 | .id = "CPE210V2", |
||
161 | .vendor = "CPE210(TP-LINK|UN|N300-2|00000000):2.0\r\n", |
||
162 | .support_list = |
||
163 | "SupportList:\r\n" |
||
164 | "CPE210(TP-LINK|EU|N300-2|00000000):2.0\r\n" |
||
165 | "CPE210(TP-LINK|EU|N300-2|45550000):2.0\r\n" |
||
166 | "CPE210(TP-LINK|EU|N300-2|55530000):2.0\r\n" |
||
167 | "CPE210(TP-LINK|UN|N300-2|00000000):2.0\r\n" |
||
168 | "CPE210(TP-LINK|UN|N300-2|45550000):2.0\r\n" |
||
169 | "CPE210(TP-LINK|UN|N300-2|55530000):2.0\r\n" |
||
170 | "CPE210(TP-LINK|US|N300-2|55530000):2.0\r\n" |
||
171 | "CPE210(TP-LINK|UN|N300-2):2.0\r\n" |
||
172 | "CPE210(TP-LINK|EU|N300-2):2.0\r\n" |
||
173 | "CPE210(TP-LINK|US|N300-2):2.0\r\n", |
||
174 | .support_trail = '\xff', |
||
175 | .soft_ver = NULL, |
||
176 | |||
177 | .partitions = { |
||
178 | {"fs-uboot", 0x00000, 0x20000}, |
||
179 | {"partition-table", 0x20000, 0x02000}, |
||
180 | {"default-mac", 0x30000, 0x00020}, |
||
181 | {"product-info", 0x31100, 0x00100}, |
||
182 | {"device-info", 0x31400, 0x00400}, |
||
183 | {"signature", 0x32000, 0x00400}, |
||
184 | {"device-id", 0x33000, 0x00100}, |
||
185 | {"os-image", 0x40000, 0x1c0000}, |
||
186 | {"file-system", 0x200000, 0x5b0000}, |
||
187 | {"soft-version", 0x7b0000, 0x00100}, |
||
188 | {"support-list", 0x7b1000, 0x01000}, |
||
189 | {"user-config", 0x7c0000, 0x10000}, |
||
190 | {"default-config", 0x7d0000, 0x10000}, |
||
191 | {"log", 0x7e0000, 0x10000}, |
||
192 | {"radio", 0x7f0000, 0x10000}, |
||
193 | {NULL, 0, 0} |
||
194 | }, |
||
195 | |||
196 | .first_sysupgrade_partition = "os-image", |
||
197 | .last_sysupgrade_partition = "support-list", |
||
198 | }, |
||
199 | |||
200 | /** Firmware layout for the CPE510/520 */ |
||
201 | { |
||
202 | .id = "CPE510", |
||
203 | .vendor = "CPE510(TP-LINK|UN|N300-5):1.0\r\n", |
||
204 | .support_list = |
||
205 | "SupportList:\r\n" |
||
206 | "CPE510(TP-LINK|UN|N300-5):1.0\r\n" |
||
207 | "CPE510(TP-LINK|UN|N300-5):1.1\r\n" |
||
208 | "CPE510(TP-LINK|UN|N300-5):1.1\r\n" |
||
209 | "CPE510(TP-LINK|US|N300-5):1.1\r\n" |
||
210 | "CPE510(TP-LINK|EU|N300-5):1.1\r\n" |
||
211 | "CPE520(TP-LINK|UN|N300-5):1.1\r\n" |
||
212 | "CPE520(TP-LINK|US|N300-5):1.1\r\n" |
||
213 | "CPE520(TP-LINK|EU|N300-5):1.1\r\n", |
||
214 | .support_trail = '\xff', |
||
215 | .soft_ver = NULL, |
||
216 | |||
217 | .partitions = { |
||
218 | {"fs-uboot", 0x00000, 0x20000}, |
||
219 | {"partition-table", 0x20000, 0x02000}, |
||
220 | {"default-mac", 0x30000, 0x00020}, |
||
221 | {"product-info", 0x31100, 0x00100}, |
||
222 | {"signature", 0x32000, 0x00400}, |
||
223 | {"os-image", 0x40000, 0x1c0000}, |
||
224 | {"file-system", 0x200000, 0x5b0000}, |
||
225 | {"soft-version", 0x7b0000, 0x00100}, |
||
226 | {"support-list", 0x7b1000, 0x00400}, |
||
227 | {"user-config", 0x7c0000, 0x10000}, |
||
228 | {"default-config", 0x7d0000, 0x10000}, |
||
229 | {"log", 0x7e0000, 0x10000}, |
||
230 | {"radio", 0x7f0000, 0x10000}, |
||
231 | {NULL, 0, 0} |
||
232 | }, |
||
233 | |||
234 | .first_sysupgrade_partition = "os-image", |
||
235 | .last_sysupgrade_partition = "support-list", |
||
236 | }, |
||
237 | |||
238 | { |
||
239 | .id = "WBS210", |
||
240 | .vendor = "CPE510(TP-LINK|UN|N300-5):1.0\r\n", |
||
241 | .support_list = |
||
242 | "SupportList:\r\n" |
||
243 | "WBS210(TP-LINK|UN|N300-2):1.20\r\n" |
||
244 | "WBS210(TP-LINK|US|N300-2):1.20\r\n" |
||
245 | "WBS210(TP-LINK|EU|N300-2):1.20\r\n", |
||
246 | .support_trail = '\xff', |
||
247 | .soft_ver = NULL, |
||
248 | |||
249 | .partitions = { |
||
250 | {"fs-uboot", 0x00000, 0x20000}, |
||
251 | {"partition-table", 0x20000, 0x02000}, |
||
252 | {"default-mac", 0x30000, 0x00020}, |
||
253 | {"product-info", 0x31100, 0x00100}, |
||
254 | {"signature", 0x32000, 0x00400}, |
||
255 | {"os-image", 0x40000, 0x1c0000}, |
||
256 | {"file-system", 0x200000, 0x5b0000}, |
||
257 | {"soft-version", 0x7b0000, 0x00100}, |
||
258 | {"support-list", 0x7b1000, 0x00400}, |
||
259 | {"user-config", 0x7c0000, 0x10000}, |
||
260 | {"default-config", 0x7d0000, 0x10000}, |
||
261 | {"log", 0x7e0000, 0x10000}, |
||
262 | {"radio", 0x7f0000, 0x10000}, |
||
263 | {NULL, 0, 0} |
||
264 | }, |
||
265 | |||
266 | .first_sysupgrade_partition = "os-image", |
||
267 | .last_sysupgrade_partition = "support-list", |
||
268 | }, |
||
269 | |||
270 | { |
||
271 | .id = "WBS510", |
||
272 | .vendor = "CPE510(TP-LINK|UN|N300-5):1.0\r\n", |
||
273 | .support_list = |
||
274 | "SupportList:\r\n" |
||
275 | "WBS510(TP-LINK|UN|N300-5):1.20\r\n" |
||
276 | "WBS510(TP-LINK|US|N300-5):1.20\r\n" |
||
277 | "WBS510(TP-LINK|EU|N300-5):1.20\r\n", |
||
278 | .support_trail = '\xff', |
||
279 | .soft_ver = NULL, |
||
280 | |||
281 | .partitions = { |
||
282 | {"fs-uboot", 0x00000, 0x20000}, |
||
283 | {"partition-table", 0x20000, 0x02000}, |
||
284 | {"default-mac", 0x30000, 0x00020}, |
||
285 | {"product-info", 0x31100, 0x00100}, |
||
286 | {"signature", 0x32000, 0x00400}, |
||
287 | {"os-image", 0x40000, 0x1c0000}, |
||
288 | {"file-system", 0x200000, 0x5b0000}, |
||
289 | {"soft-version", 0x7b0000, 0x00100}, |
||
290 | {"support-list", 0x7b1000, 0x00400}, |
||
291 | {"user-config", 0x7c0000, 0x10000}, |
||
292 | {"default-config", 0x7d0000, 0x10000}, |
||
293 | {"log", 0x7e0000, 0x10000}, |
||
294 | {"radio", 0x7f0000, 0x10000}, |
||
295 | {NULL, 0, 0} |
||
296 | }, |
||
297 | |||
298 | .first_sysupgrade_partition = "os-image", |
||
299 | .last_sysupgrade_partition = "support-list", |
||
300 | }, |
||
301 | |||
302 | /** Firmware layout for the C2600 */ |
||
303 | { |
||
304 | .id = "C2600", |
||
305 | .vendor = "", |
||
306 | .support_list = |
||
307 | "SupportList:\r\n" |
||
308 | "{product_name:Archer C2600,product_ver:1.0.0,special_id:00000000}\r\n", |
||
309 | .support_trail = '\x00', |
||
310 | .soft_ver = NULL, |
||
311 | |||
312 | /** |
||
313 | We use a bigger os-image partition than the stock images (and thus |
||
314 | smaller file-system), as our kernel doesn't fit in the stock firmware's |
||
315 | 2 MB os-image since kernel 4.14. |
||
316 | */ |
||
317 | .partitions = { |
||
318 | {"SBL1", 0x00000, 0x20000}, |
||
319 | {"MIBIB", 0x20000, 0x20000}, |
||
320 | {"SBL2", 0x40000, 0x20000}, |
||
321 | {"SBL3", 0x60000, 0x30000}, |
||
322 | {"DDRCONFIG", 0x90000, 0x10000}, |
||
323 | {"SSD", 0xa0000, 0x10000}, |
||
324 | {"TZ", 0xb0000, 0x30000}, |
||
325 | {"RPM", 0xe0000, 0x20000}, |
||
326 | {"fs-uboot", 0x100000, 0x70000}, |
||
327 | {"uboot-env", 0x170000, 0x40000}, |
||
328 | {"radio", 0x1b0000, 0x40000}, |
||
329 | {"os-image", 0x1f0000, 0x400000}, /* Stock: base 0x1f0000 size 0x200000 */ |
||
330 | {"file-system", 0x5f0000, 0x1900000}, /* Stock: base 0x3f0000 size 0x1b00000 */ |
||
331 | {"default-mac", 0x1ef0000, 0x00200}, |
||
332 | {"pin", 0x1ef0200, 0x00200}, |
||
333 | {"product-info", 0x1ef0400, 0x0fc00}, |
||
334 | {"partition-table", 0x1f00000, 0x10000}, |
||
335 | {"soft-version", 0x1f10000, 0x10000}, |
||
336 | {"support-list", 0x1f20000, 0x10000}, |
||
337 | {"profile", 0x1f30000, 0x10000}, |
||
338 | {"default-config", 0x1f40000, 0x10000}, |
||
339 | {"user-config", 0x1f50000, 0x40000}, |
||
340 | {"qos-db", 0x1f90000, 0x40000}, |
||
341 | {"usb-config", 0x1fd0000, 0x10000}, |
||
342 | {"log", 0x1fe0000, 0x20000}, |
||
343 | {NULL, 0, 0} |
||
344 | }, |
||
345 | |||
346 | .first_sysupgrade_partition = "os-image", |
||
347 | .last_sysupgrade_partition = "file-system" |
||
348 | }, |
||
349 | |||
350 | /** Firmware layout for the C25v1 */ |
||
351 | { |
||
352 | .id = "ARCHER-C25-V1", |
||
353 | .support_list = |
||
354 | "SupportList:\n" |
||
355 | "{product_name:ArcherC25,product_ver:1.0.0,special_id:00000000}\n" |
||
356 | "{product_name:ArcherC25,product_ver:1.0.0,special_id:55530000}\n" |
||
357 | "{product_name:ArcherC25,product_ver:1.0.0,special_id:45550000}\n", |
||
358 | .support_trail = '\x00', |
||
359 | .soft_ver = "soft_ver:1.0.0\n", |
||
360 | |||
361 | /** |
||
362 | We use a bigger os-image partition than the stock images (and thus |
||
363 | smaller file-system), as our kernel doesn't fit in the stock firmware's |
||
364 | 1MB os-image. |
||
365 | */ |
||
366 | .partitions = { |
||
367 | {"factory-boot", 0x00000, 0x20000}, |
||
368 | {"fs-uboot", 0x20000, 0x10000}, |
||
369 | {"os-image", 0x30000, 0x180000}, /* Stock: base 0x30000 size 0x100000 */ |
||
370 | {"file-system", 0x1b0000, 0x620000}, /* Stock: base 0x130000 size 0x6a0000 */ |
||
371 | {"user-config", 0x7d0000, 0x04000}, |
||
372 | {"default-mac", 0x7e0000, 0x00100}, |
||
373 | {"device-id", 0x7e0100, 0x00100}, |
||
374 | {"extra-para", 0x7e0200, 0x00100}, |
||
375 | {"pin", 0x7e0300, 0x00100}, |
||
376 | {"support-list", 0x7e0400, 0x00400}, |
||
377 | {"soft-version", 0x7e0800, 0x00400}, |
||
378 | {"product-info", 0x7e0c00, 0x01400}, |
||
379 | {"partition-table", 0x7e2000, 0x01000}, |
||
380 | {"profile", 0x7e3000, 0x01000}, |
||
381 | {"default-config", 0x7e4000, 0x04000}, |
||
382 | {"merge-config", 0x7ec000, 0x02000}, |
||
383 | {"qos-db", 0x7ee000, 0x02000}, |
||
384 | {"radio", 0x7f0000, 0x10000}, |
||
385 | {NULL, 0, 0} |
||
386 | }, |
||
387 | |||
388 | .first_sysupgrade_partition = "os-image", |
||
389 | .last_sysupgrade_partition = "file-system", |
||
390 | }, |
||
391 | |||
392 | /** Firmware layout for the C58v1 */ |
||
393 | { |
||
394 | .id = "ARCHER-C58-V1", |
||
395 | .vendor = "", |
||
396 | .support_list = |
||
397 | "SupportList:\r\n" |
||
398 | "{product_name:Archer C58,product_ver:1.0.0,special_id:00000000}\r\n" |
||
399 | "{product_name:Archer C58,product_ver:1.0.0,special_id:45550000}\r\n" |
||
400 | "{product_name:Archer C58,product_ver:1.0.0,special_id:55530000}\r\n", |
||
401 | .support_trail = '\x00', |
||
402 | .soft_ver = "soft_ver:1.0.0\n", |
||
403 | |||
404 | .partitions = { |
||
405 | {"fs-uboot", 0x00000, 0x10000}, |
||
406 | {"default-mac", 0x10000, 0x00200}, |
||
407 | {"pin", 0x10200, 0x00200}, |
||
408 | {"product-info", 0x10400, 0x00100}, |
||
409 | {"partition-table", 0x10500, 0x00800}, |
||
410 | {"soft-version", 0x11300, 0x00200}, |
||
411 | {"support-list", 0x11500, 0x00100}, |
||
412 | {"device-id", 0x11600, 0x00100}, |
||
413 | {"profile", 0x11700, 0x03900}, |
||
414 | {"default-config", 0x15000, 0x04000}, |
||
415 | {"user-config", 0x19000, 0x04000}, |
||
416 | {"os-image", 0x20000, 0x180000}, |
||
417 | {"file-system", 0x1a0000, 0x648000}, |
||
418 | {"certyficate", 0x7e8000, 0x08000}, |
||
419 | {"radio", 0x7f0000, 0x10000}, |
||
420 | {NULL, 0, 0} |
||
421 | }, |
||
422 | |||
423 | .first_sysupgrade_partition = "os-image", |
||
424 | .last_sysupgrade_partition = "file-system", |
||
425 | }, |
||
426 | |||
427 | /** Firmware layout for the C59v1 */ |
||
428 | { |
||
429 | .id = "ARCHER-C59-V1", |
||
430 | .vendor = "", |
||
431 | .support_list = |
||
432 | "SupportList:\r\n" |
||
433 | "{product_name:Archer C59,product_ver:1.0.0,special_id:00000000}\r\n" |
||
434 | "{product_name:Archer C59,product_ver:1.0.0,special_id:45550000}\r\n" |
||
435 | "{product_name:Archer C59,product_ver:1.0.0,special_id:52550000}\r\n" |
||
436 | "{product_name:Archer C59,product_ver:1.0.0,special_id:55530000}\r\n", |
||
437 | .support_trail = '\x00', |
||
438 | .soft_ver = "soft_ver:1.0.0\n", |
||
439 | |||
440 | .partitions = { |
||
441 | {"fs-uboot", 0x00000, 0x10000}, |
||
442 | {"default-mac", 0x10000, 0x00200}, |
||
443 | {"pin", 0x10200, 0x00200}, |
||
444 | {"device-id", 0x10400, 0x00100}, |
||
445 | {"product-info", 0x10500, 0x0fb00}, |
||
446 | {"os-image", 0x20000, 0x180000}, |
||
447 | {"file-system", 0x1a0000, 0xcb0000}, |
||
448 | {"partition-table", 0xe50000, 0x10000}, |
||
449 | {"soft-version", 0xe60000, 0x10000}, |
||
450 | {"support-list", 0xe70000, 0x10000}, |
||
451 | {"profile", 0xe80000, 0x10000}, |
||
452 | {"default-config", 0xe90000, 0x10000}, |
||
453 | {"user-config", 0xea0000, 0x40000}, |
||
454 | {"usb-config", 0xee0000, 0x10000}, |
||
455 | {"certificate", 0xef0000, 0x10000}, |
||
456 | {"qos-db", 0xf00000, 0x40000}, |
||
457 | {"log", 0xfe0000, 0x10000}, |
||
458 | {"radio", 0xff0000, 0x10000}, |
||
459 | {NULL, 0, 0} |
||
460 | }, |
||
461 | |||
462 | .first_sysupgrade_partition = "os-image", |
||
463 | .last_sysupgrade_partition = "file-system", |
||
464 | }, |
||
465 | |||
466 | /** Firmware layout for the C60v1 */ |
||
467 | { |
||
468 | .id = "ARCHER-C60-V1", |
||
469 | .vendor = "", |
||
470 | .support_list = |
||
471 | "SupportList:\r\n" |
||
472 | "{product_name:Archer C60,product_ver:1.0.0,special_id:00000000}\r\n" |
||
473 | "{product_name:Archer C60,product_ver:1.0.0,special_id:45550000}\r\n" |
||
474 | "{product_name:Archer C60,product_ver:1.0.0,special_id:55530000}\r\n", |
||
475 | .support_trail = '\x00', |
||
476 | .soft_ver = "soft_ver:1.0.0\n", |
||
477 | |||
478 | .partitions = { |
||
479 | {"fs-uboot", 0x00000, 0x10000}, |
||
480 | {"default-mac", 0x10000, 0x00200}, |
||
481 | {"pin", 0x10200, 0x00200}, |
||
482 | {"product-info", 0x10400, 0x00100}, |
||
483 | {"partition-table", 0x10500, 0x00800}, |
||
484 | {"soft-version", 0x11300, 0x00200}, |
||
485 | {"support-list", 0x11500, 0x00100}, |
||
486 | {"device-id", 0x11600, 0x00100}, |
||
487 | {"profile", 0x11700, 0x03900}, |
||
488 | {"default-config", 0x15000, 0x04000}, |
||
489 | {"user-config", 0x19000, 0x04000}, |
||
490 | {"os-image", 0x20000, 0x180000}, |
||
491 | {"file-system", 0x1a0000, 0x648000}, |
||
492 | {"certyficate", 0x7e8000, 0x08000}, |
||
493 | {"radio", 0x7f0000, 0x10000}, |
||
494 | {NULL, 0, 0} |
||
495 | }, |
||
496 | |||
497 | .first_sysupgrade_partition = "os-image", |
||
498 | .last_sysupgrade_partition = "file-system", |
||
499 | }, |
||
500 | |||
501 | /** Firmware layout for the C60v2 */ |
||
502 | { |
||
503 | .id = "ARCHER-C60-V2", |
||
504 | .vendor = "", |
||
505 | .support_list = |
||
506 | "SupportList:\r\n" |
||
507 | "{product_name:Archer C60,product_ver:2.0.0,special_id:42520000}\r\n" |
||
508 | "{product_name:Archer C60,product_ver:2.0.0,special_id:45550000}\r\n" |
||
509 | "{product_name:Archer C60,product_ver:2.0.0,special_id:55530000}\r\n", |
||
510 | .support_trail = '\x00', |
||
511 | .soft_ver = "soft_ver:2.0.0\n", |
||
512 | |||
513 | .partitions = { |
||
514 | {"factory-boot", 0x00000, 0x1fb00}, |
||
515 | {"default-mac", 0x1fb00, 0x00200}, |
||
516 | {"pin", 0x1fd00, 0x00100}, |
||
517 | {"product-info", 0x1fe00, 0x00100}, |
||
518 | {"device-id", 0x1ff00, 0x00100}, |
||
519 | {"fs-uboot", 0x20000, 0x10000}, |
||
520 | {"os-image", 0x30000, 0x180000}, |
||
521 | {"file-system", 0x1b0000, 0x620000}, |
||
522 | {"soft-version", 0x7d9500, 0x00100}, |
||
523 | {"support-list", 0x7d9600, 0x00100}, |
||
524 | {"extra-para", 0x7d9700, 0x00100}, |
||
525 | {"profile", 0x7d9800, 0x03000}, |
||
526 | {"default-config", 0x7dc800, 0x03000}, |
||
527 | {"partition-table", 0x7df800, 0x00800}, |
||
528 | {"user-config", 0x7e0000, 0x0c000}, |
||
529 | {"certificate", 0x7ec000, 0x04000}, |
||
530 | {"radio", 0x7f0000, 0x10000}, |
||
531 | {NULL, 0, 0} |
||
532 | }, |
||
533 | |||
534 | .first_sysupgrade_partition = "os-image", |
||
535 | .last_sysupgrade_partition = "file-system", |
||
536 | }, |
||
537 | |||
538 | /** Firmware layout for the C5 */ |
||
539 | { |
||
540 | .id = "ARCHER-C5-V2", |
||
541 | .vendor = "", |
||
542 | .support_list = |
||
543 | "SupportList:\r\n" |
||
544 | "{product_name:ArcherC5,product_ver:2.0.0,special_id:00000000}\r\n" |
||
545 | "{product_name:ArcherC5,product_ver:2.0.0,special_id:55530000}\r\n" |
||
546 | "{product_name:ArcherC5,product_ver:2.0.0,special_id:4A500000}\r\n", /* JP version */ |
||
547 | .support_trail = '\x00', |
||
548 | .soft_ver = NULL, |
||
549 | |||
550 | .partitions = { |
||
551 | {"fs-uboot", 0x00000, 0x40000}, |
||
552 | {"os-image", 0x40000, 0x200000}, |
||
553 | {"file-system", 0x240000, 0xc00000}, |
||
554 | {"default-mac", 0xe40000, 0x00200}, |
||
555 | {"pin", 0xe40200, 0x00200}, |
||
556 | {"product-info", 0xe40400, 0x00200}, |
||
557 | {"partition-table", 0xe50000, 0x10000}, |
||
558 | {"soft-version", 0xe60000, 0x00200}, |
||
559 | {"support-list", 0xe61000, 0x0f000}, |
||
560 | {"profile", 0xe70000, 0x10000}, |
||
561 | {"default-config", 0xe80000, 0x10000}, |
||
562 | {"user-config", 0xe90000, 0x50000}, |
||
563 | {"log", 0xee0000, 0x100000}, |
||
564 | {"radio_bk", 0xfe0000, 0x10000}, |
||
565 | {"radio", 0xff0000, 0x10000}, |
||
566 | {NULL, 0, 0} |
||
567 | }, |
||
568 | |||
569 | .first_sysupgrade_partition = "os-image", |
||
570 | .last_sysupgrade_partition = "file-system" |
||
571 | }, |
||
572 | |||
573 | /** Firmware layout for the C7 */ |
||
574 | { |
||
575 | .id = "ARCHER-C7-V4", |
||
576 | .support_list = |
||
577 | "SupportList:\n" |
||
578 | "{product_name:Archer C7,product_ver:4.0.0,special_id:00000000}\n" |
||
579 | "{product_name:Archer C7,product_ver:4.0.0,special_id:41550000}\n" |
||
580 | "{product_name:Archer C7,product_ver:4.0.0,special_id:45550000}\n" |
||
581 | "{product_name:Archer C7,product_ver:4.0.0,special_id:4B520000}\n" |
||
582 | "{product_name:Archer C7,product_ver:4.0.0,special_id:42520000}\n" |
||
583 | "{product_name:Archer C7,product_ver:4.0.0,special_id:4A500000}\n" |
||
584 | "{product_name:Archer C7,product_ver:4.0.0,special_id:52550000}\n" |
||
585 | "{product_name:Archer C7,product_ver:4.0.0,special_id:54570000}\n" |
||
586 | "{product_name:Archer C7,product_ver:4.0.0,special_id:55530000}\n" |
||
587 | "{product_name:Archer C7,product_ver:4.0.0,special_id:43410000}\n", |
||
588 | .support_trail = '\x00', |
||
589 | .soft_ver = "soft_ver:1.0.0\n", |
||
590 | |||
591 | /** |
||
592 | We use a bigger os-image partition than the stock images (and thus |
||
593 | smaller file-system), as our kernel doesn't fit in the stock firmware's |
||
594 | 1MB os-image. |
||
595 | */ |
||
596 | .partitions = { |
||
597 | {"factory-boot", 0x00000, 0x20000}, |
||
598 | {"fs-uboot", 0x20000, 0x20000}, |
||
599 | {"os-image", 0x40000, 0x180000}, /* Stock: base 0x40000 size 0x120000 */ |
||
600 | {"file-system", 0x1c0000, 0xd40000}, /* Stock: base 0x160000 size 0xda0000 */ |
||
601 | {"default-mac", 0xf00000, 0x00200}, |
||
602 | {"pin", 0xf00200, 0x00200}, |
||
603 | {"device-id", 0xf00400, 0x00100}, |
||
604 | {"product-info", 0xf00500, 0x0fb00}, |
||
605 | {"soft-version", 0xf10000, 0x00100}, |
||
606 | {"extra-para", 0xf11000, 0x01000}, |
||
607 | {"support-list", 0xf12000, 0x0a000}, |
||
608 | {"profile", 0xf1c000, 0x04000}, |
||
609 | {"default-config", 0xf20000, 0x10000}, |
||
610 | {"user-config", 0xf30000, 0x40000}, |
||
611 | {"qos-db", 0xf70000, 0x40000}, |
||
612 | {"certificate", 0xfb0000, 0x10000}, |
||
613 | {"partition-table", 0xfc0000, 0x10000}, |
||
614 | {"log", 0xfd0000, 0x20000}, |
||
615 | {"radio", 0xff0000, 0x10000}, |
||
616 | {NULL, 0, 0} |
||
617 | }, |
||
618 | |||
619 | .first_sysupgrade_partition = "os-image", |
||
620 | .last_sysupgrade_partition = "file-system", |
||
621 | }, |
||
622 | |||
623 | /** Firmware layout for the C7 v5*/ |
||
624 | { |
||
625 | .id = "ARCHER-C7-V5", |
||
626 | .support_list = |
||
627 | "SupportList:\n" |
||
628 | "{product_name:Archer C7,product_ver:5.0.0,special_id:00000000}\n" |
||
629 | "{product_name:Archer C7,product_ver:5.0.0,special_id:55530000}\n", |
||
630 | |||
631 | .support_trail = '\x00', |
||
632 | .soft_ver = "soft_ver:1.0.0\n", |
||
633 | |||
634 | /** |
||
635 | We use a bigger os-image partition than the stock images (and thus |
||
636 | smaller file-system), as our kernel doesn't fit in the stock firmware's |
||
637 | 1MB os-image. |
||
638 | */ |
||
639 | .partitions = { |
||
640 | {"factory-boot", 0x00000, 0x20000}, |
||
641 | {"fs-uboot", 0x20000, 0x20000}, |
||
642 | {"partition-table", 0x40000, 0x10000}, |
||
643 | {"radio", 0x50000, 0x10000}, |
||
644 | {"default-mac", 0x60000, 0x00200}, |
||
645 | {"pin", 0x60200, 0x00200}, |
||
646 | {"device-id", 0x60400, 0x00100}, |
||
647 | {"product-info", 0x60500, 0x0fb00}, |
||
648 | {"soft-version", 0x70000, 0x01000}, |
||
649 | {"extra-para", 0x71000, 0x01000}, |
||
650 | {"support-list", 0x72000, 0x0a000}, |
||
651 | {"profile", 0x7c000, 0x04000}, |
||
652 | {"user-config", 0x80000, 0x40000}, |
||
653 | |||
654 | |||
655 | {"os-image", 0xc0000, 0x180000}, /* Stock: base 0xc0000 size 0x120000 */ |
||
656 | {"file-system", 0x240000, 0xd80000}, /* Stock: base 0x1e0000 size 0xde0000 */ |
||
657 | |||
658 | {"log", 0xfc0000, 0x20000}, |
||
659 | {"certificate", 0xfe0000, 0x10000}, |
||
660 | {"default-config", 0xff0000, 0x10000}, |
||
661 | {NULL, 0, 0} |
||
662 | |||
663 | }, |
||
664 | |||
665 | .first_sysupgrade_partition = "os-image", |
||
666 | .last_sysupgrade_partition = "file-system", |
||
667 | }, |
||
668 | |||
669 | /** Firmware layout for the C9 */ |
||
670 | { |
||
671 | .id = "ARCHERC9", |
||
672 | .vendor = "", |
||
673 | .support_list = |
||
674 | "SupportList:\n" |
||
675 | "{product_name:ArcherC9," |
||
676 | "product_ver:1.0.0," |
||
677 | "special_id:00000000}\n", |
||
678 | .support_trail = '\x00', |
||
679 | .soft_ver = NULL, |
||
680 | |||
681 | .partitions = { |
||
682 | {"fs-uboot", 0x00000, 0x40000}, |
||
683 | {"os-image", 0x40000, 0x200000}, |
||
684 | {"file-system", 0x240000, 0xc00000}, |
||
685 | {"default-mac", 0xe40000, 0x00200}, |
||
686 | {"pin", 0xe40200, 0x00200}, |
||
687 | {"product-info", 0xe40400, 0x00200}, |
||
688 | {"partition-table", 0xe50000, 0x10000}, |
||
689 | {"soft-version", 0xe60000, 0x00200}, |
||
690 | {"support-list", 0xe61000, 0x0f000}, |
||
691 | {"profile", 0xe70000, 0x10000}, |
||
692 | {"default-config", 0xe80000, 0x10000}, |
||
693 | {"user-config", 0xe90000, 0x50000}, |
||
694 | {"log", 0xee0000, 0x100000}, |
||
695 | {"radio_bk", 0xfe0000, 0x10000}, |
||
696 | {"radio", 0xff0000, 0x10000}, |
||
697 | {NULL, 0, 0} |
||
698 | }, |
||
699 | |||
700 | .first_sysupgrade_partition = "os-image", |
||
701 | .last_sysupgrade_partition = "file-system" |
||
702 | }, |
||
703 | |||
704 | /** Firmware layout for the EAP120 */ |
||
705 | { |
||
706 | .id = "EAP120", |
||
707 | .vendor = "EAP120(TP-LINK|UN|N300-2):1.0\r\n", |
||
708 | .support_list = |
||
709 | "SupportList:\r\n" |
||
710 | "EAP120(TP-LINK|UN|N300-2):1.0\r\n", |
||
711 | .support_trail = '\xff', |
||
712 | .soft_ver = NULL, |
||
713 | |||
714 | .partitions = { |
||
715 | {"fs-uboot", 0x00000, 0x20000}, |
||
716 | {"partition-table", 0x20000, 0x02000}, |
||
717 | {"default-mac", 0x30000, 0x00020}, |
||
718 | {"support-list", 0x31000, 0x00100}, |
||
719 | {"product-info", 0x31100, 0x00100}, |
||
720 | {"soft-version", 0x32000, 0x00100}, |
||
721 | {"os-image", 0x40000, 0x180000}, |
||
722 | {"file-system", 0x1c0000, 0x600000}, |
||
723 | {"user-config", 0x7c0000, 0x10000}, |
||
724 | {"backup-config", 0x7d0000, 0x10000}, |
||
725 | {"log", 0x7e0000, 0x10000}, |
||
726 | {"radio", 0x7f0000, 0x10000}, |
||
727 | {NULL, 0, 0} |
||
728 | }, |
||
729 | |||
730 | .first_sysupgrade_partition = "os-image", |
||
731 | .last_sysupgrade_partition = "file-system" |
||
732 | }, |
||
733 | |||
734 | /** Firmware layout for the TL-WA850RE v2 */ |
||
735 | { |
||
736 | .id = "TLWA850REV2", |
||
737 | .vendor = "", |
||
738 | .support_list = |
||
739 | "SupportList:\n" |
||
740 | "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:55530000}\n" |
||
741 | "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:00000000}\n" |
||
742 | "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:55534100}\n" |
||
743 | "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:45550000}\n" |
||
744 | "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:4B520000}\n" |
||
745 | "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:42520000}\n" |
||
746 | "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:4A500000}\n" |
||
747 | "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:43410000}\n" |
||
748 | "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:41550000}\n" |
||
749 | "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:52550000}\n", |
||
750 | .support_trail = '\x00', |
||
751 | .soft_ver = NULL, |
||
752 | |||
753 | /** |
||
754 | 576KB were moved from file-system to os-image |
||
755 | in comparison to the stock image |
||
756 | */ |
||
757 | .partitions = { |
||
758 | {"fs-uboot", 0x00000, 0x20000}, |
||
759 | {"os-image", 0x20000, 0x150000}, |
||
760 | {"file-system", 0x170000, 0x240000}, |
||
761 | {"partition-table", 0x3b0000, 0x02000}, |
||
762 | {"default-mac", 0x3c0000, 0x00020}, |
||
763 | {"pin", 0x3c0100, 0x00020}, |
||
764 | {"product-info", 0x3c1000, 0x01000}, |
||
765 | {"soft-version", 0x3c2000, 0x00100}, |
||
766 | {"support-list", 0x3c3000, 0x01000}, |
||
767 | {"profile", 0x3c4000, 0x08000}, |
||
768 | {"user-config", 0x3d0000, 0x10000}, |
||
769 | {"default-config", 0x3e0000, 0x10000}, |
||
770 | {"radio", 0x3f0000, 0x10000}, |
||
771 | {NULL, 0, 0} |
||
772 | }, |
||
773 | |||
774 | .first_sysupgrade_partition = "os-image", |
||
775 | .last_sysupgrade_partition = "file-system" |
||
776 | }, |
||
777 | |||
778 | /** Firmware layout for the TL-WA855RE v1 */ |
||
779 | { |
||
780 | .id = "TLWA855REV1", |
||
781 | .vendor = "", |
||
782 | .support_list = |
||
783 | "SupportList:\n" |
||
784 | "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:00000000}\n" |
||
785 | "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:55530000}\n" |
||
786 | "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:45550000}\n" |
||
787 | "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:4B520000}\n" |
||
788 | "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:42520000}\n" |
||
789 | "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:4A500000}\n" |
||
790 | "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:43410000}\n" |
||
791 | "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:41550000}\n" |
||
792 | "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:52550000}\n", |
||
793 | .support_trail = '\x00', |
||
794 | .soft_ver = NULL, |
||
795 | |||
796 | .partitions = { |
||
797 | {"fs-uboot", 0x00000, 0x20000}, |
||
798 | {"os-image", 0x20000, 0x150000}, |
||
799 | {"file-system", 0x170000, 0x240000}, |
||
800 | {"partition-table", 0x3b0000, 0x02000}, |
||
801 | {"default-mac", 0x3c0000, 0x00020}, |
||
802 | {"pin", 0x3c0100, 0x00020}, |
||
803 | {"product-info", 0x3c1000, 0x01000}, |
||
804 | {"soft-version", 0x3c2000, 0x00100}, |
||
805 | {"support-list", 0x3c3000, 0x01000}, |
||
806 | {"profile", 0x3c4000, 0x08000}, |
||
807 | {"user-config", 0x3d0000, 0x10000}, |
||
808 | {"default-config", 0x3e0000, 0x10000}, |
||
809 | {"radio", 0x3f0000, 0x10000}, |
||
810 | {NULL, 0, 0} |
||
811 | }, |
||
812 | |||
813 | .first_sysupgrade_partition = "os-image", |
||
814 | .last_sysupgrade_partition = "file-system" |
||
815 | }, |
||
816 | |||
817 | /** Firmware layout for the TL-WR1043 v5 */ |
||
818 | { |
||
819 | .id = "TLWR1043NV5", |
||
820 | .vendor = "", |
||
821 | .support_list = |
||
822 | "SupportList:\n" |
||
823 | "{product_name:TL-WR1043N,product_ver:5.0.0,special_id:45550000}\n" |
||
824 | "{product_name:TL-WR1043N,product_ver:5.0.0,special_id:55530000}\n", |
||
825 | .support_trail = '\x00', |
||
826 | .soft_ver = "soft_ver:1.0.0\n", |
||
827 | .partitions = { |
||
828 | {"factory-boot", 0x00000, 0x20000}, |
||
829 | {"fs-uboot", 0x20000, 0x20000}, |
||
830 | {"os-image", 0x40000, 0x180000}, |
||
831 | {"file-system", 0x1c0000, 0xd40000}, |
||
832 | {"default-mac", 0xf00000, 0x00200}, |
||
833 | {"pin", 0xf00200, 0x00200}, |
||
834 | {"device-id", 0xf00400, 0x00100}, |
||
835 | {"product-info", 0xf00500, 0x0fb00}, |
||
836 | {"soft-version", 0xf10000, 0x01000}, |
||
837 | {"extra-para", 0xf11000, 0x01000}, |
||
838 | {"support-list", 0xf12000, 0x0a000}, |
||
839 | {"profile", 0xf1c000, 0x04000}, |
||
840 | {"default-config", 0xf20000, 0x10000}, |
||
841 | {"user-config", 0xf30000, 0x40000}, |
||
842 | {"qos-db", 0xf70000, 0x40000}, |
||
843 | {"certificate", 0xfb0000, 0x10000}, |
||
844 | {"partition-table", 0xfc0000, 0x10000}, |
||
845 | {"log", 0xfd0000, 0x20000}, |
||
846 | {"radio", 0xff0000, 0x10000}, |
||
847 | {NULL, 0, 0} |
||
848 | }, |
||
849 | .first_sysupgrade_partition = "os-image", |
||
850 | .last_sysupgrade_partition = "file-system" |
||
851 | }, |
||
852 | |||
853 | /** Firmware layout for the TL-WR1043 v4 */ |
||
854 | { |
||
855 | .id = "TLWR1043NDV4", |
||
856 | .vendor = "", |
||
857 | .support_list = |
||
858 | "SupportList:\n" |
||
859 | "{product_name:TL-WR1043ND,product_ver:4.0.0,special_id:45550000}\n", |
||
860 | .support_trail = '\x00', |
||
861 | .soft_ver = NULL, |
||
862 | |||
863 | /** |
||
864 | We use a bigger os-image partition than the stock images (and thus |
||
865 | smaller file-system), as our kernel doesn't fit in the stock firmware's |
||
866 | 1MB os-image. |
||
867 | */ |
||
868 | .partitions = { |
||
869 | {"fs-uboot", 0x00000, 0x20000}, |
||
870 | {"os-image", 0x20000, 0x180000}, |
||
871 | {"file-system", 0x1a0000, 0xdb0000}, |
||
872 | {"default-mac", 0xf50000, 0x00200}, |
||
873 | {"pin", 0xf50200, 0x00200}, |
||
874 | {"product-info", 0xf50400, 0x0fc00}, |
||
875 | {"soft-version", 0xf60000, 0x0b000}, |
||
876 | {"support-list", 0xf6b000, 0x04000}, |
||
877 | {"profile", 0xf70000, 0x04000}, |
||
878 | {"default-config", 0xf74000, 0x0b000}, |
||
879 | {"user-config", 0xf80000, 0x40000}, |
||
880 | {"partition-table", 0xfc0000, 0x10000}, |
||
881 | {"log", 0xfd0000, 0x20000}, |
||
882 | {"radio", 0xff0000, 0x10000}, |
||
883 | {NULL, 0, 0} |
||
884 | }, |
||
885 | |||
886 | .first_sysupgrade_partition = "os-image", |
||
887 | .last_sysupgrade_partition = "file-system" |
||
888 | }, |
||
889 | |||
890 | /** Firmware layout for the TL-WR902AC v1 */ |
||
891 | { |
||
892 | .id = "TL-WR902AC-V1", |
||
893 | .vendor = "", |
||
894 | .support_list = |
||
895 | "SupportList:\n" |
||
896 | "{product_name:TL-WR902AC,product_ver:1.0.0,special_id:45550000}\n" |
||
897 | "{product_name:TL-WR902AC,product_ver:1.0.0,special_id:55530000}\n", |
||
898 | .support_trail = '\x00', |
||
899 | .soft_ver = NULL, |
||
900 | |||
901 | /** |
||
902 | 384KB were moved from file-system to os-image |
||
903 | in comparison to the stock image |
||
904 | */ |
||
905 | .partitions = { |
||
906 | {"fs-uboot", 0x00000, 0x20000}, |
||
907 | {"os-image", 0x20000, 0x180000}, |
||
908 | {"file-system", 0x1a0000, 0x5b0000}, |
||
909 | {"default-mac", 0x750000, 0x00200}, |
||
910 | {"pin", 0x750200, 0x00200}, |
||
911 | {"product-info", 0x750400, 0x0fc00}, |
||
912 | {"soft-version", 0x760000, 0x0b000}, |
||
913 | {"support-list", 0x76b000, 0x04000}, |
||
914 | {"profile", 0x770000, 0x04000}, |
||
915 | {"default-config", 0x774000, 0x0b000}, |
||
916 | {"user-config", 0x780000, 0x40000}, |
||
917 | {"partition-table", 0x7c0000, 0x10000}, |
||
918 | {"log", 0x7d0000, 0x20000}, |
||
919 | {"radio", 0x7f0000, 0x10000}, |
||
920 | {NULL, 0, 0} |
||
921 | }, |
||
922 | |||
923 | .first_sysupgrade_partition = "os-image", |
||
924 | .last_sysupgrade_partition = "file-system", |
||
925 | }, |
||
926 | |||
927 | /** Firmware layout for the TL-WR942N V1 */ |
||
928 | { |
||
929 | .id = "TLWR942NV1", |
||
930 | .vendor = "", |
||
931 | .support_list = |
||
932 | "SupportList:\r\n" |
||
933 | "{product_name:TL-WR942N,product_ver:1.0.0,special_id:00000000}\r\n" |
||
934 | "{product_name:TL-WR942N,product_ver:1.0.0,special_id:52550000}\r\n", |
||
935 | .support_trail = '\x00', |
||
936 | .soft_ver = NULL, |
||
937 | |||
938 | .partitions = { |
||
939 | {"fs-uboot", 0x00000, 0x20000}, |
||
940 | {"os-image", 0x20000, 0x180000}, |
||
941 | {"file-system", 0x1a0000, 0xca0000}, |
||
942 | {"default-mac", 0xe40000, 0x00200}, |
||
943 | {"pin", 0xe40200, 0x00200}, |
||
944 | {"product-info", 0xe40400, 0x0fc00}, |
||
945 | {"partition-table", 0xe50000, 0x10000}, |
||
946 | {"soft-version", 0xe60000, 0x10000}, |
||
947 | {"support-list", 0xe70000, 0x10000}, |
||
948 | {"profile", 0xe80000, 0x10000}, |
||
949 | {"default-config", 0xe90000, 0x10000}, |
||
950 | {"user-config", 0xea0000, 0x40000}, |
||
951 | {"qos-db", 0xee0000, 0x40000}, |
||
952 | {"certificate", 0xf20000, 0x10000}, |
||
953 | {"usb-config", 0xfb0000, 0x10000}, |
||
954 | {"log", 0xfc0000, 0x20000}, |
||
955 | {"radio-bk", 0xfe0000, 0x10000}, |
||
956 | {"radio", 0xff0000, 0x10000}, |
||
957 | {NULL, 0, 0} |
||
958 | }, |
||
959 | |||
960 | .first_sysupgrade_partition = "os-image", |
||
961 | .last_sysupgrade_partition = "file-system", |
||
962 | }, |
||
963 | |||
964 | /** Firmware layout for the RE350 v1 */ |
||
965 | { |
||
966 | .id = "RE350-V1", |
||
967 | .vendor = "", |
||
968 | .support_list = |
||
969 | "SupportList:\n" |
||
970 | "{product_name:RE350,product_ver:1.0.0,special_id:45550000}\n" |
||
971 | "{product_name:RE350,product_ver:1.0.0,special_id:00000000}\n" |
||
972 | "{product_name:RE350,product_ver:1.0.0,special_id:41550000}\n" |
||
973 | "{product_name:RE350,product_ver:1.0.0,special_id:55530000}\n" |
||
974 | "{product_name:RE350,product_ver:1.0.0,special_id:43410000}\n" |
||
975 | "{product_name:RE350,product_ver:1.0.0,special_id:4b520000}\n" |
||
976 | "{product_name:RE350,product_ver:1.0.0,special_id:4a500000}\n", |
||
977 | .support_trail = '\x00', |
||
978 | .soft_ver = NULL, |
||
979 | |||
980 | /** |
||
981 | The original os-image partition is too small, |
||
982 | so we enlarge it to 1.75M |
||
983 | */ |
||
984 | .partitions = { |
||
985 | {"fs-uboot", 0x00000, 0x20000}, |
||
986 | {"os-image", 0x20000, 0x1c0000}, |
||
987 | {"file-system", 0x1e0000, 0x420000}, |
||
988 | {"partition-table", 0x600000, 0x02000}, |
||
989 | {"default-mac", 0x610000, 0x00020}, |
||
990 | {"pin", 0x610100, 0x00020}, |
||
991 | {"product-info", 0x611100, 0x01000}, |
||
992 | {"soft-version", 0x620000, 0x01000}, |
||
993 | {"support-list", 0x621000, 0x01000}, |
||
994 | {"profile", 0x622000, 0x08000}, |
||
995 | {"user-config", 0x630000, 0x10000}, |
||
996 | {"default-config", 0x640000, 0x10000}, |
||
997 | {"radio", 0x7f0000, 0x10000}, |
||
998 | {NULL, 0, 0} |
||
999 | }, |
||
1000 | |||
1001 | .first_sysupgrade_partition = "os-image", |
||
1002 | .last_sysupgrade_partition = "file-system" |
||
1003 | }, |
||
1004 | |||
1005 | /** Firmware layout for the RE355 */ |
||
1006 | { |
||
1007 | .id = "RE355", |
||
1008 | .vendor = "", |
||
1009 | .support_list = |
||
1010 | "SupportList:\r\n" |
||
1011 | "{product_name:RE355,product_ver:1.0.0,special_id:00000000}\r\n" |
||
1012 | "{product_name:RE355,product_ver:1.0.0,special_id:55530000}\r\n" |
||
1013 | "{product_name:RE355,product_ver:1.0.0,special_id:45550000}\r\n" |
||
1014 | "{product_name:RE355,product_ver:1.0.0,special_id:4A500000}\r\n" |
||
1015 | "{product_name:RE355,product_ver:1.0.0,special_id:43410000}\r\n" |
||
1016 | "{product_name:RE355,product_ver:1.0.0,special_id:41550000}\r\n" |
||
1017 | "{product_name:RE355,product_ver:1.0.0,special_id:4B520000}\r\n" |
||
1018 | "{product_name:RE355,product_ver:1.0.0,special_id:55534100}\r\n", |
||
1019 | .support_trail = '\x00', |
||
1020 | .soft_ver = NULL, |
||
1021 | |||
1022 | /** |
||
1023 | The flash partition table for RE355; |
||
1024 | it is almost the same as the one used by the stock images, |
||
1025 | 576KB were moved from file-system to os-image. |
||
1026 | */ |
||
1027 | .partitions = { |
||
1028 | {"fs-uboot", 0x00000, 0x20000}, |
||
1029 | {"os-image", 0x20000, 0x180000}, |
||
1030 | {"file-system", 0x1a0000, 0x460000}, |
||
1031 | {"partition-table", 0x600000, 0x02000}, |
||
1032 | {"default-mac", 0x610000, 0x00020}, |
||
1033 | {"pin", 0x610100, 0x00020}, |
||
1034 | {"product-info", 0x611100, 0x01000}, |
||
1035 | {"soft-version", 0x620000, 0x01000}, |
||
1036 | {"support-list", 0x621000, 0x01000}, |
||
1037 | {"profile", 0x622000, 0x08000}, |
||
1038 | {"user-config", 0x630000, 0x10000}, |
||
1039 | {"default-config", 0x640000, 0x10000}, |
||
1040 | {"radio", 0x7f0000, 0x10000}, |
||
1041 | {NULL, 0, 0} |
||
1042 | }, |
||
1043 | |||
1044 | .first_sysupgrade_partition = "os-image", |
||
1045 | .last_sysupgrade_partition = "file-system" |
||
1046 | }, |
||
1047 | |||
1048 | /** Firmware layout for the RE450 */ |
||
1049 | { |
||
1050 | .id = "RE450", |
||
1051 | .vendor = "", |
||
1052 | .support_list = |
||
1053 | "SupportList:\r\n" |
||
1054 | "{product_name:RE450,product_ver:1.0.0,special_id:00000000}\r\n" |
||
1055 | "{product_name:RE450,product_ver:1.0.0,special_id:55530000}\r\n" |
||
1056 | "{product_name:RE450,product_ver:1.0.0,special_id:45550000}\r\n" |
||
1057 | "{product_name:RE450,product_ver:1.0.0,special_id:4A500000}\r\n" |
||
1058 | "{product_name:RE450,product_ver:1.0.0,special_id:43410000}\r\n" |
||
1059 | "{product_name:RE450,product_ver:1.0.0,special_id:41550000}\r\n" |
||
1060 | "{product_name:RE450,product_ver:1.0.0,special_id:4B520000}\r\n" |
||
1061 | "{product_name:RE450,product_ver:1.0.0,special_id:55534100}\r\n", |
||
1062 | .support_trail = '\x00', |
||
1063 | .soft_ver = NULL, |
||
1064 | |||
1065 | /** |
||
1066 | The flash partition table for RE450; |
||
1067 | it is almost the same as the one used by the stock images, |
||
1068 | 576KB were moved from file-system to os-image. |
||
1069 | */ |
||
1070 | .partitions = { |
||
1071 | {"fs-uboot", 0x00000, 0x20000}, |
||
1072 | {"os-image", 0x20000, 0x180000}, |
||
1073 | {"file-system", 0x1a0000, 0x460000}, |
||
1074 | {"partition-table", 0x600000, 0x02000}, |
||
1075 | {"default-mac", 0x610000, 0x00020}, |
||
1076 | {"pin", 0x610100, 0x00020}, |
||
1077 | {"product-info", 0x611100, 0x01000}, |
||
1078 | {"soft-version", 0x620000, 0x01000}, |
||
1079 | {"support-list", 0x621000, 0x01000}, |
||
1080 | {"profile", 0x622000, 0x08000}, |
||
1081 | {"user-config", 0x630000, 0x10000}, |
||
1082 | {"default-config", 0x640000, 0x10000}, |
||
1083 | {"radio", 0x7f0000, 0x10000}, |
||
1084 | {NULL, 0, 0} |
||
1085 | }, |
||
1086 | |||
1087 | .first_sysupgrade_partition = "os-image", |
||
1088 | .last_sysupgrade_partition = "file-system" |
||
1089 | }, |
||
1090 | |||
1091 | {} |
||
1092 | }; |
||
1093 | |||
1094 | #define error(_ret, _errno, _str, ...) \ |
||
1095 | do { \ |
||
1096 | fprintf(stderr, _str ": %s\n", ## __VA_ARGS__, \ |
||
1097 | strerror(_errno)); \ |
||
1098 | if (_ret) \ |
||
1099 | exit(_ret); \ |
||
1100 | } while (0) |
||
1101 | |||
1102 | |||
1103 | /** Stores a uint32 as big endian */ |
||
1104 | static inline void put32(uint8_t *buf, uint32_t val) { |
||
1105 | buf[0] = val >> 24; |
||
1106 | buf[1] = val >> 16; |
||
1107 | buf[2] = val >> 8; |
||
1108 | buf[3] = val; |
||
1109 | } |
||
1110 | |||
1111 | /** Allocates a new image partition */ |
||
1112 | static struct image_partition_entry alloc_image_partition(const char *name, size_t len) { |
||
1113 | struct image_partition_entry entry = {name, len, malloc(len)}; |
||
1114 | if (!entry.data) |
||
1115 | error(1, errno, "malloc"); |
||
1116 | |||
1117 | return entry; |
||
1118 | } |
||
1119 | |||
1120 | /** Frees an image partition */ |
||
1121 | static void free_image_partition(struct image_partition_entry entry) { |
||
1122 | free(entry.data); |
||
1123 | } |
||
1124 | |||
1125 | static time_t source_date_epoch = -1; |
||
1126 | static void set_source_date_epoch() { |
||
1127 | char *env = getenv("SOURCE_DATE_EPOCH"); |
||
1128 | char *endptr = env; |
||
1129 | errno = 0; |
||
1130 | if (env && *env) { |
||
1131 | source_date_epoch = strtoull(env, &endptr, 10); |
||
1132 | if (errno || (endptr && *endptr != '\0')) { |
||
1133 | fprintf(stderr, "Invalid SOURCE_DATE_EPOCH"); |
||
1134 | exit(1); |
||
1135 | } |
||
1136 | } |
||
1137 | } |
||
1138 | |||
1139 | /** Generates the partition-table partition */ |
||
1140 | static struct image_partition_entry make_partition_table(const struct flash_partition_entry *p) { |
||
1141 | struct image_partition_entry entry = alloc_image_partition("partition-table", 0x800); |
||
1142 | |||
1143 | char *s = (char *)entry.data, *end = (char *)(s+entry.size); |
||
1144 | |||
1145 | *(s++) = 0x00; |
||
1146 | *(s++) = 0x04; |
||
1147 | *(s++) = 0x00; |
||
1148 | *(s++) = 0x00; |
||
1149 | |||
1150 | size_t i; |
||
1151 | for (i = 0; p[i].name; i++) { |
||
1152 | size_t len = end-s; |
||
1153 | size_t w = snprintf(s, len, "partition %s base 0x%05x size 0x%05x\n", p[i].name, p[i].base, p[i].size); |
||
1154 | |||
1155 | if (w > len-1) |
||
1156 | error(1, 0, "flash partition table overflow?"); |
||
1157 | |||
1158 | s += w; |
||
1159 | } |
||
1160 | |||
1161 | s++; |
||
1162 | |||
1163 | memset(s, 0xff, end-s); |
||
1164 | |||
1165 | return entry; |
||
1166 | } |
||
1167 | |||
1168 | |||
1169 | /** Generates a binary-coded decimal representation of an integer in the range [0, 99] */ |
||
1170 | static inline uint8_t bcd(uint8_t v) { |
||
1171 | return 0x10 * (v/10) + v%10; |
||
1172 | } |
||
1173 | |||
1174 | |||
1175 | /** Generates the soft-version partition */ |
||
1176 | static struct image_partition_entry make_soft_version(uint32_t rev) { |
||
1177 | struct image_partition_entry entry = alloc_image_partition("soft-version", sizeof(struct soft_version)); |
||
1178 | struct soft_version *s = (struct soft_version *)entry.data; |
||
1179 | |||
1180 | time_t t; |
||
1181 | |||
1182 | if (source_date_epoch != -1) |
||
1183 | t = source_date_epoch; |
||
1184 | else if (time(&t) == (time_t)(-1)) |
||
1185 | error(1, errno, "time"); |
||
1186 | |||
1187 | struct tm *tm = localtime(&t); |
||
1188 | |||
1189 | s->magic = htonl(0x0000000c); |
||
1190 | s->zero = 0; |
||
1191 | s->pad1 = 0xff; |
||
1192 | |||
1193 | s->version_major = 0; |
||
1194 | s->version_minor = 0; |
||
1195 | s->version_patch = 0; |
||
1196 | |||
1197 | s->year_hi = bcd((1900+tm->tm_year)/100); |
||
1198 | s->year_lo = bcd(tm->tm_year%100); |
||
1199 | s->month = bcd(tm->tm_mon+1); |
||
1200 | s->day = bcd(tm->tm_mday); |
||
1201 | s->rev = htonl(rev); |
||
1202 | |||
1203 | s->pad2 = 0xff; |
||
1204 | |||
1205 | return entry; |
||
1206 | } |
||
1207 | |||
1208 | static struct image_partition_entry make_soft_version_from_string(const char *soft_ver) { |
||
1209 | /** String length _including_ the terminating zero byte */ |
||
1210 | uint32_t ver_len = strlen(soft_ver) + 1; |
||
1211 | /** Partition contains 64 bit header, the version string, and one additional null byte */ |
||
1212 | size_t partition_len = 2*sizeof(uint32_t) + ver_len + 1; |
||
1213 | struct image_partition_entry entry = alloc_image_partition("soft-version", partition_len); |
||
1214 | |||
1215 | uint32_t *len = (uint32_t *)entry.data; |
||
1216 | len[0] = htonl(ver_len); |
||
1217 | len[1] = 0; |
||
1218 | memcpy(&len[2], soft_ver, ver_len); |
||
1219 | |||
1220 | entry.data[partition_len - 1] = 0; |
||
1221 | |||
1222 | return entry; |
||
1223 | } |
||
1224 | |||
1225 | /** Generates the support-list partition */ |
||
1226 | static struct image_partition_entry make_support_list(const struct device_info *info) { |
||
1227 | size_t len = strlen(info->support_list); |
||
1228 | struct image_partition_entry entry = alloc_image_partition("support-list", len + 9); |
||
1229 | |||
1230 | put32(entry.data, len); |
||
1231 | memset(entry.data+4, 0, 4); |
||
1232 | memcpy(entry.data+8, info->support_list, len); |
||
1233 | entry.data[len+8] = info->support_trail; |
||
1234 | |||
1235 | return entry; |
||
1236 | } |
||
1237 | |||
1238 | /** Creates a new image partition with an arbitrary name from a file */ |
||
1239 | static struct image_partition_entry read_file(const char *part_name, const char *filename, bool add_jffs2_eof) { |
||
1240 | struct stat statbuf; |
||
1241 | |||
1242 | if (stat(filename, &statbuf) < 0) |
||
1243 | error(1, errno, "unable to stat file `%s'", filename); |
||
1244 | |||
1245 | size_t len = statbuf.st_size; |
||
1246 | |||
1247 | if (add_jffs2_eof) |
||
1248 | len = ALIGN(len, 0x10000) + sizeof(jffs2_eof_mark); |
||
1249 | |||
1250 | struct image_partition_entry entry = alloc_image_partition(part_name, len); |
||
1251 | |||
1252 | FILE *file = fopen(filename, "rb"); |
||
1253 | if (!file) |
||
1254 | error(1, errno, "unable to open file `%s'", filename); |
||
1255 | |||
1256 | if (fread(entry.data, statbuf.st_size, 1, file) != 1) |
||
1257 | error(1, errno, "unable to read file `%s'", filename); |
||
1258 | |||
1259 | if (add_jffs2_eof) { |
||
1260 | uint8_t *eof = entry.data + statbuf.st_size, *end = entry.data+entry.size; |
||
1261 | |||
1262 | memset(eof, 0xff, end - eof - sizeof(jffs2_eof_mark)); |
||
1263 | memcpy(end - sizeof(jffs2_eof_mark), jffs2_eof_mark, sizeof(jffs2_eof_mark)); |
||
1264 | } |
||
1265 | |||
1266 | fclose(file); |
||
1267 | |||
1268 | return entry; |
||
1269 | } |
||
1270 | |||
1271 | /** Creates a new image partition from arbitrary data */ |
||
1272 | static struct image_partition_entry put_data(const char *part_name, const char *datain, size_t len) { |
||
1273 | |||
1274 | struct image_partition_entry entry = alloc_image_partition(part_name, len); |
||
1275 | |||
1276 | memcpy(entry.data, datain, len); |
||
1277 | |||
1278 | return entry; |
||
1279 | } |
||
1280 | |||
1281 | /** |
||
1282 | Copies a list of image partitions into an image buffer and generates the image partition table while doing so |
||
1283 | |||
1284 | Example image partition table: |
||
1285 | |||
1286 | fwup-ptn partition-table base 0x00800 size 0x00800 |
||
1287 | fwup-ptn os-image base 0x01000 size 0x113b45 |
||
1288 | fwup-ptn file-system base 0x114b45 size 0x1d0004 |
||
1289 | fwup-ptn support-list base 0x2e4b49 size 0x000d1 |
||
1290 | |||
1291 | Each line of the partition table is terminated with the bytes 09 0d 0a ("\t\r\n"), |
||
1292 | the end of the partition table is marked with a zero byte. |
||
1293 | |||
1294 | The firmware image must contain at least the partition-table and support-list partitions |
||
1295 | to be accepted. There aren't any alignment constraints for the image partitions. |
||
1296 | |||
1297 | The partition-table partition contains the actual flash layout; partitions |
||
1298 | from the image partition table are mapped to the corresponding flash partitions during |
||
1299 | the firmware upgrade. The support-list partition contains a list of devices supported by |
||
1300 | the firmware image. |
||
1301 | |||
1302 | The base offsets in the firmware partition table are relative to the end |
||
1303 | of the vendor information block, so the partition-table partition will |
||
1304 | actually start at offset 0x1814 of the image. |
||
1305 | |||
1306 | I think partition-table must be the first partition in the firmware image. |
||
1307 | */ |
||
1308 | static void put_partitions(uint8_t *buffer, const struct flash_partition_entry *flash_parts, const struct image_partition_entry *parts) { |
||
1309 | size_t i, j; |
||
1310 | char *image_pt = (char *)buffer, *end = image_pt + 0x800; |
||
1311 | |||
1312 | size_t base = 0x800; |
||
1313 | for (i = 0; parts[i].name; i++) { |
||
1314 | for (j = 0; flash_parts[j].name; j++) { |
||
1315 | if (!strcmp(flash_parts[j].name, parts[i].name)) { |
||
1316 | if (parts[i].size > flash_parts[j].size) |
||
1317 | error(1, 0, "%s partition too big (more than %u bytes)", flash_parts[j].name, (unsigned)flash_parts[j].size); |
||
1318 | break; |
||
1319 | } |
||
1320 | } |
||
1321 | |||
1322 | assert(flash_parts[j].name); |
||
1323 | |||
1324 | memcpy(buffer + base, parts[i].data, parts[i].size); |
||
1325 | |||
1326 | size_t len = end-image_pt; |
||
1327 | 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); |
||
1328 | |||
1329 | if (w > len-1) |
||
1330 | error(1, 0, "image partition table overflow?"); |
||
1331 | |||
1332 | image_pt += w; |
||
1333 | |||
1334 | base += parts[i].size; |
||
1335 | } |
||
1336 | } |
||
1337 | |||
1338 | /** Generates and writes the image MD5 checksum */ |
||
1339 | static void put_md5(uint8_t *md5, uint8_t *buffer, unsigned int len) { |
||
1340 | MD5_CTX ctx; |
||
1341 | |||
1342 | MD5_Init(&ctx); |
||
1343 | MD5_Update(&ctx, md5_salt, (unsigned int)sizeof(md5_salt)); |
||
1344 | MD5_Update(&ctx, buffer, len); |
||
1345 | MD5_Final(md5, &ctx); |
||
1346 | } |
||
1347 | |||
1348 | |||
1349 | /** |
||
1350 | Generates the firmware image in factory format |
||
1351 | |||
1352 | Image format: |
||
1353 | |||
1354 | Bytes (hex) Usage |
||
1355 | ----------- ----- |
||
1356 | 0000-0003 Image size (4 bytes, big endian) |
||
1357 | 0004-0013 MD5 hash (hash of a 16 byte salt and the image data starting with byte 0x14) |
||
1358 | 0014-0017 Vendor information length (without padding) (4 bytes, big endian) |
||
1359 | 0018-1013 Vendor information (4092 bytes, padded with 0xff; there seem to be older |
||
1360 | (VxWorks-based) TP-LINK devices which use a smaller vendor information block) |
||
1361 | 1014-1813 Image partition table (2048 bytes, padded with 0xff) |
||
1362 | 1814-xxxx Firmware partitions |
||
1363 | */ |
||
1364 | static void * generate_factory_image(const struct device_info *info, const struct image_partition_entry *parts, size_t *len) { |
||
1365 | *len = 0x1814; |
||
1366 | |||
1367 | size_t i; |
||
1368 | for (i = 0; parts[i].name; i++) |
||
1369 | *len += parts[i].size; |
||
1370 | |||
1371 | uint8_t *image = malloc(*len); |
||
1372 | if (!image) |
||
1373 | error(1, errno, "malloc"); |
||
1374 | |||
1375 | memset(image, 0xff, *len); |
||
1376 | put32(image, *len); |
||
1377 | |||
1378 | if (info->vendor) { |
||
1379 | size_t vendor_len = strlen(info->vendor); |
||
1380 | put32(image+0x14, vendor_len); |
||
1381 | memcpy(image+0x18, info->vendor, vendor_len); |
||
1382 | } |
||
1383 | |||
1384 | put_partitions(image + 0x1014, info->partitions, parts); |
||
1385 | put_md5(image+0x04, image+0x14, *len-0x14); |
||
1386 | |||
1387 | return image; |
||
1388 | } |
||
1389 | |||
1390 | /** |
||
1391 | Generates the firmware image in sysupgrade format |
||
1392 | |||
1393 | This makes some assumptions about the provided flash and image partition tables and |
||
1394 | should be generalized when TP-LINK starts building its safeloader into hardware with |
||
1395 | different flash layouts. |
||
1396 | */ |
||
1397 | static void * generate_sysupgrade_image(const struct device_info *info, const struct image_partition_entry *image_parts, size_t *len) { |
||
1398 | size_t i, j; |
||
1399 | size_t flash_first_partition_index = 0; |
||
1400 | size_t flash_last_partition_index = 0; |
||
1401 | const struct flash_partition_entry *flash_first_partition = NULL; |
||
1402 | const struct flash_partition_entry *flash_last_partition = NULL; |
||
1403 | const struct image_partition_entry *image_last_partition = NULL; |
||
1404 | |||
1405 | /** Find first and last partitions */ |
||
1406 | for (i = 0; info->partitions[i].name; i++) { |
||
1407 | if (!strcmp(info->partitions[i].name, info->first_sysupgrade_partition)) { |
||
1408 | flash_first_partition = &info->partitions[i]; |
||
1409 | flash_first_partition_index = i; |
||
1410 | } else if (!strcmp(info->partitions[i].name, info->last_sysupgrade_partition)) { |
||
1411 | flash_last_partition = &info->partitions[i]; |
||
1412 | flash_last_partition_index = i; |
||
1413 | } |
||
1414 | } |
||
1415 | |||
1416 | assert(flash_first_partition && flash_last_partition); |
||
1417 | assert(flash_first_partition_index < flash_last_partition_index); |
||
1418 | |||
1419 | /** Find last partition from image to calculate needed size */ |
||
1420 | for (i = 0; image_parts[i].name; i++) { |
||
1421 | if (!strcmp(image_parts[i].name, info->last_sysupgrade_partition)) { |
||
1422 | image_last_partition = &image_parts[i]; |
||
1423 | break; |
||
1424 | } |
||
1425 | } |
||
1426 | |||
1427 | assert(image_last_partition); |
||
1428 | |||
1429 | *len = flash_last_partition->base - flash_first_partition->base + image_last_partition->size; |
||
1430 | |||
1431 | uint8_t *image = malloc(*len); |
||
1432 | if (!image) |
||
1433 | error(1, errno, "malloc"); |
||
1434 | |||
1435 | memset(image, 0xff, *len); |
||
1436 | |||
1437 | for (i = flash_first_partition_index; i <= flash_last_partition_index; i++) { |
||
1438 | for (j = 0; image_parts[j].name; j++) { |
||
1439 | if (!strcmp(info->partitions[i].name, image_parts[j].name)) { |
||
1440 | if (image_parts[j].size > info->partitions[i].size) |
||
1441 | error(1, 0, "%s partition too big (more than %u bytes)", info->partitions[i].name, (unsigned)info->partitions[i].size); |
||
1442 | memcpy(image + info->partitions[i].base - flash_first_partition->base, image_parts[j].data, image_parts[j].size); |
||
1443 | break; |
||
1444 | } |
||
1445 | |||
1446 | assert(image_parts[j].name); |
||
1447 | } |
||
1448 | } |
||
1449 | |||
1450 | return image; |
||
1451 | } |
||
1452 | |||
1453 | /** Generates an image according to a given layout and writes it to a file */ |
||
1454 | static void build_image(const char *output, |
||
1455 | const char *kernel_image, |
||
1456 | const char *rootfs_image, |
||
1457 | uint32_t rev, |
||
1458 | bool add_jffs2_eof, |
||
1459 | bool sysupgrade, |
||
1460 | const struct device_info *info) { |
||
1461 | |||
1462 | struct image_partition_entry parts[7] = {}; |
||
1463 | |||
1464 | parts[0] = make_partition_table(info->partitions); |
||
1465 | if (info->soft_ver) |
||
1466 | parts[1] = make_soft_version_from_string(info->soft_ver); |
||
1467 | else |
||
1468 | parts[1] = make_soft_version(rev); |
||
1469 | |||
1470 | parts[2] = make_support_list(info); |
||
1471 | parts[3] = read_file("os-image", kernel_image, false); |
||
1472 | parts[4] = read_file("file-system", rootfs_image, add_jffs2_eof); |
||
1473 | |||
1474 | /* Some devices need the extra-para partition to accept the firmware */ |
||
1475 | if (strcasecmp(info->id, "ARCHER-C25-V1") == 0 || |
||
1476 | strcasecmp(info->id, "ARCHER-C60-V2") == 0 || |
||
1477 | strcasecmp(info->id, "TLWR1043NV5") == 0) { |
||
1478 | const char mdat[11] = {0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00}; |
||
1479 | parts[5] = put_data("extra-para", mdat, 11); |
||
1480 | } else if (strcasecmp(info->id, "ARCHER-C7-V4") == 0 || strcasecmp(info->id, "ARCHER-C7-V5") == 0) { |
||
1481 | const char mdat[11] = {0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0xca, 0x00, 0x01, 0x00, 0x00}; |
||
1482 | parts[5] = put_data("extra-para", mdat, 11); |
||
1483 | } |
||
1484 | |||
1485 | size_t len; |
||
1486 | void *image; |
||
1487 | if (sysupgrade) |
||
1488 | image = generate_sysupgrade_image(info, parts, &len); |
||
1489 | else |
||
1490 | image = generate_factory_image(info, parts, &len); |
||
1491 | |||
1492 | FILE *file = fopen(output, "wb"); |
||
1493 | if (!file) |
||
1494 | error(1, errno, "unable to open output file"); |
||
1495 | |||
1496 | if (fwrite(image, len, 1, file) != 1) |
||
1497 | error(1, 0, "unable to write output file"); |
||
1498 | |||
1499 | fclose(file); |
||
1500 | |||
1501 | free(image); |
||
1502 | |||
1503 | size_t i; |
||
1504 | for (i = 0; parts[i].name; i++) |
||
1505 | free_image_partition(parts[i]); |
||
1506 | } |
||
1507 | |||
1508 | /** Usage output */ |
||
1509 | static void usage(const char *argv0) { |
||
1510 | fprintf(stderr, |
||
1511 | "Usage: %s [OPTIONS...]\n" |
||
1512 | "\n" |
||
1513 | "Options:\n" |
||
1514 | " -h show this help\n" |
||
1515 | "\n" |
||
1516 | "Create a new image:\n" |
||
1517 | " -B <board> create image for the board specified with <board>\n" |
||
1518 | " -k <file> read kernel image from the file <file>\n" |
||
1519 | " -r <file> read rootfs image from the file <file>\n" |
||
1520 | " -o <file> write output to the file <file>\n" |
||
1521 | " -V <rev> sets the revision number to <rev>\n" |
||
1522 | " -j add jffs2 end-of-filesystem markers\n" |
||
1523 | " -S create sysupgrade instead of factory image\n" |
||
1524 | "Extract an old image:\n" |
||
1525 | " -x <file> extract all oem firmware partition\n" |
||
1526 | " -d <dir> destination to extract the firmware partition\n" |
||
1527 | " -z <file> convert an oem firmware into a sysupgade file. Use -o for output file\n", |
||
1528 | argv0 |
||
1529 | ); |
||
1530 | }; |
||
1531 | |||
1532 | |||
1533 | static const struct device_info *find_board(const char *id) |
||
1534 | { |
||
1535 | struct device_info *board = NULL; |
||
1536 | |||
1537 | for (board = boards; board->id != NULL; board++) |
||
1538 | if (strcasecmp(id, board->id) == 0) |
||
1539 | return board; |
||
1540 | |||
1541 | return NULL; |
||
1542 | } |
||
1543 | |||
1544 | static int add_flash_partition( |
||
1545 | struct flash_partition_entry *part_list, |
||
1546 | size_t max_entries, |
||
1547 | const char *name, |
||
1548 | unsigned long base, |
||
1549 | unsigned long size) |
||
1550 | { |
||
1551 | int ptr; |
||
1552 | /* check if the list has a free entry */ |
||
1553 | for (ptr = 0; ptr < max_entries; ptr++, part_list++) { |
||
1554 | if (part_list->name == NULL && |
||
1555 | part_list->base == 0 && |
||
1556 | part_list->size == 0) |
||
1557 | break; |
||
1558 | } |
||
1559 | |||
1560 | if (ptr == max_entries) { |
||
1561 | error(1, 0, "No free flash part entry available."); |
||
1562 | } |
||
1563 | |||
1564 | part_list->name = calloc(1, strlen(name) + 1); |
||
1565 | memcpy((char *)part_list->name, name, strlen(name)); |
||
1566 | part_list->base = base; |
||
1567 | part_list->size = size; |
||
1568 | |||
1569 | return 0; |
||
1570 | } |
||
1571 | |||
1572 | /** read the partition table into struct flash_partition_entry */ |
||
1573 | static int read_partition_table( |
||
1574 | FILE *file, long offset, |
||
1575 | struct flash_partition_entry *entries, size_t max_entries, |
||
1576 | int type) |
||
1577 | { |
||
1578 | char buf[2048]; |
||
1579 | char *ptr, *end; |
||
1580 | const char *parthdr = NULL; |
||
1581 | const char *fwuphdr = "fwup-ptn"; |
||
1582 | const char *flashhdr = "partition"; |
||
1583 | |||
1584 | /* TODO: search for the partition table */ |
||
1585 | |||
1586 | switch(type) { |
||
1587 | case 0: |
||
1588 | parthdr = fwuphdr; |
||
1589 | break; |
||
1590 | case 1: |
||
1591 | parthdr = flashhdr; |
||
1592 | break; |
||
1593 | default: |
||
1594 | error(1, 0, "Invalid partition table"); |
||
1595 | } |
||
1596 | |||
1597 | if (fseek(file, offset, SEEK_SET) < 0) |
||
1598 | error(1, errno, "Can not seek in the firmware"); |
||
1599 | |||
1600 | if (fread(buf, 1, 2048, file) < 0) |
||
1601 | error(1, errno, "Can not read fwup-ptn from the firmware"); |
||
1602 | |||
1603 | buf[2047] = '\0'; |
||
1604 | |||
1605 | /* look for the partition header */ |
||
1606 | if (memcmp(buf, parthdr, strlen(parthdr)) != 0) { |
||
1607 | fprintf(stderr, "DEBUG: can not find fwuphdr\n"); |
||
1608 | return 1; |
||
1609 | } |
||
1610 | |||
1611 | ptr = buf; |
||
1612 | end = buf + sizeof(buf); |
||
1613 | while ((ptr + strlen(parthdr)) < end && |
||
1614 | memcmp(ptr, parthdr, strlen(parthdr)) == 0) { |
||
1615 | char *end_part; |
||
1616 | char *end_element; |
||
1617 | |||
1618 | char name[32] = { 0 }; |
||
1619 | int name_len = 0; |
||
1620 | unsigned long base = 0; |
||
1621 | unsigned long size = 0; |
||
1622 | |||
1623 | end_part = memchr(ptr, '\n', (end - ptr)); |
||
1624 | if (end_part == NULL) { |
||
1625 | /* in theory this should never happen, because a partition always ends with 0x09, 0x0D, 0x0A */ |
||
1626 | break; |
||
1627 | } |
||
1628 | |||
1629 | for (int i = 0; i <= 4; i++) { |
||
1630 | if (end_part <= ptr) |
||
1631 | break; |
||
1632 | |||
1633 | end_element = memchr(ptr, 0x20, (end_part - ptr)); |
||
1634 | if (end_element == NULL) { |
||
1635 | error(1, errno, "Ignoring the rest of the partition entries."); |
||
1636 | break; |
||
1637 | } |
||
1638 | |||
1639 | switch (i) { |
||
1640 | /* partition header */ |
||
1641 | case 0: |
||
1642 | ptr = end_element + 1; |
||
1643 | continue; |
||
1644 | /* name */ |
||
1645 | case 1: |
||
1646 | name_len = (end_element - ptr) > 31 ? 31 : (end_element - ptr); |
||
1647 | strncpy(name, ptr, name_len); |
||
1648 | name[name_len] = '\0'; |
||
1649 | ptr = end_element + 1; |
||
1650 | continue; |
||
1651 | |||
1652 | /* string "base" */ |
||
1653 | case 2: |
||
1654 | ptr = end_element + 1; |
||
1655 | continue; |
||
1656 | |||
1657 | /* actual base */ |
||
1658 | case 3: |
||
1659 | base = strtoul(ptr, NULL, 16); |
||
1660 | ptr = end_element + 1; |
||
1661 | continue; |
||
1662 | |||
1663 | /* string "size" */ |
||
1664 | case 4: |
||
1665 | ptr = end_element + 1; |
||
1666 | /* actual size. The last element doesn't have a sepeartor */ |
||
1667 | size = strtoul(ptr, NULL, 16); |
||
1668 | /* the part ends with 0x09, 0x0d, 0x0a */ |
||
1669 | ptr = end_part + 1; |
||
1670 | add_flash_partition(entries, max_entries, name, base, size); |
||
1671 | continue; |
||
1672 | } |
||
1673 | } |
||
1674 | } |
||
1675 | |||
1676 | return 0; |
||
1677 | } |
||
1678 | |||
1679 | static void write_partition( |
||
1680 | FILE *input_file, |
||
1681 | size_t firmware_offset, |
||
1682 | struct flash_partition_entry *entry, |
||
1683 | FILE *output_file) |
||
1684 | { |
||
1685 | char buf[4096]; |
||
1686 | size_t offset; |
||
1687 | |||
1688 | fseek(input_file, entry->base + firmware_offset, SEEK_SET); |
||
1689 | |||
1690 | for (offset = 0; sizeof(buf) + offset <= entry->size; offset += sizeof(buf)) { |
||
1691 | if (fread(buf, sizeof(buf), 1, input_file) < 0) |
||
1692 | error(1, errno, "Can not read partition from input_file"); |
||
1693 | |||
1694 | if (fwrite(buf, sizeof(buf), 1, output_file) < 0) |
||
1695 | error(1, errno, "Can not write partition to output_file"); |
||
1696 | } |
||
1697 | /* write last chunk smaller than buffer */ |
||
1698 | if (offset < entry->size) { |
||
1699 | offset = entry->size - offset; |
||
1700 | if (fread(buf, offset, 1, input_file) < 0) |
||
1701 | error(1, errno, "Can not read partition from input_file"); |
||
1702 | if (fwrite(buf, offset, 1, output_file) < 0) |
||
1703 | error(1, errno, "Can not write partition to output_file"); |
||
1704 | } |
||
1705 | } |
||
1706 | |||
1707 | static int extract_firmware_partition(FILE *input_file, size_t firmware_offset, struct flash_partition_entry *entry, const char *output_directory) |
||
1708 | { |
||
1709 | FILE *output_file; |
||
1710 | char output[PATH_MAX]; |
||
1711 | |||
1712 | snprintf(output, PATH_MAX, "%s/%s", output_directory, entry->name); |
||
1713 | output_file = fopen(output, "wb+"); |
||
1714 | if (output_file == NULL) { |
||
1715 | error(1, errno, "Can not open output file %s", output); |
||
1716 | } |
||
1717 | |||
1718 | write_partition(input_file, firmware_offset, entry, output_file); |
||
1719 | |||
1720 | fclose(output_file); |
||
1721 | |||
1722 | return 0; |
||
1723 | } |
||
1724 | |||
1725 | /** extract all partitions from the firmware file */ |
||
1726 | static int extract_firmware(const char *input, const char *output_directory) |
||
1727 | { |
||
1728 | struct flash_partition_entry entries[16] = { 0 }; |
||
1729 | size_t max_entries = 16; |
||
1730 | size_t firmware_offset = 0x1014; |
||
1731 | FILE *input_file; |
||
1732 | |||
1733 | struct stat statbuf; |
||
1734 | |||
1735 | /* check input file */ |
||
1736 | if (stat(input, &statbuf)) { |
||
1737 | error(1, errno, "Can not read input firmware %s", input); |
||
1738 | } |
||
1739 | |||
1740 | /* check if output directory exists */ |
||
1741 | if (stat(output_directory, &statbuf)) { |
||
1742 | error(1, errno, "Failed to stat output directory %s", output_directory); |
||
1743 | } |
||
1744 | |||
1745 | if ((statbuf.st_mode & S_IFMT) != S_IFDIR) { |
||
1746 | error(1, errno, "Given output directory is not a directory %s", output_directory); |
||
1747 | } |
||
1748 | |||
1749 | input_file = fopen(input, "rb"); |
||
1750 | |||
1751 | if (read_partition_table(input_file, firmware_offset, entries, 16, 0) != 0) { |
||
1752 | error(1, 0, "Error can not read the partition table (fwup-ptn)"); |
||
1753 | } |
||
1754 | |||
1755 | for (int i = 0; i < max_entries; i++) { |
||
1756 | if (entries[i].name == NULL && |
||
1757 | entries[i].base == 0 && |
||
1758 | entries[i].size == 0) |
||
1759 | continue; |
||
1760 | |||
1761 | extract_firmware_partition(input_file, firmware_offset, &entries[i], output_directory); |
||
1762 | } |
||
1763 | |||
1764 | return 0; |
||
1765 | } |
||
1766 | |||
1767 | static struct flash_partition_entry *find_partition( |
||
1768 | struct flash_partition_entry *entries, size_t max_entries, |
||
1769 | const char *name, const char *error_msg) |
||
1770 | { |
||
1771 | for (int i = 0; i < max_entries; i++, entries++) { |
||
1772 | if (strcmp(entries->name, name) == 0) |
||
1773 | return entries; |
||
1774 | } |
||
1775 | |||
1776 | error(1, 0, "%s", error_msg); |
||
1777 | return NULL; |
||
1778 | } |
||
1779 | |||
1780 | static void write_ff(FILE *output_file, size_t size) |
||
1781 | { |
||
1782 | char buf[4096]; |
||
1783 | int offset; |
||
1784 | |||
1785 | memset(buf, 0xff, sizeof(buf)); |
||
1786 | |||
1787 | for (offset = 0; offset + sizeof(buf) < size ; offset += sizeof(buf)) { |
||
1788 | if (fwrite(buf, sizeof(buf), 1, output_file) < 0) |
||
1789 | error(1, errno, "Can not write 0xff to output_file"); |
||
1790 | } |
||
1791 | |||
1792 | /* write last chunk smaller than buffer */ |
||
1793 | if (offset < size) { |
||
1794 | offset = size - offset; |
||
1795 | if (fwrite(buf, offset, 1, output_file) < 0) |
||
1796 | error(1, errno, "Can not write partition to output_file"); |
||
1797 | } |
||
1798 | } |
||
1799 | |||
1800 | static void convert_firmware(const char *input, const char *output) |
||
1801 | { |
||
1802 | struct flash_partition_entry fwup[MAX_PARTITIONS] = { 0 }; |
||
1803 | struct flash_partition_entry flash[MAX_PARTITIONS] = { 0 }; |
||
1804 | struct flash_partition_entry *fwup_os_image = NULL, *fwup_file_system = NULL; |
||
1805 | struct flash_partition_entry *flash_os_image = NULL, *flash_file_system = NULL; |
||
1806 | struct flash_partition_entry *fwup_partition_table = NULL; |
||
1807 | size_t firmware_offset = 0x1014; |
||
1808 | FILE *input_file, *output_file; |
||
1809 | |||
1810 | struct stat statbuf; |
||
1811 | |||
1812 | /* check input file */ |
||
1813 | if (stat(input, &statbuf)) { |
||
1814 | error(1, errno, "Can not read input firmware %s", input); |
||
1815 | } |
||
1816 | |||
1817 | input_file = fopen(input, "rb"); |
||
1818 | if (!input_file) |
||
1819 | error(1, 0, "Can not open input firmware %s", input); |
||
1820 | |||
1821 | output_file = fopen(output, "wb"); |
||
1822 | if (!output_file) |
||
1823 | error(1, 0, "Can not open output firmware %s", output); |
||
1824 | |||
1825 | if (read_partition_table(input_file, firmware_offset, fwup, MAX_PARTITIONS, 0) != 0) { |
||
1826 | error(1, 0, "Error can not read the partition table (fwup-ptn)"); |
||
1827 | } |
||
1828 | |||
1829 | fwup_os_image = find_partition(fwup, MAX_PARTITIONS, |
||
1830 | "os-image", "Error can not find os-image partition (fwup)"); |
||
1831 | fwup_file_system = find_partition(fwup, MAX_PARTITIONS, |
||
1832 | "file-system", "Error can not find file-system partition (fwup)"); |
||
1833 | fwup_partition_table = find_partition(fwup, MAX_PARTITIONS, |
||
1834 | "partition-table", "Error can not find partition-table partition"); |
||
1835 | |||
1836 | /* the flash partition table has a 0x00000004 magic haeder */ |
||
1837 | if (read_partition_table(input_file, firmware_offset + fwup_partition_table->base + 4, flash, MAX_PARTITIONS, 1) != 0) |
||
1838 | error(1, 0, "Error can not read the partition table (flash)"); |
||
1839 | |||
1840 | flash_os_image = find_partition(flash, MAX_PARTITIONS, |
||
1841 | "os-image", "Error can not find os-image partition (flash)"); |
||
1842 | flash_file_system = find_partition(flash, MAX_PARTITIONS, |
||
1843 | "file-system", "Error can not find file-system partition (flash)"); |
||
1844 | |||
1845 | /* write os_image to 0x0 */ |
||
1846 | write_partition(input_file, firmware_offset, fwup_os_image, output_file); |
||
1847 | write_ff(output_file, flash_os_image->size - fwup_os_image->size); |
||
1848 | |||
1849 | /* write file-system behind os_image */ |
||
1850 | fseek(output_file, flash_file_system->base - flash_os_image->base, SEEK_SET); |
||
1851 | write_partition(input_file, firmware_offset, fwup_file_system, output_file); |
||
1852 | write_ff(output_file, flash_file_system->size - fwup_file_system->size); |
||
1853 | |||
1854 | fclose(output_file); |
||
1855 | fclose(input_file); |
||
1856 | } |
||
1857 | |||
1858 | int main(int argc, char *argv[]) { |
||
1859 | const char *board = NULL, *kernel_image = NULL, *rootfs_image = NULL, *output = NULL; |
||
1860 | const char *extract_image = NULL, *output_directory = NULL, *convert_image = NULL; |
||
1861 | bool add_jffs2_eof = false, sysupgrade = false; |
||
1862 | unsigned rev = 0; |
||
1863 | const struct device_info *info; |
||
1864 | set_source_date_epoch(); |
||
1865 | |||
1866 | while (true) { |
||
1867 | int c; |
||
1868 | |||
1869 | c = getopt(argc, argv, "B:k:r:o:V:jSh:x:d:z:"); |
||
1870 | if (c == -1) |
||
1871 | break; |
||
1872 | |||
1873 | switch (c) { |
||
1874 | case 'B': |
||
1875 | board = optarg; |
||
1876 | break; |
||
1877 | |||
1878 | case 'k': |
||
1879 | kernel_image = optarg; |
||
1880 | break; |
||
1881 | |||
1882 | case 'r': |
||
1883 | rootfs_image = optarg; |
||
1884 | break; |
||
1885 | |||
1886 | case 'o': |
||
1887 | output = optarg; |
||
1888 | break; |
||
1889 | |||
1890 | case 'V': |
||
1891 | sscanf(optarg, "r%u", &rev); |
||
1892 | break; |
||
1893 | |||
1894 | case 'j': |
||
1895 | add_jffs2_eof = true; |
||
1896 | break; |
||
1897 | |||
1898 | case 'S': |
||
1899 | sysupgrade = true; |
||
1900 | break; |
||
1901 | |||
1902 | case 'h': |
||
1903 | usage(argv[0]); |
||
1904 | return 0; |
||
1905 | |||
1906 | case 'd': |
||
1907 | output_directory = optarg; |
||
1908 | break; |
||
1909 | |||
1910 | case 'x': |
||
1911 | extract_image = optarg; |
||
1912 | break; |
||
1913 | |||
1914 | case 'z': |
||
1915 | convert_image = optarg; |
||
1916 | break; |
||
1917 | |||
1918 | default: |
||
1919 | usage(argv[0]); |
||
1920 | return 1; |
||
1921 | } |
||
1922 | } |
||
1923 | |||
1924 | if (extract_image || output_directory) { |
||
1925 | if (!extract_image) |
||
1926 | error(1, 0, "No factory/oem image given via -x <file>. Output directory is only valid with -x"); |
||
1927 | if (!output_directory) |
||
1928 | error(1, 0, "Can not extract an image without output directory. Use -d <dir>"); |
||
1929 | extract_firmware(extract_image, output_directory); |
||
1930 | } else if (convert_image) { |
||
1931 | if (!output) |
||
1932 | error(1, 0, "Can not convert a factory/oem image into sysupgrade image without output file. Use -o <file>"); |
||
1933 | convert_firmware(convert_image, output); |
||
1934 | } else { |
||
1935 | if (!board) |
||
1936 | error(1, 0, "no board has been specified"); |
||
1937 | if (!kernel_image) |
||
1938 | error(1, 0, "no kernel image has been specified"); |
||
1939 | if (!rootfs_image) |
||
1940 | error(1, 0, "no rootfs image has been specified"); |
||
1941 | if (!output) |
||
1942 | error(1, 0, "no output filename has been specified"); |
||
1943 | |||
1944 | info = find_board(board); |
||
1945 | |||
1946 | if (info == NULL) |
||
1947 | error(1, 0, "unsupported board %s", board); |
||
1948 | |||
1949 | build_image(output, kernel_image, rootfs_image, rev, add_jffs2_eof, sysupgrade, info); |
||
1950 | } |
||
1951 | |||
1952 | return 0; |
||
1953 | } |