nexmon – Rev 1
?pathlinks?
#!/usr/bin/env python
"""
# Copyright (C) 2010 Michael Buesch <m@bues.ch>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2
# as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
"""
import sys
import getopt
def indexToName(index):
D11UCODE_NAMETAG_START = 0
D11LCN0BSINITVALS24 = 1
D11LCN0INITVALS24 = 2
D11LCN1BSINITVALS24 = 3
D11LCN1INITVALS24 = 4
D11LCN2BSINITVALS24 = 5
D11LCN2INITVALS24 = 6
D11N0ABSINITVALS16 = 7
D11N0BSINITVALS16 = 8
D11N0INITVALS16 = 9
D11UCODE_OVERSIGHT16_MIMO = 10
D11UCODE_OVERSIGHT16_MIMOSZ = 11
D11UCODE_OVERSIGHT24_LCN = 12
D11UCODE_OVERSIGHT24_LCNSZ = 13
D11UCODE_OVERSIGHT_BOMMAJOR = 14
D11UCODE_OVERSIGHT_BOMMINOR = 15
namemap = {
D11UCODE_NAMETAG_START : "start",
D11LCN0BSINITVALS24 : "LCN0 bs initvals 24",
D11LCN0INITVALS24 : "LCN0 initvals 24",
D11LCN1BSINITVALS24 : "LCN1 bs initvals 24",
D11LCN1INITVALS24 : "LCN1 initvals 24",
D11LCN2BSINITVALS24 : "LCN2 bs initvals 24",
D11LCN2INITVALS24 : "LCN2 initvals 24",
D11N0ABSINITVALS16 : "N0A bs initvals 16",
D11N0BSINITVALS16 : "N0 bs initvals 16",
D11N0INITVALS16 : "N0 initvals 16",
D11UCODE_OVERSIGHT16_MIMO : "microcode 16 MIMO",
D11UCODE_OVERSIGHT16_MIMOSZ : "microcode 16 MIMO size",
D11UCODE_OVERSIGHT24_LCN : "microcode 24 LCN",
D11UCODE_OVERSIGHT24_LCNSZ : "microcode 24 LCN size",
D11UCODE_OVERSIGHT_BOMMAJOR : "bom major",
D11UCODE_OVERSIGHT_BOMMINOR : "bom minor",
}
try:
return namemap[index]
except KeyError:
return "Unknown"
def parseHeader(hdr_data, sortByOffset):
sections = []
for i in range(0, len(hdr_data), 3 * 4):
offset = ord(hdr_data[i + 0]) | (ord(hdr_data[i + 1]) << 8) |\
(ord(hdr_data[i + 2]) << 16) | (ord(hdr_data[i + 3]) << 24)
length = ord(hdr_data[i + 4]) | (ord(hdr_data[i + 5]) << 8) |\
(ord(hdr_data[i + 6]) << 16) | (ord(hdr_data[i + 7]) << 24)
index = ord(hdr_data[i + 8]) | (ord(hdr_data[i + 9]) << 8) |\
(ord(hdr_data[i + 10]) << 16) | (ord(hdr_data[i + 11]) << 24)
sections.append( (offset, length, index) )
if sortByOffset:
sections.sort(key = lambda x: x[0]) # Sort by offset
else:
sections.sort(key = lambda x: x[2]) # Sort by index
return sections
def generateHeaderData(sections):
data = []
for section in sections:
(offset, length, index) = section
data.append(chr(offset & 0xFF))
data.append(chr((offset >> 8) & 0xFF))
data.append(chr((offset >> 16) & 0xFF))
data.append(chr((offset >> 24) & 0xFF))
data.append(chr(length & 0xFF))
data.append(chr((length >> 8) & 0xFF))
data.append(chr((length >> 16) & 0xFF))
data.append(chr((length >> 24) & 0xFF))
data.append(chr(index & 0xFF))
data.append(chr((index >> 8) & 0xFF))
data.append(chr((index >> 16) & 0xFF))
data.append(chr((index >> 24) & 0xFF))
return "".join(data)
def getSectionByIndex(sections, searchIndex):
for section in sections:
(offset, length, index) = section
if searchIndex == index:
return section
return None
def parseHeaderFile(hdr_filepath, sortByOffset=False):
try:
hdr_data = file(hdr_filepath, "rb").read()
except (IOError), e:
print "Failed to read header file: %s" % e.strerror
return None
if len(hdr_data) % (3 * 4) != 0:
print "Invalid header file format"
return None
return parseHeader(hdr_data, sortByOffset)
def dumpInfo(hdr_filepath):
sections = parseHeaderFile(hdr_filepath)
if not sections:
return 1
for section in sections:
(offset, length, index) = section
print "Index %2d %24s ==> offset:0x%08X length:0x%08X" %\
(index, indexToName(index), offset, length)
return 0
def extractSection(hdr_filepath, bin_filepath, extractIndex, outfilePath):
sections = parseHeaderFile(hdr_filepath)
if not sections:
return 1
section = getSectionByIndex(sections, extractIndex)
if not section:
print "Did not find a section with index %d" % extractIndex
return 1
(offset, length, index) = section
try:
bin_data = file(bin_filepath, "rb").read()
except (IOError), e:
print "Failed to read bin file: %s" % e.strerror
return 1
try:
outfile = file(outfilePath, "wb")
outfile.write(bin_data[offset : offset + length])
except IndexError:
print "Binfile index error."
return 1
except (IOError), e:
print "Failed to write output file: %s" % e.strerror
return 1
return 0
def mergeSection(hdr_filepath, bin_filepath, mergeIndex, mergefilePath):
sections = parseHeaderFile(hdr_filepath, sortByOffset=True)
if not sections:
return 1
try:
bin_data = file(bin_filepath, "rb").read()
except (IOError), e:
print "Failed to read bin file: %s" % e.strerror
return 1
try:
merge_data = file(mergefilePath, "rb").read()
except (IOError), e:
print "Failed to open merge output file: %s" % e.strerror
return 1
newBin = []
newSections = []
newOffset = 0
foundIt = False
for section in sections:
(offset, length, index) = section
if index == mergeIndex:
if foundIt:
print "Confused. Multiple sections with index %d?" % index
return 1
foundIt = True
# We overwrite this section
newBin.append(merge_data)
newSections.append( (newOffset, len(merge_data), index) )
newOffset += len(merge_data)
else:
try:
newBin.append(bin_data[offset : offset + length])
except IndexError:
print "Failed to read input data"
return 1
newSections.append( (newOffset, length, index) )
newOffset += length
if not foundIt:
print "Did not find section with index %d" % mergeIndex
return 1
newBin = "".join(newBin)
newHdr = generateHeaderData(newSections)
try:
file(bin_filepath, "wb").write(newBin)
file(hdr_filepath, "wb").write(newHdr)
except (IOError), e:
print "Failed to write bin or header file: %s" % e.strerror
return 1
return 0
def usage():
print "BRCM80211 firmware converter tool"
print ""
print "Usage: %s [OPTIONS]" % sys.argv[0]
print ""
print " -H|--header FILE Use FILE as header file"
print " -B|--bin FILE Use FILE as bin file"
print ""
print "Actions:"
print " -d|--dump Dump general information"
print " -x|--extract INDEX:FILE Extract the section with index INDEX to FILE"
print " -m|--merge INDEX:FILE Merges FILE into the bin file stream at INDEX"
print " A Merge modifies the files specified in -H and -B"
print ""
print " -h|--help Print this help text"
def main():
opt_header = None
opt_bin = None
opt_action = None
opt_index = None
opt_outfile = None
opt_mergefile = None
try:
(opts, args) = getopt.getopt(sys.argv[1:],
"hH:B:dx:m:",
[ "help", "header=", "bin=", "dump", "extract=", "merge=", ])
except getopt.GetoptError:
usage()
return 1
for (o, v) in opts:
if o in ("-h", "--help"):
usage()
return 0;
if o in ("-H", "--header"):
opt_header = v
if o in ("-B", "--bin"):
opt_bin = v
if o in ("-d", "--dump"):
opt_action = "dump"
if o in ("-x", "--extract"):
opt_action = "extract"
try:
v = v.split(':')
opt_index = int(v[0])
opt_outfile = v[1]
except IndexError, ValueError:
print "Invalid -x|--extract index number\n"
usage()
return 1
if o in ("-m", "--merge"):
opt_action = "merge"
try:
v = v.split(':')
opt_index = int(v[0])
opt_mergefile = v[1]
except IndexError, ValueError:
print "Invalid -m|--merge index and/or merge file name\n"
usage()
return 1
if not opt_action:
print "No action specified\n"
usage()
return 1
if opt_action == "dump":
if not opt_header:
print "No header file specified\n"
usage()
return 1
return dumpInfo(opt_header)
elif opt_action == "extract":
if not opt_header or not opt_bin:
print "No header or bin file specified\n"
usage()
return 1
return extractSection(opt_header, opt_bin, opt_index, opt_outfile)
elif opt_action == "merge":
if not opt_header or not opt_bin:
print "No header or bin file specified\n"
usage()
return 1
return mergeSection(opt_header, opt_bin, opt_index, opt_mergefile)
return 1
if __name__ == "__main__":
sys.exit(main())