rpcd: iwinfo plugin fixes
[openwrt.git] / tools / firmware-utils / src / makeamitbin.c
1 /*
2  *  makeamitbin - create firmware binaries for MGB100
3  *
4  *  Copyright (C) 2007 Volker Weiss     <dev@tintuc.de>
5  *                     Christian Welzel <dev@welzel-online.ch>
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  * 
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  * 
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  *
21  */
22
23
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27
28
29 /* defaults: Level One WAP-0007 */
30 static char *ascii1 = "DDC_RUS001";
31 static char *ascii2 = "Queen";
32
33 static struct hdrinfo {
34   char *name;
35         unsigned long unknown; /* can probably be any number, maybe version number */
36         int topalign;
37         unsigned int addr;
38         unsigned int size;
39 } hdrinfo[] = {
40         { "bios", 0xc76be111, 1, 0x3fa000, 0x006000 },        /* BIOS */
41         { "recovery", 0xc76be222, 0, 0x3f0000, 0x004000 },    /* Recovery Loader */
42         { "linux", 0xc76bee9d, 0, 0x000000, 0x100000 },       /* Linux */
43         { "ramdisk", 0xc76bee9d, 0, 0x100000, 0x280000 },     /* ramdisk */
44         { "amitconfig", 0xc76bee8b, 0, 0x380000, 0x060000 },  /* AMIT config */
45         { "redboot", 0x00000000, 1, 0x3d0000, 0x030000 },     /* Redboot 128kB image */
46         { "redbootlow", 0, 0, 0x3e0000, 0x18000 },            /* Redboot 1. part */
47         { "redboothigh", 0, 0, 0x3fa000, 0x6000 },            /* Redboot 2. part */
48         { "linux3g", 0xcb5f06b5, 0, 0x000000, 0x100000 },       /* Linux */
49         { "ramdisk3g", 0xcb5f06b5, 0, 0x100000, 0x280000 },     /* ramdisk */
50         { NULL }
51 };
52
53 /*
54 CHD2WLANU_R400b7
55
56 11e1 6bc7
57 22e2 6bc7
58 5dc3 47c8
59 5cc3 47c8
60 21c3 47c8
61 */
62
63 /*
64 20060106_DDC_WAP-0007_R400b4
65
66 11e1 6bc7
67 22e2 6bc7
68 9dee 6bc7
69 9dee 6bc7
70 8bee 6bc7
71 */
72
73 /*
74 WMU-6000FS_R400b6
75
76 11e1 6bc7
77 22e2 6bc7
78 6d2d 0fc8
79 6c2d 0fc8
80 542d 0fc8
81 */
82
83 /*
84 WAP-0007(R4.00b8)_2006-10-02
85
86 9979 5fc8
87 22e2 6bc7
88 c46e cec8
89 c36e cec8
90 a76e cec8
91 */
92
93
94
95 #define HDRSIZE              80
96
97 #define COPY_SHORT(d, o, v)  d[o+0] = (unsigned char)((v) & 0xff); \
98                              d[o+1] = (unsigned char)(((v) >> 8) & 0xff)
99 #define COPY_LONG(d, o, v)   d[o+0] = (unsigned char)((v) & 0xff); \
100                              d[o+1] = (unsigned char)(((v) >> 8) & 0xff); \
101                                                                                                            d[o+2] = (unsigned char)(((v) >> 16) & 0xff); \
102                                                                                                            d[o+3] = (unsigned char)(((v) >> 24) & 0xff)
103 #define READ_SHORT(d, o)     ((unsigned short)(d[o+0]) + \
104                              (((unsigned short)(d[o+1])) << 8))
105
106 /*
107 00..0d ASCII product ID
108 0e..0f checksum of payload
109 10..1b ASCII Queen
110 1c..1f AMIT BIOS: 11e1 6bc7, Recovery Tool: 22e2 6bc7
111        Linux: 5dc3 47c8, ramdisk: 5cc3 47c8
112                          AMIT FS: 21c3 47c8    VERSION NUMBER??????
113 20..23 offset in flash aligned to segment boundary
114 24..27 length in flash aligned to segment boundary
115 28..2b offset in flash (payload)
116 2c..2f length (payload)
117 30..3f always 0
118 40..47 always 4248 0101 5000 0001 (last maybe .....0501)
119 48..4b same as 20..23
120 4c..4d always 0b00
121 4e..4f inverted checksum of header
122 */
123
124 unsigned short checksum(unsigned char *data, long size)
125 {
126         long n;
127         unsigned short d, cs = 0;
128         for (n = 0; n < size; n += 2)
129         {
130                 d = READ_SHORT(data, n);
131                 cs += d;
132                 if (cs < d)
133                         cs++;
134         }
135         if (size & 1)
136         {
137                 d = data[n];
138                 cs += d;
139                 if (cs < d)
140                         cs++;
141         }
142         return cs;
143 }
144
145 void showhdr(unsigned char *hdr)
146 {
147         int i, j;
148         for (j = 0; j < 5; j++)
149         {
150                 for (i = 0; i < 16; i++)
151                 {
152                         printf("%02x ", (unsigned int)(hdr[j * 16 + i]));
153                 }
154                 printf("   ");
155                 for (i = 0; i < 16; i++)
156                 {
157                         unsigned char d = hdr[j * 16 + i];
158                         printf("%c", (d >= ' ' && d < 127) ? d : '.');
159                 }
160                 printf("\n");
161         }
162 }
163
164 void makehdr(unsigned char *hdr, struct hdrinfo *info,
165              unsigned char *data, long size, int last)
166 {
167         unsigned int offset = info->addr + 0x10;
168         memset(hdr, 0, HDRSIZE);
169         if (info->topalign)
170                 offset = info->addr + info->size - size;        /* top align */
171         strncpy((char *)hdr + 0x00, ascii1, 14);
172         strncpy((char *)hdr + 0x10, ascii2, 12);
173         COPY_LONG(hdr, 0x1c, info->unknown);
174         COPY_LONG(hdr, 0x20, info->addr);
175         COPY_LONG(hdr, 0x24, info->size);
176         COPY_LONG(hdr, 0x28, offset);
177         COPY_LONG(hdr, 0x2c, size);
178         COPY_LONG(hdr, 0x40, 0x01014842);
179         COPY_LONG(hdr, 0x44, last ? 0x01050050 : 0x01000050);
180         COPY_LONG(hdr, 0x48, info->addr);
181         COPY_SHORT(hdr, 0x4c, info->unknown == 0xcb5f06b5 ? 0x0016 : 0x000b);
182         COPY_SHORT(hdr, 0x0e, checksum(data, size));
183         COPY_SHORT(hdr, 0x4e, ~checksum(hdr, HDRSIZE));
184 }
185
186 unsigned char *read_file(const char *name, long *size)
187 {
188         FILE *f;
189         unsigned char *data = NULL;
190         *size = 0;
191         f = fopen(name, "r");
192         if (f != NULL)
193         {
194                 if (fseek(f, 0, SEEK_END) == 0)
195                 {
196             *size = ftell(f);
197                         if (*size != -1)
198                         {
199                                 if (fseek(f, 0, SEEK_SET) == 0)
200                                 {
201                                         data = (unsigned char *)malloc(*size);
202                                         if (data != NULL)
203                                         {
204                                                 if (fread(data, sizeof(char), *size, f) != *size)
205                                                 {
206                                                         free(data);
207                                                         data = NULL;
208                                                 }
209                                         }
210                                 }
211                         }
212                 }
213                 fclose(f);
214         }
215         return data;
216 }
217
218 struct hdrinfo *find_hdrinfo(const char *name)
219 {
220         int n;
221         for (n = 0; hdrinfo[n].name != NULL; n++)
222         {
223                 if (strcmp(name, hdrinfo[n].name) == 0)
224                         return &hdrinfo[n];
225         }
226         return NULL;
227 }
228
229 void oferror(FILE *f)
230 {
231         printf("file error\n");
232         exit(2);
233 }
234
235 void showhelp(void)
236 {
237         printf("Syntax: makeamitbin [options]\n");
238         printf("Options:\n");
239         printf("  -1 ID1\tFirmware identifier 1, e.g. 'DDC_RUS001' for manufacturer LevelOne\n");
240         printf("  -2 ID2\tFirmware identifier 2, 'Queen' in all known cases\n");
241         printf("  -o FILE\tOutput file\n");
242         printf("  -ids\t\tShow a list of known firmware identifiers.\n");
243         exit(1);
244 }
245
246 void show_fwids(void)
247 {
248         printf("List of known firmware identifiers:\n");
249         printf("Manufacturer\t\tProduct\t\tIdentifier\n");
250         printf("=====================================================\n");
251         printf("Conceptronic\t\tCHD2WLANU\tLLM_RUS001\n");
252         printf("Pearl\t\t\tPE6643\t\tQueen\n");
253         printf("Micronica\t\tMGB100\t\tQueen\n");
254         printf("LevelOne\t\tWAP-0007\tDDC_RUS001\n");
255         printf("SMC\t\t\tWAPS-G\t\tSMC_RUS001\n");
256         printf("OvisLink (AirLive)\tWMU-6\t\tOVS_RUS001\n");
257         printf("SafeCom SWSAPUR-5\tFMW\t\tSafeco_RPS001\n");
258         exit(1);
259 }
260
261 int main(int argc, char *argv[])
262 {
263         unsigned char hdr[HDRSIZE];
264         unsigned char *data;
265         FILE *of;
266         char *outfile = NULL;
267         char *type;
268         struct hdrinfo *info;
269         long size;
270         int last = 0;
271         int n;
272         for (n = 1; n < argc; n++)
273         {
274                 if (strcmp(argv[n], "-1") == 0)
275                         ascii1 = argv[n+1];
276                 if (strcmp(argv[n], "-2") == 0)
277                         ascii2 = argv[n+1];
278                 if (strcmp(argv[n], "-o") == 0)
279                         outfile = argv[n+1];
280                 if (strcmp(argv[n], "-ids") == 0)
281                         show_fwids();
282         }
283         if (ascii1 == NULL || ascii2 == NULL || outfile == NULL)
284                 showhelp();
285         of = fopen(outfile, "w");
286         if (of == NULL)
287                 oferror(of);
288         for (n = 1; n < argc; n++)
289         {
290                 if (strncmp(argv[n], "-", 1) != 0)
291                 {
292                         type = argv[n++];
293                         if (n >= argc)
294                                 showhelp();
295                         last = ((n + 1) >= argc);               /* dirty, options first! */
296                         info = find_hdrinfo(type);
297                         if (info == NULL)
298                                 showhelp();
299                         data = read_file(argv[n], &size);
300                         if (data == NULL)
301                                 showhelp();
302                         makehdr(hdr, info, data, size, last);
303                         /* showhdr(hdr); */
304                         if (fwrite(hdr, HDRSIZE, 1, of) != 1)
305                                 oferror(of);
306                         if (fwrite(data, size, 1, of) != 1)
307                                 oferror(of);
308                         free(data);
309                 }
310                 else
311                         n++;
312         }
313         if (fclose(of) != 0)
314                 oferror(NULL);
315         return 0;
316 }