===================================================================
@@ -0,0 +1,344 @@
+/*
+ * virtual SPROM image writer for broadcom 43xx wireless devices
+ *
+ * This program creates an on-disk image of an SPROM for those BCM43xx
+ * devices that do not have a built-in SPROM. The image is created from
+ * one obtained from a BCM4315 with a random MAC address.
+ *
+ * Copyright (c) 2010 Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ * Some routines copied from b43-fwcutter, which is
+ *
+ * Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+ * 2005-2007 Michael Buesch <mb@bu3sch.de>
+ * 2005 Alex Beregszaszi
+ * 2007 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * Other routines from ssb_sprom, which is
+ *
+ * Copyright (c) 2006-2008 Michael Buesch <mb@bu3sch.de>
+ * Copyright (c) 2008 Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <stdint.h>
+#include <errno.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "vsprom.h"
+
+static struct cmdline_args cmdargs;
+
+uint8_t crc8(uint8_t crc, uint8_t data)
+{
+ static const uint8_t t[] = {
+ 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
+ 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
+ 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
+ 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
+ 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
+ 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
+ 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
+ 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
+ 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
+ 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
+ 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
+ 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
+ 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
+ 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
+ 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
+ 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
+ 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
+ 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
+ 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
+ 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
+ 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
+ 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
+ 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
+ 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
+ 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
+ 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
+ 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
+ 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
+ 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
+ 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
+ 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
+ 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F,
+ };
+ return t[crc ^ data];
+}
+
+static uint8_t sprom_crc(uint8_t *sprom, int sprom_size)
+{
+ int i;
+ uint8_t crc = 0xFF;
+
+ for (i = 0; i < sprom_size - 1; i++)
+ crc = crc8(crc, sprom[i]);
+ crc ^= 0xFF;
+
+ return crc;
+}
+
+static int validate_input(uint8_t *sprom, int sprom_size)
+{
+ uint8_t crc, expected_crc;
+
+ crc = sprom_crc(sprom, sprom_size);
+ expected_crc = sprom[sprom_size - 1];
+ if (crc != expected_crc) {
+ fprintf(stderr, "Corrupt input data (crc: 0x%02X, expected: 0x%02X)\n",
+ crc, expected_crc);
+ return 1;
+ }
+ return 0;
+}
+
+static void output_sprom_image(void)
+{
+ char nbuf[1024];
+ FILE *fd;
+ int i, r;
+ int sprom_size;
+
+ /* Rev 8 SPROM data copied from a BCM4312 */
+ uint8_t sprom_data[] = {
+ 0x01, 0x28, 0x00, 0x00, 0x7C, 0x13, 0x3C, 0x10, 0x78, 0x00,
+ 0xBE, 0x6D, 0x00, 0x00, 0xC4, 0x2B, 0x64, 0x2A, 0x64, 0x29,
+ 0x64, 0x2C, 0xE7, 0x3C, 0xFF, 0x46, 0x7F, 0x47, 0x00, 0x0C,
+ 0x40, 0x78, 0xA0, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x15, 0x43, 0x00, 0x80,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x72, 0x53,
+ 0x11, 0x12, 0x01, 0x0A, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1A, 0x00, 0xFE, 0x73, 0x64, 0xAD, 0x53, 0x55, 0x01, 0x00,
+ 0xFF, 0x83, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x02, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0xFF, 0xFF, 0x6C, 0x00,
+ 0xFF, 0xFF, 0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0x4A, 0x3E, 0x57, 0x1A, 0x8A, 0xF9, 0x91, 0xFE,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0x08, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x08, 0x5C
+ };
+
+ sprom_size = sizeof(sprom_data);
+ if (validate_input(sprom_data, sprom_size))
+ return;;
+ /* Initialize the random number generator */
+ srand(time(NULL));
+ /* generate a random MAC */
+ for (i = 0; i < 6; i++)
+ sprom_data[0x8C + i] = rand() % 64;
+ /* Adjust the random MAC to satisfy the following:
+ * 1. Clear the multicast bit - lsb of first byte
+ * 2. Set the LAA bit - bit 1 of first byte
+ */
+ sprom_data[0x8C] = (sprom_data[0x8C] & ~1) | 2;
+ /* calculate the new CRC and store it */
+ sprom_data[sprom_size - 1] = sprom_crc(sprom_data, sprom_size);
+
+ r = snprintf(nbuf, sizeof(nbuf),
+ "%s/ssb", cmdargs.target_dir);
+ if (r >= sizeof(nbuf)) {
+ fprintf(stderr, "name too long");
+ exit(2);
+ }
+
+ r = mkdir(nbuf, 0770);
+ if (r && errno != EEXIST) {
+ perror("failed to create output directory");
+ exit(2);
+ }
+
+ /* output the massaged SPROM image */
+ r = snprintf(nbuf, sizeof(nbuf), "%s/ssb/vsprom_image", cmdargs.target_dir);
+ if (r >= sizeof(nbuf)) {
+ fprintf(stderr, "name too long");
+ exit(2);
+ }
+ fd = fopen(nbuf, "r");
+ if (fd && !cmdargs.overwrite) {
+ printf("The virtual sprom already exists."
+ " To overwite, use the -O switch\n");
+ fclose(fd);
+ return;
+ }
+ fd = fopen(nbuf, "w");
+ if (!fd) {
+ printf("Failed to open SPROM image file\n");
+ return;
+ }
+ if (fwrite(sprom_data, sizeof(sprom_data), 1, fd) != 1)
+ printf("Error writing SPROM image file\n");
+ else
+ printf("Wrote virtual SPROM image at %s\n", nbuf);
+ fclose(fd);
+}
+
+static void print_usage(int argc, char *argv[])
+{
+ printf("\n%s\n", argv[0]);
+ printf("\nA tool to create an on-disk SPROM image for a Broadcom 43xx device\n");
+ printf("\nUsage: %s [OPTION]\n", argv[0]);
+ printf(" -O|--overwrite "
+ "Overwrite an existing image\n");
+ printf(" -w|--target-dir DIR "
+ "Write SPROM image to DIR (sub-directory /ssb is implicit)\n");
+ printf(" -h|--help "
+ "Print this help\n");
+ printf("\nExample: %s -w /lib/firmware\n"
+ " to store an SPROM image in /lib/firmware/ssb\n",
+ argv[0]);
+}
+
+static int do_cmp_arg(char **argv, int *pos,
+ const char *template,
+ int allow_merged,
+ char **param)
+{
+ char *arg;
+ char *next_arg;
+ size_t arg_len, template_len;
+
+ arg = argv[*pos];
+ next_arg = argv[*pos + 1];
+ arg_len = strlen(arg);
+ template_len = strlen(template);
+
+ if (param) {
+ /* Maybe we have a merged parameter here.
+ * A merged parameter is "-pfoobar" for example.
+ */
+ if (allow_merged && arg_len > template_len) {
+ if (memcmp(arg, template, template_len) == 0) {
+ *param = arg + template_len;
+ return ARG_MATCH;
+ }
+ return ARG_NOMATCH;
+ } else if (arg_len != template_len)
+ return ARG_NOMATCH;
+ *param = next_arg;
+ }
+ if (strcmp(arg, template) == 0) {
+ if (param) {
+ /* Skip the parameter on the next iteration. */
+ (*pos)++;
+ if (!*param) {
+ printf("%s needs a parameter\n", arg);
+ return ARG_ERROR;
+ }
+ }
+ return ARG_MATCH;
+ }
+
+ return ARG_NOMATCH;
+}
+
+/* Simple and lean command line argument parsing. */
+static int cmp_arg(char **argv, int *pos,
+ const char *long_template,
+ const char *short_template,
+ char **param)
+{
+ int err;
+
+ if (long_template) {
+ err = do_cmp_arg(argv, pos, long_template, 0, param);
+ if (err == ARG_MATCH || err == ARG_ERROR)
+ return err;
+ }
+ err = ARG_NOMATCH;
+ if (short_template)
+ err = do_cmp_arg(argv, pos, short_template, 1, param);
+ return err;
+}
+
+int main(int argc, char **argv)
+{
+ int i, res;
+ char *param;
+
+ cmdargs.overwrite = 0;
+ cmdargs.target_dir = ".";
+ for (i = 0; i < argc; i++) {
+ res = cmp_arg(argv, &i, "--target-dir", "-w", ¶m);
+ if (res == ARG_MATCH) {
+ cmdargs.target_dir = param;
+ continue;
+ } else if (res == ARG_ERROR)
+ goto out;
+ res = cmp_arg(argv, &i, "--overwrite", "-O", NULL);
+ if (res == ARG_MATCH) {
+ cmdargs.overwrite = 1;
+ continue;
+ } else if (res == ARG_ERROR)
+ goto out;
+ res = cmp_arg(argv, &i, "--help", "-h", NULL);
+ if (res == ARG_MATCH) {
+ goto out;
+ return 0;
+ } else if (res == ARG_ERROR)
+ goto out;
+ }
+ output_sprom_image();
+ return 0;
+out:
+ print_usage(argc, argv);
+ return 1;
+}
===================================================================
@@ -0,0 +1,37 @@
+CC = gcc
+
+PREFIX ?= /usr/local
+CFLAGS ?= -Os -fomit-frame-pointer
+CFLAGS += -std=c99 -Wall -pedantic -D_BSD_SOURCE
+LDFLAGS ?=
+
+SRCS = vsprom.c
+BIN = ssb-vsprom
+
+.SUFFIXES:
+.PHONY: all install clean distclean
+.DEFAULT_GOAL := all
+.SILENT:
+
+OBJS = vsprom.o
+
+# Generate object files
+$(OBJS): $(SRCS) vsprom.h
+ echo Compiling $<
+ $(CC) -o $@ -c $(CFLAGS) $<
+
+all: $(BIN)
+
+$(BIN): $(OBJS)
+ echo Linking $(BIN)
+ $(CC) $(CFLAGS) -o $(BIN) $(OBJS) $(LDFLAGS)
+
+install: all
+ install -d -o 0 -g 0 -m 755 $(PREFIX)/bin/
+ install -o 0 -g 0 -m 755 $(BIN) $(PREFIX)/bin/
+
+clean:
+ -rm -Rf obj dep *.orig *.rej *~
+
+distclean: clean
+ -rm -f *.fw $(BIN)
===================================================================
@@ -0,0 +1,13 @@
+#ifndef VSPROM_H
+#define VSPROM_H
+
+struct cmdline_args {
+ const char *target_dir;
+ int overwrite;
+};
+
+#define ARG_MATCH 0
+#define ARG_NOMATCH 1
+#define ARG_ERROR -1
+
+#endif /* VSPROM_H */