 a8d751c243
			
		
	
	a8d751c243
	
	
	
		
			
			Installs to /lib/firmware for newer cfg80211 versions Signed-off-by: Felix Fietkau <nbd@nbd.name>
		
			
				
	
	
		
			252 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			252 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| From: Johannes Berg <johannes.berg@intel.com>
 | |
| Date: Mon, 9 Oct 2017 11:50:57 +0200
 | |
| Subject: [PATCH] regdb: write firmware file format (version code 20)
 | |
| 
 | |
| TODO: clean up the Makefile stuff ...
 | |
| 
 | |
| Signed-off-by: Johannes Berg <johannes.berg@intel.com>
 | |
| ---
 | |
|  create mode 100755 db2fw.py
 | |
| 
 | |
| --- a/Makefile
 | |
| +++ b/Makefile
 | |
| @@ -1,7 +1,5 @@
 | |
|  # Install prefix
 | |
|  PREFIX ?= /usr
 | |
| -CRDA_PATH ?= $(PREFIX)/lib/crda
 | |
| -CRDA_KEY_PATH ?= $(CRDA_PATH)/pubkeys
 | |
|  
 | |
|  MANDIR ?= $(PREFIX)/share/man/
 | |
|  
 | |
| @@ -30,39 +28,47 @@ REGDB_AUTHOR ?= $(shell if [ -f $(DISTRO
 | |
|  		fi)
 | |
|  
 | |
|  REGDB_PRIVKEY ?= ~/.wireless-regdb-$(REGDB_AUTHOR).key.priv.pem
 | |
| -REGDB_PUBKEY ?= $(REGDB_AUTHOR).key.pub.pem
 | |
| -
 | |
| -REGDB_UPSTREAM_PUBKEY ?= sforshee.key.pub.pem
 | |
| +REGDB_PUBCERT ?= $(REGDB_AUTHOR).x509.pem
 | |
|  
 | |
|  REGDB_CHANGED = $(shell $(SHA1SUM) -c --status sha1sum.txt >/dev/null 2>&1; \
 | |
|          if [ $$? -ne 0 ]; then \
 | |
| -                echo maintainer-clean $(REGDB_PUBKEY); \
 | |
| +                echo maintainer-clean $(REGDB_PUBCERT); \
 | |
|          fi)
 | |
|  
 | |
|  .PHONY: all clean mrproper install maintainer-clean install-distro-key
 | |
|  
 | |
| -all: $(REGDB_CHANGED) regulatory.bin sha1sum.txt
 | |
| +all: $(REGDB_CHANGED) regulatory.db.p7s sha1sum.txt
 | |
|  
 | |
|  clean:
 | |
|  	@rm -f *.pyc *.gz
 | |
|  
 | |
|  maintainer-clean: clean
 | |
| -	@rm -f regulatory.bin
 | |
| +	@rm -f regulatory.db regulatory.db.p7s
 | |
|  
 | |
|  mrproper: clean maintainer-clean
 | |
| -	@echo Removed public key, regulatory.bin and compresed man pages
 | |
| -	@rm -f $(REGDB_PUBKEY) .custom
 | |
| +	@echo Removed public key, regulatory.db* and compressed man pages
 | |
| +	@rm -f $(REGDB_PUBCERT) .custom
 | |
|  
 | |
| -regulatory.bin: db.txt $(REGDB_PRIVKEY) $(REGDB_PUBKEY)
 | |
| -	@echo Generating $@ digitally signed by $(REGDB_AUTHOR)...
 | |
| -	./db2bin.py regulatory.bin db.txt $(REGDB_PRIVKEY)
 | |
| +regulatory.db: db.txt db2fw.py
 | |
| +	@echo "Generating $@"
 | |
| +	./db2fw.py regulatory.db db.txt
 | |
| +
 | |
| +regulatory.db.p7s: regulatory.db $(REGDB_PRIVKEY) $(REGDB_PUBCERT)
 | |
| +	@echo "Signing regulatory.db (by $(REGDB_AUTHOR))..."
 | |
| +	@openssl smime -sign \
 | |
| +		-signer $(REGDB_PUBCERT) \
 | |
| +		-inkey $(REGDB_PRIVKEY) \
 | |
| +		-in $< -nosmimecap -binary \
 | |
| +		-outform DER -out $@
 | |
|  
 | |
|  sha1sum.txt: db.txt
 | |
|  	sha1sum $< > $@
 | |
|  
 | |
| -$(REGDB_PUBKEY): $(REGDB_PRIVKEY)
 | |
| -	@echo "Generating public key for $(REGDB_AUTHOR)..."
 | |
| -	openssl rsa -in $(REGDB_PRIVKEY) -out $(REGDB_PUBKEY) -pubout -outform PEM
 | |
| +$(REGDB_PUBCERT): $(REGDB_PRIVKEY)
 | |
| +	@echo "Generating certificate for $(REGDB_AUTHOR)..."
 | |
| +	@openssl req -config regulatory.openssl.conf \
 | |
| +		-key $(REGDB_PRIVKEY) -days 36500 -utf8 -nodes -batch \
 | |
| +		-x509 -outform PEM -out $(REGDB_PUBCERT)
 | |
|  	@echo $(REGDB_PUBKEY) > .custom
 | |
|  
 | |
|  
 | |
| @@ -97,16 +103,7 @@ install-distro-key: maintainer-clean $(D
 | |
|  #	make maintainer-clean
 | |
|  #	make
 | |
|  #	sudo make install
 | |
| -install: regulatory.bin.5.gz
 | |
| -	install -m 755 -d $(DESTDIR)/$(CRDA_PATH)
 | |
| -	install -m 755 -d $(DESTDIR)/$(CRDA_KEY_PATH)
 | |
| -	if [ -f .custom ]; then \
 | |
| -		install -m 644 -t $(DESTDIR)/$(CRDA_KEY_PATH)/ $(shell cat .custom); \
 | |
| -	fi
 | |
| -	install -m 644 -t $(DESTDIR)/$(CRDA_KEY_PATH)/ $(REGDB_UPSTREAM_PUBKEY)
 | |
| -	install -m 644 -t $(DESTDIR)/$(CRDA_PATH)/ regulatory.bin
 | |
| +install: regulatory.db.5.gz
 | |
| +	install -m 644 -t $(DESTDIR)/$(CRDA_PATH)/ regulatory.db
 | |
|  	install -m 755 -d $(DESTDIR)/$(MANDIR)/man5/
 | |
| -	install -m 644 -t $(DESTDIR)/$(MANDIR)/man5/ regulatory.bin.5.gz
 | |
| -
 | |
| -uninstall:
 | |
| -	rm -rf $(DESTDIR)/$(CRDA_PATH)/
 | |
| +	install -m 644 -t $(DESTDIR)/$(MANDIR)/man5/ regulatory.db.5.gz
 | |
| --- a/README
 | |
| +++ b/README
 | |
| @@ -18,8 +18,8 @@ python module is used by the web viewer
 | |
|  implemented as a MoinMoin macro (and used on http://wireless.kernel.org)
 | |
|  to allow viewing the database for verification.
 | |
|  
 | |
| -The dbparse module is also used by db2bin.py, the `compiler', which
 | |
| -compiles and signs the binary database.
 | |
| +The dbparse module is also used by db2bin.py and db2fw.py, the `compilers'
 | |
| +that compile the database to its binary formats.
 | |
|  
 | |
|  For more information, please see the CRDA git repository:
 | |
|  
 | |
| --- /dev/null
 | |
| +++ b/db2fw.py
 | |
| @@ -0,0 +1,133 @@
 | |
| +#!/usr/bin/env python
 | |
| +
 | |
| +from cStringIO import StringIO
 | |
| +import struct
 | |
| +import hashlib
 | |
| +from dbparse import DBParser
 | |
| +import sys
 | |
| +
 | |
| +MAGIC = 0x52474442
 | |
| +VERSION = 20
 | |
| +
 | |
| +if len(sys.argv) < 3:
 | |
| +    print 'Usage: %s output-file input-file' % sys.argv[0]
 | |
| +    sys.exit(2)
 | |
| +
 | |
| +def create_rules(countries):
 | |
| +    result = {}
 | |
| +    for c in countries.itervalues():
 | |
| +        for rule in c.permissions:
 | |
| +            result[rule] = 1
 | |
| +    return result.keys()
 | |
| +
 | |
| +def create_collections(countries):
 | |
| +    result = {}
 | |
| +    for c in countries.itervalues():
 | |
| +        result[(c.permissions, c.dfs_region)] = 1
 | |
| +    return result.keys()
 | |
| +
 | |
| +
 | |
| +def be32(output, val):
 | |
| +    output.write(struct.pack('>I', val))
 | |
| +def be16(output, val):
 | |
| +    output.write(struct.pack('>H', val))
 | |
| +
 | |
| +class PTR(object):
 | |
| +    def __init__(self, output):
 | |
| +        self._output = output
 | |
| +        self._pos = output.tell()
 | |
| +        be16(output, 0)
 | |
| +        self._written = False
 | |
| +
 | |
| +    def set(self, val=None):
 | |
| +        if val is None:
 | |
| +            val = self._output.tell()
 | |
| +        assert val & 3 == 0
 | |
| +        self._offset = val
 | |
| +        pos = self._output.tell()
 | |
| +        self._output.seek(self._pos)
 | |
| +        be16(self._output, val >> 2)
 | |
| +        self._output.seek(pos)
 | |
| +        self._written = True
 | |
| +
 | |
| +    def get(self):
 | |
| +        return self._offset
 | |
| +
 | |
| +    @property
 | |
| +    def written(self):
 | |
| +        return self._written
 | |
| +
 | |
| +p = DBParser()
 | |
| +countries = p.parse(file(sys.argv[2]))
 | |
| +rules = create_rules(countries)
 | |
| +rules.sort(cmp=lambda x, y: cmp(x.freqband, y.freqband))
 | |
| +collections = create_collections(countries)
 | |
| +collections.sort(cmp=lambda x, y: cmp(x[0][0].freqband, y[0][0].freqband))
 | |
| +
 | |
| +output = StringIO()
 | |
| +
 | |
| +# struct regdb_file_header
 | |
| +be32(output, MAGIC)
 | |
| +be32(output, VERSION)
 | |
| +
 | |
| +country_ptrs = {}
 | |
| +countrynames = countries.keys()
 | |
| +countrynames.sort()
 | |
| +for alpha2 in countrynames:
 | |
| +    coll = countries[alpha2]
 | |
| +    output.write(struct.pack('>cc', str(alpha2[0]), str(alpha2[1])))
 | |
| +    country_ptrs[alpha2] = PTR(output)
 | |
| +output.write('\x00' * 4)
 | |
| +
 | |
| +reg_rules = {}
 | |
| +flags = 0
 | |
| +for reg_rule in rules:
 | |
| +    freq_range, power_rule = reg_rule.freqband, reg_rule.power
 | |
| +    reg_rules[reg_rule] = output.tell()
 | |
| +    assert power_rule.max_ant_gain == 0
 | |
| +    flags = 0
 | |
| +    # convert to new rule flags
 | |
| +    assert reg_rule.flags & ~0x899 == 0
 | |
| +    if reg_rule.flags & 1<<0:
 | |
| +        flags |= 1<<0
 | |
| +    if reg_rule.flags & 1<<3:
 | |
| +        flags |= 1<<1
 | |
| +    if reg_rule.flags & 1<<4:
 | |
| +        flags |= 1<<2
 | |
| +    if reg_rule.flags & 1<<7:
 | |
| +        flags |= 1<<3
 | |
| +    if reg_rule.flags & 1<<11:
 | |
| +        flags |= 1<<4
 | |
| +    rule_len = 16
 | |
| +    cac_timeout = 0 # TODO
 | |
| +    if not (flags & 1<<2):
 | |
| +        cac_timeout = 0
 | |
| +    if cac_timeout:
 | |
| +        rule_len += 2
 | |
| +    output.write(struct.pack('>BBHIII', rule_len, flags, power_rule.max_eirp * 100,
 | |
| +                             freq_range.start * 1000, freq_range.end * 1000, freq_range.maxbw * 1000,
 | |
| +                             ))
 | |
| +    if cac_timeout:
 | |
| +        output.write(struct.pack('>H', cac_timeout))
 | |
| +    while rule_len % 4:
 | |
| +        output.write('\0')
 | |
| +        rule_len += 1
 | |
| +
 | |
| +for coll in collections:
 | |
| +    for alpha2 in countrynames:
 | |
| +        if (countries[alpha2].permissions, countries[alpha2].dfs_region) == coll:
 | |
| +            assert not country_ptrs[alpha2].written
 | |
| +            country_ptrs[alpha2].set()
 | |
| +    slen = 3
 | |
| +    output.write(struct.pack('>BBBx', slen, len(list(coll[0])), coll[1]))
 | |
| +    coll = list(coll[0])
 | |
| +    for regrule in coll:
 | |
| +        be16(output, reg_rules[regrule] >> 2)
 | |
| +    if len(coll) % 2:
 | |
| +        be16(output, 0)
 | |
| +
 | |
| +for alpha2 in countrynames:
 | |
| +    assert country_ptrs[alpha2].written
 | |
| +
 | |
| +outfile = open(sys.argv[1], 'w')
 | |
| +outfile.write(output.getvalue())
 |