18b7c156eSVernon Mauery#!/usr/bin/env python3 28b7c156eSVernon Mauery 3*844f8fc1SPatrick Williamsimport re 4*844f8fc1SPatrick Williamsimport sys 5*844f8fc1SPatrick Williams 68b7c156eSVernon Mauery 78b7c156eSVernon Mauerydef usage(): 88b7c156eSVernon Mauery sys.stderr.write("Usage: $0 allowlist-config-in allowlist-header-out\n") 98b7c156eSVernon Mauery sys.stderr.write(" Reads in allowlist config, sorting the contents\n") 108b7c156eSVernon Mauery sys.stderr.write(" and outputs a header file\n") 118b7c156eSVernon Mauery sys.exit(-1) 128b7c156eSVernon Mauery 13*844f8fc1SPatrick Williams 148b7c156eSVernon Maueryclass Error(Exception): 158b7c156eSVernon Mauery pass 168b7c156eSVernon Mauery 17*844f8fc1SPatrick Williams 188b7c156eSVernon Maueryclass DuplicateEntry(Error): 198b7c156eSVernon Mauery def __init__(self, e): 208b7c156eSVernon Mauery super(Error, self).__init__( 21*844f8fc1SPatrick Williams "Multiple entries with matching netfn/cmd found ({})".format(e) 22*844f8fc1SPatrick Williams ) 23*844f8fc1SPatrick Williams 248b7c156eSVernon Mauery 258b7c156eSVernon Maueryclass ParseError(Error): 268b7c156eSVernon Mauery def __init__(self, d): 278b7c156eSVernon Mauery super(Error, self).__init__("Parse error at: '{}'".format(d)) 288b7c156eSVernon Mauery 29*844f8fc1SPatrick Williams 308b7c156eSVernon Maueryclass entry: 318b7c156eSVernon Mauery linere = re.compile( 32*844f8fc1SPatrick Williams r"(0x[0-9a-f]{2}):(0x[0-9a-f]{2})((:(0x[0-9a-f]{4}))?)\s*((//\s*(.*))?)", # noqa: E501 33*844f8fc1SPatrick Williams re.I, 348b7c156eSVernon Mauery ) 35*844f8fc1SPatrick Williams 368b7c156eSVernon Mauery def __init__(self, data): 378b7c156eSVernon Mauery # parse data line into values: 388b7c156eSVernon Mauery # type 1, two values: netfn, cmd 398b7c156eSVernon Mauery # type 2, three values: netfn, cmd, channels 408b7c156eSVernon Mauery try: 418b7c156eSVernon Mauery m = self.linere.fullmatch(data).groups() 42*844f8fc1SPatrick Williams except Exception: 438b7c156eSVernon Mauery raise ParseError(data) 448b7c156eSVernon Mauery self.netfn = int(m[0], 16) 458b7c156eSVernon Mauery self.cmd = int(m[1], 16) 468b7c156eSVernon Mauery if m[4] is not None: 478b7c156eSVernon Mauery self.channels = int(m[4], 16) 488b7c156eSVernon Mauery else: 498b7c156eSVernon Mauery # if no channel was provided, default to previous behavior, which 508b7c156eSVernon Mauery # is allow all interfaces, including the system interface (ch 15) 51*844f8fc1SPatrick Williams self.channels = 0xFFFF 528b7c156eSVernon Mauery if m[6] is not None: 538b7c156eSVernon Mauery self.comment = "// " + m[7] 548b7c156eSVernon Mauery else: 558b7c156eSVernon Mauery self.comment = "//" 56*844f8fc1SPatrick Williams 578b7c156eSVernon Mauery def __str__(self): 58*844f8fc1SPatrick Williams return " ".join( 59*844f8fc1SPatrick Williams [ 60*844f8fc1SPatrick Williams "{", 618b7c156eSVernon Mauery "0x{0.netfn:02x},".format(self), 628b7c156eSVernon Mauery "0x{0.cmd:02x},".format(self), 638b7c156eSVernon Mauery "0x{0.channels:04x}".format(self), 648b7c156eSVernon Mauery "},", 658b7c156eSVernon Mauery "{0.comment}".format(self), 66*844f8fc1SPatrick Williams ] 67*844f8fc1SPatrick Williams ) 68*844f8fc1SPatrick Williams 698b7c156eSVernon Mauery def __lt__(self, other): 708b7c156eSVernon Mauery if self.netfn == other.netfn: 718b7c156eSVernon Mauery return self.cmd < other.cmd 728b7c156eSVernon Mauery return self.netfn < other.netfn 73*844f8fc1SPatrick Williams 748b7c156eSVernon Mauery def match(self, other): 758b7c156eSVernon Mauery return (self.netfn == other.netfn) and (self.cmd == other.cmd) 768b7c156eSVernon Mauery 77*844f8fc1SPatrick Williams 788b7c156eSVernon Mauerydef parse(config): 798b7c156eSVernon Mauery entries = [] 808b7c156eSVernon Mauery with open(config) as f: 818b7c156eSVernon Mauery for line in f: 828b7c156eSVernon Mauery line = line.strip() 83*844f8fc1SPatrick Williams if len(line) == 0 or line[0] == "#": 848b7c156eSVernon Mauery continue 858b7c156eSVernon Mauery e = entry(line) 868b7c156eSVernon Mauery if any([e.match(item) for item in entries]): 878b7c156eSVernon Mauery d = DuplicateEntry(e) 888b7c156eSVernon Mauery sys.stderr.write("WARNING: {}\n".format(d)) 898b7c156eSVernon Mauery else: 908b7c156eSVernon Mauery entries.append(e) 918b7c156eSVernon Mauery entries.sort() 928b7c156eSVernon Mauery return entries 938b7c156eSVernon Mauery 94*844f8fc1SPatrick Williams 958b7c156eSVernon Mauerydef output(entries, hppfile): 968b7c156eSVernon Mauery lines = [ 978b7c156eSVernon Mauery "#pragma once", 988b7c156eSVernon Mauery "", 998b7c156eSVernon Mauery "// AUTOGENERATED FILE; DO NOT MODIFY", 1008b7c156eSVernon Mauery "", 1018b7c156eSVernon Mauery "#include <array>", 1028b7c156eSVernon Mauery "#include <tuple>", 1038b7c156eSVernon Mauery "", 104*844f8fc1SPatrick Williams ( 105*844f8fc1SPatrick Williams "using netfncmd_tuple = std::tuple<unsigned char, unsigned char," 106*844f8fc1SPatrick Williams " unsigned short>;" 107*844f8fc1SPatrick Williams ), 1088b7c156eSVernon Mauery "", 1098b7c156eSVernon Mauery "constexpr const std::array<netfncmd_tuple, {}> allowlist = ".format( 110*844f8fc1SPatrick Williams len(entries) 111*844f8fc1SPatrick Williams ), 112*844f8fc1SPatrick Williams "{{", 1138b7c156eSVernon Mauery ] 114*844f8fc1SPatrick Williams lines.extend([" {}".format(e) for e in entries]) 115*844f8fc1SPatrick Williams lines.append("}};\n") 1168b7c156eSVernon Mauery 1178b7c156eSVernon Mauery with open(hppfile, "w") as hpp: 1188b7c156eSVernon Mauery hpp.write("\n".join(lines)) 1198b7c156eSVernon Mauery 1208b7c156eSVernon Mauery 1218b7c156eSVernon Maueryif __name__ == "__main__": 1228b7c156eSVernon Mauery if len(sys.argv) != 3: 1238b7c156eSVernon Mauery usage() 1248b7c156eSVernon Mauery config = sys.argv[1] 1258b7c156eSVernon Mauery header = sys.argv[2] 1268b7c156eSVernon Mauery entries = parse(config) 1278b7c156eSVernon Mauery output(entries, header) 128