1#!/usr/bin/env python3 2 3import re 4import sys 5 6 7def usage(): 8 sys.stderr.write("Usage: $0 allowlist-config-in allowlist-header-out\n") 9 sys.stderr.write(" Reads in allowlist config, sorting the contents\n") 10 sys.stderr.write(" and outputs a header file\n") 11 sys.exit(-1) 12 13 14class Error(Exception): 15 pass 16 17 18class DuplicateEntry(Error): 19 def __init__(self, e): 20 super(Error, self).__init__( 21 "Multiple entries with matching netfn/cmd found ({})".format(e) 22 ) 23 24 25class ParseError(Error): 26 def __init__(self, d): 27 super(Error, self).__init__("Parse error at: '{}'".format(d)) 28 29 30class entry: 31 linere = re.compile( 32 r"(0x[0-9a-f]{2}):(0x[0-9a-f]{2})((:(0x[0-9a-f]{4}))?)\s*((//\s*(.*))?)", # noqa: E501 33 re.I, 34 ) 35 36 def __init__(self, data): 37 # parse data line into values: 38 # type 1, two values: netfn, cmd 39 # type 2, three values: netfn, cmd, channels 40 try: 41 m = self.linere.fullmatch(data).groups() 42 except Exception: 43 raise ParseError(data) 44 self.netfn = int(m[0], 16) 45 self.cmd = int(m[1], 16) 46 if m[4] is not None: 47 self.channels = int(m[4], 16) 48 else: 49 # if no channel was provided, default to previous behavior, which 50 # is allow all interfaces, including the system interface (ch 15) 51 self.channels = 0xFFFF 52 if m[6] is not None: 53 self.comment = "// " + m[7] 54 else: 55 self.comment = "//" 56 57 def __str__(self): 58 return " ".join( 59 [ 60 "{", 61 "0x{0.netfn:02x},".format(self), 62 "0x{0.cmd:02x},".format(self), 63 "0x{0.channels:04x}".format(self), 64 "},", 65 "{0.comment}".format(self), 66 ] 67 ) 68 69 def __lt__(self, other): 70 if self.netfn == other.netfn: 71 return self.cmd < other.cmd 72 return self.netfn < other.netfn 73 74 def match(self, other): 75 return (self.netfn == other.netfn) and (self.cmd == other.cmd) 76 77 78def parse(config): 79 entries = [] 80 with open(config) as f: 81 for line in f: 82 line = line.strip() 83 if len(line) == 0 or line[0] == "#": 84 continue 85 e = entry(line) 86 if any([e.match(item) for item in entries]): 87 d = DuplicateEntry(e) 88 sys.stderr.write("WARNING: {}\n".format(d)) 89 else: 90 entries.append(e) 91 entries.sort() 92 return entries 93 94 95def output(entries, hppfile): 96 lines = [ 97 "#pragma once", 98 "", 99 "// AUTOGENERATED FILE; DO NOT MODIFY", 100 "", 101 "#include <array>", 102 "#include <tuple>", 103 "", 104 ( 105 "using netfncmd_tuple = std::tuple<unsigned char, unsigned char," 106 " unsigned short>;" 107 ), 108 "", 109 "constexpr const std::array<netfncmd_tuple, {}> allowlist = ".format( 110 len(entries) 111 ), 112 "{{", 113 ] 114 lines.extend([" {}".format(e) for e in entries]) 115 lines.append("}};\n") 116 117 with open(hppfile, "w") as hpp: 118 hpp.write("\n".join(lines)) 119 120 121if __name__ == "__main__": 122 if len(sys.argv) != 3: 123 usage() 124 config = sys.argv[1] 125 header = sys.argv[2] 126 entries = parse(config) 127 output(entries, header) 128