blob: 77bc6d990ac5ba44a376053e1e0adc4e90e7cc61 [file] [log] [blame]
Vernon Mauery0d0cd162020-01-31 10:04:10 -08001#!/usr/bin/env python3
2
Patrick Williams844f8fc2022-12-05 09:57:48 -06003import re
4import sys
5
Vernon Mauery0d0cd162020-01-31 10:04:10 -08006
7def usage():
Vernon Mauery8b7c1562022-09-27 16:10:38 -07008 sys.stderr.write("Usage: $0 allowlist-config-in allowlist-header-out\n")
9 sys.stderr.write(" Reads in allowlist config, sorting the contents\n")
Vernon Mauery0d0cd162020-01-31 10:04:10 -080010 sys.stderr.write(" and outputs a header file\n")
11 sys.exit(-1)
12
Patrick Williams844f8fc2022-12-05 09:57:48 -060013
Vernon Mauery0d0cd162020-01-31 10:04:10 -080014class Error(Exception):
15 pass
16
Patrick Williams844f8fc2022-12-05 09:57:48 -060017
Vernon Mauery0d0cd162020-01-31 10:04:10 -080018class DuplicateEntry(Error):
19 def __init__(self, e):
20 super(Error, self).__init__(
Patrick Williams844f8fc2022-12-05 09:57:48 -060021 "Multiple entries with matching netfn/cmd found ({})".format(e)
22 )
23
Vernon Mauery0d0cd162020-01-31 10:04:10 -080024
25class ParseError(Error):
26 def __init__(self, d):
27 super(Error, self).__init__("Parse error at: '{}'".format(d))
28
Patrick Williams844f8fc2022-12-05 09:57:48 -060029
Vernon Mauery0d0cd162020-01-31 10:04:10 -080030class entry:
31 linere = re.compile(
Patrick Williams844f8fc2022-12-05 09:57:48 -060032 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
Vernon Mauery0d0cd162020-01-31 10:04:10 -080036 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()
Patrick Williams844f8fc2022-12-05 09:57:48 -060042 except Exception:
Vernon Mauery0d0cd162020-01-31 10:04:10 -080043 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)
Patrick Williams844f8fc2022-12-05 09:57:48 -060051 self.channels = 0xFFFF
Vernon Mauery0d0cd162020-01-31 10:04:10 -080052 if m[6] is not None:
53 self.comment = "// " + m[7]
54 else:
55 self.comment = "//"
Patrick Williams844f8fc2022-12-05 09:57:48 -060056
Vernon Mauery0d0cd162020-01-31 10:04:10 -080057 def __str__(self):
Patrick Williams844f8fc2022-12-05 09:57:48 -060058 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
Vernon Mauery0d0cd162020-01-31 10:04:10 -080069 def __lt__(self, other):
70 if self.netfn == other.netfn:
71 return self.cmd < other.cmd
72 return self.netfn < other.netfn
Patrick Williams844f8fc2022-12-05 09:57:48 -060073
Vernon Mauery0d0cd162020-01-31 10:04:10 -080074 def match(self, other):
75 return (self.netfn == other.netfn) and (self.cmd == other.cmd)
76
Patrick Williams844f8fc2022-12-05 09:57:48 -060077
Vernon Mauery0d0cd162020-01-31 10:04:10 -080078def parse(config):
79 entries = []
80 with open(config) as f:
81 for line in f:
82 line = line.strip()
Patrick Williams844f8fc2022-12-05 09:57:48 -060083 if len(line) == 0 or line[0] == "#":
Vernon Mauery0d0cd162020-01-31 10:04:10 -080084 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
Patrick Williams844f8fc2022-12-05 09:57:48 -060094
Vernon Mauery0d0cd162020-01-31 10:04:10 -080095def output(entries, hppfile):
96 lines = [
Patrick Williams844f8fc2022-12-05 09:57:48 -060097 "#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")
Vernon Mauery0d0cd162020-01-31 10:04:10 -0800116
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)