OpenWrt – Blame information for rev 4
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
4 | office | 1 | /* |
2 | * Copyright (C) 2004 Manuel Novoa III <mjn3@codepoet.org> |
||
3 | * |
||
4 | * This program is free software; you can redistribute it and/or modify |
||
5 | * it under the terms of the GNU General Public License as published by |
||
6 | * the Free Software Foundation; either version 2 of the License, or |
||
7 | * (at your option) any later version. |
||
8 | * |
||
9 | * This program is distributed in the hope that it will be useful, |
||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||
12 | * General Public License for more details. |
||
13 | * |
||
14 | * You should have received a copy of the GNU General Public License |
||
15 | * along with this program; if not, write to the Free Software |
||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||
17 | */ |
||
18 | |||
19 | /* July 29, 2004 |
||
20 | * |
||
21 | * This is a hacked replacement for the 'addpattern' utility used to |
||
22 | * create wrt54g .bin firmware files. It isn't pretty, but it does |
||
23 | * the job for me. |
||
24 | * |
||
25 | * Extensions: |
||
26 | * -v allows setting the version string on the command line. |
||
27 | * -{0|1} sets the (currently ignored) hw_ver flag in the header |
||
28 | * to 0 or 1 respectively. |
||
29 | */ |
||
30 | |||
31 | /* January 12, 2005 |
||
32 | * |
||
33 | * Modified by rodent at rodent dot za dot net |
||
34 | * Support added for the new WRT54G v2.2 and WRT54GS v1.1 "flags" |
||
35 | * Without the flags set to 0x7, the above units will refuse to flash. |
||
36 | * |
||
37 | * Extensions: |
||
38 | * -{0|1|2} sets {0|1} sets hw_ver flag to 0/1. {2} sets hw_ver to 1 |
||
39 | * and adds the new hardware "flags" for the v2.2/v1.1 units |
||
40 | */ |
||
41 | |||
42 | /* January 1, 2007 |
||
43 | * |
||
44 | * Modified by juan.i.gonzalez at subdown dot net |
||
45 | * Support added for the AG241v2 and similar |
||
46 | * |
||
47 | * Extensions: |
||
48 | * -r #.# adds revision hardware flags. AG241v2 and similar. |
||
49 | * |
||
50 | * AG241V2 firmware sets the hw_ver to 0x44. |
||
51 | * |
||
52 | * Example: -r 2.0 |
||
53 | * |
||
54 | * Convert 2.0 to 20 to be an integer, and add 0x30 to skip special ASCII |
||
55 | * #define HW_Version ((HW_REV * 10) + 0x30) -> from cyutils.h |
||
56 | */ |
||
57 | |||
58 | #include <stdio.h> |
||
59 | #include <stdlib.h> |
||
60 | #include <string.h> |
||
61 | #include <errno.h> |
||
62 | #include <time.h> |
||
63 | #include <unistd.h> |
||
64 | #include <sys/stat.h> |
||
65 | |||
66 | /**********************************************************************/ |
||
67 | |||
68 | #define CODE_ID "U2ND" /* from code_pattern.h */ |
||
69 | #define CODE_PATTERN "W54S" /* from code_pattern.h */ |
||
70 | #define PBOT_PATTERN "PBOT" |
||
71 | |||
72 | #define CYBERTAN_VERSION "v3.37.2" /* from cyutils.h */ |
||
73 | |||
74 | /* WRT54G v2.2 and WRT54GS v1.1 "flags" (from 3.37.32 firmware cyutils.h) */ |
||
75 | #define SUPPORT_4712_CHIP 0x0001 |
||
76 | #define SUPPORT_INTEL_FLASH 0x0002 |
||
77 | #define SUPPORT_5325E_SWITCH 0x0004 |
||
78 | /* (from 3.00.24 firmware cyutils.h) */ |
||
79 | #define SUPPORT_4704_CHIP 0x0008 |
||
80 | #define SUPPORT_5352E_CHIP 0x0010 |
||
81 | /* (from WD My Net Wi-Fi Range Extender's cyutils.s) */ |
||
82 | #define SUPPORT_4703_CHIP 0x0020 |
||
83 | |||
84 | struct code_header { /* from cyutils.h */ |
||
85 | char magic[8]; |
||
86 | char fwdate[3]; |
||
87 | char fwvern[3]; |
||
88 | char id[4]; /* U2ND */ |
||
89 | char hw_ver; /* 0: for 4702, 1: for 4712 -- new in 2.04.3 */ |
||
90 | |||
91 | unsigned char sn; // Serial Number |
||
92 | unsigned char flags[2]; /* SUPPORT_ flags new for 3.37.2 (WRT54G v2.2 and WRT54GS v1.1) */ |
||
93 | unsigned char stable[2]; // The image is stable (for dual image) |
||
94 | unsigned char try1[2]; // Try to boot image first time (for dual image) |
||
95 | unsigned char try2[2]; // Try to boot image second time (for dual image) |
||
96 | unsigned char try3[2]; // Try to boot image third time (for dual_image) |
||
97 | unsigned char res3[2]; |
||
98 | } ; |
||
99 | |||
100 | struct board_info { |
||
101 | char *id; |
||
102 | char *pattern; |
||
103 | char hw_ver; |
||
104 | char sn; |
||
105 | char flags[2]; |
||
106 | }; |
||
107 | |||
108 | struct board_info boards[] = { |
||
109 | { |
||
110 | .id = "E2100L", |
||
111 | .pattern = "NL1X", |
||
112 | .hw_ver = 0x00, |
||
113 | .sn = 0x0f, |
||
114 | .flags = {0x3f, 0x00}, |
||
115 | }, |
||
116 | { |
||
117 | .id = "WRT160NL", |
||
118 | .pattern = "NL16", |
||
119 | .hw_ver = 0x00, |
||
120 | .sn = 0x0f, |
||
121 | .flags = {0x3f, 0x00}, |
||
122 | }, |
||
123 | { |
||
124 | .id = "mynet-rext", |
||
125 | .pattern = "WDHNSTFH", |
||
126 | .hw_ver = 0x00, |
||
127 | .sn = 0x00, |
||
128 | .flags = {0x3f, 0x00}, |
||
129 | }, { |
||
130 | /* Terminating entry */ |
||
131 | .id = NULL, |
||
132 | } |
||
133 | }; |
||
134 | |||
135 | /**********************************************************************/ |
||
136 | |||
137 | void usage(void) __attribute__ (( __noreturn__ )); |
||
138 | |||
139 | void usage(void) |
||
140 | { |
||
141 | fprintf(stderr, "Usage: addpattern [-i trxfile] [-o binfile] [-B board_id] [-p pattern] [-s serial] [-g] [-b] [-v v#.#.#] [-r #.#] [-{0|1|2|4|5}] -h\n"); |
||
142 | exit(EXIT_FAILURE); |
||
143 | } |
||
144 | |||
145 | static time_t source_date_epoch = -1; |
||
146 | static void set_source_date_epoch() { |
||
147 | char *env = getenv("SOURCE_DATE_EPOCH"); |
||
148 | char *endptr = env; |
||
149 | errno = 0; |
||
150 | if (env && *env) { |
||
151 | source_date_epoch = strtoull(env, &endptr, 10); |
||
152 | if (errno || (endptr && *endptr != '\0')) { |
||
153 | fprintf(stderr, "Invalid SOURCE_DATE_EPOCH"); |
||
154 | exit(1); |
||
155 | } |
||
156 | } |
||
157 | } |
||
158 | |||
159 | struct board_info *find_board(char *id) |
||
160 | { |
||
161 | struct board_info *board; |
||
162 | |||
163 | for (board = boards; board->id != NULL; board++) |
||
164 | if (strcasecmp(id, board->id) == 0) |
||
165 | return board; |
||
166 | |||
167 | return NULL; |
||
168 | } |
||
169 | |||
170 | int main(int argc, char **argv) |
||
171 | { |
||
172 | char buf[1024]; /* keep this at 1k or adjust garbage calc below */ |
||
173 | struct code_header *hdr; |
||
174 | FILE *in = stdin; |
||
175 | FILE *out = stdout; |
||
176 | char *ifn = NULL; |
||
177 | char *ofn = NULL; |
||
178 | char *pattern = CODE_PATTERN; |
||
179 | char *pbotpat = PBOT_PATTERN; |
||
180 | char *version = CYBERTAN_VERSION; |
||
181 | char *board_id = NULL; |
||
182 | struct board_info *board = NULL; |
||
183 | int gflag = 0; |
||
184 | int pbotflag = 0; |
||
185 | int c; |
||
186 | int v0, v1, v2; |
||
187 | size_t off, n; |
||
188 | time_t t; |
||
189 | struct tm *ptm; |
||
190 | |||
191 | fprintf(stderr, "mjn3's addpattern replacement - v0.81\n"); |
||
192 | |||
193 | hdr = (struct code_header *) buf; |
||
194 | memset(hdr, 0, sizeof(struct code_header)); |
||
195 | |||
196 | while ((c = getopt(argc, argv, "i:o:p:s:gbv:01245hr:B:")) != -1) { |
||
197 | switch (c) { |
||
198 | case 'i': |
||
199 | ifn = optarg; |
||
200 | break; |
||
201 | case 'o': |
||
202 | ofn = optarg; |
||
203 | break; |
||
204 | case 'p': |
||
205 | pattern = optarg; |
||
206 | break; |
||
207 | case 's': |
||
208 | hdr->sn = (unsigned char) atoi (optarg); |
||
209 | break; |
||
210 | case 'g': |
||
211 | gflag = 1; |
||
212 | break; |
||
213 | case 'b': |
||
214 | pbotflag = 1; |
||
215 | break; |
||
216 | case 'v': /* extension to allow setting version */ |
||
217 | version = optarg; |
||
218 | break; |
||
219 | case '0': |
||
220 | hdr->hw_ver = 0; |
||
221 | break; |
||
222 | case '1': |
||
223 | hdr->hw_ver = 1; |
||
224 | break; |
||
225 | case '2': /* new 54G v2.2 and 54GS v1.1 flags */ |
||
226 | hdr->hw_ver = 1; |
||
227 | hdr->flags[0] |= SUPPORT_4712_CHIP; |
||
228 | hdr->flags[0] |= SUPPORT_INTEL_FLASH; |
||
229 | hdr->flags[0] |= SUPPORT_5325E_SWITCH; |
||
230 | break; |
||
231 | case '4': |
||
232 | /* V4 firmware sets the flags to 0x1f */ |
||
233 | hdr->hw_ver = 0; |
||
234 | hdr->flags[0] = 0x1f; |
||
235 | break; |
||
236 | case '5': |
||
237 | /* V5 is appended to trxV2 image */ |
||
238 | hdr->stable[0] = 0x73; // force image to be stable |
||
239 | hdr->stable[1] = 0x00; |
||
240 | hdr->try1[0] = 0x74; // force try1 to be set |
||
241 | hdr->try1[1] = 0x00; |
||
242 | hdr->try2[0] = hdr->try2[1] = 0xFF; |
||
243 | hdr->try3[0] = hdr->try3[1] = 0xFF; |
||
244 | break; |
||
245 | case 'r': |
||
246 | hdr->hw_ver = (char)(atof(optarg)*10)+0x30; |
||
247 | break; |
||
248 | case 'B': |
||
249 | board_id = optarg; |
||
250 | break; |
||
251 | |||
252 | case 'h': |
||
253 | default: |
||
254 | usage(); |
||
255 | } |
||
256 | } |
||
257 | |||
258 | if (optind != argc || optind == 1) { |
||
259 | fprintf(stderr, "illegal arg \"%s\"\n", argv[optind]); |
||
260 | usage(); |
||
261 | } |
||
262 | |||
263 | if (board_id) { |
||
264 | board = find_board(board_id); |
||
265 | if (board == NULL) { |
||
266 | fprintf(stderr, "unknown board \"%s\"\n", board_id); |
||
267 | usage(); |
||
268 | } |
||
269 | pattern = board->pattern; |
||
270 | hdr->hw_ver = board->hw_ver; |
||
271 | hdr->sn = board->sn; |
||
272 | hdr->flags[0] = board->flags[0]; |
||
273 | hdr->flags[1] = board->flags[1]; |
||
274 | } |
||
275 | |||
276 | if (strlen(pattern) > 8) { |
||
277 | fprintf(stderr, "illegal pattern \"%s\"\n", pattern); |
||
278 | usage(); |
||
279 | } |
||
280 | |||
281 | if (ifn && !(in = fopen(ifn, "r"))) { |
||
282 | fprintf(stderr, "can not open \"%s\" for reading\n", ifn); |
||
283 | usage(); |
||
284 | } |
||
285 | |||
286 | if (ofn && !(out = fopen(ofn, "w"))) { |
||
287 | fprintf(stderr, "can not open \"%s\" for writing\n", ofn); |
||
288 | usage(); |
||
289 | } |
||
290 | |||
291 | set_source_date_epoch(); |
||
292 | if (source_date_epoch != -1) { |
||
293 | t = source_date_epoch; |
||
294 | } else if ((time(&t) == (time_t)(-1))) { |
||
295 | fprintf(stderr, "time call failed\n"); |
||
296 | return EXIT_FAILURE; |
||
297 | } |
||
298 | |||
299 | ptm = localtime(&t); |
||
300 | |||
301 | if (3 != sscanf(version, "v%d.%d.%d", &v0, &v1, &v2)) { |
||
302 | fprintf(stderr, "bad version string \"%s\"\n", version); |
||
303 | return EXIT_FAILURE; |
||
304 | } |
||
305 | |||
306 | memcpy(hdr->magic, pattern, strlen(pattern)); |
||
307 | if (pbotflag) |
||
308 | memcpy(&hdr->magic[4], pbotpat, 4); |
||
309 | hdr->fwdate[0] = ptm->tm_year % 100; |
||
310 | hdr->fwdate[1] = ptm->tm_mon + 1; |
||
311 | hdr->fwdate[2] = ptm->tm_mday; |
||
312 | hdr->fwvern[0] = v0; |
||
313 | hdr->fwvern[1] = v1; |
||
314 | hdr->fwvern[2] = v2; |
||
315 | memcpy(hdr->id, CODE_ID, strlen(CODE_ID)); |
||
316 | |||
317 | off = sizeof(struct code_header); |
||
318 | |||
319 | fprintf(stderr, "writing firmware v%d.%d.%d on %d/%d/%d (y/m/d)\n", |
||
320 | v0, v1, v2, |
||
321 | hdr->fwdate[0], hdr->fwdate[1], hdr->fwdate[2]); |
||
322 | |||
323 | |||
324 | while ((n = fread(buf + off, 1, sizeof(buf)-off, in) + off) > 0) { |
||
325 | off = 0; |
||
326 | if (n < sizeof(buf)) { |
||
327 | if (ferror(in)) { |
||
328 | FREAD_ERROR: |
||
329 | fprintf(stderr, "fread error\n"); |
||
330 | return EXIT_FAILURE; |
||
331 | } |
||
332 | if (gflag) { |
||
333 | gflag = sizeof(buf) - n; |
||
334 | memset(buf + n, 0xff, gflag); |
||
335 | fprintf(stderr, "adding %d bytes of garbage\n", gflag); |
||
336 | n = sizeof(buf); |
||
337 | } |
||
338 | } |
||
339 | if (!fwrite(buf, n, 1, out)) { |
||
340 | FWRITE_ERROR: |
||
341 | fprintf(stderr, "fwrite error\n"); |
||
342 | return EXIT_FAILURE; |
||
343 | } |
||
344 | } |
||
345 | |||
346 | if (ferror(in)) { |
||
347 | goto FREAD_ERROR; |
||
348 | } |
||
349 | |||
350 | if (fflush(out)) { |
||
351 | goto FWRITE_ERROR; |
||
352 | } |
||
353 | |||
354 | fclose(in); |
||
355 | fclose(out); |
||
356 | |||
357 | return EXIT_SUCCESS; |
||
358 | } |