2 * firmware cutter for broadcom 43xx wireless driver files
4 * Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
5 * 2005 Michael Buesch <mbuesch@freenet.de>
6 * 2005 Alex Beregszaszi
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; see the file COPYING. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
31 typedef unsigned char byte
;
33 #define DRIVER_UNSUPPORTED 0x01 /* no support for this driver file */
34 #define BYTE_ORDER_BIG_ENDIAN 0x02 /* ppc driver files */
35 #define BYTE_ORDER_LITTLE_ENDIAN 0x04 /* x86, mips driver files */
37 #define MISSING_INITVAL_08 0x10 /* initval 8 is missing */
38 #define MISSING_INITVAL_80211_A 0x20 /* initvals 3,7,9,10 (802.11a cards) are empty */
40 #define FIRMWARE_UCODE_OFFSET 100
41 #define FIRMWARE_UNDEFINED 0
42 #define FIRMWARE_PCM_4 4
43 #define FIRMWARE_PCM_5 5
44 #define FIRMWARE_UCODE_2 (FIRMWARE_UCODE_OFFSET + 2)
45 #define FIRMWARE_UCODE_4 (FIRMWARE_UCODE_OFFSET + 4)
46 #define FIRMWARE_UCODE_5 (FIRMWARE_UCODE_OFFSET + 5)
47 #define FIRMWARE_UCODE_11 (FIRMWARE_UCODE_OFFSET + 11)
50 #define fwcutter_stringify_1(x) #x
51 #define fwcutter_stringify(x) fwcutter_stringify_1(x)
52 #define FWCUTTER_VERSION fwcutter_stringify(FWCUTTER_VERSION_)
55 #include "fwcutter_list.h"
61 const char *target_dir
;
65 static struct cmdline_args cmdargs
;
69 static void write_little_endian(FILE *f
, byte
*buffer
, int len
)
74 swapbuf
[0] = buffer
[3]; swapbuf
[1] = buffer
[2];
75 swapbuf
[2] = buffer
[1]; swapbuf
[3] = buffer
[0];
76 fwrite(swapbuf
, 4, 1, f
);
82 static void write_big_endian(FILE *f
, byte
*buffer
, int len
)
85 fwrite(buffer
, 4, 1, f
);
91 static void write_fw(const char *outfilename
, uint8_t flags
, byte
*data
, int len
)
96 snprintf(outfile
, sizeof(outfile
),
97 "%s/%s", cmdargs
.target_dir
, outfilename
);
99 fw
= fopen(outfile
, "w");
105 if (flags
& BYTE_ORDER_LITTLE_ENDIAN
)
106 write_little_endian(fw
, data
, len
);
107 else if (flags
& BYTE_ORDER_BIG_ENDIAN
)
108 write_big_endian(fw
, data
, len
);
110 printf("unknown byteorder...\n");
116 static void write_iv(uint8_t flags
, byte
*data
)
119 char ivfilename
[2048];
122 for (i
= 1; i
<= 10; i
++) {
124 if ((flags
& MISSING_INITVAL_08
) && (i
==8)) {
125 printf("*****: Sorry, initval08 is not available in driver file \"%s\".\n", cmdargs
.infile
);
126 printf("*****: Extracting firmware from an old driver is bad. Choose a more recent one.\n");
127 printf("*****: Luckily bcm43xx driver doesn't include initval08 uploads at the moment.\n");
128 printf("*****: But this can be added in the future...\n");
132 snprintf(ivfilename
, sizeof(ivfilename
),
133 "%s/bcm43xx_initval%02d%s.fw",
134 cmdargs
.target_dir
, i
, cmdargs
.postfix
);
135 fw
= fopen(ivfilename
, "w");
142 printf("extracting bcm43xx_initval%02d%s.fw ...\n", i
, cmdargs
.postfix
);
146 if ((data
[0]==0xff) && (data
[1]==0xff) && (data
[2]==0x00) && (data
[3]==0x00)) {
151 if (flags
& BYTE_ORDER_LITTLE_ENDIAN
)
152 fprintf(fw
, "%c%c%c%c%c%c%c%c",
153 data
[1], data
[0], /* offset */
154 data
[3], data
[2], /* size */
155 data
[7], data
[6], data
[5], data
[4]); /* value */
156 else if (flags
& BYTE_ORDER_BIG_ENDIAN
)
157 fprintf(fw
, "%c%c%c%c%c%c%c%c",
158 data
[0], data
[1], /* offset */
159 data
[2], data
[3], /* size */
160 data
[4], data
[5], data
[6], data
[7]); /* value */
162 printf("unknown byteorder...\n");
173 static byte
* read_file(const char* filename
)
179 file
= fopen(filename
, "rb");
184 if (fseek(file
, 0, SEEK_END
)) {
185 perror("cannot seek");
189 fseek(file
, 0, SEEK_SET
);
192 fputs("out of memory\n", stderr
);
195 if (fread(data
, 1, len
, file
) != len
) {
196 perror("cannot read");
203 static void extract_fw(uint8_t fwtype
, uint8_t flags
, uint32_t pos
, uint32_t length
)
209 case FIRMWARE_UCODE_2
:
210 case FIRMWARE_UCODE_4
:
211 case FIRMWARE_UCODE_5
:
212 case FIRMWARE_UCODE_11
:
213 snprintf(outfile
, sizeof(outfile
), "bcm43xx_microcode%i%s.fw",
214 fwtype
- FIRMWARE_UCODE_OFFSET
, cmdargs
.postfix
);
218 snprintf(outfile
, sizeof(outfile
), "bcm43xx_pcm%i%s.fw",
219 fwtype
, cmdargs
.postfix
);
222 snprintf(outfile
, sizeof(outfile
), "bcm43xx_unknown.fw");
226 printf("extracting %s ...\n", outfile
);
227 filedata
= read_file(cmdargs
.infile
);
228 write_fw(outfile
, flags
, filedata
+ pos
, length
);
231 printf("*****: Sorry, it's not posible to extract \"%s\".\n", outfile
);
232 printf("*****: Extracting firmware from an old driver is bad. Choose a more recent one.\n");
235 case FIRMWARE_UCODE_2
:
236 printf("*****: bcm43xx driver will not work with with core revision 2.\n");
238 case FIRMWARE_UCODE_4
:
239 printf("*****: bcm43xx driver will not work with with core revision 4.\n");
241 case FIRMWARE_UCODE_5
:
242 printf("*****: bcm43xx driver will not work with with core revision 5 or higher.\n");
244 case FIRMWARE_UCODE_11
:
245 printf("*****: Luckily bcm43xx driver doesn't include microcode11 uploads at the moment.\n");
246 printf("*****: But this can be added in the future...\n");
249 printf("*****: bcm43xx driver will not work with with core revision 4 or smaller.\n");
252 printf("*****: bcm43xx driver will not work with with core revision 5 or higher.\n");
258 static void extract_iv(uint8_t flags
, uint32_t pos
)
263 filedata
= read_file(cmdargs
.infile
);
264 write_iv(flags
, filedata
+ pos
);
269 static void print_banner(void)
271 printf("fwcutter " FWCUTTER_VERSION
"\n");
274 static void print_file(const struct file
*file
)
276 printf("%s\t", file
->name
);
277 if (strlen(file
->name
) < 8)
280 printf("%s\t", file
->version
);
281 if (strlen(file
->version
) < 8)
283 if (strlen(file
->version
) < 16)
286 if (!(file
->flags
& DRIVER_UNSUPPORTED
)) {
287 if (file
->flags
& MISSING_INITVAL_80211_A
)
293 printf(" %s", file
->md5
);
297 static void print_supported_files(void)
302 printf("\nExtracting firmware is possible from these binary driver files:\n\n");
303 printf("<filename>\t<version>\t <802.11><MD5 checksum>\n\n");
304 for (i
= 0; i
< FILES
; i
++) {
305 if (files
[i
].flags
& DRIVER_UNSUPPORTED
)
307 print_file(&files
[i
]);
309 printf("\n\nExtracting firmware is IMPOSSIBLE from these binary driver files:\n\n");
310 printf("<filename>\t<version>\t <MD5 checksum>\n\n");
311 for (i
= 0; i
< FILES
; i
++) {
312 if (!(files
[i
].flags
& DRIVER_UNSUPPORTED
))
314 print_file(&files
[i
]);
318 static const struct file
* find_file(FILE *fd
)
320 unsigned char buffer
[16384], signature
[16];
321 struct MD5Context md5c
;
326 while ((i
= (int) fread(buffer
, 1, sizeof(buffer
), fd
)) > 0)
327 MD5Update(&md5c
, buffer
, (unsigned) i
);
328 MD5Final(signature
, &md5c
);
330 snprintf(md5sig
, sizeof(md5sig
),
331 "%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x",
332 signature
[0], signature
[1], signature
[2], signature
[3],
333 signature
[4], signature
[5], signature
[6], signature
[7],
334 signature
[8], signature
[9], signature
[10], signature
[11],
335 signature
[12], signature
[13], signature
[14], signature
[15]);
337 for (i
= 0; i
< FILES
; ++i
) {
338 if (strcasecmp(md5sig
, files
[i
].md5
) == 0) {
339 if (files
[i
].flags
& DRIVER_UNSUPPORTED
) {
340 printf("Extracting firmware from this file is IMPOSSIBLE. (too old)\n");
343 printf("fwcutter can cut the firmware out of %s\n", cmdargs
.infile
);
344 printf(" filename : %s\n", files
[i
].name
);
345 printf(" version : %s\n", files
[i
].version
);
346 printf(" MD5 : %s\n\n", files
[i
].md5
);
347 if (files
[i
].flags
& MISSING_INITVAL_80211_A
) {
348 printf("WARNING! This firmware doesn't include support for 802.11a cards.\n");
349 printf("WARNING! Use this firmware only for 802.11b/g cards.\n\n");
354 printf("Sorry, the input file is either wrong or not supported by fwcutter.\n");
355 printf("I can't find the MD5sum %s :(\n", md5sig
);
360 static void get_endianess(void)
362 const unsigned char x
[] = { 0xde, 0xad, 0xbe, 0xef, };
363 const uint32_t *p
= (uint32_t *)x
;
365 if (*p
== 0xdeadbeef) {
367 } else if (*p
== 0xefbeadde) {
370 printf("Confused: NUXI endian machine??\n");
375 static void print_usage(int argc
, char *argv
[])
378 printf("\nUsage: %s [OPTION] [driver.sys]\n", argv
[0]);
379 printf(" -l|--list List supported driver versions\n");
380 printf(" -i|--identify Only identify the driver file (don't extract)\n");
381 printf(" -w|--target-dir DIR Extract and write firmware to DIR\n");
382 printf(" -p|--postfix \".FOO\" Postfix for firmware filenames (.FOO.fw)\n");
383 printf(" -v|--version Print fwcutter version\n");
384 printf(" -h|--help Print this help\n");
385 printf("\nExample: %s bcmwl5.sys\n"
386 " to extract the firmware blobs from bcmwl5.sys\n", argv
[0]);
390 #define ARG_NOMATCH 1
393 static int do_cmp_arg(char **argv
, int *pos
,
394 const char *template,
400 size_t arg_len
, template_len
;
403 next_arg
= argv
[*pos
+ 1];
404 arg_len
= strlen(arg
);
405 template_len
= strlen(template);
408 /* Maybe we have a merged parameter here.
409 * A merged parameter is "-pfoobar" for example.
411 if (allow_merged
&& arg_len
> template_len
) {
412 if (memcmp(arg
, template, template_len
) == 0) {
413 *param
= arg
+ template_len
;
417 } else if (arg_len
!= template_len
)
421 if (strcmp(arg
, template) == 0) {
423 /* Skip the parameter on the next iteration. */
426 printf("%s needs a parameter\n", arg
);
436 /* Simple and lean command line argument parsing. */
437 static int cmp_arg(char **argv
, int *pos
,
438 const char *long_template
,
439 const char *short_template
,
445 err
= do_cmp_arg(argv
, pos
, long_template
, 0, param
);
446 if (err
== ARG_MATCH
|| err
== ARG_ERROR
)
451 err
= do_cmp_arg(argv
, pos
, short_template
, 1, param
);
455 static int parse_args(int argc
, char *argv
[])
462 for (i
= 1; i
< argc
; i
++) {
463 res
= cmp_arg(argv
, &i
, "--list", "-l", 0);
464 if (res
== ARG_MATCH
) {
465 print_supported_files();
467 } else if (res
== ARG_ERROR
)
470 res
= cmp_arg(argv
, &i
, "--version", "-v", 0);
471 if (res
== ARG_MATCH
) {
474 } else if (res
== ARG_ERROR
)
477 res
= cmp_arg(argv
, &i
, "--help", "-h", 0);
478 if (res
== ARG_MATCH
)
480 else if (res
== ARG_ERROR
)
483 res
= cmp_arg(argv
, &i
, "--identify", "-i", 0);
484 if (res
== ARG_MATCH
) {
485 cmdargs
.identify_only
= 1;
487 } else if (res
== ARG_ERROR
)
490 res
= cmp_arg(argv
, &i
, "--target-dir", "-w", ¶m
);
491 if (res
== ARG_MATCH
) {
492 cmdargs
.target_dir
= param
;
494 } else if (res
== ARG_ERROR
)
497 res
= cmp_arg(argv
, &i
, "--postfix", "-p", ¶m
);
498 if (res
== ARG_MATCH
) {
499 cmdargs
.postfix
= param
;
501 } else if (res
== ARG_ERROR
)
504 cmdargs
.infile
= argv
[i
];
513 print_usage(argc
, argv
);
518 int main(int argc
, char *argv
[])
521 const struct file
*file
;
526 cmdargs
.target_dir
= ".";
527 cmdargs
.postfix
= "";
528 err
= parse_args(argc
, argv
);
534 fd
= fopen(cmdargs
.infile
, "rb");
536 fprintf(stderr
, "Cannot open input file %s\n", cmdargs
.infile
);
541 file
= find_file(fd
);
544 if (cmdargs
.identify_only
) {
549 extract_fw(FIRMWARE_UCODE_2
, file
->flags
, file
->uc2_pos
, file
->uc2_length
);
550 extract_fw(FIRMWARE_UCODE_4
, file
->flags
, file
->uc4_pos
, file
->uc4_length
);
551 extract_fw(FIRMWARE_UCODE_5
, file
->flags
, file
->uc5_pos
, file
->uc5_length
);
552 extract_fw(FIRMWARE_UCODE_11
, file
->flags
, file
->uc11_pos
, file
->uc11_length
);
553 extract_fw(FIRMWARE_PCM_4
, file
->flags
, file
->pcm4_pos
, file
->pcm4_length
);
554 extract_fw(FIRMWARE_PCM_5
, file
->flags
, file
->pcm5_pos
, file
->pcm5_length
);
555 extract_iv(file
->flags
, file
->iv_pos
);
This page took 0.069119 seconds and 5 git commands to generate.