diff -Nru wireless-regdb-2022.06.06/db2bin.py wireless-regdb-2022.06.06/db2bin.py --- wireless-regdb-2022.06.06/db2bin.py 2022-06-06 14:46:02.000000000 +0000 +++ wireless-regdb-2022.06.06/db2bin.py 2023-10-30 19:12:05.000000000 +0000 @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/python3 from io import BytesIO, open import struct diff -Nru wireless-regdb-2022.06.06/db2fw.py wireless-regdb-2022.06.06/db2fw.py --- wireless-regdb-2022.06.06/db2fw.py 2022-06-06 14:46:02.000000000 +0000 +++ wireless-regdb-2022.06.06/db2fw.py 2023-10-30 19:12:05.000000000 +0000 @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/python3 from io import BytesIO, open import struct diff -Nru wireless-regdb-2022.06.06/dbparse.py wireless-regdb-2022.06.06/dbparse.py --- wireless-regdb-2022.06.06/dbparse.py 2022-06-06 14:46:02.000000000 +0000 +++ wireless-regdb-2022.06.06/dbparse.py 2023-10-30 19:12:05.000000000 +0000 @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/python3 from functools import total_ordering import sys, math diff -Nru wireless-regdb-2022.06.06/debian/bzr-builder.manifest wireless-regdb-2022.06.06/debian/bzr-builder.manifest --- wireless-regdb-2022.06.06/debian/bzr-builder.manifest 1970-01-01 00:00:00.000000000 +0000 +++ wireless-regdb-2022.06.06/debian/bzr-builder.manifest 2023-10-30 19:12:07.000000000 +0000 @@ -0,0 +1,2 @@ +# bzr-builder format 0.3 deb-version {debupstream}-N~11 +lp:~mmach/netext73/wireless-regdb revid:netbit73@gmail.com-20230616172116-g64t2d2ylovlh5v8 diff -Nru wireless-regdb-2022.06.06/debian/changelog wireless-regdb-2022.06.06/debian/changelog --- wireless-regdb-2022.06.06/debian/changelog 2023-07-17 21:43:02.000000000 +0000 +++ wireless-regdb-2022.06.06/debian/changelog 2023-10-30 19:12:07.000000000 +0000 @@ -1,8 +1,8 @@ -wireless-regdb (2022.06.06-0ubuntu2) mantic; urgency=medium +wireless-regdb (2022.06.06-N~11~ubuntu24.04.1) noble; urgency=low - * Drop shipping unused /lib/crda/regulatory.bin + * Auto build. - -- Dimitri John Ledkov Mon, 17 Jul 2023 22:43:02 +0100 + -- NetBit73 Mon, 30 Oct 2023 19:12:07 +0000 wireless-regdb (2022.06.06-0ubuntu1) kinetic; urgency=medium diff -Nru wireless-regdb-2022.06.06/debian/rules wireless-regdb-2022.06.06/debian/rules --- wireless-regdb-2022.06.06/debian/rules 2023-07-17 21:42:41.000000000 +0000 +++ wireless-regdb-2022.06.06/debian/rules 2023-10-30 19:12:05.000000000 +0000 @@ -43,7 +43,7 @@ # Install from source dir to ship upstream binaries $(MAKE) DESTDIR=$(CURDIR)/$(DIR) install # crda will install public keys - rm -r $(DIR)/lib/crda + rm -r $(DIR)/lib/crda/pubkeys override_dh_auto_clean: rm -rf .wireless-regdb-$(REGDB_AUTHOR).key.priv.pem $(REGDB_AUTHOR).key.pub.pem $(REGDB_AUTHOR).x509.pem diff -Nru wireless-regdb-2022.06.06/debian/source/format wireless-regdb-2022.06.06/debian/source/format --- wireless-regdb-2022.06.06/debian/source/format 2021-08-28 16:54:08.000000000 +0000 +++ wireless-regdb-2022.06.06/debian/source/format 2023-10-30 19:12:05.000000000 +0000 @@ -1 +1 @@ -3.0 (quilt) +3.0 (native) diff -Nru wireless-regdb-2022.06.06/Makefile wireless-regdb-2022.06.06/Makefile --- wireless-regdb-2022.06.06/Makefile 2022-06-06 14:46:02.000000000 +0000 +++ wireless-regdb-2022.06.06/Makefile 2023-10-30 19:12:05.000000000 +0000 @@ -30,7 +30,7 @@ echo custom-user; \ fi) -REGDB_PRIVKEY ?= ~/.wireless-regdb-$(REGDB_AUTHOR).key.priv.pem +REGDB_PRIVKEY ?= .wireless-regdb-$(REGDB_AUTHOR).key.priv.pem REGDB_PUBKEY ?= $(REGDB_AUTHOR).key.pub.pem REGDB_PUBCERT ?= $(REGDB_AUTHOR).x509.pem diff -Nru wireless-regdb-2022.06.06/.pc/applied-patches wireless-regdb-2022.06.06/.pc/applied-patches --- wireless-regdb-2022.06.06/.pc/applied-patches 1970-01-01 00:00:00.000000000 +0000 +++ wireless-regdb-2022.06.06/.pc/applied-patches 2023-10-30 19:12:05.000000000 +0000 @@ -0,0 +1,2 @@ +store-privkey-in-builddir.patch +run-scripts-with-python-3.patch diff -Nru wireless-regdb-2022.06.06/.pc/.quilt_patches wireless-regdb-2022.06.06/.pc/.quilt_patches --- wireless-regdb-2022.06.06/.pc/.quilt_patches 1970-01-01 00:00:00.000000000 +0000 +++ wireless-regdb-2022.06.06/.pc/.quilt_patches 2023-10-30 19:12:05.000000000 +0000 @@ -0,0 +1 @@ +debian/patches diff -Nru wireless-regdb-2022.06.06/.pc/.quilt_series wireless-regdb-2022.06.06/.pc/.quilt_series --- wireless-regdb-2022.06.06/.pc/.quilt_series 1970-01-01 00:00:00.000000000 +0000 +++ wireless-regdb-2022.06.06/.pc/.quilt_series 2023-10-30 19:12:05.000000000 +0000 @@ -0,0 +1 @@ +series diff -Nru wireless-regdb-2022.06.06/.pc/run-scripts-with-python-3.patch/db2bin.py wireless-regdb-2022.06.06/.pc/run-scripts-with-python-3.patch/db2bin.py --- wireless-regdb-2022.06.06/.pc/run-scripts-with-python-3.patch/db2bin.py 1970-01-01 00:00:00.000000000 +0000 +++ wireless-regdb-2022.06.06/.pc/run-scripts-with-python-3.patch/db2bin.py 2023-10-30 19:12:05.000000000 +0000 @@ -0,0 +1,147 @@ +#!/usr/bin/env python + +from io import BytesIO, open +import struct +import hashlib +from dbparse import DBParser +import sys + +MAGIC = 0x52474442 +VERSION = 19 + +if len(sys.argv) < 3: + print('Usage: %s output-file input-file [key-file]' % sys.argv[0]) + sys.exit(2) + +def create_rules(countries): + result = {} + for c in countries.values(): + for rule in c.permissions: + result[rule] = 1 + return list(result) + +def create_collections(countries): + result = {} + for c in countries.values(): + result[c.permissions] = 1 + return list(result) + + +def be32(output, val): + output.write(struct.pack('>I', val)) + +class PTR(object): + def __init__(self, output): + self._output = output + self._pos = output.tell() + be32(output, 0xFFFFFFFF) + + def set(self, val=None): + if val is None: + val = self._output.tell() + self._offset = val + pos = self._output.tell() + self._output.seek(self._pos) + be32(self._output, val) + self._output.seek(pos) + + def get(self): + return self._offset + +p = DBParser() +countries = p.parse(open(sys.argv[2], 'r', encoding='utf-8')) + +countrynames = list(countries) +countrynames.sort() + +power = [] +bands = [] +for alpha2 in countrynames: + for perm in countries[alpha2].permissions: + if not perm.freqband in bands: + bands.append(perm.freqband) + if not perm.power in power: + power.append(perm.power) +rules = create_rules(countries) +rules.sort() +collections = create_collections(countries) +collections.sort() + +output = BytesIO() + +# struct regdb_file_header +be32(output, MAGIC) +be32(output, VERSION) +reg_country_ptr = PTR(output) +# add number of countries +be32(output, len(countries)) +siglen = PTR(output) + +power_rules = {} +for pr in power: + power_rules[pr] = output.tell() + pr = [int(v * 100.0) for v in (pr.max_ant_gain, pr.max_eirp)] + # struct regdb_file_power_rule + output.write(struct.pack('>II', *pr)) + +freq_ranges = {} +for fr in bands: + freq_ranges[fr] = output.tell() + fr = [int(f * 1000.0) for f in (fr.start, fr.end, fr.maxbw)] + # struct regdb_file_freq_range + output.write(struct.pack('>III', *fr)) + + +reg_rules = {} +for reg_rule in rules: + freq_range, power_rule = reg_rule.freqband, reg_rule.power + reg_rules[reg_rule] = output.tell() + # struct regdb_file_reg_rule + output.write(struct.pack('>III', freq_ranges[freq_range], power_rules[power_rule], + reg_rule.flags)) + + +reg_rules_collections = {} + +for coll in collections: + reg_rules_collections[coll] = output.tell() + # struct regdb_file_reg_rules_collection + coll = list(coll) + be32(output, len(coll)) + coll.sort() + for regrule in coll: + be32(output, reg_rules[regrule]) + +# update country pointer now! +reg_country_ptr.set() + +for alpha2 in countrynames: + coll = countries[alpha2] + # struct regdb_file_reg_country + output.write(struct.pack('>2sxBI', alpha2, coll.dfs_region, reg_rules_collections[coll.permissions])) + + +if len(sys.argv) > 3: + # Load RSA only now so people can use this script + # without having those libraries installed to verify + # their SQL changes + from M2Crypto import RSA + + # determine signature length + key = RSA.load_key(sys.argv[3]) + hash = hashlib.sha1() + hash.update(output.getvalue()) + sig = key.sign(hash.digest()) + # write it to file + siglen.set(len(sig)) + # sign again + hash = hashlib.sha1() + hash.update(output.getvalue()) + sig = key.sign(hash.digest()) + + output.write(sig) +else: + siglen.set(0) + +outfile = open(sys.argv[1], 'wb') +outfile.write(output.getvalue()) diff -Nru wireless-regdb-2022.06.06/.pc/run-scripts-with-python-3.patch/db2fw.py wireless-regdb-2022.06.06/.pc/run-scripts-with-python-3.patch/db2fw.py --- wireless-regdb-2022.06.06/.pc/run-scripts-with-python-3.patch/db2fw.py 1970-01-01 00:00:00.000000000 +0000 +++ wireless-regdb-2022.06.06/.pc/run-scripts-with-python-3.patch/db2fw.py 2023-10-30 19:12:05.000000000 +0000 @@ -0,0 +1,158 @@ +#!/usr/bin/env python + +from io import BytesIO, open +import struct +import hashlib +from dbparse import DBParser +import sys +from math import log + +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.values(): + for rule in c.permissions: + result[rule] = 1 + return list(result) + +def create_collections(countries): + result = {} + for c in countries.values(): + result[(c.permissions, c.dfs_region)] = 1 + return list(result) + +def create_wmms(countries): + result = {} + for c in countries.values(): + for rule in c.permissions: + if rule.wmmrule is not None: + result[rule.wmmrule] = 1 + return list(result) + +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(open(sys.argv[2], 'r', encoding='utf-8')) +rules = create_rules(countries) +rules.sort() +collections = create_collections(countries) +collections.sort() +wmms = create_wmms(countries) +wmms.sort() + +output = BytesIO() + +# struct regdb_file_header +be32(output, MAGIC) +be32(output, VERSION) + +country_ptrs = {} +countrynames = list(countries) +countrynames.sort() +for alpha2 in countrynames: + coll = countries[alpha2] + output.write(struct.pack('>2s', alpha2)) + country_ptrs[alpha2] = PTR(output) +output.write(b'\x00' * 4) + +wmmdb = {} +for w in wmms: + assert output.tell() & 3 == 0 + wmmdb[w] = output.tell() >> 2 + for r in w._as_tuple(): + ecw = int(log(r[0] + 1, 2)) << 4 | int(log(r[1] + 1, 2)) + ac = (ecw, r[2],r[3]) + output.write(struct.pack('>BBH', *ac)) + +reg_rules = {} +flags = 0 +for reg_rule in rules: + freq_range, power_rule, wmm_rule = reg_rule.freqband, reg_rule.power, reg_rule.wmmrule + 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 or wmm_rule: + rule_len += 2 + if wmm_rule is not None: + rule_len += 2 + output.write(struct.pack('>BBHIII', rule_len, flags, int(power_rule.max_eirp * 100), + int(freq_range.start * 1000), int(freq_range.end * 1000), int(freq_range.maxbw * 1000), + )) + if rule_len > 16: + output.write(struct.pack('>H', cac_timeout)) + + if rule_len > 18: + be16(output, wmmdb[wmm_rule]) + + 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], 'wb') +outfile.write(output.getvalue()) diff -Nru wireless-regdb-2022.06.06/.pc/run-scripts-with-python-3.patch/dbparse.py wireless-regdb-2022.06.06/.pc/run-scripts-with-python-3.patch/dbparse.py --- wireless-regdb-2022.06.06/.pc/run-scripts-with-python-3.patch/dbparse.py 1970-01-01 00:00:00.000000000 +0000 +++ wireless-regdb-2022.06.06/.pc/run-scripts-with-python-3.patch/dbparse.py 2023-10-30 19:12:05.000000000 +0000 @@ -0,0 +1,515 @@ +#!/usr/bin/env python + +from functools import total_ordering +import sys, math +from math import ceil, log +from collections import defaultdict, OrderedDict + +# must match enum nl80211_reg_rule_flags + +flag_definitions = { + 'NO-OFDM': 1<<0, + 'NO-CCK': 1<<1, + 'NO-INDOOR': 1<<2, + 'NO-OUTDOOR': 1<<3, + 'DFS': 1<<4, + 'PTP-ONLY': 1<<5, + 'PTMP-ONLY': 1<<6, + 'NO-IR': 1<<7, + # hole at bit 8 + # hole at bit 9. FIXME: Where is NO-HT40 defined? + 'NO-HT40': 1<<10, + 'AUTO-BW': 1<<11, +} + +dfs_regions = { + 'DFS-FCC': 1, + 'DFS-ETSI': 2, + 'DFS-JP': 3, +} + +@total_ordering + +class WmmRule(object): + + def __init__(self, vo_c, vi_c, be_c, bk_c, vo_ap, vi_ap, be_ap, bk_ap): + self.vo_c = vo_c + self.vi_c = vi_c + self.be_c = be_c + self.bk_c = bk_c + self.vo_ap = vo_ap + self.vi_ap = vi_ap + self.be_ap = be_ap + self.bk_ap = bk_ap + + def _as_tuple(self): + return (self.vo_c, self.vi_c, self.be_c, self.bk_c, + self.vo_ap, self.vi_ap, self.be_ap, self.bk_ap) + + def __eq__(self, other): + if other is None: + return False + return (self._as_tuple() == other._as_tuple()) + + def __ne__(self, other): + return not (self == other) + + def __lt__(self, other): + if other is None: + return False + return (self._as_tuple() < other._as_tuple()) + + def __hash__(self): + return hash(self._as_tuple()) + +class FreqBand(object): + def __init__(self, start, end, bw, comments=None): + self.start = start + self.end = end + self.maxbw = bw + self.comments = comments or [] + + def _as_tuple(self): + return (self.start, self.end, self.maxbw) + + def __eq__(self, other): + return (self._as_tuple() == other._as_tuple()) + + def __ne__(self, other): + return not (self == other) + + def __lt__(self, other): + return (self._as_tuple() < other._as_tuple()) + + def __hash__(self): + return hash(self._as_tuple()) + + def __str__(self): + return '' % ( + self.start, self.end, self.maxbw) + +@total_ordering +class PowerRestriction(object): + def __init__(self, max_ant_gain, max_eirp, comments = None): + self.max_ant_gain = max_ant_gain + self.max_eirp = max_eirp + self.comments = comments or [] + + def _as_tuple(self): + return (self.max_ant_gain, self.max_eirp) + + def __eq__(self, other): + return (self._as_tuple() == other._as_tuple()) + + def __ne__(self, other): + return not (self == other) + + def __lt__(self, other): + return (self._as_tuple() < other._as_tuple()) + + def __hash__(self): + return hash(self._as_tuple()) + + def __str__(self): + return '' + +class DFSRegionError(Exception): + def __init__(self, dfs_region): + self.dfs_region = dfs_region + +class FlagError(Exception): + def __init__(self, flag): + self.flag = flag + +@total_ordering +class Permission(object): + def __init__(self, freqband, power, flags, wmmrule): + assert isinstance(freqband, FreqBand) + assert isinstance(power, PowerRestriction) + assert isinstance(wmmrule, WmmRule) or wmmrule is None + self.freqband = freqband + self.power = power + self.wmmrule = wmmrule + self.flags = 0 + for flag in flags: + if not flag in flag_definitions: + raise FlagError(flag) + self.flags |= flag_definitions[flag] + self.textflags = flags + + def _as_tuple(self): + return (self.freqband, self.power, self.flags, self.wmmrule) + + def __eq__(self, other): + return (self._as_tuple() == other._as_tuple()) + + def __ne__(self, other): + return not (self == other) + + def __lt__(self, other): + return (self._as_tuple() < other._as_tuple()) + + def __hash__(self): + return hash(self._as_tuple()) + + def __str__(self): + return str(self.freqband) + str(self.power) + str(self.wmmrule) + +class Country(object): + def __init__(self, dfs_region, permissions=None, comments=None): + self._permissions = permissions or [] + self.comments = comments or [] + self.dfs_region = 0 + + if dfs_region: + if not dfs_region in dfs_regions: + raise DFSRegionError(dfs_region) + self.dfs_region = dfs_regions[dfs_region] + + def add(self, perm): + assert isinstance(perm, Permission) + self._permissions.append(perm) + self._permissions.sort() + + def __contains__(self, perm): + assert isinstance(perm, Permission) + return perm in self._permissions + + def __str__(self): + r = ['(%s, %s)' % (str(b), str(p)) for b, p in self._permissions] + return '' % (', '.join(r)) + + def _get_permissions_tuple(self): + return tuple(self._permissions) + permissions = property(_get_permissions_tuple) + +class SyntaxError(Exception): + pass + +class DBParser(object): + def __init__(self, warn=None): + self._warn_callout = warn or sys.stderr.write + + def _syntax_error(self, txt=None): + txt = txt and ' (%s)' % txt or '' + raise SyntaxError("Syntax error in line %d%s" % (self._lineno, txt)) + + def _warn(self, txt): + self._warn_callout("Warning (line %d): %s\n" % (self._lineno, txt)) + + def _parse_band_def(self, bname, banddef, dupwarn=True): + try: + freqs, bw = banddef.split('@') + bw = float(bw) + except ValueError: + bw = 20.0 + + try: + start, end = freqs.split('-') + start = float(start) + end = float(end) + # The kernel will reject these, so might as well reject this + # upon building it. + if start <= 0: + self._syntax_error("Invalid start freq (%d)" % start) + if end <= 0: + self._syntax_error("Invalid end freq (%d)" % end) + if start > end: + self._syntax_error("Inverted freq range (%d - %d)" % (start, end)) + if start == end: + self._syntax_error("Start and end freqs are equal (%d)" % start) + except ValueError: + self._syntax_error("band must have frequency range") + + b = FreqBand(start, end, bw, comments=self._comments) + self._comments = [] + self._banddup[bname] = bname + if b in self._bandrev: + if dupwarn: + self._warn('Duplicate band definition ("%s" and "%s")' % ( + bname, self._bandrev[b])) + self._banddup[bname] = self._bandrev[b] + self._bands[bname] = b + self._bandrev[b] = bname + self._bandline[bname] = self._lineno + + def _parse_band(self, line): + try: + bname, line = line.split(':', 1) + if not bname: + self._syntax_error("'band' keyword must be followed by name") + except ValueError: + self._syntax_error("band name must be followed by colon") + + if bname in flag_definitions: + self._syntax_error("Invalid band name") + + self._parse_band_def(bname, line) + + def _parse_power(self, line): + try: + pname, line = line.split(':', 1) + if not pname: + self._syntax_error("'power' keyword must be followed by name") + except ValueError: + self._syntax_error("power name must be followed by colon") + + if pname in flag_definitions: + self._syntax_error("Invalid power name") + + self._parse_power_def(pname, line) + + def _parse_power_def(self, pname, line, dupwarn=True): + try: + max_eirp = line + if max_eirp == 'N/A': + max_eirp = '0' + max_ant_gain = float(0) + def conv_pwr(pwr): + if pwr.endswith('mW'): + pwr = float(pwr[:-2]) + return 10.0 * math.log10(pwr) + else: + return float(pwr) + max_eirp = conv_pwr(max_eirp) + except ValueError: + self._syntax_error("invalid power data") + + p = PowerRestriction(max_ant_gain, max_eirp, + comments=self._comments) + self._comments = [] + self._powerdup[pname] = pname + if p in self._powerrev: + if dupwarn: + self._warn('Duplicate power definition ("%s" and "%s")' % ( + pname, self._powerrev[p])) + self._powerdup[pname] = self._powerrev[p] + self._power[pname] = p + self._powerrev[p] = pname + self._powerline[pname] = self._lineno + + def _parse_wmmrule(self, line): + regions = line[:-1].strip() + if not regions: + self._syntax_error("'wmmrule' keyword must be followed by region") + + regions = regions.split(',') + + self._current_regions = {} + for region in regions: + if region in self._wmm_rules: + self._warn("region %s was added already to wmm rules" % region) + self._current_regions[region] = 1 + self._comments = [] + + def _validate_input(self, cw_min, cw_max, aifsn, cot): + if cw_min < 1: + self._syntax_error("Invalid cw_min value (%d)" % cw_min) + if cw_max < 1: + self._syntax_error("Invalid cw_max value (%d)" % cw_max) + if cw_min > cw_max: + self._syntax_error("Inverted contention window (%d - %d)" % + (cw_min, cw_max)) + if not (bin(cw_min + 1).count('1') == 1 and cw_min < 2**15): + self._syntax_error("Invalid cw_min value should be power of 2 - 1 (%d)" + % cw_min) + if not (bin(cw_max + 1).count('1') == 1 and cw_max < 2**15): + self._syntax_error("Invalid cw_max value should be power of 2 - 1 (%d)" + % cw_max) + if aifsn < 1: + self._syntax_error("Invalid aifsn value (%d)" % aifsn) + if cot < 0: + self._syntax_error("Invalid cot value (%d)" % cot) + + + def _validate_size(self, var, bytcnt): + return bytcnt < ceil(len(bin(var)[2:]) / 8.0) + + def _parse_wmmrule_item(self, line): + bytcnt = (2.0, 2.0, 1.0, 2.0) + try: + ac, cval = line.split(':') + if not ac: + self._syntax_error("wmm item must have ac prefix") + except ValueError: + self._syntax_error("access category must be followed by colon") + p = tuple([int(v.split('=', 1)[1]) for v in cval.split(',')]) + self._validate_input(*p) + for v, b in zip(p, bytcnt): + if self._validate_size(v, b): + self._syntax_error("unexpected input size expect %d got %d" + % (b, v)) + + for r in self._current_regions: + self._wmm_rules[r][ac] = p + + def _parse_country(self, line): + try: + cname, cvals= line.split(':', 1) + dfs_region = cvals.strip() + if not cname: + self._syntax_error("'country' keyword must be followed by name") + except ValueError: + self._syntax_error("country name must be followed by colon") + + cnames = cname.split(',') + + self._current_countries = {} + for cname in cnames: + if len(cname) != 2: + self._warn("country '%s' not alpha2" % cname) + cname = cname.encode('ascii') + if not cname in self._countries: + self._countries[cname] = Country(dfs_region, comments=self._comments) + self._current_countries[cname] = self._countries[cname] + self._comments = [] + + def _parse_country_item(self, line): + if line[0] == '(': + try: + band, line = line[1:].split('),', 1) + bname = 'UNNAMED %d' % self._lineno + self._parse_band_def(bname, band, dupwarn=False) + except: + self._syntax_error("Badly parenthesised band definition") + else: + try: + bname, line = line.split(',', 1) + if not bname: + self._syntax_error("country definition must have band") + if not line: + self._syntax_error("country definition must have power") + except ValueError: + self._syntax_error("country definition must have band and power") + + if line[0] == '(': + items = line.split('),', 1) + if len(items) == 1: + pname = items[0] + line = '' + if not pname[-1] == ')': + self._syntax_error("Badly parenthesised power definition") + pname = pname[:-1] + flags = [] + else: + pname = items[0] + flags = items[1].split(',') + power = pname[1:] + pname = 'UNNAMED %d' % self._lineno + self._parse_power_def(pname, power, dupwarn=False) + else: + line = line.split(',') + pname = line[0] + flags = line[1:] + w = None + if flags and 'wmmrule' in flags[-1]: + try: + region = flags.pop().split('=', 1)[1] + if region not in self._wmm_rules.keys(): + self._syntax_error("No wmm rule for %s" % region) + except IndexError: + self._syntax_error("flags is empty list or no region was found") + w = WmmRule(*self._wmm_rules[region].values()) + + if not bname in self._bands: + self._syntax_error("band does not exist") + if not pname in self._power: + self._syntax_error("power does not exist") + self._bands_used[bname] = True + self._power_used[pname] = True + # de-duplicate so binary database is more compact + bname = self._banddup[bname] + pname = self._powerdup[pname] + b = self._bands[bname] + p = self._power[pname] + try: + perm = Permission(b, p, flags, w) + except FlagError as e: + self._syntax_error("Invalid flag '%s'" % e.flag) + for cname, c in self._current_countries.items(): + if perm in c: + self._warn('Rule "%s, %s" added to "%s" twice' % ( + bname, pname, cname)) + else: + c.add(perm) + + def parse(self, f): + self._current_countries = None + self._current_regions = None + self._bands = {} + self._power = {} + self._countries = {} + self._bands_used = {} + self._power_used = {} + self._bandrev = {} + self._powerrev = {} + self._banddup = {} + self._powerdup = {} + self._bandline = {} + self._powerline = {} + self._wmm_rules = defaultdict(lambda: OrderedDict()) + + self._comments = [] + + self._lineno = 0 + for line in f: + self._lineno += 1 + line = line.strip() + if line[0:1] == '#': + self._comments.append(line[1:].strip()) + line = line.replace(' ', '').replace('\t', '') + if not line: + self._current_regions = None + self._comments = [] + line = line.split('#')[0] + if not line: + continue + if line[0:4] == 'band': + self._parse_band(line[4:]) + self._current_countries = None + self._current_regions = None + self._comments = [] + elif line[0:5] == 'power': + self._parse_power(line[5:]) + self._current_countries = None + self._current_regions = None + self._comments = [] + elif line[0:7] == 'country': + self._parse_country(line[7:]) + self._comments = [] + self._current_regions = None + elif self._current_countries is not None: + self._current_regions = None + self._parse_country_item(line) + self._comments = [] + elif line[0:7] == 'wmmrule': + self._parse_wmmrule(line[7:]) + self._current_countries = None + self._comments = [] + elif self._current_regions is not None: + self._parse_wmmrule_item(line) + self._current_countries = None + self._comments = [] + else: + self._syntax_error("Expected band, power or country definition") + + countries = self._countries + bands = {} + for k, v in self._bands.items(): + if k in self._bands_used: + bands[self._banddup[k]] = v + continue + # we de-duplicated, but don't warn again about the dupes + if self._banddup[k] == k: + self._lineno = self._bandline[k] + self._warn('Unused band definition "%s"' % k) + power = {} + for k, v in self._power.items(): + if k in self._power_used: + power[self._powerdup[k]] = v + continue + # we de-duplicated, but don't warn again about the dupes + if self._powerdup[k] == k: + self._lineno = self._powerline[k] + self._warn('Unused power definition "%s"' % k) + return countries diff -Nru wireless-regdb-2022.06.06/.pc/store-privkey-in-builddir.patch/Makefile wireless-regdb-2022.06.06/.pc/store-privkey-in-builddir.patch/Makefile --- wireless-regdb-2022.06.06/.pc/store-privkey-in-builddir.patch/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ wireless-regdb-2022.06.06/.pc/store-privkey-in-builddir.patch/Makefile 2023-10-30 19:12:05.000000000 +0000 @@ -0,0 +1,129 @@ +# Install prefix +PREFIX ?= /usr +CRDA_PATH ?= $(PREFIX)/lib/crda +CRDA_KEY_PATH ?= $(CRDA_PATH)/pubkeys +FIRMWARE_PATH ?= /lib/firmware + +MANDIR ?= $(PREFIX)/share/man/ + +SHA1SUM ?= /usr/bin/sha1sum +LSB_RELEASE ?= /usr/bin/lsb_release +WHOAMI ?= /usr/bin/whoami + +# Distro name: Ubuntu, Debian, Fedora, if not present you get +# "custom-distro", if your distribution does not have the LSB stuff, +# then set this variable when calling make if you don't want "custom-distro" +LSB_ID ?= $(shell if [ -f $(LSB_RELEASE) ]; then \ + $(LSB_RELEASE) -i -s; \ + else \ + echo custom-distro; \ + fi) + +DISTRO_PRIVKEY ?= ~/.wireless-regdb-$(LSB_ID).key.priv.pem +DISTRO_PUBKEY ?= ~/.wireless-regdb-$(LSB_ID).key.priv.pem + +REGDB_AUTHOR ?= $(shell if [ -f $(DISTRO_PRIVKEY) ]; then \ + echo $(LSB_ID) ; \ + elif [ -f $(WHOAMI) ]; then \ + $(WHOAMI); \ + else \ + echo custom-user; \ + fi) + +REGDB_PRIVKEY ?= ~/.wireless-regdb-$(REGDB_AUTHOR).key.priv.pem +REGDB_PUBKEY ?= $(REGDB_AUTHOR).key.pub.pem +REGDB_PUBCERT ?= $(REGDB_AUTHOR).x509.pem + +REGDB_UPSTREAM_PUBKEY ?= sforshee.key.pub.pem + +REGDB_CHANGED = $(shell $(SHA1SUM) -c --status sha1sum.txt >/dev/null 2>&1; \ + if [ $$? -ne 0 ]; then \ + echo maintainer-clean $(REGDB_PUBKEY) $(REGDB_PUBCERT); \ + fi) + +.PHONY: all clean mrproper install maintainer-clean install-distro-key + +all: $(REGDB_CHANGED) regulatory.bin sha1sum.txt regulatory.db.p7s + +clean: + @rm -f *.pyc *.gz + +maintainer-clean: clean + @rm -f regulatory.bin regulatory.db regulatory.db.p7s + +mrproper: clean maintainer-clean + @echo Removed public key, regulatory.bin, regulatory.db* and compressed man pages + @rm -f $(REGDB_PUBKEY) $(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)..." + ./gen-pubcert.sh $(REGDB_PRIVKEY) $(REGDB_PUBCERT) $(REGDB_AUTHOR) + @echo $(REGDB_PUBKEY) > .custom + + +$(REGDB_PRIVKEY): + @echo "Generating private key for $(REGDB_AUTHOR)..." + openssl genrsa -out $(REGDB_PRIVKEY) 2048 + +ifneq ($(shell test -e $(DISTRO_PRIVKEY) && echo yes),yes) +$(DISTRO_PRIVKEY): + @echo "Generating private key for $(LSB_ID) packager..." + openssl genrsa -out $(DISTRO_PRIVKEY) 2048 +endif + +install-distro-key: maintainer-clean $(DISTRO_PRIVKEY) + +%.gz: % + gzip < $< > $@ + +# Users should just do: +# sudo make install +# +# Developers should do: +# make maintainer-clean +# make +# sudo make install +# +# Distributions packagers should do only once: +# make install-distro-key +# This will create a private key for you and install it into +# ~/.wireless-regdb-$(LSB_ID).key.priv.pem +# To make new releaes just do: +# make maintainer-clean +# make +# sudo make install +install: regulatory.bin.5.gz regulatory.db.5.gz + install -m 755 -d $(DESTDIR)/$(CRDA_PATH) + install -m 755 -d $(DESTDIR)/$(CRDA_KEY_PATH) + install -m 755 -d $(DESTDIR)/$(FIRMWARE_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 -m 644 -t $(DESTDIR)/$(FIRMWARE_PATH) regulatory.db regulatory.db.p7s + install -m 755 -d $(DESTDIR)/$(MANDIR)/man5/ + install -m 644 -t $(DESTDIR)/$(MANDIR)/man5/ regulatory.bin.5.gz regulatory.db.5.gz diff -Nru wireless-regdb-2022.06.06/.pc/.version wireless-regdb-2022.06.06/.pc/.version --- wireless-regdb-2022.06.06/.pc/.version 1970-01-01 00:00:00.000000000 +0000 +++ wireless-regdb-2022.06.06/.pc/.version 2023-10-30 19:12:05.000000000 +0000 @@ -0,0 +1 @@ +2