2 # Parses the nl80211.h interface and generate appropriate enums and fields
3 # (value_string) for packet-netlink-nl80211.c
5 # Copyright (c) 2017, Peter Wu <peter@lekensteyn.nl>
6 # Copyright (c) 2018, Mikael Kanstrup <mikael.kanstrup@sony.com>
8 # Wireshark - Network traffic analyzer
9 # By Gerald Combs <gerald@wireshark.org>
10 # Copyright 1998 Gerald Combs
12 # SPDX-License-Identifier: GPL-2.0-or-later
15 # To update the dissector source file, run this from the source directory:
17 # python tools/generate-nl80211-fields.py --update
25 # Begin of comment, followed by the actual array definition
26 HEADER
= "/* Definitions from linux/nl80211.h {{{ */\n"
27 FOOTER
= "/* }}} */\n"
28 # Enums to extract from the header file
30 # 'enum_name': ('field_name', field_type', 'field_blurb')
31 'nl80211_commands': ('Command', 'FT_UINT8', '"Generic Netlink Command"'),
32 'nl80211_attrs': (None, None, None),
33 'nl80211_iftype': (None, None, None),
34 'nl80211_sta_flags': (None, None, None),
35 'nl80211_sta_p2p_ps_status': ('Attribute Value', 'FT_UINT8', None),
36 'nl80211_he_gi': (None, None, None),
37 'nl80211_he_ltf': (None, None, None),
38 'nl80211_he_ru_alloc': (None, None, None),
39 'nl80211_eht_gi': (None, None, None),
40 'nl80211_eht_ru_alloc': (None, None, None),
41 'nl80211_rate_info': (None, None, None),
42 'nl80211_sta_bss_param': (None, None, None),
43 'nl80211_sta_info': (None, None, None),
44 'nl80211_tid_stats': (None, None, None),
45 'nl80211_txq_stats': (None, None, None),
46 'nl80211_mpath_flags': (None, None, None),
47 'nl80211_mpath_info': (None, None, None),
48 'nl80211_band_iftype_attr': (None, None, None),
49 'nl80211_band_attr': (None, None, None),
50 'nl80211_wmm_rule': (None, None, None),
51 'nl80211_frequency_attr': (None, None, None),
52 'nl80211_bitrate_attr': (None, None, None),
53 'nl80211_reg_initiator': ('Attribute Value', 'FT_UINT8', None),
54 'nl80211_reg_type': ('Attribute Value', 'FT_UINT8', None),
55 'nl80211_reg_rule_attr': (None, None, None),
56 'nl80211_sched_scan_match_attr': (None, None, None),
57 'nl80211_reg_rule_flags': (None, None, None),
58 'nl80211_dfs_regions': ('Attribute Value', 'FT_UINT8', None),
59 'nl80211_user_reg_hint_type': ('Attribute Value', 'FT_UINT32', None),
60 'nl80211_survey_info': (None, None, None),
61 'nl80211_mntr_flags': (None, None, None),
62 'nl80211_mesh_power_mode': ('Attribute Value', 'FT_UINT32', None),
63 'nl80211_meshconf_params': (None, None, None),
64 'nl80211_mesh_setup_params': (None, None, None),
65 'nl80211_txq_attr': (None, None, None),
66 'nl80211_ac': (None, None, None),
67 'nl80211_channel_type': ('Attribute Value', 'FT_UINT32', None),
68 'nl80211_key_mode': (None, None, None),
69 'nl80211_chan_width': ('Attribute Value', 'FT_UINT32', None),
70 'nl80211_bss_scan_width': ('Attribute Value', 'FT_UINT32', None),
71 'nl80211_bss_use_for': (None, None, None),
72 'nl80211_bss_cannot_use_reasons': (None, None, None),
73 'nl80211_bss': (None, None, None),
74 'nl80211_bss_status': ('Attribute Value', 'FT_UINT32', None),
75 'nl80211_auth_type': ('Attribute Value', 'FT_UINT32', None),
76 'nl80211_key_type': ('Attribute Value', 'FT_UINT32', None),
77 'nl80211_mfp': ('Attribute Value', 'FT_UINT32', None),
78 'nl80211_wpa_versions': (None, None, None),
79 'nl80211_key_default_types': (None, None, None),
80 'nl80211_key_attributes': (None, None, None),
81 'nl80211_tx_rate_attributes': (None, None, None),
82 'nl80211_txrate_gi': (None, None, None),
83 'nl80211_band': (None, None, None),
84 'nl80211_ps_state': ('Attribute Value', 'FT_UINT32', None),
85 'nl80211_attr_cqm': (None, None, None),
86 'nl80211_cqm_rssi_threshold_event': (None, None, None),
87 'nl80211_tx_power_setting': ('Attribute Value', 'FT_UINT32', None),
88 'nl80211_tid_config': (None, None, None),
89 'nl80211_tx_rate_setting': (None, None, None),
90 'nl80211_tid_config_attr': (None, None, None),
91 'nl80211_packet_pattern_attr': (None, None, None),
92 'nl80211_wowlan_triggers': (None, None, None),
93 'nl80211_wowlan_tcp_attrs': (None, None, None),
94 'nl80211_attr_coalesce_rule': (None, None, None),
95 'nl80211_coalesce_condition': (None, None, None),
96 'nl80211_iface_limit_attrs': (None, None, None),
97 'nl80211_if_combination_attrs': (None, None, None),
98 'nl80211_plink_state': ('Attribute Value', 'FT_UINT8', None),
99 'nl80211_plink_action': ('Attribute Value', 'FT_UINT8', None),
100 'nl80211_rekey_data': (None, None, None),
101 'nl80211_hidden_ssid': (None, None, None),
102 'nl80211_sta_wme_attr': (None, None, None),
103 'nl80211_pmksa_candidate_attr': (None, None, None),
104 'nl80211_tdls_operation': ('Attribute Value', 'FT_UINT8', None),
105 'nl80211_ap_sme_features': (None, None, None),
106 'nl80211_feature_flags': (None, None, None),
107 'nl80211_ext_feature_index': (None, None, None),
108 'nl80211_probe_resp_offload_support_attr': (None, None, None),
109 'nl80211_connect_failed_reason': ('Attribute Value', 'FT_UINT32', None),
110 'nl80211_timeout_reason': ('Attribute Value', 'FT_UINT32', None),
111 'nl80211_scan_flags': (None, None, None),
112 'nl80211_acl_policy': ('Attribute Value', 'FT_UINT32', None),
113 'nl80211_smps_mode': ('Attribute Value', 'FT_UINT8', None),
114 'nl80211_radar_event': ('Attribute Value', 'FT_UINT32', None),
115 'nl80211_dfs_state': (None, None, None),
116 'nl80211_protocol_features': (None, None, None),
117 'nl80211_crit_proto_id': ('Attribute Value', 'FT_UINT16', None),
118 'nl80211_rxmgmt_flags': (None, None, None),
119 'nl80211_tdls_peer_capability': (None, None, None),
120 'nl80211_sched_scan_plan': (None, None, None),
121 'nl80211_bss_select_attr': (None, None, None),
122 'nl80211_nan_function_type': (None, None, None),
123 'nl80211_nan_publish_type': (None, None, None),
124 'nl80211_nan_func_term_reason': (None, None, None),
125 'nl80211_nan_func_attributes': (None, None, None),
126 'nl80211_nan_srf_attributes': (None, None, None),
127 'nl80211_nan_match_attributes': (None, None, None),
128 'nl80211_external_auth_action': ('Attribute Value', 'FT_UINT32', None),
129 'nl80211_ftm_responder_attributes': (None, None, None),
130 'nl80211_ftm_responder_stats': (None, None, None),
131 'nl80211_preamble': (None, None, None),
132 'nl80211_peer_measurement_type': (None, None, None),
133 'nl80211_peer_measurement_status': (None, None, None),
134 'nl80211_peer_measurement_req': (None, None, None),
135 'nl80211_peer_measurement_resp': (None, None, None),
136 'nl80211_peer_measurement_peer_attrs': (None, None, None),
137 'nl80211_peer_measurement_attrs': (None, None, None),
138 'nl80211_peer_measurement_ftm_capa': (None, None, None),
139 'nl80211_peer_measurement_ftm_req': (None, None, None),
140 'nl80211_peer_measurement_ftm_failure_reasons': (None, None, None),
141 'nl80211_peer_measurement_ftm_resp': (None, None, None),
142 'nl80211_obss_pd_attributes': (None, None, None),
143 'nl80211_bss_color_attributes': (None, None, None),
144 'nl80211_iftype_akm_attributes': (None, None, None),
145 'nl80211_fils_discovery_attributes': (None, None, None),
146 'nl80211_unsol_bcast_probe_resp_attributes': (None, None, None),
147 'nl80211_sae_pwe_mechanism': (None, None, None),
148 'nl80211_sar_type': (None, None, None),
149 'nl80211_sar_attrs': (None, None, None),
150 'nl80211_sar_specs_attrs': (None, None, None),
151 'nl80211_mbssid_config_attributes': (None, None, None),
152 'nl80211_ap_settings_flags': (None, None, None),
153 'nl80211_wiphy_radio_attrs': (None, None, None),
154 'nl80211_wiphy_radio_freq_range': (None, None, None),
157 SOURCE_FILE
= "epan/dissectors/packet-netlink-nl80211.c"
158 # URL where the latest version can be found
159 URL
= "https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/include/uapi/linux/nl80211.h"
161 def make_enum(name
, values
, expressions
, indent
):
162 code
= 'enum ws_%s {\n' % name
163 for value
, expression
in zip(values
, expressions
):
164 if expression
and 'NL80211' in expression
:
165 expression
= 'WS_%s' % expression
167 code
+= '%sWS_%s = %s,\n' % (indent
, value
, expression
)
169 code
+= '%sWS_%s,\n' % (indent
, value
)
174 def make_value_string(name
, values
, indent
,):
175 code
= 'static const value_string ws_%s_vals[] = {\n' % name
178 code
+= indent
+ ('{ WS_%s,' % value
).ljust(align
- 1) + ' '
179 code
+= '"%s" },\n' % value
180 code
+= '%s{ 0, NULL }\n' % indent
182 code
+= 'static value_string_ext ws_%s_vals_ext =' % name
183 code
+= ' VALUE_STRING_EXT_INIT(ws_%s_vals);\n' % name
186 def remove_prefix(prefix
, text
):
187 if text
.startswith(prefix
):
188 return text
[len(prefix
):]
191 def make_hf_defs(name
, indent
):
192 code
= 'static int hf_%s;' % name
195 def make_hf(name
, indent
):
196 (field_name
, field_type
, field_blurb
) = EXPORT_ENUMS
.get(name
)
199 # Fill in default values
201 field_name
= 'Attribute Type'
203 field_type
= 'FT_UINT16'
207 # Special treatment of already existing field names
209 'nl80211_attrs': 'nl80211_attr_type',
210 'nl80211_commands': 'nl80211_cmd'
212 if rename_fields
.get(name
):
213 field_abbrev
= rename_fields
[name
]
214 field_abbrev
= remove_prefix('nl80211_', field_abbrev
)
216 code
= indent
+ indent
+ '{ &hf_%s,\n' % name
217 code
+= indent
*3 + '{ "%s", "nl80211.%s",\n' % (field_name
, field_abbrev
)
218 code
+= indent
*3 + ' %s, BASE_DEC | BASE_EXT_STRING,\n' % (field_type
)
219 code
+= indent
*3 + ' VALS_EXT_PTR(&ws_%s_vals_ext), 0x00,\n' % (name
)
220 code
+= indent
*3 + ' %s, HFILL },\n' % (field_blurb
)
221 code
+= indent
+ indent
+ '},'
224 def make_ett_defs(name
, indent
):
225 code
= 'static int ett_%s;' % name
228 def make_ett(name
, indent
):
229 code
= indent
+ indent
+ '&ett_%s,' % name
232 class EnumStore(object):
233 __RE_ENUM_VALUE
= re
.compile(
234 r
'\s+?(?P<value>\w+)(?:\ /\*.*?\*\/)?(?:\s*=\s*(?P<expression>.*?))?(?:\s*,|$)',
235 re
.MULTILINE | re
.DOTALL
)
237 def __init__(self
, name
, values
):
240 self
.expressions
= []
242 self
.parse_values(values
)
245 def parse_values(self
, values
):
246 for m
in self
.__RE
_ENUM
_VALUE
.finditer(values
):
247 value
, expression
= m
.groups()
248 if value
.startswith('NUM_'):
250 if value
.endswith('_AFTER_LAST'):
252 if value
.endswith('_LAST'):
254 if value
.startswith('__') and value
.endswith('_NUM'):
256 if expression
and expression
in self
.values
:
259 self
.values
.append(value
)
260 self
.expressions
.append(expression
)
263 return self
.name
, self
.values
, self
.expressions
265 RE_ENUM
= re
.compile(
266 r
'enum\s+?(?P<enum>\w+)\s+?\{(?P<values>.*?)\}\;',
267 re
.MULTILINE | re
.DOTALL
)
268 RE_COMMENT
= re
.compile(r
'/\*.*?\*/', re
.MULTILINE | re
.DOTALL
)
270 def parse_header(content
):
272 content
= re
.sub(RE_COMMENT
, '', content
)
275 for m
in RE_ENUM
.finditer(content
):
276 enum
= m
.group('enum')
277 values
= m
.group('values')
278 if enum
in EXPORT_ENUMS
:
279 enums
.append(EnumStore(enum
, values
).finish())
285 Reads the source file and tries to split it in the parts before, inside and
288 begin
, block
, end
= '', '', ''
290 # Stages: 1 (before block), 2 (in block, skip), 3 (after block)
292 with
open(SOURCE_FILE
) as f
:
294 if line
== FOOTER
and stage
== 2:
295 stage
= 3 # End of block
302 if line
== HEADER
and stage
== 1:
303 stage
= 2 # Begin of block
304 if line
== HEADER
and stage
== 3:
305 stage
= 2 # Begin of next code block
306 parts
.append((begin
, block
, end
))
307 begin
, block
, end
= '', '', ''
309 parts
.append((begin
, block
, end
))
310 if stage
!= 3 or len(parts
) != 3:
311 raise RuntimeError("Could not parse file (in stage %d) (parts %d)" % (stage
, len(parts
)))
314 parser
= argparse
.ArgumentParser()
315 parser
.add_argument("--update", action
="store_true",
316 help="Update %s as needed instead of writing to stdout" % SOURCE_FILE
)
317 parser
.add_argument("--indent", default
=" " * 4,
318 help="indentation (use \\t for tabs, default 4 spaces)")
319 parser
.add_argument("header_file", nargs
="?", default
=URL
,
320 help="nl80211.h header file (use - for stdin or a HTTP(S) URL, "
321 "default %(default)s)")
324 args
= parser
.parse_args()
326 indent
= args
.indent
.replace("\\t", "\t")
328 if any(args
.header_file
.startswith(proto
) for proto
in ('http:', 'https')):
329 r
= requests
.get(args
.header_file
)
331 enums
= parse_header(r
.text
)
332 elif args
.header_file
== "-":
333 enums
= parse_header(sys
.stdin
.read())
335 with
open(args
.header_file
) as f
:
336 enums
= parse_header(f
.read())
338 assert len(enums
) == len(EXPORT_ENUMS
), \
339 "Could not parse data, found %d/%d results" % \
340 (len(enums
), len(EXPORT_ENUMS
))
342 code_enums
, code_vals
, code_hf_defs
, code_ett_defs
, code_hf
, code_ett
= '', '', '', '', '', ''
343 for enum_name
, enum_values
, expressions
in enums
:
344 code_enums
+= make_enum(enum_name
, enum_values
, expressions
, indent
) + '\n'
345 code_vals
+= make_value_string(enum_name
, enum_values
, indent
) + '\n'
346 code_hf_defs
+= make_hf_defs(enum_name
, indent
) + '\n'
347 code_ett_defs
+= make_ett_defs(enum_name
, indent
) + '\n'
348 code_hf
+= make_hf(enum_name
, indent
) + '\n'
349 code_ett
+= make_ett(enum_name
, indent
) + '\n'
351 code_top
= code_enums
+ code_vals
+ code_hf_defs
+ '\n' + code_ett_defs
352 code_top
= code_top
.rstrip("\n") + "\n"
354 code
= [code_top
, code_hf
, code_ett
]
358 parts
= parse_source()
360 # Check if file needs update
361 for (begin
, old_code
, end
), new_code
in zip(parts
, code
):
362 if old_code
!= new_code
:
366 print("File is up-to-date")
369 with
open(SOURCE_FILE
, "w") as f
:
370 for (begin
, old_code
, end
), new_code
in zip(parts
, code
):
374 print("Updated %s" % SOURCE_FILE
)
376 for new_code
in code
:
379 if __name__
== '__main__':
383 # Editor modelines - https://www.wireshark.org/tools/modelines.html
388 # indent-tabs-mode: nil
391 # vi: set shiftwidth=4 tabstop=8 expandtab:
392 # :indentSize=4:tabSize=8:noTabs=true: