~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/net/ynl/ynl-gen-c.py

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

Diff markup

Differences between /tools/net/ynl/ynl-gen-c.py (Version linux-6.12-rc7) and /tools/net/ynl/ynl-gen-c.py (Version linux-6.6.60)


  1 #!/usr/bin/env python3                              1 #!/usr/bin/env python3
  2 # SPDX-License-Identifier: ((GPL-2.0 WITH Linu      2 # SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
  3                                                     3 
  4 import argparse                                     4 import argparse
  5 import collections                                  5 import collections
  6 import filecmp                                 << 
  7 import os                                           6 import os
  8 import re                                           7 import re
  9 import shutil                                       8 import shutil
 10 import tempfile                                     9 import tempfile
 11 import yaml                                        10 import yaml
 12                                                    11 
 13 from lib import SpecFamily, SpecAttrSet, SpecA     12 from lib import SpecFamily, SpecAttrSet, SpecAttr, SpecOperation, SpecEnumSet, SpecEnumEntry
 14                                                    13 
 15                                                    14 
 16 def c_upper(name):                                 15 def c_upper(name):
 17     return name.upper().replace('-', '_')          16     return name.upper().replace('-', '_')
 18                                                    17 
 19                                                    18 
 20 def c_lower(name):                                 19 def c_lower(name):
 21     return name.lower().replace('-', '_')          20     return name.lower().replace('-', '_')
 22                                                    21 
 23                                                    22 
 24 def limit_to_number(name):                     << 
 25     """                                        << 
 26     Turn a string limit like u32-max or s64-mi << 
 27     """                                        << 
 28     if name[0] == 'u' and name.endswith('-min' << 
 29         return 0                               << 
 30     width = int(name[1:-4])                    << 
 31     if name[0] == 's':                         << 
 32         width -= 1                             << 
 33     value = (1 << width) - 1                   << 
 34     if name[0] == 's' and name.endswith('-min' << 
 35         value = -value - 1                     << 
 36     return value                               << 
 37                                                << 
 38                                                << 
 39 class BaseNlLib:                                   23 class BaseNlLib:
 40     def get_family_id(self):                       24     def get_family_id(self):
 41         return 'ys->family_id'                     25         return 'ys->family_id'
 42                                                    26 
                                                   >>  27     def parse_cb_run(self, cb, data, is_dump=False, indent=1):
                                                   >>  28         ind = '\n\t\t' + '\t' * indent + ' '
                                                   >>  29         if is_dump:
                                                   >>  30             return f"mnl_cb_run2(ys->rx_buf, len, 0, 0, {cb}, {data},{ind}ynl_cb_array, NLMSG_MIN_TYPE)"
                                                   >>  31         else:
                                                   >>  32             return f"mnl_cb_run2(ys->rx_buf, len, ys->seq, ys->portid,{ind}{cb}, {data},{ind}" + \
                                                   >>  33                    "ynl_cb_array, NLMSG_MIN_TYPE)"
                                                   >>  34 
 43                                                    35 
 44 class Type(SpecAttr):                              36 class Type(SpecAttr):
 45     def __init__(self, family, attr_set, attr,     37     def __init__(self, family, attr_set, attr, value):
 46         super().__init__(family, attr_set, att     38         super().__init__(family, attr_set, attr, value)
 47                                                    39 
 48         self.attr = attr                           40         self.attr = attr
 49         self.attr_set = attr_set                   41         self.attr_set = attr_set
 50         self.type = attr['type']                   42         self.type = attr['type']
 51         self.checks = attr.get('checks', {})       43         self.checks = attr.get('checks', {})
 52                                                    44 
 53         self.request = False                   << 
 54         self.reply = False                     << 
 55                                                << 
 56         if 'len' in attr:                          45         if 'len' in attr:
 57             self.len = attr['len']                 46             self.len = attr['len']
 58                                                << 
 59         if 'nested-attributes' in attr:            47         if 'nested-attributes' in attr:
 60             self.nested_attrs = attr['nested-a     48             self.nested_attrs = attr['nested-attributes']
 61             if self.nested_attrs == family.nam     49             if self.nested_attrs == family.name:
 62                 self.nested_render_name = c_lo !!  50                 self.nested_render_name = f"{family.name}"
 63             else:                                  51             else:
 64                 self.nested_render_name = c_lo !!  52                 self.nested_render_name = f"{family.name}_{c_lower(self.nested_attrs)}"
 65                                                    53 
 66             if self.nested_attrs in self.famil     54             if self.nested_attrs in self.family.consts:
 67                 self.nested_struct_type = 'str     55                 self.nested_struct_type = 'struct ' + self.nested_render_name + '_'
 68             else:                                  56             else:
 69                 self.nested_struct_type = 'str     57                 self.nested_struct_type = 'struct ' + self.nested_render_name
 70                                                    58 
 71         self.c_name = c_lower(self.name)           59         self.c_name = c_lower(self.name)
 72         if self.c_name in _C_KW:                   60         if self.c_name in _C_KW:
 73             self.c_name += '_'                     61             self.c_name += '_'
 74                                                    62 
 75         # Added by resolve():                      63         # Added by resolve():
 76         self.enum_name = None                      64         self.enum_name = None
 77         delattr(self, "enum_name")                 65         delattr(self, "enum_name")
 78                                                    66 
 79     def get_limit(self, limit, default=None):  << 
 80         value = self.checks.get(limit, default << 
 81         if value is None:                      << 
 82             return value                       << 
 83         elif value in self.family.consts:      << 
 84             return c_upper(f"{self.family['nam << 
 85         if not isinstance(value, int):         << 
 86             value = limit_to_number(value)     << 
 87         return value                           << 
 88                                                << 
 89     def resolve(self):                             67     def resolve(self):
 90         if 'name-prefix' in self.attr:             68         if 'name-prefix' in self.attr:
 91             enum_name = f"{self.attr['name-pre     69             enum_name = f"{self.attr['name-prefix']}{self.name}"
 92         else:                                      70         else:
 93             enum_name = f"{self.attr_set.name_     71             enum_name = f"{self.attr_set.name_prefix}{self.name}"
 94         self.enum_name = c_upper(enum_name)        72         self.enum_name = c_upper(enum_name)
 95                                                    73 
 96     def is_multi_val(self):                        74     def is_multi_val(self):
 97         return None                                75         return None
 98                                                    76 
 99     def is_scalar(self):                           77     def is_scalar(self):
100         return self.type in {'u8', 'u16', 'u32     78         return self.type in {'u8', 'u16', 'u32', 'u64', 's32', 's64'}
101                                                    79 
102     def is_recursive(self):                    << 
103         return False                           << 
104                                                << 
105     def is_recursive_for_op(self, ri):         << 
106         return self.is_recursive() and not ri. << 
107                                                << 
108     def presence_type(self):                       80     def presence_type(self):
109         return 'bit'                               81         return 'bit'
110                                                    82 
111     def presence_member(self, space, type_filt     83     def presence_member(self, space, type_filter):
112         if self.presence_type() != type_filter     84         if self.presence_type() != type_filter:
113             return                                 85             return
114                                                    86 
115         if self.presence_type() == 'bit':          87         if self.presence_type() == 'bit':
116             pfx = '__' if space == 'user' else     88             pfx = '__' if space == 'user' else ''
117             return f"{pfx}u32 {self.c_name}:1;     89             return f"{pfx}u32 {self.c_name}:1;"
118                                                    90 
119         if self.presence_type() == 'len':          91         if self.presence_type() == 'len':
120             pfx = '__' if space == 'user' else     92             pfx = '__' if space == 'user' else ''
121             return f"{pfx}u32 {self.c_name}_le     93             return f"{pfx}u32 {self.c_name}_len;"
122                                                    94 
123     def _complex_member_type(self, ri):            95     def _complex_member_type(self, ri):
124         return None                                96         return None
125                                                    97 
126     def free_needs_iter(self):                     98     def free_needs_iter(self):
127         return False                               99         return False
128                                                   100 
129     def free(self, ri, var, ref):                 101     def free(self, ri, var, ref):
130         if self.is_multi_val() or self.presenc    102         if self.is_multi_val() or self.presence_type() == 'len':
131             ri.cw.p(f'free({var}->{ref}{self.c    103             ri.cw.p(f'free({var}->{ref}{self.c_name});')
132                                                   104 
133     def arg_member(self, ri):                     105     def arg_member(self, ri):
134         member = self._complex_member_type(ri)    106         member = self._complex_member_type(ri)
135         if member:                                107         if member:
136             arg = [member + ' *' + self.c_name    108             arg = [member + ' *' + self.c_name]
137             if self.presence_type() == 'count'    109             if self.presence_type() == 'count':
138                 arg += ['unsigned int n_' + se    110                 arg += ['unsigned int n_' + self.c_name]
139             return arg                            111             return arg
140         raise Exception(f"Struct member not im    112         raise Exception(f"Struct member not implemented for class type {self.type}")
141                                                   113 
142     def struct_member(self, ri):                  114     def struct_member(self, ri):
143         if self.is_multi_val():                   115         if self.is_multi_val():
144             ri.cw.p(f"unsigned int n_{self.c_n    116             ri.cw.p(f"unsigned int n_{self.c_name};")
145         member = self._complex_member_type(ri)    117         member = self._complex_member_type(ri)
146         if member:                                118         if member:
147             ptr = '*' if self.is_multi_val() e    119             ptr = '*' if self.is_multi_val() else ''
148             if self.is_recursive_for_op(ri):   << 
149                 ptr = '*'                      << 
150             ri.cw.p(f"{member} {ptr}{self.c_na    120             ri.cw.p(f"{member} {ptr}{self.c_name};")
151             return                                121             return
152         members = self.arg_member(ri)             122         members = self.arg_member(ri)
153         for one in members:                       123         for one in members:
154             ri.cw.p(one + ';')                    124             ri.cw.p(one + ';')
155                                                   125 
156     def _attr_policy(self, policy):               126     def _attr_policy(self, policy):
157         return '{ .type = ' + policy + ', }'      127         return '{ .type = ' + policy + ', }'
158                                                   128 
159     def attr_policy(self, cw):                    129     def attr_policy(self, cw):
160         policy = c_upper('nla-' + self.attr['t    130         policy = c_upper('nla-' + self.attr['type'])
161                                                   131 
162         spec = self._attr_policy(policy)          132         spec = self._attr_policy(policy)
163         cw.p(f"\t[{self.enum_name}] = {spec},"    133         cw.p(f"\t[{self.enum_name}] = {spec},")
164                                                   134 
165     def _attr_typol(self):                        135     def _attr_typol(self):
166         raise Exception(f"Type policy not impl    136         raise Exception(f"Type policy not implemented for class type {self.type}")
167                                                   137 
168     def attr_typol(self, cw):                     138     def attr_typol(self, cw):
169         typol = self._attr_typol()                139         typol = self._attr_typol()
170         cw.p(f'[{self.enum_name}] = {"{"} .nam    140         cw.p(f'[{self.enum_name}] = {"{"} .name = "{self.name}", {typol}{"}"},')
171                                                   141 
172     def _attr_put_line(self, ri, var, line):      142     def _attr_put_line(self, ri, var, line):
173         if self.presence_type() == 'bit':         143         if self.presence_type() == 'bit':
174             ri.cw.p(f"if ({var}->_present.{sel    144             ri.cw.p(f"if ({var}->_present.{self.c_name})")
175         elif self.presence_type() == 'len':       145         elif self.presence_type() == 'len':
176             ri.cw.p(f"if ({var}->_present.{sel    146             ri.cw.p(f"if ({var}->_present.{self.c_name}_len)")
177         ri.cw.p(f"{line};")                       147         ri.cw.p(f"{line};")
178                                                   148 
179     def _attr_put_simple(self, ri, var, put_ty    149     def _attr_put_simple(self, ri, var, put_type):
180         line = f"ynl_attr_put_{put_type}(nlh,  !! 150         line = f"mnl_attr_put_{put_type}(nlh, {self.enum_name}, {var}->{self.c_name})"
181         self._attr_put_line(ri, var, line)        151         self._attr_put_line(ri, var, line)
182                                                   152 
183     def attr_put(self, ri, var):                  153     def attr_put(self, ri, var):
184         raise Exception(f"Put not implemented     154         raise Exception(f"Put not implemented for class type {self.type}")
185                                                   155 
186     def _attr_get(self, ri, var):                 156     def _attr_get(self, ri, var):
187         raise Exception(f"Attr get not impleme    157         raise Exception(f"Attr get not implemented for class type {self.type}")
188                                                   158 
189     def attr_get(self, ri, var, first):           159     def attr_get(self, ri, var, first):
190         lines, init_lines, local_vars = self._    160         lines, init_lines, local_vars = self._attr_get(ri, var)
191         if type(lines) is str:                    161         if type(lines) is str:
192             lines = [lines]                       162             lines = [lines]
193         if type(init_lines) is str:               163         if type(init_lines) is str:
194             init_lines = [init_lines]             164             init_lines = [init_lines]
195                                                   165 
196         kw = 'if' if first else 'else if'         166         kw = 'if' if first else 'else if'
197         ri.cw.block_start(line=f"{kw} (type ==    167         ri.cw.block_start(line=f"{kw} (type == {self.enum_name})")
198         if local_vars:                            168         if local_vars:
199             for local in local_vars:              169             for local in local_vars:
200                 ri.cw.p(local)                    170                 ri.cw.p(local)
201             ri.cw.nl()                            171             ri.cw.nl()
202                                                   172 
203         if not self.is_multi_val():               173         if not self.is_multi_val():
204             ri.cw.p("if (ynl_attr_validate(yar    174             ri.cw.p("if (ynl_attr_validate(yarg, attr))")
205             ri.cw.p("return YNL_PARSE_CB_ERROR !! 175             ri.cw.p("return MNL_CB_ERROR;")
206             if self.presence_type() == 'bit':     176             if self.presence_type() == 'bit':
207                 ri.cw.p(f"{var}->_present.{sel    177                 ri.cw.p(f"{var}->_present.{self.c_name} = 1;")
208                                                   178 
209         if init_lines:                            179         if init_lines:
210             ri.cw.nl()                            180             ri.cw.nl()
211             for line in init_lines:               181             for line in init_lines:
212                 ri.cw.p(line)                     182                 ri.cw.p(line)
213                                                   183 
214         for line in lines:                        184         for line in lines:
215             ri.cw.p(line)                         185             ri.cw.p(line)
216         ri.cw.block_end()                         186         ri.cw.block_end()
217         return True                               187         return True
218                                                   188 
219     def _setter_lines(self, ri, member, presen    189     def _setter_lines(self, ri, member, presence):
220         raise Exception(f"Setter not implement    190         raise Exception(f"Setter not implemented for class type {self.type}")
221                                                   191 
222     def setter(self, ri, space, direction, der    192     def setter(self, ri, space, direction, deref=False, ref=None):
223         ref = (ref if ref else []) + [self.c_n    193         ref = (ref if ref else []) + [self.c_name]
224         var = "req"                               194         var = "req"
225         member = f"{var}->{'.'.join(ref)}"        195         member = f"{var}->{'.'.join(ref)}"
226                                                   196 
227         code = []                                 197         code = []
228         presence = ''                             198         presence = ''
229         for i in range(0, len(ref)):              199         for i in range(0, len(ref)):
230             presence = f"{var}->{'.'.join(ref[    200             presence = f"{var}->{'.'.join(ref[:i] + [''])}_present.{ref[i]}"
231             # Every layer below last is a nest    201             # Every layer below last is a nest, so we know it uses bit presence
232             # last layer is "self" and may be     202             # last layer is "self" and may be a complex type
233             if i == len(ref) - 1 and self.pres    203             if i == len(ref) - 1 and self.presence_type() != 'bit':
234                 continue                          204                 continue
235             code.append(presence + ' = 1;')       205             code.append(presence + ' = 1;')
236         code += self._setter_lines(ri, member,    206         code += self._setter_lines(ri, member, presence)
237                                                   207 
238         func_name = f"{op_prefix(ri, direction    208         func_name = f"{op_prefix(ri, direction, deref=deref)}_set_{'_'.join(ref)}"
239         free = bool([x for x in code if 'free(    209         free = bool([x for x in code if 'free(' in x])
240         alloc = bool([x for x in code if 'allo    210         alloc = bool([x for x in code if 'alloc(' in x])
241         if free and not alloc:                    211         if free and not alloc:
242             func_name = '__' + func_name          212             func_name = '__' + func_name
243         ri.cw.write_func('static inline void',    213         ri.cw.write_func('static inline void', func_name, body=code,
244                          args=[f'{type_name(ri    214                          args=[f'{type_name(ri, direction, deref=deref)} *{var}'] + self.arg_member(ri))
245                                                   215 
246                                                   216 
247 class TypeUnused(Type):                           217 class TypeUnused(Type):
248     def presence_type(self):                      218     def presence_type(self):
249         return ''                                 219         return ''
250                                                   220 
251     def arg_member(self, ri):                     221     def arg_member(self, ri):
252         return []                                 222         return []
253                                                   223 
254     def _attr_get(self, ri, var):                 224     def _attr_get(self, ri, var):
255         return ['return YNL_PARSE_CB_ERROR;'], !! 225         return ['return MNL_CB_ERROR;'], None, None
256                                                   226 
257     def _attr_typol(self):                        227     def _attr_typol(self):
258         return '.type = YNL_PT_REJECT, '          228         return '.type = YNL_PT_REJECT, '
259                                                   229 
260     def attr_policy(self, cw):                    230     def attr_policy(self, cw):
261         pass                                      231         pass
262                                                   232 
263     def attr_put(self, ri, var):               << 
264         pass                                   << 
265                                                << 
266     def attr_get(self, ri, var, first):        << 
267         pass                                   << 
268                                                << 
269     def setter(self, ri, space, direction, der << 
270         pass                                   << 
271                                                << 
272                                                   233 
273 class TypePad(Type):                              234 class TypePad(Type):
274     def presence_type(self):                      235     def presence_type(self):
275         return ''                                 236         return ''
276                                                   237 
277     def arg_member(self, ri):                     238     def arg_member(self, ri):
278         return []                                 239         return []
279                                                   240 
280     def _attr_typol(self):                        241     def _attr_typol(self):
281         return '.type = YNL_PT_IGNORE, '          242         return '.type = YNL_PT_IGNORE, '
282                                                   243 
283     def attr_put(self, ri, var):                  244     def attr_put(self, ri, var):
284         pass                                      245         pass
285                                                   246 
286     def attr_get(self, ri, var, first):           247     def attr_get(self, ri, var, first):
287         pass                                      248         pass
288                                                   249 
289     def attr_policy(self, cw):                    250     def attr_policy(self, cw):
290         pass                                      251         pass
291                                                   252 
292     def setter(self, ri, space, direction, der    253     def setter(self, ri, space, direction, deref=False, ref=None):
293         pass                                      254         pass
294                                                   255 
295                                                   256 
296 class TypeScalar(Type):                           257 class TypeScalar(Type):
297     def __init__(self, family, attr_set, attr,    258     def __init__(self, family, attr_set, attr, value):
298         super().__init__(family, attr_set, att    259         super().__init__(family, attr_set, attr, value)
299                                                   260 
300         self.byte_order_comment = ''              261         self.byte_order_comment = ''
301         if 'byte-order' in attr:                  262         if 'byte-order' in attr:
302             self.byte_order_comment = f" /* {a    263             self.byte_order_comment = f" /* {attr['byte-order']} */"
303                                                   264 
304         if 'enum' in self.attr:                << 
305             enum = self.family.consts[self.att << 
306             low, high = enum.value_range()     << 
307             if 'min' not in self.checks:       << 
308                 if low != 0 or self.type[0] == << 
309                     self.checks['min'] = low   << 
310             if 'max' not in self.checks:       << 
311                 self.checks['max'] = high      << 
312                                                << 
313         if 'min' in self.checks and 'max' in s << 
314             if self.get_limit('min') > self.ge << 
315                 raise Exception(f'Invalid limi << 
316             self.checks['range'] = True        << 
317                                                << 
318         low = min(self.get_limit('min', 0), se << 
319         high = max(self.get_limit('min', 0), s << 
320         if low < 0 and self.type[0] == 'u':    << 
321             raise Exception(f'Invalid limit fo << 
322         if low < -32768 or high > 32767:       << 
323             self.checks['full-range'] = True   << 
324                                                << 
325         # Added by resolve():                     265         # Added by resolve():
326         self.is_bitfield = None                   266         self.is_bitfield = None
327         delattr(self, "is_bitfield")              267         delattr(self, "is_bitfield")
328         self.type_name = None                     268         self.type_name = None
329         delattr(self, "type_name")                269         delattr(self, "type_name")
330                                                   270 
331     def resolve(self):                            271     def resolve(self):
332         self.resolve_up(super())                  272         self.resolve_up(super())
333                                                   273 
334         if 'enum-as-flags' in self.attr and se    274         if 'enum-as-flags' in self.attr and self.attr['enum-as-flags']:
335             self.is_bitfield = True               275             self.is_bitfield = True
336         elif 'enum' in self.attr:                 276         elif 'enum' in self.attr:
337             self.is_bitfield = self.family.con    277             self.is_bitfield = self.family.consts[self.attr['enum']]['type'] == 'flags'
338         else:                                     278         else:
339             self.is_bitfield = False              279             self.is_bitfield = False
340                                                   280 
341         if not self.is_bitfield and 'enum' in  !! 281         maybe_enum = not self.is_bitfield and 'enum' in self.attr
342             self.type_name = self.family.const !! 282         if maybe_enum and self.family.consts[self.attr['enum']].enum_name:
343         elif self.is_auto_scalar:              !! 283             self.type_name = f"enum {self.family.name}_{c_lower(self.attr['enum'])}"
344             self.type_name = '__' + self.type[ << 
345         else:                                     284         else:
346             self.type_name = '__' + self.type     285             self.type_name = '__' + self.type
347                                                   286 
                                                   >> 287     def _mnl_type(self):
                                                   >> 288         t = self.type
                                                   >> 289         # mnl does not have a helper for signed types
                                                   >> 290         if t[0] == 's':
                                                   >> 291             t = 'u' + t[1:]
                                                   >> 292         return t
                                                   >> 293 
348     def _attr_policy(self, policy):               294     def _attr_policy(self, policy):
349         if 'flags-mask' in self.checks or self    295         if 'flags-mask' in self.checks or self.is_bitfield:
350             if self.is_bitfield:                  296             if self.is_bitfield:
351                 enum = self.family.consts[self    297                 enum = self.family.consts[self.attr['enum']]
352                 mask = enum.get_mask(as_flags=    298                 mask = enum.get_mask(as_flags=True)
353             else:                                 299             else:
354                 flags = self.family.consts[sel    300                 flags = self.family.consts[self.checks['flags-mask']]
355                 flag_cnt = len(flags['entries'    301                 flag_cnt = len(flags['entries'])
356                 mask = (1 << flag_cnt) - 1        302                 mask = (1 << flag_cnt) - 1
357             return f"NLA_POLICY_MASK({policy},    303             return f"NLA_POLICY_MASK({policy}, 0x{mask:x})"
358         elif 'full-range' in self.checks:      << 
359             return f"NLA_POLICY_FULL_RANGE({po << 
360         elif 'range' in self.checks:           << 
361             return f"NLA_POLICY_RANGE({policy} << 
362         elif 'min' in self.checks:                304         elif 'min' in self.checks:
363             return f"NLA_POLICY_MIN({policy},  !! 305             return f"NLA_POLICY_MIN({policy}, {self.checks['min']})"
364         elif 'max' in self.checks:             !! 306         elif 'enum' in self.attr:
365             return f"NLA_POLICY_MAX({policy},  !! 307             enum = self.family.consts[self.attr['enum']]
                                                   >> 308             low, high = enum.value_range()
                                                   >> 309             if low == 0:
                                                   >> 310                 return f"NLA_POLICY_MAX({policy}, {high})"
                                                   >> 311             return f"NLA_POLICY_RANGE({policy}, {low}, {high})"
366         return super()._attr_policy(policy)       312         return super()._attr_policy(policy)
367                                                   313 
368     def _attr_typol(self):                        314     def _attr_typol(self):
369         return f'.type = YNL_PT_U{c_upper(self !! 315         return f'.type = YNL_PT_U{self.type[1:]}, '
370                                                   316 
371     def arg_member(self, ri):                     317     def arg_member(self, ri):
372         return [f'{self.type_name} {self.c_nam    318         return [f'{self.type_name} {self.c_name}{self.byte_order_comment}']
373                                                   319 
374     def attr_put(self, ri, var):                  320     def attr_put(self, ri, var):
375         self._attr_put_simple(ri, var, self.ty !! 321         self._attr_put_simple(ri, var, self._mnl_type())
376                                                   322 
377     def _attr_get(self, ri, var):                 323     def _attr_get(self, ri, var):
378         return f"{var}->{self.c_name} = ynl_at !! 324         return f"{var}->{self.c_name} = mnl_attr_get_{self._mnl_type()}(attr);", None, None
379                                                   325 
380     def _setter_lines(self, ri, member, presen    326     def _setter_lines(self, ri, member, presence):
381         return [f"{member} = {self.c_name};"]     327         return [f"{member} = {self.c_name};"]
382                                                   328 
383                                                   329 
384 class TypeFlag(Type):                             330 class TypeFlag(Type):
385     def arg_member(self, ri):                     331     def arg_member(self, ri):
386         return []                                 332         return []
387                                                   333 
388     def _attr_typol(self):                        334     def _attr_typol(self):
389         return '.type = YNL_PT_FLAG, '            335         return '.type = YNL_PT_FLAG, '
390                                                   336 
391     def attr_put(self, ri, var):                  337     def attr_put(self, ri, var):
392         self._attr_put_line(ri, var, f"ynl_att !! 338         self._attr_put_line(ri, var, f"mnl_attr_put(nlh, {self.enum_name}, 0, NULL)")
393                                                   339 
394     def _attr_get(self, ri, var):                 340     def _attr_get(self, ri, var):
395         return [], None, None                     341         return [], None, None
396                                                   342 
397     def _setter_lines(self, ri, member, presen    343     def _setter_lines(self, ri, member, presence):
398         return []                                 344         return []
399                                                   345 
400                                                   346 
401 class TypeString(Type):                           347 class TypeString(Type):
402     def arg_member(self, ri):                     348     def arg_member(self, ri):
403         return [f"const char *{self.c_name}"]     349         return [f"const char *{self.c_name}"]
404                                                   350 
405     def presence_type(self):                      351     def presence_type(self):
406         return 'len'                              352         return 'len'
407                                                   353 
408     def struct_member(self, ri):                  354     def struct_member(self, ri):
409         ri.cw.p(f"char *{self.c_name};")          355         ri.cw.p(f"char *{self.c_name};")
410                                                   356 
411     def _attr_typol(self):                        357     def _attr_typol(self):
412         return f'.type = YNL_PT_NUL_STR, '        358         return f'.type = YNL_PT_NUL_STR, '
413                                                   359 
414     def _attr_policy(self, policy):               360     def _attr_policy(self, policy):
415         if 'exact-len' in self.checks:         !! 361         mem = '{ .type = ' + policy
416             mem = 'NLA_POLICY_EXACT_LEN(' + st !! 362         if 'max-len' in self.checks:
417         else:                                  !! 363             mem += ', .len = ' + str(self.checks['max-len'])
418             mem = '{ .type = ' + policy        !! 364         mem += ', }'
419             if 'max-len' in self.checks:       << 
420                 mem += ', .len = ' + str(self. << 
421             mem += ', }'                       << 
422         return mem                                365         return mem
423                                                   366 
424     def attr_policy(self, cw):                    367     def attr_policy(self, cw):
425         if self.checks.get('unterminated-ok',     368         if self.checks.get('unterminated-ok', False):
426             policy = 'NLA_STRING'                 369             policy = 'NLA_STRING'
427         else:                                     370         else:
428             policy = 'NLA_NUL_STRING'             371             policy = 'NLA_NUL_STRING'
429                                                   372 
430         spec = self._attr_policy(policy)          373         spec = self._attr_policy(policy)
431         cw.p(f"\t[{self.enum_name}] = {spec},"    374         cw.p(f"\t[{self.enum_name}] = {spec},")
432                                                   375 
433     def attr_put(self, ri, var):                  376     def attr_put(self, ri, var):
434         self._attr_put_simple(ri, var, 'str')  !! 377         self._attr_put_simple(ri, var, 'strz')
435                                                   378 
436     def _attr_get(self, ri, var):                 379     def _attr_get(self, ri, var):
437         len_mem = var + '->_present.' + self.c    380         len_mem = var + '->_present.' + self.c_name + '_len'
438         return [f"{len_mem} = len;",              381         return [f"{len_mem} = len;",
439                 f"{var}->{self.c_name} = mallo    382                 f"{var}->{self.c_name} = malloc(len + 1);",
440                 f"memcpy({var}->{self.c_name}, !! 383                 f"memcpy({var}->{self.c_name}, mnl_attr_get_str(attr), len);",
441                 f"{var}->{self.c_name}[len] =     384                 f"{var}->{self.c_name}[len] = 0;"], \
442                ['len = strnlen(ynl_attr_get_st !! 385                ['len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr));'], \
443                ['unsigned int len;']              386                ['unsigned int len;']
444                                                   387 
445     def _setter_lines(self, ri, member, presen    388     def _setter_lines(self, ri, member, presence):
446         return [f"free({member});",               389         return [f"free({member});",
447                 f"{presence}_len = strlen({sel    390                 f"{presence}_len = strlen({self.c_name});",
448                 f"{member} = malloc({presence}    391                 f"{member} = malloc({presence}_len + 1);",
449                 f'memcpy({member}, {self.c_nam    392                 f'memcpy({member}, {self.c_name}, {presence}_len);',
450                 f'{member}[{presence}_len] = 0    393                 f'{member}[{presence}_len] = 0;']
451                                                   394 
452                                                   395 
453 class TypeBinary(Type):                           396 class TypeBinary(Type):
454     def arg_member(self, ri):                     397     def arg_member(self, ri):
455         return [f"const void *{self.c_name}",     398         return [f"const void *{self.c_name}", 'size_t len']
456                                                   399 
457     def presence_type(self):                      400     def presence_type(self):
458         return 'len'                              401         return 'len'
459                                                   402 
460     def struct_member(self, ri):                  403     def struct_member(self, ri):
461         ri.cw.p(f"void *{self.c_name};")          404         ri.cw.p(f"void *{self.c_name};")
462                                                   405 
463     def _attr_typol(self):                        406     def _attr_typol(self):
464         return f'.type = YNL_PT_BINARY,'          407         return f'.type = YNL_PT_BINARY,'
465                                                   408 
466     def _attr_policy(self, policy):               409     def _attr_policy(self, policy):
467         if 'exact-len' in self.checks:         !! 410         mem = '{ '
468             mem = 'NLA_POLICY_EXACT_LEN(' + st !! 411         if len(self.checks) == 1 and 'min-len' in self.checks:
                                                   >> 412             mem += '.len = ' + str(self.checks['min-len'])
                                                   >> 413         elif len(self.checks) == 0:
                                                   >> 414             mem += '.type = NLA_BINARY'
469         else:                                     415         else:
470             mem = '{ '                         !! 416             raise Exception('One or more of binary type checks not implemented, yet')
471             if len(self.checks) == 1 and 'min- !! 417         mem += ', }'
472                 mem += '.len = ' + str(self.ge << 
473             elif len(self.checks) == 0:        << 
474                 mem += '.type = NLA_BINARY'    << 
475             else:                              << 
476                 raise Exception('One or more o << 
477             mem += ', }'                       << 
478         return mem                                418         return mem
479                                                   419 
480     def attr_put(self, ri, var):                  420     def attr_put(self, ri, var):
481         self._attr_put_line(ri, var, f"ynl_att !! 421         self._attr_put_line(ri, var, f"mnl_attr_put(nlh, {self.enum_name}, " +
482                             f"{var}->{self.c_n !! 422                             f"{var}->_present.{self.c_name}_len, {var}->{self.c_name})")
483                                                   423 
484     def _attr_get(self, ri, var):                 424     def _attr_get(self, ri, var):
485         len_mem = var + '->_present.' + self.c    425         len_mem = var + '->_present.' + self.c_name + '_len'
486         return [f"{len_mem} = len;",              426         return [f"{len_mem} = len;",
487                 f"{var}->{self.c_name} = mallo    427                 f"{var}->{self.c_name} = malloc(len);",
488                 f"memcpy({var}->{self.c_name}, !! 428                 f"memcpy({var}->{self.c_name}, mnl_attr_get_payload(attr), len);"], \
489                ['len = ynl_attr_data_len(attr) !! 429                ['len = mnl_attr_get_payload_len(attr);'], \
490                ['unsigned int len;']              430                ['unsigned int len;']
491                                                   431 
492     def _setter_lines(self, ri, member, presen    432     def _setter_lines(self, ri, member, presence):
493         return [f"free({member});",               433         return [f"free({member});",
494                 f"{presence}_len = len;",         434                 f"{presence}_len = len;",
495                 f"{member} = malloc({presence}    435                 f"{member} = malloc({presence}_len);",
496                 f'memcpy({member}, {self.c_nam    436                 f'memcpy({member}, {self.c_name}, {presence}_len);']
497                                                   437 
498                                                   438 
499 class TypeBitfield32(Type):                    << 
500     def _complex_member_type(self, ri):        << 
501         return "struct nla_bitfield32"         << 
502                                                << 
503     def _attr_typol(self):                     << 
504         return f'.type = YNL_PT_BITFIELD32, '  << 
505                                                << 
506     def _attr_policy(self, policy):            << 
507         if not 'enum' in self.attr:            << 
508             raise Exception('Enum required for << 
509         enum = self.family.consts[self.attr['e << 
510         mask = enum.get_mask(as_flags=True)    << 
511         return f"NLA_POLICY_BITFIELD32({mask}) << 
512                                                << 
513     def attr_put(self, ri, var):               << 
514         line = f"ynl_attr_put(nlh, {self.enum_ << 
515         self._attr_put_line(ri, var, line)     << 
516                                                << 
517     def _attr_get(self, ri, var):              << 
518         return f"memcpy(&{var}->{self.c_name}, << 
519                                                << 
520     def _setter_lines(self, ri, member, presen << 
521         return [f"memcpy(&{member}, {self.c_na << 
522                                                << 
523                                                << 
524 class TypeNest(Type):                             439 class TypeNest(Type):
525     def is_recursive(self):                    << 
526         return self.family.pure_nested_structs << 
527                                                << 
528     def _complex_member_type(self, ri):           440     def _complex_member_type(self, ri):
529         return self.nested_struct_type            441         return self.nested_struct_type
530                                                   442 
531     def free(self, ri, var, ref):                 443     def free(self, ri, var, ref):
532         at = '&'                               !! 444         ri.cw.p(f'{self.nested_render_name}_free(&{var}->{ref}{self.c_name});')
533         if self.is_recursive_for_op(ri):       << 
534             at = ''                            << 
535             ri.cw.p(f'if ({var}->{ref}{self.c_ << 
536         ri.cw.p(f'{self.nested_render_name}_fr << 
537                                                   445 
538     def _attr_typol(self):                        446     def _attr_typol(self):
539         return f'.type = YNL_PT_NEST, .nest =     447         return f'.type = YNL_PT_NEST, .nest = &{self.nested_render_name}_nest, '
540                                                   448 
541     def _attr_policy(self, policy):               449     def _attr_policy(self, policy):
542         return 'NLA_POLICY_NESTED(' + self.nes    450         return 'NLA_POLICY_NESTED(' + self.nested_render_name + '_nl_policy)'
543                                                   451 
544     def attr_put(self, ri, var):                  452     def attr_put(self, ri, var):
545         at = '' if self.is_recursive_for_op(ri << 
546         self._attr_put_line(ri, var, f"{self.n    453         self._attr_put_line(ri, var, f"{self.nested_render_name}_put(nlh, " +
547                             f"{self.enum_name} !! 454                             f"{self.enum_name}, &{var}->{self.c_name})")
548                                                   455 
549     def _attr_get(self, ri, var):                 456     def _attr_get(self, ri, var):
550         get_lines = [f"if ({self.nested_render    457         get_lines = [f"if ({self.nested_render_name}_parse(&parg, attr))",
551                      "return YNL_PARSE_CB_ERRO !! 458                      "return MNL_CB_ERROR;"]
552         init_lines = [f"parg.rsp_policy = &{se    459         init_lines = [f"parg.rsp_policy = &{self.nested_render_name}_nest;",
553                       f"parg.data = &{var}->{s    460                       f"parg.data = &{var}->{self.c_name};"]
554         return get_lines, init_lines, None        461         return get_lines, init_lines, None
555                                                   462 
556     def setter(self, ri, space, direction, der    463     def setter(self, ri, space, direction, deref=False, ref=None):
557         ref = (ref if ref else []) + [self.c_n    464         ref = (ref if ref else []) + [self.c_name]
558                                                   465 
559         for _, attr in ri.family.pure_nested_s    466         for _, attr in ri.family.pure_nested_structs[self.nested_attrs].member_list():
560             if attr.is_recursive():            << 
561                 continue                       << 
562             attr.setter(ri, self.nested_attrs,    467             attr.setter(ri, self.nested_attrs, direction, deref=deref, ref=ref)
563                                                   468 
564                                                   469 
565 class TypeMultiAttr(Type):                        470 class TypeMultiAttr(Type):
566     def __init__(self, family, attr_set, attr,    471     def __init__(self, family, attr_set, attr, value, base_type):
567         super().__init__(family, attr_set, att    472         super().__init__(family, attr_set, attr, value)
568                                                   473 
569         self.base_type = base_type                474         self.base_type = base_type
570                                                   475 
571     def is_multi_val(self):                       476     def is_multi_val(self):
572         return True                               477         return True
573                                                   478 
574     def presence_type(self):                      479     def presence_type(self):
575         return 'count'                            480         return 'count'
576                                                   481 
                                                   >> 482     def _mnl_type(self):
                                                   >> 483         t = self.type
                                                   >> 484         # mnl does not have a helper for signed types
                                                   >> 485         if t[0] == 's':
                                                   >> 486             t = 'u' + t[1:]
                                                   >> 487         return t
                                                   >> 488 
577     def _complex_member_type(self, ri):           489     def _complex_member_type(self, ri):
578         if 'type' not in self.attr or self.att    490         if 'type' not in self.attr or self.attr['type'] == 'nest':
579             return self.nested_struct_type        491             return self.nested_struct_type
580         elif self.attr['type'] in scalars:        492         elif self.attr['type'] in scalars:
581             scalar_pfx = '__' if ri.ku_space =    493             scalar_pfx = '__' if ri.ku_space == 'user' else ''
582             return scalar_pfx + self.attr['typ    494             return scalar_pfx + self.attr['type']
583         else:                                     495         else:
584             raise Exception(f"Sub-type {self.a    496             raise Exception(f"Sub-type {self.attr['type']} not supported yet")
585                                                   497 
586     def free_needs_iter(self):                    498     def free_needs_iter(self):
587         return 'type' not in self.attr or self    499         return 'type' not in self.attr or self.attr['type'] == 'nest'
588                                                   500 
589     def free(self, ri, var, ref):                 501     def free(self, ri, var, ref):
590         if self.attr['type'] in scalars:          502         if self.attr['type'] in scalars:
591             ri.cw.p(f"free({var}->{ref}{self.c    503             ri.cw.p(f"free({var}->{ref}{self.c_name});")
592         elif 'type' not in self.attr or self.a    504         elif 'type' not in self.attr or self.attr['type'] == 'nest':
593             ri.cw.p(f"for (i = 0; i < {var}->{    505             ri.cw.p(f"for (i = 0; i < {var}->{ref}n_{self.c_name}; i++)")
594             ri.cw.p(f'{self.nested_render_name    506             ri.cw.p(f'{self.nested_render_name}_free(&{var}->{ref}{self.c_name}[i]);')
595             ri.cw.p(f"free({var}->{ref}{self.c    507             ri.cw.p(f"free({var}->{ref}{self.c_name});")
596         else:                                     508         else:
597             raise Exception(f"Free of MultiAtt    509             raise Exception(f"Free of MultiAttr sub-type {self.attr['type']} not supported yet")
598                                                   510 
599     def _attr_policy(self, policy):               511     def _attr_policy(self, policy):
600         return self.base_type._attr_policy(pol    512         return self.base_type._attr_policy(policy)
601                                                   513 
602     def _attr_typol(self):                        514     def _attr_typol(self):
603         return self.base_type._attr_typol()       515         return self.base_type._attr_typol()
604                                                   516 
605     def _attr_get(self, ri, var):                 517     def _attr_get(self, ri, var):
606         return f'n_{self.c_name}++;', None, No    518         return f'n_{self.c_name}++;', None, None
607                                                   519 
608     def attr_put(self, ri, var):                  520     def attr_put(self, ri, var):
609         if self.attr['type'] in scalars:          521         if self.attr['type'] in scalars:
610             put_type = self.type               !! 522             put_type = self._mnl_type()
611             ri.cw.p(f"for (unsigned int i = 0;    523             ri.cw.p(f"for (unsigned int i = 0; i < {var}->n_{self.c_name}; i++)")
612             ri.cw.p(f"ynl_attr_put_{put_type}( !! 524             ri.cw.p(f"mnl_attr_put_{put_type}(nlh, {self.enum_name}, {var}->{self.c_name}[i]);")
613         elif 'type' not in self.attr or self.a    525         elif 'type' not in self.attr or self.attr['type'] == 'nest':
614             ri.cw.p(f"for (unsigned int i = 0;    526             ri.cw.p(f"for (unsigned int i = 0; i < {var}->n_{self.c_name}; i++)")
615             self._attr_put_line(ri, var, f"{se    527             self._attr_put_line(ri, var, f"{self.nested_render_name}_put(nlh, " +
616                                 f"{self.enum_n    528                                 f"{self.enum_name}, &{var}->{self.c_name}[i])")
617         else:                                     529         else:
618             raise Exception(f"Put of MultiAttr    530             raise Exception(f"Put of MultiAttr sub-type {self.attr['type']} not supported yet")
619                                                   531 
620     def _setter_lines(self, ri, member, presen    532     def _setter_lines(self, ri, member, presence):
621         # For multi-attr we have a count, not     533         # For multi-attr we have a count, not presence, hack up the presence
622         presence = presence[:-(len('_present.'    534         presence = presence[:-(len('_present.') + len(self.c_name))] + "n_" + self.c_name
623         return [f"free({member});",               535         return [f"free({member});",
624                 f"{member} = {self.c_name};",     536                 f"{member} = {self.c_name};",
625                 f"{presence} = n_{self.c_name}    537                 f"{presence} = n_{self.c_name};"]
626                                                   538 
627                                                   539 
628 class TypeArrayNest(Type):                        540 class TypeArrayNest(Type):
629     def is_multi_val(self):                       541     def is_multi_val(self):
630         return True                               542         return True
631                                                   543 
632     def presence_type(self):                      544     def presence_type(self):
633         return 'count'                            545         return 'count'
634                                                   546 
635     def _complex_member_type(self, ri):           547     def _complex_member_type(self, ri):
636         if 'sub-type' not in self.attr or self    548         if 'sub-type' not in self.attr or self.attr['sub-type'] == 'nest':
637             return self.nested_struct_type        549             return self.nested_struct_type
638         elif self.attr['sub-type'] in scalars:    550         elif self.attr['sub-type'] in scalars:
639             scalar_pfx = '__' if ri.ku_space =    551             scalar_pfx = '__' if ri.ku_space == 'user' else ''
640             return scalar_pfx + self.attr['sub    552             return scalar_pfx + self.attr['sub-type']
641         else:                                     553         else:
642             raise Exception(f"Sub-type {self.a    554             raise Exception(f"Sub-type {self.attr['sub-type']} not supported yet")
643                                                   555 
644     def _attr_typol(self):                        556     def _attr_typol(self):
645         return f'.type = YNL_PT_NEST, .nest =     557         return f'.type = YNL_PT_NEST, .nest = &{self.nested_render_name}_nest, '
646                                                   558 
647     def _attr_get(self, ri, var):                 559     def _attr_get(self, ri, var):
648         local_vars = ['const struct nlattr *at    560         local_vars = ['const struct nlattr *attr2;']
649         get_lines = [f'attr_{self.c_name} = at    561         get_lines = [f'attr_{self.c_name} = attr;',
650                      'ynl_attr_for_each_nested !! 562                      'mnl_attr_for_each_nested(attr2, attr)',
651                      f'\t{var}->n_{self.c_name    563                      f'\t{var}->n_{self.c_name}++;']
652         return get_lines, None, local_vars        564         return get_lines, None, local_vars
653                                                   565 
654                                                   566 
655 class TypeNestTypeValue(Type):                    567 class TypeNestTypeValue(Type):
656     def _complex_member_type(self, ri):           568     def _complex_member_type(self, ri):
657         return self.nested_struct_type            569         return self.nested_struct_type
658                                                   570 
659     def _attr_typol(self):                        571     def _attr_typol(self):
660         return f'.type = YNL_PT_NEST, .nest =     572         return f'.type = YNL_PT_NEST, .nest = &{self.nested_render_name}_nest, '
661                                                   573 
662     def _attr_get(self, ri, var):                 574     def _attr_get(self, ri, var):
663         prev = 'attr'                             575         prev = 'attr'
664         tv_args = ''                              576         tv_args = ''
665         get_lines = []                            577         get_lines = []
666         local_vars = []                           578         local_vars = []
667         init_lines = [f"parg.rsp_policy = &{se    579         init_lines = [f"parg.rsp_policy = &{self.nested_render_name}_nest;",
668                       f"parg.data = &{var}->{s    580                       f"parg.data = &{var}->{self.c_name};"]
669         if 'type-value' in self.attr:             581         if 'type-value' in self.attr:
670             tv_names = [c_lower(x) for x in se    582             tv_names = [c_lower(x) for x in self.attr["type-value"]]
671             local_vars += [f'const struct nlat    583             local_vars += [f'const struct nlattr *attr_{", *attr_".join(tv_names)};']
672             local_vars += [f'__u32 {", ".join(    584             local_vars += [f'__u32 {", ".join(tv_names)};']
673             for level in self.attr["type-value    585             for level in self.attr["type-value"]:
674                 level = c_lower(level)            586                 level = c_lower(level)
675                 get_lines += [f'attr_{level} = !! 587                 get_lines += [f'attr_{level} = mnl_attr_get_payload({prev});']
676                 get_lines += [f'{level} = ynl_ !! 588                 get_lines += [f'{level} = mnl_attr_get_type(attr_{level});']
677                 prev = 'attr_' + level            589                 prev = 'attr_' + level
678                                                   590 
679             tv_args = f", {', '.join(tv_names)    591             tv_args = f", {', '.join(tv_names)}"
680                                                   592 
681         get_lines += [f"{self.nested_render_na    593         get_lines += [f"{self.nested_render_name}_parse(&parg, {prev}{tv_args});"]
682         return get_lines, init_lines, local_va    594         return get_lines, init_lines, local_vars
683                                                   595 
684                                                   596 
685 class Struct:                                     597 class Struct:
686     def __init__(self, family, space_name, typ    598     def __init__(self, family, space_name, type_list=None, inherited=None):
687         self.family = family                      599         self.family = family
688         self.space_name = space_name              600         self.space_name = space_name
689         self.attr_set = family.attr_sets[space    601         self.attr_set = family.attr_sets[space_name]
690         # Use list to catch comparisons with e    602         # Use list to catch comparisons with empty sets
691         self._inherited = inherited if inherit    603         self._inherited = inherited if inherited is not None else []
692         self.inherited = []                       604         self.inherited = []
693                                                   605 
694         self.nested = type_list is None           606         self.nested = type_list is None
695         if family.name == c_lower(space_name):    607         if family.name == c_lower(space_name):
696             self.render_name = c_lower(family. !! 608             self.render_name = f"{family.name}"
697         else:                                     609         else:
698             self.render_name = c_lower(family. !! 610             self.render_name = f"{family.name}_{c_lower(space_name)}"
699         self.struct_name = 'struct ' + self.re    611         self.struct_name = 'struct ' + self.render_name
700         if self.nested and space_name in famil    612         if self.nested and space_name in family.consts:
701             self.struct_name += '_'               613             self.struct_name += '_'
702         self.ptr_name = self.struct_name + ' *    614         self.ptr_name = self.struct_name + ' *'
703         # All attr sets this one contains, dir << 
704         self.child_nests = set()               << 
705                                                   615 
706         self.request = False                      616         self.request = False
707         self.reply = False                        617         self.reply = False
708         self.recursive = False                 << 
709                                                   618 
710         self.attr_list = []                       619         self.attr_list = []
711         self.attrs = dict()                       620         self.attrs = dict()
712         if type_list is not None:                 621         if type_list is not None:
713             for t in type_list:                   622             for t in type_list:
714                 self.attr_list.append((t, self    623                 self.attr_list.append((t, self.attr_set[t]),)
715         else:                                     624         else:
716             for t in self.attr_set:               625             for t in self.attr_set:
717                 self.attr_list.append((t, self    626                 self.attr_list.append((t, self.attr_set[t]),)
718                                                   627 
719         max_val = 0                               628         max_val = 0
720         self.attr_max_val = None                  629         self.attr_max_val = None
721         for name, attr in self.attr_list:         630         for name, attr in self.attr_list:
722             if attr.value >= max_val:             631             if attr.value >= max_val:
723                 max_val = attr.value              632                 max_val = attr.value
724                 self.attr_max_val = attr          633                 self.attr_max_val = attr
725             self.attrs[name] = attr               634             self.attrs[name] = attr
726                                                   635 
727     def __iter__(self):                           636     def __iter__(self):
728         yield from self.attrs                     637         yield from self.attrs
729                                                   638 
730     def __getitem__(self, key):                   639     def __getitem__(self, key):
731         return self.attrs[key]                    640         return self.attrs[key]
732                                                   641 
733     def member_list(self):                        642     def member_list(self):
734         return self.attr_list                     643         return self.attr_list
735                                                   644 
736     def set_inherited(self, new_inherited):       645     def set_inherited(self, new_inherited):
737         if self._inherited != new_inherited:      646         if self._inherited != new_inherited:
738             raise Exception("Inheriting differ    647             raise Exception("Inheriting different members not supported")
739         self.inherited = [c_lower(x) for x in     648         self.inherited = [c_lower(x) for x in sorted(self._inherited)]
740                                                   649 
741                                                   650 
742 class EnumEntry(SpecEnumEntry):                   651 class EnumEntry(SpecEnumEntry):
743     def __init__(self, enum_set, yaml, prev, v    652     def __init__(self, enum_set, yaml, prev, value_start):
744         super().__init__(enum_set, yaml, prev,    653         super().__init__(enum_set, yaml, prev, value_start)
745                                                   654 
746         if prev:                                  655         if prev:
747             self.value_change = (self.value !=    656             self.value_change = (self.value != prev.value + 1)
748         else:                                     657         else:
749             self.value_change = (self.value !=    658             self.value_change = (self.value != 0)
750         self.value_change = self.value_change     659         self.value_change = self.value_change or self.enum_set['type'] == 'flags'
751                                                   660 
752         # Added by resolve:                       661         # Added by resolve:
753         self.c_name = None                        662         self.c_name = None
754         delattr(self, "c_name")                   663         delattr(self, "c_name")
755                                                   664 
756     def resolve(self):                            665     def resolve(self):
757         self.resolve_up(super())                  666         self.resolve_up(super())
758                                                   667 
759         self.c_name = c_upper(self.enum_set.va    668         self.c_name = c_upper(self.enum_set.value_pfx + self.name)
760                                                   669 
761                                                   670 
762 class EnumSet(SpecEnumSet):                       671 class EnumSet(SpecEnumSet):
763     def __init__(self, family, yaml):             672     def __init__(self, family, yaml):
764         self.render_name = c_lower(family.iden !! 673         self.render_name = c_lower(family.name + '-' + yaml['name'])
765                                                   674 
766         if 'enum-name' in yaml:                   675         if 'enum-name' in yaml:
767             if yaml['enum-name']:                 676             if yaml['enum-name']:
768                 self.enum_name = 'enum ' + c_l    677                 self.enum_name = 'enum ' + c_lower(yaml['enum-name'])
769                 self.user_type = self.enum_nam << 
770             else:                                 678             else:
771                 self.enum_name = None             679                 self.enum_name = None
772         else:                                     680         else:
773             self.enum_name = 'enum ' + self.re    681             self.enum_name = 'enum ' + self.render_name
774                                                   682 
775         if self.enum_name:                     !! 683         self.value_pfx = yaml.get('name-prefix', f"{family.name}-{yaml['name']}-")
776             self.user_type = self.enum_name    << 
777         else:                                  << 
778             self.user_type = 'int'             << 
779                                                << 
780         self.value_pfx = yaml.get('name-prefix << 
781                                                   684 
782         super().__init__(family, yaml)            685         super().__init__(family, yaml)
783                                                   686 
784     def new_entry(self, entry, prev_entry, val    687     def new_entry(self, entry, prev_entry, value_start):
785         return EnumEntry(self, entry, prev_ent    688         return EnumEntry(self, entry, prev_entry, value_start)
786                                                   689 
787     def value_range(self):                        690     def value_range(self):
788         low = min([x.value for x in self.entri    691         low = min([x.value for x in self.entries.values()])
789         high = max([x.value for x in self.entr    692         high = max([x.value for x in self.entries.values()])
790                                                   693 
791         if high - low + 1 != len(self.entries)    694         if high - low + 1 != len(self.entries):
792             raise Exception("Can't get value r    695             raise Exception("Can't get value range for a noncontiguous enum")
793                                                   696 
794         return low, high                          697         return low, high
795                                                   698 
796                                                   699 
797 class AttrSet(SpecAttrSet):                       700 class AttrSet(SpecAttrSet):
798     def __init__(self, family, yaml):             701     def __init__(self, family, yaml):
799         super().__init__(family, yaml)            702         super().__init__(family, yaml)
800                                                   703 
801         if self.subset_of is None:                704         if self.subset_of is None:
802             if 'name-prefix' in yaml:             705             if 'name-prefix' in yaml:
803                 pfx = yaml['name-prefix']         706                 pfx = yaml['name-prefix']
804             elif self.name == family.name:        707             elif self.name == family.name:
805                 pfx = family.ident_name + '-a- !! 708                 pfx = family.name + '-a-'
806             else:                                 709             else:
807                 pfx = f"{family.ident_name}-a- !! 710                 pfx = f"{family.name}-a-{self.name}-"
808             self.name_prefix = c_upper(pfx)       711             self.name_prefix = c_upper(pfx)
809             self.max_name = c_upper(self.yaml.    712             self.max_name = c_upper(self.yaml.get('attr-max-name', f"{self.name_prefix}max"))
810             self.cnt_name = c_upper(self.yaml. << 
811         else:                                     713         else:
812             self.name_prefix = family.attr_set    714             self.name_prefix = family.attr_sets[self.subset_of].name_prefix
813             self.max_name = family.attr_sets[s    715             self.max_name = family.attr_sets[self.subset_of].max_name
814             self.cnt_name = family.attr_sets[s << 
815                                                   716 
816         # Added by resolve:                       717         # Added by resolve:
817         self.c_name = None                        718         self.c_name = None
818         delattr(self, "c_name")                   719         delattr(self, "c_name")
819                                                   720 
820     def resolve(self):                            721     def resolve(self):
821         self.c_name = c_lower(self.name)          722         self.c_name = c_lower(self.name)
822         if self.c_name in _C_KW:                  723         if self.c_name in _C_KW:
823             self.c_name += '_'                    724             self.c_name += '_'
824         if self.c_name == self.family.c_name:     725         if self.c_name == self.family.c_name:
825             self.c_name = ''                      726             self.c_name = ''
826                                                   727 
827     def new_attr(self, elem, value):              728     def new_attr(self, elem, value):
828         if elem['type'] in scalars:               729         if elem['type'] in scalars:
829             t = TypeScalar(self.family, self,     730             t = TypeScalar(self.family, self, elem, value)
830         elif elem['type'] == 'unused':            731         elif elem['type'] == 'unused':
831             t = TypeUnused(self.family, self,     732             t = TypeUnused(self.family, self, elem, value)
832         elif elem['type'] == 'pad':               733         elif elem['type'] == 'pad':
833             t = TypePad(self.family, self, ele    734             t = TypePad(self.family, self, elem, value)
834         elif elem['type'] == 'flag':              735         elif elem['type'] == 'flag':
835             t = TypeFlag(self.family, self, el    736             t = TypeFlag(self.family, self, elem, value)
836         elif elem['type'] == 'string':            737         elif elem['type'] == 'string':
837             t = TypeString(self.family, self,     738             t = TypeString(self.family, self, elem, value)
838         elif elem['type'] == 'binary':            739         elif elem['type'] == 'binary':
839             t = TypeBinary(self.family, self,     740             t = TypeBinary(self.family, self, elem, value)
840         elif elem['type'] == 'bitfield32':     << 
841             t = TypeBitfield32(self.family, se << 
842         elif elem['type'] == 'nest':              741         elif elem['type'] == 'nest':
843             t = TypeNest(self.family, self, el    742             t = TypeNest(self.family, self, elem, value)
844         elif elem['type'] == 'indexed-array' a !! 743         elif elem['type'] == 'array-nest':
845             if elem["sub-type"] == 'nest':     !! 744             t = TypeArrayNest(self.family, self, elem, value)
846                 t = TypeArrayNest(self.family, << 
847             else:                              << 
848                 raise Exception(f'new_attr: un << 
849         elif elem['type'] == 'nest-type-value'    745         elif elem['type'] == 'nest-type-value':
850             t = TypeNestTypeValue(self.family,    746             t = TypeNestTypeValue(self.family, self, elem, value)
851         else:                                     747         else:
852             raise Exception(f"No typed class f    748             raise Exception(f"No typed class for type {elem['type']}")
853                                                   749 
854         if 'multi-attr' in elem and elem['mult    750         if 'multi-attr' in elem and elem['multi-attr']:
855             t = TypeMultiAttr(self.family, sel    751             t = TypeMultiAttr(self.family, self, elem, value, t)
856                                                   752 
857         return t                                  753         return t
858                                                   754 
859                                                   755 
860 class Operation(SpecOperation):                   756 class Operation(SpecOperation):
861     def __init__(self, family, yaml, req_value    757     def __init__(self, family, yaml, req_value, rsp_value):
862         super().__init__(family, yaml, req_val    758         super().__init__(family, yaml, req_value, rsp_value)
863                                                   759 
864         self.render_name = c_lower(family.iden !! 760         self.render_name = family.name + '_' + c_lower(self.name)
865                                                   761 
866         self.dual_policy = ('do' in yaml and '    762         self.dual_policy = ('do' in yaml and 'request' in yaml['do']) and \
867                          ('dump' in yaml and '    763                          ('dump' in yaml and 'request' in yaml['dump'])
868                                                   764 
869         self.has_ntf = False                      765         self.has_ntf = False
870                                                   766 
871         # Added by resolve:                       767         # Added by resolve:
872         self.enum_name = None                     768         self.enum_name = None
873         delattr(self, "enum_name")                769         delattr(self, "enum_name")
874                                                   770 
875     def resolve(self):                            771     def resolve(self):
876         self.resolve_up(super())                  772         self.resolve_up(super())
877                                                   773 
878         if not self.is_async:                     774         if not self.is_async:
879             self.enum_name = self.family.op_pr    775             self.enum_name = self.family.op_prefix + c_upper(self.name)
880         else:                                     776         else:
881             self.enum_name = self.family.async    777             self.enum_name = self.family.async_op_prefix + c_upper(self.name)
882                                                   778 
883     def mark_has_ntf(self):                       779     def mark_has_ntf(self):
884         self.has_ntf = True                       780         self.has_ntf = True
885                                                   781 
886                                                   782 
887 class Family(SpecFamily):                         783 class Family(SpecFamily):
888     def __init__(self, file_name, exclude_ops)    784     def __init__(self, file_name, exclude_ops):
889         # Added by resolve:                       785         # Added by resolve:
890         self.c_name = None                        786         self.c_name = None
891         delattr(self, "c_name")                   787         delattr(self, "c_name")
892         self.op_prefix = None                     788         self.op_prefix = None
893         delattr(self, "op_prefix")                789         delattr(self, "op_prefix")
894         self.async_op_prefix = None               790         self.async_op_prefix = None
895         delattr(self, "async_op_prefix")          791         delattr(self, "async_op_prefix")
896         self.mcgrps = None                        792         self.mcgrps = None
897         delattr(self, "mcgrps")                   793         delattr(self, "mcgrps")
898         self.consts = None                        794         self.consts = None
899         delattr(self, "consts")                   795         delattr(self, "consts")
900         self.hooks = None                         796         self.hooks = None
901         delattr(self, "hooks")                    797         delattr(self, "hooks")
902                                                   798 
903         super().__init__(file_name, exclude_op    799         super().__init__(file_name, exclude_ops=exclude_ops)
904                                                   800 
905         self.fam_key = c_upper(self.yaml.get('    801         self.fam_key = c_upper(self.yaml.get('c-family-name', self.yaml["name"] + '_FAMILY_NAME'))
906         self.ver_key = c_upper(self.yaml.get('    802         self.ver_key = c_upper(self.yaml.get('c-version-name', self.yaml["name"] + '_FAMILY_VERSION'))
907                                                   803 
908         if 'definitions' not in self.yaml:        804         if 'definitions' not in self.yaml:
909             self.yaml['definitions'] = []         805             self.yaml['definitions'] = []
910                                                   806 
911         if 'uapi-header' in self.yaml:            807         if 'uapi-header' in self.yaml:
912             self.uapi_header = self.yaml['uapi    808             self.uapi_header = self.yaml['uapi-header']
913         else:                                     809         else:
914             self.uapi_header = f"linux/{self.i !! 810             self.uapi_header = f"linux/{self.name}.h"
915         if self.uapi_header.startswith("linux/ << 
916             self.uapi_header_name = self.uapi_ << 
917         else:                                  << 
918             self.uapi_header_name = self.ident << 
919                                                   811 
920     def resolve(self):                            812     def resolve(self):
921         self.resolve_up(super())                  813         self.resolve_up(super())
922                                                   814 
923         if self.yaml.get('protocol', 'genetlin    815         if self.yaml.get('protocol', 'genetlink') not in {'genetlink', 'genetlink-c', 'genetlink-legacy'}:
924             raise Exception("Codegen only supp    816             raise Exception("Codegen only supported for genetlink")
925                                                   817 
926         self.c_name = c_lower(self.ident_name) !! 818         self.c_name = c_lower(self.name)
927         if 'name-prefix' in self.yaml['operati    819         if 'name-prefix' in self.yaml['operations']:
928             self.op_prefix = c_upper(self.yaml    820             self.op_prefix = c_upper(self.yaml['operations']['name-prefix'])
929         else:                                     821         else:
930             self.op_prefix = c_upper(self.yaml    822             self.op_prefix = c_upper(self.yaml['name'] + '-cmd-')
931         if 'async-prefix' in self.yaml['operat    823         if 'async-prefix' in self.yaml['operations']:
932             self.async_op_prefix = c_upper(sel    824             self.async_op_prefix = c_upper(self.yaml['operations']['async-prefix'])
933         else:                                     825         else:
934             self.async_op_prefix = self.op_pre    826             self.async_op_prefix = self.op_prefix
935                                                   827 
936         self.mcgrps = self.yaml.get('mcast-gro    828         self.mcgrps = self.yaml.get('mcast-groups', {'list': []})
937                                                   829 
938         self.hooks = dict()                       830         self.hooks = dict()
939         for when in ['pre', 'post']:              831         for when in ['pre', 'post']:
940             self.hooks[when] = dict()             832             self.hooks[when] = dict()
941             for op_mode in ['do', 'dump']:        833             for op_mode in ['do', 'dump']:
942                 self.hooks[when][op_mode] = di    834                 self.hooks[when][op_mode] = dict()
943                 self.hooks[when][op_mode]['set    835                 self.hooks[when][op_mode]['set'] = set()
944                 self.hooks[when][op_mode]['lis    836                 self.hooks[when][op_mode]['list'] = []
945                                                   837 
946         # dict space-name -> 'request': set(at    838         # dict space-name -> 'request': set(attrs), 'reply': set(attrs)
947         self.root_sets = dict()                   839         self.root_sets = dict()
948         # dict space-name -> set('request', 'r    840         # dict space-name -> set('request', 'reply')
949         self.pure_nested_structs = dict()         841         self.pure_nested_structs = dict()
950                                                   842 
951         self._mark_notify()                       843         self._mark_notify()
952         self._mock_up_events()                    844         self._mock_up_events()
953                                                   845 
954         self._load_root_sets()                    846         self._load_root_sets()
955         self._load_nested_sets()                  847         self._load_nested_sets()
956         self._load_attr_use()                  << 
957         self._load_hooks()                        848         self._load_hooks()
958                                                   849 
959         self.kernel_policy = self.yaml.get('ke    850         self.kernel_policy = self.yaml.get('kernel-policy', 'split')
960         if self.kernel_policy == 'global':        851         if self.kernel_policy == 'global':
961             self._load_global_policy()            852             self._load_global_policy()
962                                                   853 
963     def new_enum(self, elem):                     854     def new_enum(self, elem):
964         return EnumSet(self, elem)                855         return EnumSet(self, elem)
965                                                   856 
966     def new_attr_set(self, elem):                 857     def new_attr_set(self, elem):
967         return AttrSet(self, elem)                858         return AttrSet(self, elem)
968                                                   859 
969     def new_operation(self, elem, req_value, r    860     def new_operation(self, elem, req_value, rsp_value):
970         return Operation(self, elem, req_value    861         return Operation(self, elem, req_value, rsp_value)
971                                                   862 
972     def _mark_notify(self):                       863     def _mark_notify(self):
973         for op in self.msgs.values():             864         for op in self.msgs.values():
974             if 'notify' in op:                    865             if 'notify' in op:
975                 self.ops[op['notify']].mark_ha    866                 self.ops[op['notify']].mark_has_ntf()
976                                                   867 
977     # Fake a 'do' equivalent of all events, so    868     # Fake a 'do' equivalent of all events, so that we can render their response parsing
978     def _mock_up_events(self):                    869     def _mock_up_events(self):
979         for op in self.yaml['operations']['lis    870         for op in self.yaml['operations']['list']:
980             if 'event' in op:                     871             if 'event' in op:
981                 op['do'] = {                      872                 op['do'] = {
982                     'reply': {                    873                     'reply': {
983                         'attributes': op['even    874                         'attributes': op['event']['attributes']
984                     }                             875                     }
985                 }                                 876                 }
986                                                   877 
987     def _load_root_sets(self):                    878     def _load_root_sets(self):
988         for op_name, op in self.msgs.items():     879         for op_name, op in self.msgs.items():
989             if 'attribute-set' not in op:         880             if 'attribute-set' not in op:
990                 continue                          881                 continue
991                                                   882 
992             req_attrs = set()                     883             req_attrs = set()
993             rsp_attrs = set()                     884             rsp_attrs = set()
994             for op_mode in ['do', 'dump']:        885             for op_mode in ['do', 'dump']:
995                 if op_mode in op and 'request'    886                 if op_mode in op and 'request' in op[op_mode]:
996                     req_attrs.update(set(op[op    887                     req_attrs.update(set(op[op_mode]['request']['attributes']))
997                 if op_mode in op and 'reply' i    888                 if op_mode in op and 'reply' in op[op_mode]:
998                     rsp_attrs.update(set(op[op    889                     rsp_attrs.update(set(op[op_mode]['reply']['attributes']))
999             if 'event' in op:                     890             if 'event' in op:
1000                 rsp_attrs.update(set(op['even    891                 rsp_attrs.update(set(op['event']['attributes']))
1001                                                  892 
1002             if op['attribute-set'] not in sel    893             if op['attribute-set'] not in self.root_sets:
1003                 self.root_sets[op['attribute-    894                 self.root_sets[op['attribute-set']] = {'request': req_attrs, 'reply': rsp_attrs}
1004             else:                                895             else:
1005                 self.root_sets[op['attribute-    896                 self.root_sets[op['attribute-set']]['request'].update(req_attrs)
1006                 self.root_sets[op['attribute-    897                 self.root_sets[op['attribute-set']]['reply'].update(rsp_attrs)
1007                                                  898 
1008     def _sort_pure_types(self):               << 
1009         # Try to reorder according to depende << 
1010         pns_key_list = list(self.pure_nested_ << 
1011         pns_key_seen = set()                  << 
1012         rounds = len(pns_key_list) ** 2  # it << 
1013         for _ in range(rounds):               << 
1014             if len(pns_key_list) == 0:        << 
1015                 break                         << 
1016             name = pns_key_list.pop(0)        << 
1017             finished = True                   << 
1018             for _, spec in self.attr_sets[nam << 
1019                 if 'nested-attributes' in spe << 
1020                     nested = spec['nested-att << 
1021                     # If the unknown nest we  << 
1022                     if self.pure_nested_struc << 
1023                         continue              << 
1024                     if nested not in pns_key_ << 
1025                         # Dicts are sorted, t << 
1026                         struct = self.pure_ne << 
1027                         self.pure_nested_stru << 
1028                         finished = False      << 
1029                         break                 << 
1030             if finished:                      << 
1031                 pns_key_seen.add(name)        << 
1032             else:                             << 
1033                 pns_key_list.append(name)     << 
1034                                               << 
1035     def _load_nested_sets(self):                 899     def _load_nested_sets(self):
1036         attr_set_queue = list(self.root_sets.    900         attr_set_queue = list(self.root_sets.keys())
1037         attr_set_seen = set(self.root_sets.ke    901         attr_set_seen = set(self.root_sets.keys())
1038                                                  902 
1039         while len(attr_set_queue):               903         while len(attr_set_queue):
1040             a_set = attr_set_queue.pop(0)        904             a_set = attr_set_queue.pop(0)
1041             for attr, spec in self.attr_sets[    905             for attr, spec in self.attr_sets[a_set].items():
1042                 if 'nested-attributes' not in    906                 if 'nested-attributes' not in spec:
1043                     continue                     907                     continue
1044                                                  908 
1045                 nested = spec['nested-attribu    909                 nested = spec['nested-attributes']
1046                 if nested not in attr_set_see    910                 if nested not in attr_set_seen:
1047                     attr_set_queue.append(nes    911                     attr_set_queue.append(nested)
1048                     attr_set_seen.add(nested)    912                     attr_set_seen.add(nested)
1049                                                  913 
1050                 inherit = set()                  914                 inherit = set()
1051                 if nested not in self.root_se    915                 if nested not in self.root_sets:
1052                     if nested not in self.pur    916                     if nested not in self.pure_nested_structs:
1053                         self.pure_nested_stru    917                         self.pure_nested_structs[nested] = Struct(self, nested, inherited=inherit)
1054                 else:                            918                 else:
1055                     raise Exception(f'Using a    919                     raise Exception(f'Using attr set as root and nested not supported - {nested}')
1056                                                  920 
1057                 if 'type-value' in spec:         921                 if 'type-value' in spec:
1058                     if nested in self.root_se    922                     if nested in self.root_sets:
1059                         raise Exception("Inhe    923                         raise Exception("Inheriting members to a space used as root not supported")
1060                     inherit.update(set(spec['    924                     inherit.update(set(spec['type-value']))
1061                 elif spec['type'] == 'indexed !! 925                 elif spec['type'] == 'array-nest':
1062                     inherit.add('idx')           926                     inherit.add('idx')
1063                 self.pure_nested_structs[nest    927                 self.pure_nested_structs[nested].set_inherited(inherit)
1064                                                  928 
1065         for root_set, rs_members in self.root    929         for root_set, rs_members in self.root_sets.items():
1066             for attr, spec in self.attr_sets[    930             for attr, spec in self.attr_sets[root_set].items():
1067                 if 'nested-attributes' in spe    931                 if 'nested-attributes' in spec:
1068                     nested = spec['nested-att    932                     nested = spec['nested-attributes']
1069                     if attr in rs_members['re    933                     if attr in rs_members['request']:
1070                         self.pure_nested_stru    934                         self.pure_nested_structs[nested].request = True
1071                     if attr in rs_members['re    935                     if attr in rs_members['reply']:
1072                         self.pure_nested_stru    936                         self.pure_nested_structs[nested].reply = True
1073                                                  937 
1074         self._sort_pure_types()               !! 938         # Try to reorder according to dependencies
1075                                               !! 939         pns_key_list = list(self.pure_nested_structs.keys())
1076         # Propagate the request / reply / rec !! 940         pns_key_seen = set()
                                                   >> 941         rounds = len(pns_key_list)**2  # it's basically bubble sort
                                                   >> 942         for _ in range(rounds):
                                                   >> 943             if len(pns_key_list) == 0:
                                                   >> 944                 break
                                                   >> 945             name = pns_key_list.pop(0)
                                                   >> 946             finished = True
                                                   >> 947             for _, spec in self.attr_sets[name].items():
                                                   >> 948                 if 'nested-attributes' in spec:
                                                   >> 949                     if spec['nested-attributes'] not in pns_key_seen:
                                                   >> 950                         # Dicts are sorted, this will make struct last
                                                   >> 951                         struct = self.pure_nested_structs.pop(name)
                                                   >> 952                         self.pure_nested_structs[name] = struct
                                                   >> 953                         finished = False
                                                   >> 954                         break
                                                   >> 955             if finished:
                                                   >> 956                 pns_key_seen.add(name)
                                                   >> 957             else:
                                                   >> 958                 pns_key_list.append(name)
                                                   >> 959         # Propagate the request / reply
1077         for attr_set, struct in reversed(self    960         for attr_set, struct in reversed(self.pure_nested_structs.items()):
1078             for _, spec in self.attr_sets[att    961             for _, spec in self.attr_sets[attr_set].items():
1079                 if 'nested-attributes' in spe    962                 if 'nested-attributes' in spec:
1080                     child_name = spec['nested !! 963                     child = self.pure_nested_structs.get(spec['nested-attributes'])
1081                     struct.child_nests.add(ch << 
1082                     child = self.pure_nested_ << 
1083                     if child:                    964                     if child:
1084                         if not child.recursiv << 
1085                             struct.child_nest << 
1086                         child.request |= stru    965                         child.request |= struct.request
1087                         child.reply |= struct    966                         child.reply |= struct.reply
1088                 if attr_set in struct.child_n << 
1089                     struct.recursive = True   << 
1090                                               << 
1091         self._sort_pure_types()               << 
1092                                               << 
1093     def _load_attr_use(self):                 << 
1094         for _, struct in self.pure_nested_str << 
1095             if struct.request:                << 
1096                 for _, arg in struct.member_l << 
1097                     arg.request = True        << 
1098             if struct.reply:                  << 
1099                 for _, arg in struct.member_l << 
1100                     arg.reply = True          << 
1101                                               << 
1102         for root_set, rs_members in self.root << 
1103             for attr, spec in self.attr_sets[ << 
1104                 if attr in rs_members['reques << 
1105                     spec.request = True       << 
1106                 if attr in rs_members['reply' << 
1107                     spec.reply = True         << 
1108                                                  967 
1109     def _load_global_policy(self):               968     def _load_global_policy(self):
1110         global_set = set()                       969         global_set = set()
1111         attr_set_name = None                     970         attr_set_name = None
1112         for op_name, op in self.ops.items():     971         for op_name, op in self.ops.items():
1113             if not op:                           972             if not op:
1114                 continue                         973                 continue
1115             if 'attribute-set' not in op:        974             if 'attribute-set' not in op:
1116                 continue                         975                 continue
1117                                                  976 
1118             if attr_set_name is None:            977             if attr_set_name is None:
1119                 attr_set_name = op['attribute    978                 attr_set_name = op['attribute-set']
1120             if attr_set_name != op['attribute    979             if attr_set_name != op['attribute-set']:
1121                 raise Exception('For a global    980                 raise Exception('For a global policy all ops must use the same set')
1122                                                  981 
1123             for op_mode in ['do', 'dump']:       982             for op_mode in ['do', 'dump']:
1124                 if op_mode in op:                983                 if op_mode in op:
1125                     req = op[op_mode].get('re    984                     req = op[op_mode].get('request')
1126                     if req:                      985                     if req:
1127                         global_set.update(req    986                         global_set.update(req.get('attributes', []))
1128                                                  987 
1129         self.global_policy = []                  988         self.global_policy = []
1130         self.global_policy_set = attr_set_nam    989         self.global_policy_set = attr_set_name
1131         for attr in self.attr_sets[attr_set_n    990         for attr in self.attr_sets[attr_set_name]:
1132             if attr in global_set:               991             if attr in global_set:
1133                 self.global_policy.append(att    992                 self.global_policy.append(attr)
1134                                                  993 
1135     def _load_hooks(self):                       994     def _load_hooks(self):
1136         for op in self.ops.values():             995         for op in self.ops.values():
1137             for op_mode in ['do', 'dump']:       996             for op_mode in ['do', 'dump']:
1138                 if op_mode not in op:            997                 if op_mode not in op:
1139                     continue                     998                     continue
1140                 for when in ['pre', 'post']:     999                 for when in ['pre', 'post']:
1141                     if when not in op[op_mode    1000                     if when not in op[op_mode]:
1142                         continue                 1001                         continue
1143                     name = op[op_mode][when]     1002                     name = op[op_mode][when]
1144                     if name in self.hooks[whe    1003                     if name in self.hooks[when][op_mode]['set']:
1145                         continue                 1004                         continue
1146                     self.hooks[when][op_mode]    1005                     self.hooks[when][op_mode]['set'].add(name)
1147                     self.hooks[when][op_mode]    1006                     self.hooks[when][op_mode]['list'].append(name)
1148                                                  1007 
1149                                                  1008 
1150 class RenderInfo:                                1009 class RenderInfo:
1151     def __init__(self, cw, family, ku_space,     1010     def __init__(self, cw, family, ku_space, op, op_mode, attr_set=None):
1152         self.family = family                     1011         self.family = family
1153         self.nl = cw.nlib                        1012         self.nl = cw.nlib
1154         self.ku_space = ku_space                 1013         self.ku_space = ku_space
1155         self.op_mode = op_mode                   1014         self.op_mode = op_mode
1156         self.op = op                             1015         self.op = op
1157                                                  1016 
1158         self.fixed_hdr = None                 << 
1159         if op and op.fixed_header:            << 
1160             self.fixed_hdr = 'struct ' + c_lo << 
1161                                               << 
1162         # 'do' and 'dump' response parsing is    1017         # 'do' and 'dump' response parsing is identical
1163         self.type_consistent = True              1018         self.type_consistent = True
1164         if op_mode != 'do' and 'dump' in op:  !! 1019         if op_mode != 'do' and 'dump' in op and 'do' in op:
1165             if 'do' in op:                    !! 1020             if ('reply' in op['do']) != ('reply' in op["dump"]):
1166                 if ('reply' in op['do']) != ( !! 1021                 self.type_consistent = False
1167                     self.type_consistent = Fa !! 1022             elif 'reply' in op['do'] and op["do"]["reply"] != op["dump"]["reply"]:
1168                 elif 'reply' in op['do'] and  << 
1169                     self.type_consistent = Fa << 
1170             else:                             << 
1171                 self.type_consistent = False     1023                 self.type_consistent = False
1172                                                  1024 
1173         self.attr_set = attr_set                 1025         self.attr_set = attr_set
1174         if not self.attr_set:                    1026         if not self.attr_set:
1175             self.attr_set = op['attribute-set    1027             self.attr_set = op['attribute-set']
1176                                                  1028 
1177         self.type_name_conflict = False          1029         self.type_name_conflict = False
1178         if op:                                   1030         if op:
1179             self.type_name = c_lower(op.name)    1031             self.type_name = c_lower(op.name)
1180         else:                                    1032         else:
1181             self.type_name = c_lower(attr_set    1033             self.type_name = c_lower(attr_set)
1182             if attr_set in family.consts:        1034             if attr_set in family.consts:
1183                 self.type_name_conflict = Tru    1035                 self.type_name_conflict = True
1184                                                  1036 
1185         self.cw = cw                             1037         self.cw = cw
1186                                                  1038 
1187         self.struct = dict()                     1039         self.struct = dict()
1188         if op_mode == 'notify':                  1040         if op_mode == 'notify':
1189             op_mode = 'do'                       1041             op_mode = 'do'
1190         for op_dir in ['request', 'reply']:      1042         for op_dir in ['request', 'reply']:
1191             if op:                            !! 1043             if op and op_dir in op[op_mode]:
1192                 type_list = []                !! 1044                 self.struct[op_dir] = Struct(family, self.attr_set,
1193                 if op_dir in op[op_mode]:     !! 1045                                              type_list=op[op_mode][op_dir]['attributes'])
1194                     type_list = op[op_mode][o << 
1195                 self.struct[op_dir] = Struct( << 
1196         if op_mode == 'event':                   1046         if op_mode == 'event':
1197             self.struct['reply'] = Struct(fam    1047             self.struct['reply'] = Struct(family, self.attr_set, type_list=op['event']['attributes'])
1198                                                  1048 
1199                                                  1049 
1200 class CodeWriter:                                1050 class CodeWriter:
1201     def __init__(self, nlib, out_file=None, o !! 1051     def __init__(self, nlib, out_file=None):
1202         self.nlib = nlib                         1052         self.nlib = nlib
1203         self._overwrite = overwrite           << 
1204                                                  1053 
1205         self._nl = False                         1054         self._nl = False
1206         self._block_end = False                  1055         self._block_end = False
1207         self._silent_block = False               1056         self._silent_block = False
1208         self._ind = 0                            1057         self._ind = 0
1209         self._ifdef_block = None              << 
1210         if out_file is None:                     1058         if out_file is None:
1211             self._out = os.sys.stdout            1059             self._out = os.sys.stdout
1212         else:                                    1060         else:
1213             self._out = tempfile.NamedTempora !! 1061             self._out = tempfile.TemporaryFile('w+')
1214             self._out_file = out_file            1062             self._out_file = out_file
1215                                                  1063 
1216     def __del__(self):                           1064     def __del__(self):
1217         self.close_out_file()                    1065         self.close_out_file()
1218                                                  1066 
1219     def close_out_file(self):                    1067     def close_out_file(self):
1220         if self._out == os.sys.stdout:           1068         if self._out == os.sys.stdout:
1221             return                               1069             return
1222         # Avoid modifying the file if content << 
1223         self._out.flush()                     << 
1224         if not self._overwrite and os.path.is << 
1225             if filecmp.cmp(self._out.name, se << 
1226                 return                        << 
1227         with open(self._out_file, 'w+') as ou    1070         with open(self._out_file, 'w+') as out_file:
1228             self._out.seek(0)                    1071             self._out.seek(0)
1229             shutil.copyfileobj(self._out, out    1072             shutil.copyfileobj(self._out, out_file)
1230             self._out.close()                    1073             self._out.close()
1231         self._out = os.sys.stdout                1074         self._out = os.sys.stdout
1232                                                  1075 
1233     @classmethod                                 1076     @classmethod
1234     def _is_cond(cls, line):                     1077     def _is_cond(cls, line):
1235         return line.startswith('if') or line.    1078         return line.startswith('if') or line.startswith('while') or line.startswith('for')
1236                                                  1079 
1237     def p(self, line, add_ind=0):                1080     def p(self, line, add_ind=0):
1238         if self._block_end:                      1081         if self._block_end:
1239             self._block_end = False              1082             self._block_end = False
1240             if line.startswith('else'):          1083             if line.startswith('else'):
1241                 line = '} ' + line               1084                 line = '} ' + line
1242             else:                                1085             else:
1243                 self._out.write('\t' * self._    1086                 self._out.write('\t' * self._ind + '}\n')
1244                                                  1087 
1245         if self._nl:                             1088         if self._nl:
1246             self._out.write('\n')                1089             self._out.write('\n')
1247             self._nl = False                     1090             self._nl = False
1248                                                  1091 
1249         ind = self._ind                          1092         ind = self._ind
1250         if line[-1] == ':':                      1093         if line[-1] == ':':
1251             ind -= 1                             1094             ind -= 1
1252         if self._silent_block:                   1095         if self._silent_block:
1253             ind += 1                             1096             ind += 1
1254         self._silent_block = line.endswith(')    1097         self._silent_block = line.endswith(')') and CodeWriter._is_cond(line)
1255         if line[0] == '#':                    << 
1256             ind = 0                           << 
1257         if add_ind:                              1098         if add_ind:
1258             ind += add_ind                       1099             ind += add_ind
1259         self._out.write('\t' * ind + line + '    1100         self._out.write('\t' * ind + line + '\n')
1260                                                  1101 
1261     def nl(self):                                1102     def nl(self):
1262         self._nl = True                          1103         self._nl = True
1263                                                  1104 
1264     def block_start(self, line=''):              1105     def block_start(self, line=''):
1265         if line:                                 1106         if line:
1266             line = line + ' '                    1107             line = line + ' '
1267         self.p(line + '{')                       1108         self.p(line + '{')
1268         self._ind += 1                           1109         self._ind += 1
1269                                                  1110 
1270     def block_end(self, line=''):                1111     def block_end(self, line=''):
1271         if line and line[0] not in {';', ','}    1112         if line and line[0] not in {';', ','}:
1272             line = ' ' + line                    1113             line = ' ' + line
1273         self._ind -= 1                           1114         self._ind -= 1
1274         self._nl = False                         1115         self._nl = False
1275         if not line:                             1116         if not line:
1276             # Delay printing closing bracket     1117             # Delay printing closing bracket in case "else" comes next
1277             if self._block_end:                  1118             if self._block_end:
1278                 self._out.write('\t' * (self.    1119                 self._out.write('\t' * (self._ind + 1) + '}\n')
1279             self._block_end = True               1120             self._block_end = True
1280         else:                                    1121         else:
1281             self.p('}' + line)                   1122             self.p('}' + line)
1282                                                  1123 
1283     def write_doc_line(self, doc, indent=True    1124     def write_doc_line(self, doc, indent=True):
1284         words = doc.split()                      1125         words = doc.split()
1285         line = ' *'                              1126         line = ' *'
1286         for word in words:                       1127         for word in words:
1287             if len(line) + len(word) >= 79:      1128             if len(line) + len(word) >= 79:
1288                 self.p(line)                     1129                 self.p(line)
1289                 line = ' *'                      1130                 line = ' *'
1290                 if indent:                       1131                 if indent:
1291                     line += '  '                 1132                     line += '  '
1292             line += ' ' + word                   1133             line += ' ' + word
1293         self.p(line)                             1134         self.p(line)
1294                                                  1135 
1295     def write_func_prot(self, qual_ret, name,    1136     def write_func_prot(self, qual_ret, name, args=None, doc=None, suffix=''):
1296         if not args:                             1137         if not args:
1297             args = ['void']                      1138             args = ['void']
1298                                                  1139 
1299         if doc:                                  1140         if doc:
1300             self.p('/*')                         1141             self.p('/*')
1301             self.p(' * ' + doc)                  1142             self.p(' * ' + doc)
1302             self.p(' */')                        1143             self.p(' */')
1303                                                  1144 
1304         oneline = qual_ret                       1145         oneline = qual_ret
1305         if qual_ret[-1] != '*':                  1146         if qual_ret[-1] != '*':
1306             oneline += ' '                       1147             oneline += ' '
1307         oneline += f"{name}({', '.join(args)}    1148         oneline += f"{name}({', '.join(args)}){suffix}"
1308                                                  1149 
1309         if len(oneline) < 80:                    1150         if len(oneline) < 80:
1310             self.p(oneline)                      1151             self.p(oneline)
1311             return                               1152             return
1312                                                  1153 
1313         v = qual_ret                             1154         v = qual_ret
1314         if len(v) > 3:                           1155         if len(v) > 3:
1315             self.p(v)                            1156             self.p(v)
1316             v = ''                               1157             v = ''
1317         elif qual_ret[-1] != '*':                1158         elif qual_ret[-1] != '*':
1318             v += ' '                             1159             v += ' '
1319         v += name + '('                          1160         v += name + '('
1320         ind = '\t' * (len(v) // 8) + ' ' * (l    1161         ind = '\t' * (len(v) // 8) + ' ' * (len(v) % 8)
1321         delta_ind = len(v) - len(ind)            1162         delta_ind = len(v) - len(ind)
1322         v += args[0]                             1163         v += args[0]
1323         i = 1                                    1164         i = 1
1324         while i < len(args):                     1165         while i < len(args):
1325             next_len = len(v) + len(args[i])     1166             next_len = len(v) + len(args[i])
1326             if v[0] == '\t':                     1167             if v[0] == '\t':
1327                 next_len += delta_ind            1168                 next_len += delta_ind
1328             if next_len > 76:                    1169             if next_len > 76:
1329                 self.p(v + ',')                  1170                 self.p(v + ',')
1330                 v = ind                          1171                 v = ind
1331             else:                                1172             else:
1332                 v += ', '                        1173                 v += ', '
1333             v += args[i]                         1174             v += args[i]
1334             i += 1                               1175             i += 1
1335         self.p(v + ')' + suffix)                 1176         self.p(v + ')' + suffix)
1336                                                  1177 
1337     def write_func_lvar(self, local_vars):       1178     def write_func_lvar(self, local_vars):
1338         if not local_vars:                       1179         if not local_vars:
1339             return                               1180             return
1340                                                  1181 
1341         if type(local_vars) is str:              1182         if type(local_vars) is str:
1342             local_vars = [local_vars]            1183             local_vars = [local_vars]
1343                                                  1184 
1344         local_vars.sort(key=len, reverse=True    1185         local_vars.sort(key=len, reverse=True)
1345         for var in local_vars:                   1186         for var in local_vars:
1346             self.p(var)                          1187             self.p(var)
1347         self.nl()                                1188         self.nl()
1348                                                  1189 
1349     def write_func(self, qual_ret, name, body    1190     def write_func(self, qual_ret, name, body, args=None, local_vars=None):
1350         self.write_func_prot(qual_ret=qual_re    1191         self.write_func_prot(qual_ret=qual_ret, name=name, args=args)
1351         self.write_func_lvar(local_vars=local    1192         self.write_func_lvar(local_vars=local_vars)
1352                                                  1193 
1353         self.block_start()                       1194         self.block_start()
1354         for line in body:                        1195         for line in body:
1355             self.p(line)                         1196             self.p(line)
1356         self.block_end()                         1197         self.block_end()
1357                                                  1198 
1358     def writes_defines(self, defines):           1199     def writes_defines(self, defines):
1359         longest = 0                              1200         longest = 0
1360         for define in defines:                   1201         for define in defines:
1361             if len(define[0]) > longest:         1202             if len(define[0]) > longest:
1362                 longest = len(define[0])         1203                 longest = len(define[0])
1363         longest = ((longest + 8) // 8) * 8       1204         longest = ((longest + 8) // 8) * 8
1364         for define in defines:                   1205         for define in defines:
1365             line = '#define ' + define[0]        1206             line = '#define ' + define[0]
1366             line += '\t' * ((longest - len(de    1207             line += '\t' * ((longest - len(define[0]) + 7) // 8)
1367             if type(define[1]) is int:           1208             if type(define[1]) is int:
1368                 line += str(define[1])           1209                 line += str(define[1])
1369             elif type(define[1]) is str:         1210             elif type(define[1]) is str:
1370                 line += '"' + define[1] + '"'    1211                 line += '"' + define[1] + '"'
1371             self.p(line)                         1212             self.p(line)
1372                                                  1213 
1373     def write_struct_init(self, members):        1214     def write_struct_init(self, members):
1374         longest = max([len(x[0]) for x in mem    1215         longest = max([len(x[0]) for x in members])
1375         longest += 1  # because we prepend a     1216         longest += 1  # because we prepend a .
1376         longest = ((longest + 8) // 8) * 8       1217         longest = ((longest + 8) // 8) * 8
1377         for one in members:                      1218         for one in members:
1378             line = '.' + one[0]                  1219             line = '.' + one[0]
1379             line += '\t' * ((longest - len(on    1220             line += '\t' * ((longest - len(one[0]) - 1 + 7) // 8)
1380             line += '= ' + str(one[1]) + ','  !! 1221             line += '= ' + one[1] + ','
1381             self.p(line)                         1222             self.p(line)
1382                                                  1223 
1383     def ifdef_block(self, config):            << 
1384         config_option = None                  << 
1385         if config:                            << 
1386             config_option = 'CONFIG_' + c_upp << 
1387         if self._ifdef_block == config_option << 
1388             return                            << 
1389                                               << 
1390         if self._ifdef_block:                 << 
1391             self.p('#endif /* ' + self._ifdef << 
1392         if config_option:                     << 
1393             self.p('#ifdef ' + config_option) << 
1394         self._ifdef_block = config_option     << 
1395                                               << 
1396                                                  1224 
1397 scalars = {'u8', 'u16', 'u32', 'u64', 's32',  !! 1225 scalars = {'u8', 'u16', 'u32', 'u64', 's32', 's64'}
1398                                                  1226 
1399 direction_to_suffix = {                          1227 direction_to_suffix = {
1400     'reply': '_rsp',                             1228     'reply': '_rsp',
1401     'request': '_req',                           1229     'request': '_req',
1402     '': ''                                       1230     '': ''
1403 }                                                1231 }
1404                                                  1232 
1405 op_mode_to_wrapper = {                           1233 op_mode_to_wrapper = {
1406     'do': '',                                    1234     'do': '',
1407     'dump': '_list',                             1235     'dump': '_list',
1408     'notify': '_ntf',                            1236     'notify': '_ntf',
1409     'event': '',                                 1237     'event': '',
1410 }                                                1238 }
1411                                                  1239 
1412 _C_KW = {                                        1240 _C_KW = {
1413     'auto',                                      1241     'auto',
1414     'bool',                                      1242     'bool',
1415     'break',                                     1243     'break',
1416     'case',                                      1244     'case',
1417     'char',                                      1245     'char',
1418     'const',                                     1246     'const',
1419     'continue',                                  1247     'continue',
1420     'default',                                   1248     'default',
1421     'do',                                        1249     'do',
1422     'double',                                    1250     'double',
1423     'else',                                      1251     'else',
1424     'enum',                                      1252     'enum',
1425     'extern',                                    1253     'extern',
1426     'float',                                     1254     'float',
1427     'for',                                       1255     'for',
1428     'goto',                                      1256     'goto',
1429     'if',                                        1257     'if',
1430     'inline',                                    1258     'inline',
1431     'int',                                       1259     'int',
1432     'long',                                      1260     'long',
1433     'register',                                  1261     'register',
1434     'return',                                    1262     'return',
1435     'short',                                     1263     'short',
1436     'signed',                                    1264     'signed',
1437     'sizeof',                                    1265     'sizeof',
1438     'static',                                    1266     'static',
1439     'struct',                                    1267     'struct',
1440     'switch',                                    1268     'switch',
1441     'typedef',                                   1269     'typedef',
1442     'union',                                     1270     'union',
1443     'unsigned',                                  1271     'unsigned',
1444     'void',                                      1272     'void',
1445     'volatile',                                  1273     'volatile',
1446     'while'                                      1274     'while'
1447 }                                                1275 }
1448                                                  1276 
1449                                                  1277 
1450 def rdir(direction):                             1278 def rdir(direction):
1451     if direction == 'reply':                     1279     if direction == 'reply':
1452         return 'request'                         1280         return 'request'
1453     if direction == 'request':                   1281     if direction == 'request':
1454         return 'reply'                           1282         return 'reply'
1455     return direction                             1283     return direction
1456                                                  1284 
1457                                                  1285 
1458 def op_prefix(ri, direction, deref=False):       1286 def op_prefix(ri, direction, deref=False):
1459     suffix = f"_{ri.type_name}"                  1287     suffix = f"_{ri.type_name}"
1460                                                  1288 
1461     if not ri.op_mode or ri.op_mode == 'do':     1289     if not ri.op_mode or ri.op_mode == 'do':
1462         suffix += f"{direction_to_suffix[dire    1290         suffix += f"{direction_to_suffix[direction]}"
1463     else:                                        1291     else:
1464         if direction == 'request':               1292         if direction == 'request':
1465             suffix += '_req_dump'                1293             suffix += '_req_dump'
1466         else:                                    1294         else:
1467             if ri.type_consistent:               1295             if ri.type_consistent:
1468                 if deref:                        1296                 if deref:
1469                     suffix += f"{direction_to    1297                     suffix += f"{direction_to_suffix[direction]}"
1470                 else:                            1298                 else:
1471                     suffix += op_mode_to_wrap    1299                     suffix += op_mode_to_wrapper[ri.op_mode]
1472             else:                                1300             else:
1473                 suffix += '_rsp'                 1301                 suffix += '_rsp'
1474                 suffix += '_dump' if deref el    1302                 suffix += '_dump' if deref else '_list'
1475                                                  1303 
1476     return f"{ri.family.c_name}{suffix}"      !! 1304     return f"{ri.family['name']}{suffix}"
1477                                                  1305 
1478                                                  1306 
1479 def type_name(ri, direction, deref=False):       1307 def type_name(ri, direction, deref=False):
1480     return f"struct {op_prefix(ri, direction,    1308     return f"struct {op_prefix(ri, direction, deref=deref)}"
1481                                                  1309 
1482                                                  1310 
1483 def print_prototype(ri, direction, terminate=    1311 def print_prototype(ri, direction, terminate=True, doc=None):
1484     suffix = ';' if terminate else ''            1312     suffix = ';' if terminate else ''
1485                                                  1313 
1486     fname = ri.op.render_name                    1314     fname = ri.op.render_name
1487     if ri.op_mode == 'dump':                     1315     if ri.op_mode == 'dump':
1488         fname += '_dump'                         1316         fname += '_dump'
1489                                                  1317 
1490     args = ['struct ynl_sock *ys']               1318     args = ['struct ynl_sock *ys']
1491     if 'request' in ri.op[ri.op_mode]:           1319     if 'request' in ri.op[ri.op_mode]:
1492         args.append(f"{type_name(ri, directio    1320         args.append(f"{type_name(ri, direction)} *" + f"{direction_to_suffix[direction][1:]}")
1493                                                  1321 
1494     ret = 'int'                                  1322     ret = 'int'
1495     if 'reply' in ri.op[ri.op_mode]:             1323     if 'reply' in ri.op[ri.op_mode]:
1496         ret = f"{type_name(ri, rdir(direction    1324         ret = f"{type_name(ri, rdir(direction))} *"
1497                                                  1325 
1498     ri.cw.write_func_prot(ret, fname, args, d    1326     ri.cw.write_func_prot(ret, fname, args, doc=doc, suffix=suffix)
1499                                                  1327 
1500                                                  1328 
1501 def print_req_prototype(ri):                     1329 def print_req_prototype(ri):
1502     print_prototype(ri, "request", doc=ri.op[    1330     print_prototype(ri, "request", doc=ri.op['doc'])
1503                                                  1331 
1504                                                  1332 
1505 def print_dump_prototype(ri):                    1333 def print_dump_prototype(ri):
1506     print_prototype(ri, "request")               1334     print_prototype(ri, "request")
1507                                                  1335 
1508                                                  1336 
1509 def put_typol_fwd(cw, struct):                << 
1510     cw.p(f'extern const struct ynl_policy_nes << 
1511                                               << 
1512                                               << 
1513 def put_typol(cw, struct):                       1337 def put_typol(cw, struct):
1514     type_max = struct.attr_set.max_name          1338     type_max = struct.attr_set.max_name
1515     cw.block_start(line=f'const struct ynl_po !! 1339     cw.block_start(line=f'struct ynl_policy_attr {struct.render_name}_policy[{type_max} + 1] =')
1516                                                  1340 
1517     for _, arg in struct.member_list():          1341     for _, arg in struct.member_list():
1518         arg.attr_typol(cw)                       1342         arg.attr_typol(cw)
1519                                                  1343 
1520     cw.block_end(line=';')                       1344     cw.block_end(line=';')
1521     cw.nl()                                      1345     cw.nl()
1522                                                  1346 
1523     cw.block_start(line=f'const struct ynl_po !! 1347     cw.block_start(line=f'struct ynl_policy_nest {struct.render_name}_nest =')
1524     cw.p(f'.max_attr = {type_max},')             1348     cw.p(f'.max_attr = {type_max},')
1525     cw.p(f'.table = {struct.render_name}_poli    1349     cw.p(f'.table = {struct.render_name}_policy,')
1526     cw.block_end(line=';')                       1350     cw.block_end(line=';')
1527     cw.nl()                                      1351     cw.nl()
1528                                                  1352 
1529                                                  1353 
1530 def _put_enum_to_str_helper(cw, render_name,     1354 def _put_enum_to_str_helper(cw, render_name, map_name, arg_name, enum=None):
1531     args = [f'int {arg_name}']                   1355     args = [f'int {arg_name}']
1532     if enum:                                  !! 1356     if enum and not ('enum-name' in enum and not enum['enum-name']):
1533         args = [enum.user_type + ' ' + arg_na !! 1357         args = [f'enum {render_name} {arg_name}']
1534     cw.write_func_prot('const char *', f'{ren    1358     cw.write_func_prot('const char *', f'{render_name}_str', args)
1535     cw.block_start()                             1359     cw.block_start()
1536     if enum and enum.type == 'flags':            1360     if enum and enum.type == 'flags':
1537         cw.p(f'{arg_name} = ffs({arg_name}) -    1361         cw.p(f'{arg_name} = ffs({arg_name}) - 1;')
1538     cw.p(f'if ({arg_name} < 0 || {arg_name} > !! 1362     cw.p(f'if ({arg_name} < 0 || {arg_name} >= (int)MNL_ARRAY_SIZE({map_name}))')
1539     cw.p('return NULL;')                         1363     cw.p('return NULL;')
1540     cw.p(f'return {map_name}[{arg_name}];')      1364     cw.p(f'return {map_name}[{arg_name}];')
1541     cw.block_end()                               1365     cw.block_end()
1542     cw.nl()                                      1366     cw.nl()
1543                                                  1367 
1544                                                  1368 
1545 def put_op_name_fwd(family, cw):                 1369 def put_op_name_fwd(family, cw):
1546     cw.write_func_prot('const char *', f'{fam !! 1370     cw.write_func_prot('const char *', f'{family.name}_op_str', ['int op'], suffix=';')
1547                                                  1371 
1548                                                  1372 
1549 def put_op_name(family, cw):                     1373 def put_op_name(family, cw):
1550     map_name = f'{family.c_name}_op_strmap'   !! 1374     map_name = f'{family.name}_op_strmap'
1551     cw.block_start(line=f"static const char *    1375     cw.block_start(line=f"static const char * const {map_name}[] =")
1552     for op_name, op in family.msgs.items():      1376     for op_name, op in family.msgs.items():
1553         if op.rsp_value:                         1377         if op.rsp_value:
1554             # Make sure we don't add duplicat << 
1555             # produce the same response in le << 
1556             if family.rsp_by_value[op.rsp_val << 
1557                 cw.p(f'// skip "{op_name}", d << 
1558                 continue                      << 
1559                                               << 
1560             if op.req_value == op.rsp_value:     1378             if op.req_value == op.rsp_value:
1561                 cw.p(f'[{op.enum_name}] = "{o    1379                 cw.p(f'[{op.enum_name}] = "{op_name}",')
1562             else:                                1380             else:
1563                 cw.p(f'[{op.rsp_value}] = "{o    1381                 cw.p(f'[{op.rsp_value}] = "{op_name}",')
1564     cw.block_end(line=';')                       1382     cw.block_end(line=';')
1565     cw.nl()                                      1383     cw.nl()
1566                                                  1384 
1567     _put_enum_to_str_helper(cw, family.c_name !! 1385     _put_enum_to_str_helper(cw, family.name + '_op', map_name, 'op')
1568                                                  1386 
1569                                                  1387 
1570 def put_enum_to_str_fwd(family, cw, enum):       1388 def put_enum_to_str_fwd(family, cw, enum):
1571     args = [enum.user_type + ' value']        !! 1389     args = [f'enum {enum.render_name} value']
                                                   >> 1390     if 'enum-name' in enum and not enum['enum-name']:
                                                   >> 1391         args = ['int value']
1572     cw.write_func_prot('const char *', f'{enu    1392     cw.write_func_prot('const char *', f'{enum.render_name}_str', args, suffix=';')
1573                                                  1393 
1574                                                  1394 
1575 def put_enum_to_str(family, cw, enum):           1395 def put_enum_to_str(family, cw, enum):
1576     map_name = f'{enum.render_name}_strmap'      1396     map_name = f'{enum.render_name}_strmap'
1577     cw.block_start(line=f"static const char *    1397     cw.block_start(line=f"static const char * const {map_name}[] =")
1578     for entry in enum.entries.values():          1398     for entry in enum.entries.values():
1579         cw.p(f'[{entry.value}] = "{entry.name    1399         cw.p(f'[{entry.value}] = "{entry.name}",')
1580     cw.block_end(line=';')                       1400     cw.block_end(line=';')
1581     cw.nl()                                      1401     cw.nl()
1582                                                  1402 
1583     _put_enum_to_str_helper(cw, enum.render_n    1403     _put_enum_to_str_helper(cw, enum.render_name, map_name, 'value', enum=enum)
1584                                                  1404 
1585                                                  1405 
1586 def put_req_nested_prototype(ri, struct, suff !! 1406 def put_req_nested(ri, struct):
1587     func_args = ['struct nlmsghdr *nlh',         1407     func_args = ['struct nlmsghdr *nlh',
1588                  'unsigned int attr_type',       1408                  'unsigned int attr_type',
1589                  f'{struct.ptr_name}obj']        1409                  f'{struct.ptr_name}obj']
1590                                                  1410 
1591     ri.cw.write_func_prot('int', f'{struct.re !! 1411     ri.cw.write_func_prot('int', f'{struct.render_name}_put', func_args)
1592                           suffix=suffix)      << 
1593                                               << 
1594                                               << 
1595 def put_req_nested(ri, struct):               << 
1596     put_req_nested_prototype(ri, struct, suff << 
1597     ri.cw.block_start()                          1412     ri.cw.block_start()
1598     ri.cw.write_func_lvar('struct nlattr *nes    1413     ri.cw.write_func_lvar('struct nlattr *nest;')
1599                                                  1414 
1600     ri.cw.p("nest = ynl_attr_nest_start(nlh,  !! 1415     ri.cw.p("nest = mnl_attr_nest_start(nlh, attr_type);")
1601                                                  1416 
1602     for _, arg in struct.member_list():          1417     for _, arg in struct.member_list():
1603         arg.attr_put(ri, "obj")                  1418         arg.attr_put(ri, "obj")
1604                                                  1419 
1605     ri.cw.p("ynl_attr_nest_end(nlh, nest);")  !! 1420     ri.cw.p("mnl_attr_nest_end(nlh, nest);")
1606                                                  1421 
1607     ri.cw.nl()                                   1422     ri.cw.nl()
1608     ri.cw.p('return 0;')                         1423     ri.cw.p('return 0;')
1609     ri.cw.block_end()                            1424     ri.cw.block_end()
1610     ri.cw.nl()                                   1425     ri.cw.nl()
1611                                                  1426 
1612                                                  1427 
1613 def _multi_parse(ri, struct, init_lines, loca    1428 def _multi_parse(ri, struct, init_lines, local_vars):
1614     if struct.nested:                            1429     if struct.nested:
1615         iter_line = "ynl_attr_for_each_nested !! 1430         iter_line = "mnl_attr_for_each_nested(attr, nested)"
1616     else:                                        1431     else:
1617         if ri.fixed_hdr:                      !! 1432         iter_line = "mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr))"
1618             local_vars += ['void *hdr;']      << 
1619         iter_line = "ynl_attr_for_each(attr,  << 
1620                                                  1433 
1621     array_nests = set()                          1434     array_nests = set()
1622     multi_attrs = set()                          1435     multi_attrs = set()
1623     needs_parg = False                           1436     needs_parg = False
1624     for arg, aspec in struct.member_list():      1437     for arg, aspec in struct.member_list():
1625         if aspec['type'] == 'indexed-array' a !! 1438         if aspec['type'] == 'array-nest':
1626             if aspec["sub-type"] == 'nest':   !! 1439             local_vars.append(f'const struct nlattr *attr_{aspec.c_name};')
1627                 local_vars.append(f'const str !! 1440             array_nests.add(arg)
1628                 array_nests.add(arg)          << 
1629             else:                             << 
1630                 raise Exception(f'Not support << 
1631         if 'multi-attr' in aspec:                1441         if 'multi-attr' in aspec:
1632             multi_attrs.add(arg)                 1442             multi_attrs.add(arg)
1633         needs_parg |= 'nested-attributes' in     1443         needs_parg |= 'nested-attributes' in aspec
1634     if array_nests or multi_attrs:               1444     if array_nests or multi_attrs:
1635         local_vars.append('int i;')              1445         local_vars.append('int i;')
1636     if needs_parg:                               1446     if needs_parg:
1637         local_vars.append('struct ynl_parse_a    1447         local_vars.append('struct ynl_parse_arg parg;')
1638         init_lines.append('parg.ys = yarg->ys    1448         init_lines.append('parg.ys = yarg->ys;')
1639                                                  1449 
1640     all_multi = array_nests | multi_attrs        1450     all_multi = array_nests | multi_attrs
1641                                                  1451 
1642     for anest in sorted(all_multi):              1452     for anest in sorted(all_multi):
1643         local_vars.append(f"unsigned int n_{s    1453         local_vars.append(f"unsigned int n_{struct[anest].c_name} = 0;")
1644                                                  1454 
1645     ri.cw.block_start()                          1455     ri.cw.block_start()
1646     ri.cw.write_func_lvar(local_vars)            1456     ri.cw.write_func_lvar(local_vars)
1647                                                  1457 
1648     for line in init_lines:                      1458     for line in init_lines:
1649         ri.cw.p(line)                            1459         ri.cw.p(line)
1650     ri.cw.nl()                                   1460     ri.cw.nl()
1651                                                  1461 
1652     for arg in struct.inherited:                 1462     for arg in struct.inherited:
1653         ri.cw.p(f'dst->{arg} = {arg};')          1463         ri.cw.p(f'dst->{arg} = {arg};')
1654                                                  1464 
1655     if ri.fixed_hdr:                          << 
1656         ri.cw.p('hdr = ynl_nlmsg_data_offset( << 
1657         ri.cw.p(f"memcpy(&dst->_hdr, hdr, siz << 
1658     for anest in sorted(all_multi):              1465     for anest in sorted(all_multi):
1659         aspec = struct[anest]                    1466         aspec = struct[anest]
1660         ri.cw.p(f"if (dst->{aspec.c_name})")     1467         ri.cw.p(f"if (dst->{aspec.c_name})")
1661         ri.cw.p(f'return ynl_error_parse(yarg    1468         ri.cw.p(f'return ynl_error_parse(yarg, "attribute already present ({struct.attr_set.name}.{aspec.name})");')
1662                                                  1469 
1663     ri.cw.nl()                                   1470     ri.cw.nl()
1664     ri.cw.block_start(line=iter_line)            1471     ri.cw.block_start(line=iter_line)
1665     ri.cw.p('unsigned int type = ynl_attr_typ !! 1472     ri.cw.p('unsigned int type = mnl_attr_get_type(attr);')
1666     ri.cw.nl()                                   1473     ri.cw.nl()
1667                                                  1474 
1668     first = True                                 1475     first = True
1669     for _, arg in struct.member_list():          1476     for _, arg in struct.member_list():
1670         good = arg.attr_get(ri, 'dst', first=    1477         good = arg.attr_get(ri, 'dst', first=first)
1671         # First may be 'unused' or 'pad', ign    1478         # First may be 'unused' or 'pad', ignore those
1672         first &= not good                        1479         first &= not good
1673                                                  1480 
1674     ri.cw.block_end()                            1481     ri.cw.block_end()
1675     ri.cw.nl()                                   1482     ri.cw.nl()
1676                                                  1483 
1677     for anest in sorted(array_nests):            1484     for anest in sorted(array_nests):
1678         aspec = struct[anest]                    1485         aspec = struct[anest]
1679                                                  1486 
1680         ri.cw.block_start(line=f"if (n_{aspec    1487         ri.cw.block_start(line=f"if (n_{aspec.c_name})")
1681         ri.cw.p(f"dst->{aspec.c_name} = callo !! 1488         ri.cw.p(f"dst->{aspec.c_name} = calloc({aspec.c_name}, sizeof(*dst->{aspec.c_name}));")
1682         ri.cw.p(f"dst->n_{aspec.c_name} = n_{    1489         ri.cw.p(f"dst->n_{aspec.c_name} = n_{aspec.c_name};")
1683         ri.cw.p('i = 0;')                        1490         ri.cw.p('i = 0;')
1684         ri.cw.p(f"parg.rsp_policy = &{aspec.n    1491         ri.cw.p(f"parg.rsp_policy = &{aspec.nested_render_name}_nest;")
1685         ri.cw.block_start(line=f"ynl_attr_for !! 1492         ri.cw.block_start(line=f"mnl_attr_for_each_nested(attr, attr_{aspec.c_name})")
1686         ri.cw.p(f"parg.data = &dst->{aspec.c_    1493         ri.cw.p(f"parg.data = &dst->{aspec.c_name}[i];")
1687         ri.cw.p(f"if ({aspec.nested_render_na !! 1494         ri.cw.p(f"if ({aspec.nested_render_name}_parse(&parg, attr, mnl_attr_get_type(attr)))")
1688         ri.cw.p('return YNL_PARSE_CB_ERROR;') !! 1495         ri.cw.p('return MNL_CB_ERROR;')
1689         ri.cw.p('i++;')                          1496         ri.cw.p('i++;')
1690         ri.cw.block_end()                        1497         ri.cw.block_end()
1691         ri.cw.block_end()                        1498         ri.cw.block_end()
1692     ri.cw.nl()                                   1499     ri.cw.nl()
1693                                                  1500 
1694     for anest in sorted(multi_attrs):            1501     for anest in sorted(multi_attrs):
1695         aspec = struct[anest]                    1502         aspec = struct[anest]
1696         ri.cw.block_start(line=f"if (n_{aspec    1503         ri.cw.block_start(line=f"if (n_{aspec.c_name})")
1697         ri.cw.p(f"dst->{aspec.c_name} = callo    1504         ri.cw.p(f"dst->{aspec.c_name} = calloc(n_{aspec.c_name}, sizeof(*dst->{aspec.c_name}));")
1698         ri.cw.p(f"dst->n_{aspec.c_name} = n_{    1505         ri.cw.p(f"dst->n_{aspec.c_name} = n_{aspec.c_name};")
1699         ri.cw.p('i = 0;')                        1506         ri.cw.p('i = 0;')
1700         if 'nested-attributes' in aspec:         1507         if 'nested-attributes' in aspec:
1701             ri.cw.p(f"parg.rsp_policy = &{asp    1508             ri.cw.p(f"parg.rsp_policy = &{aspec.nested_render_name}_nest;")
1702         ri.cw.block_start(line=iter_line)        1509         ri.cw.block_start(line=iter_line)
1703         ri.cw.block_start(line=f"if (ynl_attr !! 1510         ri.cw.block_start(line=f"if (mnl_attr_get_type(attr) == {aspec.enum_name})")
1704         if 'nested-attributes' in aspec:         1511         if 'nested-attributes' in aspec:
1705             ri.cw.p(f"parg.data = &dst->{aspe    1512             ri.cw.p(f"parg.data = &dst->{aspec.c_name}[i];")
1706             ri.cw.p(f"if ({aspec.nested_rende    1513             ri.cw.p(f"if ({aspec.nested_render_name}_parse(&parg, attr))")
1707             ri.cw.p('return YNL_PARSE_CB_ERRO !! 1514             ri.cw.p('return MNL_CB_ERROR;')
1708         elif aspec.type in scalars:           !! 1515         elif aspec['type'] in scalars:
1709             ri.cw.p(f"dst->{aspec.c_name}[i]  !! 1516             t = aspec['type']
                                                   >> 1517             if t[0] == 's':
                                                   >> 1518                 t = 'u' + t[1:]
                                                   >> 1519             ri.cw.p(f"dst->{aspec.c_name}[i] = mnl_attr_get_{t}(attr);")
1710         else:                                    1520         else:
1711             raise Exception('Nest parsing typ    1521             raise Exception('Nest parsing type not supported yet')
1712         ri.cw.p('i++;')                          1522         ri.cw.p('i++;')
1713         ri.cw.block_end()                        1523         ri.cw.block_end()
1714         ri.cw.block_end()                        1524         ri.cw.block_end()
1715         ri.cw.block_end()                        1525         ri.cw.block_end()
1716     ri.cw.nl()                                   1526     ri.cw.nl()
1717                                                  1527 
1718     if struct.nested:                            1528     if struct.nested:
1719         ri.cw.p('return 0;')                     1529         ri.cw.p('return 0;')
1720     else:                                        1530     else:
1721         ri.cw.p('return YNL_PARSE_CB_OK;')    !! 1531         ri.cw.p('return MNL_CB_OK;')
1722     ri.cw.block_end()                            1532     ri.cw.block_end()
1723     ri.cw.nl()                                   1533     ri.cw.nl()
1724                                                  1534 
1725                                                  1535 
1726 def parse_rsp_nested_prototype(ri, struct, su !! 1536 def parse_rsp_nested(ri, struct):
1727     func_args = ['struct ynl_parse_arg *yarg'    1537     func_args = ['struct ynl_parse_arg *yarg',
1728                  'const struct nlattr *nested    1538                  'const struct nlattr *nested']
1729     for arg in struct.inherited:                 1539     for arg in struct.inherited:
1730         func_args.append('__u32 ' + arg)         1540         func_args.append('__u32 ' + arg)
1731                                                  1541 
1732     ri.cw.write_func_prot('int', f'{struct.re << 
1733                           suffix=suffix)      << 
1734                                               << 
1735                                               << 
1736 def parse_rsp_nested(ri, struct):             << 
1737     parse_rsp_nested_prototype(ri, struct, su << 
1738                                               << 
1739     local_vars = ['const struct nlattr *attr;    1542     local_vars = ['const struct nlattr *attr;',
1740                   f'{struct.ptr_name}dst = ya    1543                   f'{struct.ptr_name}dst = yarg->data;']
1741     init_lines = []                              1544     init_lines = []
1742                                                  1545 
                                                   >> 1546     ri.cw.write_func_prot('int', f'{struct.render_name}_parse', func_args)
                                                   >> 1547 
1743     _multi_parse(ri, struct, init_lines, loca    1548     _multi_parse(ri, struct, init_lines, local_vars)
1744                                                  1549 
1745                                                  1550 
1746 def parse_rsp_msg(ri, deref=False):              1551 def parse_rsp_msg(ri, deref=False):
1747     if 'reply' not in ri.op[ri.op_mode] and r    1552     if 'reply' not in ri.op[ri.op_mode] and ri.op_mode != 'event':
1748         return                                   1553         return
1749                                                  1554 
1750     func_args = ['const struct nlmsghdr *nlh'    1555     func_args = ['const struct nlmsghdr *nlh',
1751                  'struct ynl_parse_arg *yarg' !! 1556                  'void *data']
1752                                                  1557 
1753     local_vars = [f'{type_name(ri, "reply", d    1558     local_vars = [f'{type_name(ri, "reply", deref=deref)} *dst;',
                                                   >> 1559                   'struct ynl_parse_arg *yarg = data;',
1754                   'const struct nlattr *attr;    1560                   'const struct nlattr *attr;']
1755     init_lines = ['dst = yarg->data;']           1561     init_lines = ['dst = yarg->data;']
1756                                                  1562 
1757     ri.cw.write_func_prot('int', f'{op_prefix    1563     ri.cw.write_func_prot('int', f'{op_prefix(ri, "reply", deref=deref)}_parse', func_args)
1758                                                  1564 
1759     if ri.struct["reply"].member_list():         1565     if ri.struct["reply"].member_list():
1760         _multi_parse(ri, ri.struct["reply"],     1566         _multi_parse(ri, ri.struct["reply"], init_lines, local_vars)
1761     else:                                        1567     else:
1762         # Empty reply                            1568         # Empty reply
1763         ri.cw.block_start()                      1569         ri.cw.block_start()
1764         ri.cw.p('return YNL_PARSE_CB_OK;')    !! 1570         ri.cw.p('return MNL_CB_OK;')
1765         ri.cw.block_end()                        1571         ri.cw.block_end()
1766         ri.cw.nl()                               1572         ri.cw.nl()
1767                                                  1573 
1768                                                  1574 
1769 def print_req(ri):                               1575 def print_req(ri):
1770     ret_ok = '0'                                 1576     ret_ok = '0'
1771     ret_err = '-1'                               1577     ret_err = '-1'
1772     direction = "request"                        1578     direction = "request"
1773     local_vars = ['struct ynl_req_state yrs = !! 1579     local_vars = ['struct nlmsghdr *nlh;',
1774                   'struct nlmsghdr *nlh;',    << 
1775                   'int err;']                    1580                   'int err;']
1776                                                  1581 
1777     if 'reply' in ri.op[ri.op_mode]:             1582     if 'reply' in ri.op[ri.op_mode]:
1778         ret_ok = 'rsp'                           1583         ret_ok = 'rsp'
1779         ret_err = 'NULL'                         1584         ret_err = 'NULL'
1780         local_vars += [f'{type_name(ri, rdir( !! 1585         local_vars += [f'{type_name(ri, rdir(direction))} *rsp;',
1781                                               !! 1586                        'struct ynl_req_state yrs = { .yarg = { .ys = ys, }, };']
1782     if ri.fixed_hdr:                          << 
1783         local_vars += ['size_t hdr_len;',     << 
1784                        'void *hdr;']          << 
1785                                                  1587 
1786     print_prototype(ri, direction, terminate=    1588     print_prototype(ri, direction, terminate=False)
1787     ri.cw.block_start()                          1589     ri.cw.block_start()
1788     ri.cw.write_func_lvar(local_vars)            1590     ri.cw.write_func_lvar(local_vars)
1789                                                  1591 
1790     ri.cw.p(f"nlh = ynl_gemsg_start_req(ys, {    1592     ri.cw.p(f"nlh = ynl_gemsg_start_req(ys, {ri.nl.get_family_id()}, {ri.op.enum_name}, 1);")
1791                                                  1593 
1792     ri.cw.p(f"ys->req_policy = &{ri.struct['r    1594     ri.cw.p(f"ys->req_policy = &{ri.struct['request'].render_name}_nest;")
1793     if 'reply' in ri.op[ri.op_mode]:             1595     if 'reply' in ri.op[ri.op_mode]:
1794         ri.cw.p(f"yrs.yarg.rsp_policy = &{ri.    1596         ri.cw.p(f"yrs.yarg.rsp_policy = &{ri.struct['reply'].render_name}_nest;")
1795     ri.cw.nl()                                   1597     ri.cw.nl()
1796                                               << 
1797     if ri.fixed_hdr:                          << 
1798         ri.cw.p("hdr_len = sizeof(req->_hdr); << 
1799         ri.cw.p("hdr = ynl_nlmsg_put_extra_he << 
1800         ri.cw.p("memcpy(hdr, &req->_hdr, hdr_ << 
1801         ri.cw.nl()                            << 
1802                                               << 
1803     for _, attr in ri.struct["request"].membe    1598     for _, attr in ri.struct["request"].member_list():
1804         attr.attr_put(ri, "req")                 1599         attr.attr_put(ri, "req")
1805     ri.cw.nl()                                   1600     ri.cw.nl()
1806                                                  1601 
                                                   >> 1602     parse_arg = "NULL"
1807     if 'reply' in ri.op[ri.op_mode]:             1603     if 'reply' in ri.op[ri.op_mode]:
1808         ri.cw.p('rsp = calloc(1, sizeof(*rsp)    1604         ri.cw.p('rsp = calloc(1, sizeof(*rsp));')
1809         ri.cw.p('yrs.yarg.data = rsp;')          1605         ri.cw.p('yrs.yarg.data = rsp;')
1810         ri.cw.p(f"yrs.cb = {op_prefix(ri, 're    1606         ri.cw.p(f"yrs.cb = {op_prefix(ri, 'reply')}_parse;")
1811         if ri.op.value is not None:              1607         if ri.op.value is not None:
1812             ri.cw.p(f'yrs.rsp_cmd = {ri.op.en    1608             ri.cw.p(f'yrs.rsp_cmd = {ri.op.enum_name};')
1813         else:                                    1609         else:
1814             ri.cw.p(f'yrs.rsp_cmd = {ri.op.rs    1610             ri.cw.p(f'yrs.rsp_cmd = {ri.op.rsp_value};')
1815         ri.cw.nl()                               1611         ri.cw.nl()
1816     ri.cw.p("err = ynl_exec(ys, nlh, &yrs);") !! 1612         parse_arg = '&yrs'
                                                   >> 1613     ri.cw.p(f"err = ynl_exec(ys, nlh, {parse_arg});")
1817     ri.cw.p('if (err < 0)')                      1614     ri.cw.p('if (err < 0)')
1818     if 'reply' in ri.op[ri.op_mode]:             1615     if 'reply' in ri.op[ri.op_mode]:
1819         ri.cw.p('goto err_free;')                1616         ri.cw.p('goto err_free;')
1820     else:                                        1617     else:
1821         ri.cw.p('return -1;')                    1618         ri.cw.p('return -1;')
1822     ri.cw.nl()                                   1619     ri.cw.nl()
1823                                                  1620 
1824     ri.cw.p(f"return {ret_ok};")                 1621     ri.cw.p(f"return {ret_ok};")
1825     ri.cw.nl()                                   1622     ri.cw.nl()
1826                                                  1623 
1827     if 'reply' in ri.op[ri.op_mode]:             1624     if 'reply' in ri.op[ri.op_mode]:
1828         ri.cw.p('err_free:')                     1625         ri.cw.p('err_free:')
1829         ri.cw.p(f"{call_free(ri, rdir(directi    1626         ri.cw.p(f"{call_free(ri, rdir(direction), 'rsp')}")
1830         ri.cw.p(f"return {ret_err};")            1627         ri.cw.p(f"return {ret_err};")
1831                                                  1628 
1832     ri.cw.block_end()                            1629     ri.cw.block_end()
1833                                                  1630 
1834                                                  1631 
1835 def print_dump(ri):                              1632 def print_dump(ri):
1836     direction = "request"                        1633     direction = "request"
1837     print_prototype(ri, direction, terminate=    1634     print_prototype(ri, direction, terminate=False)
1838     ri.cw.block_start()                          1635     ri.cw.block_start()
1839     local_vars = ['struct ynl_dump_state yds     1636     local_vars = ['struct ynl_dump_state yds = {};',
1840                   'struct nlmsghdr *nlh;',       1637                   'struct nlmsghdr *nlh;',
1841                   'int err;']                    1638                   'int err;']
1842                                                  1639 
1843     if ri.fixed_hdr:                          !! 1640     for var in local_vars:
1844         local_vars += ['size_t hdr_len;',     !! 1641         ri.cw.p(f'{var}')
1845                        'void *hdr;']          !! 1642     ri.cw.nl()
1846                                               << 
1847     ri.cw.write_func_lvar(local_vars)         << 
1848                                                  1643 
1849     ri.cw.p('yds.yarg.ys = ys;')              !! 1644     ri.cw.p('yds.ys = ys;')
1850     ri.cw.p(f"yds.yarg.rsp_policy = &{ri.stru << 
1851     ri.cw.p("yds.yarg.data = NULL;")          << 
1852     ri.cw.p(f"yds.alloc_sz = sizeof({type_nam    1645     ri.cw.p(f"yds.alloc_sz = sizeof({type_name(ri, rdir(direction))});")
1853     ri.cw.p(f"yds.cb = {op_prefix(ri, 'reply'    1646     ri.cw.p(f"yds.cb = {op_prefix(ri, 'reply', deref=True)}_parse;")
1854     if ri.op.value is not None:                  1647     if ri.op.value is not None:
1855         ri.cw.p(f'yds.rsp_cmd = {ri.op.enum_n    1648         ri.cw.p(f'yds.rsp_cmd = {ri.op.enum_name};')
1856     else:                                        1649     else:
1857         ri.cw.p(f'yds.rsp_cmd = {ri.op.rsp_va    1650         ri.cw.p(f'yds.rsp_cmd = {ri.op.rsp_value};')
                                                   >> 1651     ri.cw.p(f"yds.rsp_policy = &{ri.struct['reply'].render_name}_nest;")
1858     ri.cw.nl()                                   1652     ri.cw.nl()
1859     ri.cw.p(f"nlh = ynl_gemsg_start_dump(ys,     1653     ri.cw.p(f"nlh = ynl_gemsg_start_dump(ys, {ri.nl.get_family_id()}, {ri.op.enum_name}, 1);")
1860                                                  1654 
1861     if ri.fixed_hdr:                          << 
1862         ri.cw.p("hdr_len = sizeof(req->_hdr); << 
1863         ri.cw.p("hdr = ynl_nlmsg_put_extra_he << 
1864         ri.cw.p("memcpy(hdr, &req->_hdr, hdr_ << 
1865         ri.cw.nl()                            << 
1866                                               << 
1867     if "request" in ri.op[ri.op_mode]:           1655     if "request" in ri.op[ri.op_mode]:
1868         ri.cw.p(f"ys->req_policy = &{ri.struc    1656         ri.cw.p(f"ys->req_policy = &{ri.struct['request'].render_name}_nest;")
1869         ri.cw.nl()                               1657         ri.cw.nl()
1870         for _, attr in ri.struct["request"].m    1658         for _, attr in ri.struct["request"].member_list():
1871             attr.attr_put(ri, "req")             1659             attr.attr_put(ri, "req")
1872     ri.cw.nl()                                   1660     ri.cw.nl()
1873                                                  1661 
1874     ri.cw.p('err = ynl_exec_dump(ys, nlh, &yd    1662     ri.cw.p('err = ynl_exec_dump(ys, nlh, &yds);')
1875     ri.cw.p('if (err < 0)')                      1663     ri.cw.p('if (err < 0)')
1876     ri.cw.p('goto free_list;')                   1664     ri.cw.p('goto free_list;')
1877     ri.cw.nl()                                   1665     ri.cw.nl()
1878                                                  1666 
1879     ri.cw.p('return yds.first;')                 1667     ri.cw.p('return yds.first;')
1880     ri.cw.nl()                                   1668     ri.cw.nl()
1881     ri.cw.p('free_list:')                        1669     ri.cw.p('free_list:')
1882     ri.cw.p(call_free(ri, rdir(direction), 'y    1670     ri.cw.p(call_free(ri, rdir(direction), 'yds.first'))
1883     ri.cw.p('return NULL;')                      1671     ri.cw.p('return NULL;')
1884     ri.cw.block_end()                            1672     ri.cw.block_end()
1885                                                  1673 
1886                                                  1674 
1887 def call_free(ri, direction, var):               1675 def call_free(ri, direction, var):
1888     return f"{op_prefix(ri, direction)}_free(    1676     return f"{op_prefix(ri, direction)}_free({var});"
1889                                                  1677 
1890                                                  1678 
1891 def free_arg_name(direction):                    1679 def free_arg_name(direction):
1892     if direction:                                1680     if direction:
1893         return direction_to_suffix[direction]    1681         return direction_to_suffix[direction][1:]
1894     return 'obj'                                 1682     return 'obj'
1895                                                  1683 
1896                                                  1684 
1897 def print_alloc_wrapper(ri, direction):          1685 def print_alloc_wrapper(ri, direction):
1898     name = op_prefix(ri, direction)              1686     name = op_prefix(ri, direction)
1899     ri.cw.write_func_prot(f'static inline str    1687     ri.cw.write_func_prot(f'static inline struct {name} *', f"{name}_alloc", [f"void"])
1900     ri.cw.block_start()                          1688     ri.cw.block_start()
1901     ri.cw.p(f'return calloc(1, sizeof(struct     1689     ri.cw.p(f'return calloc(1, sizeof(struct {name}));')
1902     ri.cw.block_end()                            1690     ri.cw.block_end()
1903                                                  1691 
1904                                                  1692 
1905 def print_free_prototype(ri, direction, suffi    1693 def print_free_prototype(ri, direction, suffix=';'):
1906     name = op_prefix(ri, direction)              1694     name = op_prefix(ri, direction)
1907     struct_name = name                           1695     struct_name = name
1908     if ri.type_name_conflict:                    1696     if ri.type_name_conflict:
1909         struct_name += '_'                       1697         struct_name += '_'
1910     arg = free_arg_name(direction)               1698     arg = free_arg_name(direction)
1911     ri.cw.write_func_prot('void', f"{name}_fr    1699     ri.cw.write_func_prot('void', f"{name}_free", [f"struct {struct_name} *{arg}"], suffix=suffix)
1912                                                  1700 
1913                                                  1701 
1914 def _print_type(ri, direction, struct):          1702 def _print_type(ri, direction, struct):
1915     suffix = f'_{ri.type_name}{direction_to_s    1703     suffix = f'_{ri.type_name}{direction_to_suffix[direction]}'
1916     if not direction and ri.type_name_conflic    1704     if not direction and ri.type_name_conflict:
1917         suffix += '_'                            1705         suffix += '_'
1918                                                  1706 
1919     if ri.op_mode == 'dump':                     1707     if ri.op_mode == 'dump':
1920         suffix += '_dump'                        1708         suffix += '_dump'
1921                                                  1709 
1922     ri.cw.block_start(line=f"struct {ri.famil !! 1710     ri.cw.block_start(line=f"struct {ri.family['name']}{suffix}")
1923                                               << 
1924     if ri.fixed_hdr:                          << 
1925         ri.cw.p(ri.fixed_hdr + ' _hdr;')      << 
1926         ri.cw.nl()                            << 
1927                                                  1711 
1928     meta_started = False                         1712     meta_started = False
1929     for _, attr in struct.member_list():         1713     for _, attr in struct.member_list():
1930         for type_filter in ['len', 'bit']:       1714         for type_filter in ['len', 'bit']:
1931             line = attr.presence_member(ri.ku    1715             line = attr.presence_member(ri.ku_space, type_filter)
1932             if line:                             1716             if line:
1933                 if not meta_started:             1717                 if not meta_started:
1934                     ri.cw.block_start(line=f"    1718                     ri.cw.block_start(line=f"struct")
1935                     meta_started = True          1719                     meta_started = True
1936                 ri.cw.p(line)                    1720                 ri.cw.p(line)
1937     if meta_started:                             1721     if meta_started:
1938         ri.cw.block_end(line='_present;')        1722         ri.cw.block_end(line='_present;')
1939         ri.cw.nl()                               1723         ri.cw.nl()
1940                                                  1724 
1941     for arg in struct.inherited:                 1725     for arg in struct.inherited:
1942         ri.cw.p(f"__u32 {arg};")                 1726         ri.cw.p(f"__u32 {arg};")
1943                                                  1727 
1944     for _, attr in struct.member_list():         1728     for _, attr in struct.member_list():
1945         attr.struct_member(ri)                   1729         attr.struct_member(ri)
1946                                                  1730 
1947     ri.cw.block_end(line=';')                    1731     ri.cw.block_end(line=';')
1948     ri.cw.nl()                                   1732     ri.cw.nl()
1949                                                  1733 
1950                                                  1734 
1951 def print_type(ri, direction):                   1735 def print_type(ri, direction):
1952     _print_type(ri, direction, ri.struct[dire    1736     _print_type(ri, direction, ri.struct[direction])
1953                                                  1737 
1954                                                  1738 
1955 def print_type_full(ri, struct):                 1739 def print_type_full(ri, struct):
1956     _print_type(ri, "", struct)                  1740     _print_type(ri, "", struct)
1957                                                  1741 
1958                                                  1742 
1959 def print_type_helpers(ri, direction, deref=F    1743 def print_type_helpers(ri, direction, deref=False):
1960     print_free_prototype(ri, direction)          1744     print_free_prototype(ri, direction)
1961     ri.cw.nl()                                   1745     ri.cw.nl()
1962                                                  1746 
1963     if ri.ku_space == 'user' and direction ==    1747     if ri.ku_space == 'user' and direction == 'request':
1964         for _, attr in ri.struct[direction].m    1748         for _, attr in ri.struct[direction].member_list():
1965             attr.setter(ri, ri.attr_set, dire    1749             attr.setter(ri, ri.attr_set, direction, deref=deref)
1966     ri.cw.nl()                                   1750     ri.cw.nl()
1967                                                  1751 
1968                                                  1752 
1969 def print_req_type_helpers(ri):                  1753 def print_req_type_helpers(ri):
1970     if len(ri.struct["request"].attr_list) == << 
1971         return                                << 
1972     print_alloc_wrapper(ri, "request")           1754     print_alloc_wrapper(ri, "request")
1973     print_type_helpers(ri, "request")            1755     print_type_helpers(ri, "request")
1974                                                  1756 
1975                                                  1757 
1976 def print_rsp_type_helpers(ri):                  1758 def print_rsp_type_helpers(ri):
1977     if 'reply' not in ri.op[ri.op_mode]:         1759     if 'reply' not in ri.op[ri.op_mode]:
1978         return                                   1760         return
1979     print_type_helpers(ri, "reply")              1761     print_type_helpers(ri, "reply")
1980                                                  1762 
1981                                                  1763 
1982 def print_parse_prototype(ri, direction, term    1764 def print_parse_prototype(ri, direction, terminate=True):
1983     suffix = "_rsp" if direction == "reply" e    1765     suffix = "_rsp" if direction == "reply" else "_req"
1984     term = ';' if terminate else ''              1766     term = ';' if terminate else ''
1985                                                  1767 
1986     ri.cw.write_func_prot('void', f"{ri.op.re    1768     ri.cw.write_func_prot('void', f"{ri.op.render_name}{suffix}_parse",
1987                           ['const struct nlat    1769                           ['const struct nlattr **tb',
1988                            f"struct {ri.op.re    1770                            f"struct {ri.op.render_name}{suffix} *req"],
1989                           suffix=term)           1771                           suffix=term)
1990                                                  1772 
1991                                                  1773 
1992 def print_req_type(ri):                          1774 def print_req_type(ri):
1993     if len(ri.struct["request"].attr_list) == << 
1994         return                                << 
1995     print_type(ri, "request")                    1775     print_type(ri, "request")
1996                                                  1776 
1997                                                  1777 
1998 def print_req_free(ri):                          1778 def print_req_free(ri):
1999     if 'request' not in ri.op[ri.op_mode]:       1779     if 'request' not in ri.op[ri.op_mode]:
2000         return                                   1780         return
2001     _free_type(ri, 'request', ri.struct['requ    1781     _free_type(ri, 'request', ri.struct['request'])
2002                                                  1782 
2003                                                  1783 
2004 def print_rsp_type(ri):                          1784 def print_rsp_type(ri):
2005     if (ri.op_mode == 'do' or ri.op_mode == '    1785     if (ri.op_mode == 'do' or ri.op_mode == 'dump') and 'reply' in ri.op[ri.op_mode]:
2006         direction = 'reply'                      1786         direction = 'reply'
2007     elif ri.op_mode == 'event':                  1787     elif ri.op_mode == 'event':
2008         direction = 'reply'                      1788         direction = 'reply'
2009     else:                                        1789     else:
2010         return                                   1790         return
2011     print_type(ri, direction)                    1791     print_type(ri, direction)
2012                                                  1792 
2013                                                  1793 
2014 def print_wrapped_type(ri):                      1794 def print_wrapped_type(ri):
2015     ri.cw.block_start(line=f"{type_name(ri, '    1795     ri.cw.block_start(line=f"{type_name(ri, 'reply')}")
2016     if ri.op_mode == 'dump':                     1796     if ri.op_mode == 'dump':
2017         ri.cw.p(f"{type_name(ri, 'reply')} *n    1797         ri.cw.p(f"{type_name(ri, 'reply')} *next;")
2018     elif ri.op_mode == 'notify' or ri.op_mode    1798     elif ri.op_mode == 'notify' or ri.op_mode == 'event':
2019         ri.cw.p('__u16 family;')                 1799         ri.cw.p('__u16 family;')
2020         ri.cw.p('__u8 cmd;')                     1800         ri.cw.p('__u8 cmd;')
2021         ri.cw.p('struct ynl_ntf_base_type *ne    1801         ri.cw.p('struct ynl_ntf_base_type *next;')
2022         ri.cw.p(f"void (*free)({type_name(ri,    1802         ri.cw.p(f"void (*free)({type_name(ri, 'reply')} *ntf);")
2023     ri.cw.p(f"{type_name(ri, 'reply', deref=T !! 1803     ri.cw.p(f"{type_name(ri, 'reply', deref=True)} obj __attribute__ ((aligned (8)));")
2024     ri.cw.block_end(line=';')                    1804     ri.cw.block_end(line=';')
2025     ri.cw.nl()                                   1805     ri.cw.nl()
2026     print_free_prototype(ri, 'reply')            1806     print_free_prototype(ri, 'reply')
2027     ri.cw.nl()                                   1807     ri.cw.nl()
2028                                                  1808 
2029                                                  1809 
2030 def _free_type_members_iter(ri, struct):         1810 def _free_type_members_iter(ri, struct):
2031     for _, attr in struct.member_list():         1811     for _, attr in struct.member_list():
2032         if attr.free_needs_iter():               1812         if attr.free_needs_iter():
2033             ri.cw.p('unsigned int i;')           1813             ri.cw.p('unsigned int i;')
2034             ri.cw.nl()                           1814             ri.cw.nl()
2035             break                                1815             break
2036                                                  1816 
2037                                                  1817 
2038 def _free_type_members(ri, var, struct, ref='    1818 def _free_type_members(ri, var, struct, ref=''):
2039     for _, attr in struct.member_list():         1819     for _, attr in struct.member_list():
2040         attr.free(ri, var, ref)                  1820         attr.free(ri, var, ref)
2041                                                  1821 
2042                                                  1822 
2043 def _free_type(ri, direction, struct):           1823 def _free_type(ri, direction, struct):
2044     var = free_arg_name(direction)               1824     var = free_arg_name(direction)
2045                                                  1825 
2046     print_free_prototype(ri, direction, suffi    1826     print_free_prototype(ri, direction, suffix='')
2047     ri.cw.block_start()                          1827     ri.cw.block_start()
2048     _free_type_members_iter(ri, struct)          1828     _free_type_members_iter(ri, struct)
2049     _free_type_members(ri, var, struct)          1829     _free_type_members(ri, var, struct)
2050     if direction:                                1830     if direction:
2051         ri.cw.p(f'free({var});')                 1831         ri.cw.p(f'free({var});')
2052     ri.cw.block_end()                            1832     ri.cw.block_end()
2053     ri.cw.nl()                                   1833     ri.cw.nl()
2054                                                  1834 
2055                                                  1835 
2056 def free_rsp_nested_prototype(ri):            << 
2057         print_free_prototype(ri, "")          << 
2058                                               << 
2059                                               << 
2060 def free_rsp_nested(ri, struct):                 1836 def free_rsp_nested(ri, struct):
2061     _free_type(ri, "", struct)                   1837     _free_type(ri, "", struct)
2062                                                  1838 
2063                                                  1839 
2064 def print_rsp_free(ri):                          1840 def print_rsp_free(ri):
2065     if 'reply' not in ri.op[ri.op_mode]:         1841     if 'reply' not in ri.op[ri.op_mode]:
2066         return                                   1842         return
2067     _free_type(ri, 'reply', ri.struct['reply'    1843     _free_type(ri, 'reply', ri.struct['reply'])
2068                                                  1844 
2069                                                  1845 
2070 def print_dump_type_free(ri):                    1846 def print_dump_type_free(ri):
2071     sub_type = type_name(ri, 'reply')            1847     sub_type = type_name(ri, 'reply')
2072                                                  1848 
2073     print_free_prototype(ri, 'reply', suffix=    1849     print_free_prototype(ri, 'reply', suffix='')
2074     ri.cw.block_start()                          1850     ri.cw.block_start()
2075     ri.cw.p(f"{sub_type} *next = rsp;")          1851     ri.cw.p(f"{sub_type} *next = rsp;")
2076     ri.cw.nl()                                   1852     ri.cw.nl()
2077     ri.cw.block_start(line='while ((void *)ne    1853     ri.cw.block_start(line='while ((void *)next != YNL_LIST_END)')
2078     _free_type_members_iter(ri, ri.struct['re    1854     _free_type_members_iter(ri, ri.struct['reply'])
2079     ri.cw.p('rsp = next;')                       1855     ri.cw.p('rsp = next;')
2080     ri.cw.p('next = rsp->next;')                 1856     ri.cw.p('next = rsp->next;')
2081     ri.cw.nl()                                   1857     ri.cw.nl()
2082                                                  1858 
2083     _free_type_members(ri, 'rsp', ri.struct['    1859     _free_type_members(ri, 'rsp', ri.struct['reply'], ref='obj.')
2084     ri.cw.p(f'free(rsp);')                       1860     ri.cw.p(f'free(rsp);')
2085     ri.cw.block_end()                            1861     ri.cw.block_end()
2086     ri.cw.block_end()                            1862     ri.cw.block_end()
2087     ri.cw.nl()                                   1863     ri.cw.nl()
2088                                                  1864 
2089                                                  1865 
2090 def print_ntf_type_free(ri):                     1866 def print_ntf_type_free(ri):
2091     print_free_prototype(ri, 'reply', suffix=    1867     print_free_prototype(ri, 'reply', suffix='')
2092     ri.cw.block_start()                          1868     ri.cw.block_start()
2093     _free_type_members_iter(ri, ri.struct['re    1869     _free_type_members_iter(ri, ri.struct['reply'])
2094     _free_type_members(ri, 'rsp', ri.struct['    1870     _free_type_members(ri, 'rsp', ri.struct['reply'], ref='obj.')
2095     ri.cw.p(f'free(rsp);')                       1871     ri.cw.p(f'free(rsp);')
2096     ri.cw.block_end()                            1872     ri.cw.block_end()
2097     ri.cw.nl()                                   1873     ri.cw.nl()
2098                                                  1874 
2099                                                  1875 
2100 def print_req_policy_fwd(cw, struct, ri=None,    1876 def print_req_policy_fwd(cw, struct, ri=None, terminate=True):
2101     if terminate and ri and policy_should_be_    1877     if terminate and ri and policy_should_be_static(struct.family):
2102         return                                   1878         return
2103                                                  1879 
2104     if terminate:                                1880     if terminate:
2105         prefix = 'extern '                       1881         prefix = 'extern '
2106     else:                                        1882     else:
2107         if ri and policy_should_be_static(str    1883         if ri and policy_should_be_static(struct.family):
2108             prefix = 'static '                   1884             prefix = 'static '
2109         else:                                    1885         else:
2110             prefix = ''                          1886             prefix = ''
2111                                                  1887 
2112     suffix = ';' if terminate else ' = {'        1888     suffix = ';' if terminate else ' = {'
2113                                                  1889 
2114     max_attr = struct.attr_max_val               1890     max_attr = struct.attr_max_val
2115     if ri:                                       1891     if ri:
2116         name = ri.op.render_name                 1892         name = ri.op.render_name
2117         if ri.op.dual_policy:                    1893         if ri.op.dual_policy:
2118             name += '_' + ri.op_mode             1894             name += '_' + ri.op_mode
2119     else:                                        1895     else:
2120         name = struct.render_name                1896         name = struct.render_name
2121     cw.p(f"{prefix}const struct nla_policy {n    1897     cw.p(f"{prefix}const struct nla_policy {name}_nl_policy[{max_attr.enum_name} + 1]{suffix}")
2122                                                  1898 
2123                                                  1899 
2124 def print_req_policy(cw, struct, ri=None):       1900 def print_req_policy(cw, struct, ri=None):
2125     if ri and ri.op:                          << 
2126         cw.ifdef_block(ri.op.get('config-cond << 
2127     print_req_policy_fwd(cw, struct, ri=ri, t    1901     print_req_policy_fwd(cw, struct, ri=ri, terminate=False)
2128     for _, arg in struct.member_list():          1902     for _, arg in struct.member_list():
2129         arg.attr_policy(cw)                      1903         arg.attr_policy(cw)
2130     cw.p("};")                                   1904     cw.p("};")
2131     cw.ifdef_block(None)                      << 
2132     cw.nl()                                      1905     cw.nl()
2133                                                  1906 
2134                                                  1907 
2135 def kernel_can_gen_family_struct(family):        1908 def kernel_can_gen_family_struct(family):
2136     return family.proto == 'genetlink'           1909     return family.proto == 'genetlink'
2137                                                  1910 
2138                                                  1911 
2139 def policy_should_be_static(family):             1912 def policy_should_be_static(family):
2140     return family.kernel_policy == 'split' or    1913     return family.kernel_policy == 'split' or kernel_can_gen_family_struct(family)
2141                                                  1914 
2142                                                  1915 
2143 def print_kernel_policy_ranges(family, cw):   << 
2144     first = True                              << 
2145     for _, attr_set in family.attr_sets.items << 
2146         if attr_set.subset_of:                << 
2147             continue                          << 
2148                                               << 
2149         for _, attr in attr_set.items():      << 
2150             if not attr.request:              << 
2151                 continue                      << 
2152             if 'full-range' not in attr.check << 
2153                 continue                      << 
2154                                               << 
2155             if first:                         << 
2156                 cw.p('/* Integer value ranges << 
2157                 first = False                 << 
2158                                               << 
2159             sign = '' if attr.type[0] == 'u'  << 
2160             suffix = 'ULL' if attr.type[0] == << 
2161             cw.block_start(line=f'static cons << 
2162             members = []                      << 
2163             if 'min' in attr.checks:          << 
2164                 members.append(('min', str(at << 
2165             if 'max' in attr.checks:          << 
2166                 members.append(('max', str(at << 
2167             cw.write_struct_init(members)     << 
2168             cw.block_end(line=';')            << 
2169             cw.nl()                           << 
2170                                               << 
2171                                               << 
2172 def print_kernel_op_table_fwd(family, cw, ter    1916 def print_kernel_op_table_fwd(family, cw, terminate):
2173     exported = not kernel_can_gen_family_stru    1917     exported = not kernel_can_gen_family_struct(family)
2174                                                  1918 
2175     if not terminate or exported:                1919     if not terminate or exported:
2176         cw.p(f"/* Ops table for {family.ident !! 1920         cw.p(f"/* Ops table for {family.name} */")
2177                                                  1921 
2178         pol_to_struct = {'global': 'genl_smal    1922         pol_to_struct = {'global': 'genl_small_ops',
2179                          'per-op': 'genl_ops'    1923                          'per-op': 'genl_ops',
2180                          'split': 'genl_split    1924                          'split': 'genl_split_ops'}
2181         struct_type = pol_to_struct[family.ke    1925         struct_type = pol_to_struct[family.kernel_policy]
2182                                                  1926 
2183         if not exported:                         1927         if not exported:
2184             cnt = ""                             1928             cnt = ""
2185         elif family.kernel_policy == 'split':    1929         elif family.kernel_policy == 'split':
2186             cnt = 0                              1930             cnt = 0
2187             for op in family.ops.values():       1931             for op in family.ops.values():
2188                 if 'do' in op:                   1932                 if 'do' in op:
2189                     cnt += 1                     1933                     cnt += 1
2190                 if 'dump' in op:                 1934                 if 'dump' in op:
2191                     cnt += 1                     1935                     cnt += 1
2192         else:                                    1936         else:
2193             cnt = len(family.ops)                1937             cnt = len(family.ops)
2194                                                  1938 
2195         qual = 'static const' if not exported    1939         qual = 'static const' if not exported else 'const'
2196         line = f"{qual} struct {struct_type}  !! 1940         line = f"{qual} struct {struct_type} {family.name}_nl_ops[{cnt}]"
2197         if terminate:                            1941         if terminate:
2198             cw.p(f"extern {line};")              1942             cw.p(f"extern {line};")
2199         else:                                    1943         else:
2200             cw.block_start(line=line + ' =')     1944             cw.block_start(line=line + ' =')
2201                                                  1945 
2202     if not terminate:                            1946     if not terminate:
2203         return                                   1947         return
2204                                                  1948 
2205     cw.nl()                                      1949     cw.nl()
2206     for name in family.hooks['pre']['do']['li    1950     for name in family.hooks['pre']['do']['list']:
2207         cw.write_func_prot('int', c_lower(nam    1951         cw.write_func_prot('int', c_lower(name),
2208                            ['const struct gen    1952                            ['const struct genl_split_ops *ops',
2209                             'struct sk_buff *    1953                             'struct sk_buff *skb', 'struct genl_info *info'], suffix=';')
2210     for name in family.hooks['post']['do']['l    1954     for name in family.hooks['post']['do']['list']:
2211         cw.write_func_prot('void', c_lower(na    1955         cw.write_func_prot('void', c_lower(name),
2212                            ['const struct gen    1956                            ['const struct genl_split_ops *ops',
2213                             'struct sk_buff *    1957                             'struct sk_buff *skb', 'struct genl_info *info'], suffix=';')
2214     for name in family.hooks['pre']['dump']['    1958     for name in family.hooks['pre']['dump']['list']:
2215         cw.write_func_prot('int', c_lower(nam    1959         cw.write_func_prot('int', c_lower(name),
2216                            ['struct netlink_c    1960                            ['struct netlink_callback *cb'], suffix=';')
2217     for name in family.hooks['post']['dump'][    1961     for name in family.hooks['post']['dump']['list']:
2218         cw.write_func_prot('int', c_lower(nam    1962         cw.write_func_prot('int', c_lower(name),
2219                            ['struct netlink_c    1963                            ['struct netlink_callback *cb'], suffix=';')
2220                                                  1964 
2221     cw.nl()                                      1965     cw.nl()
2222                                                  1966 
2223     for op_name, op in family.ops.items():       1967     for op_name, op in family.ops.items():
2224         if op.is_async:                          1968         if op.is_async:
2225             continue                             1969             continue
2226                                                  1970 
2227         if 'do' in op:                           1971         if 'do' in op:
2228             name = c_lower(f"{family.ident_na !! 1972             name = c_lower(f"{family.name}-nl-{op_name}-doit")
2229             cw.write_func_prot('int', name,      1973             cw.write_func_prot('int', name,
2230                                ['struct sk_bu    1974                                ['struct sk_buff *skb', 'struct genl_info *info'], suffix=';')
2231                                                  1975 
2232         if 'dump' in op:                         1976         if 'dump' in op:
2233             name = c_lower(f"{family.ident_na !! 1977             name = c_lower(f"{family.name}-nl-{op_name}-dumpit")
2234             cw.write_func_prot('int', name,      1978             cw.write_func_prot('int', name,
2235                                ['struct sk_bu    1979                                ['struct sk_buff *skb', 'struct netlink_callback *cb'], suffix=';')
2236     cw.nl()                                      1980     cw.nl()
2237                                                  1981 
2238                                                  1982 
2239 def print_kernel_op_table_hdr(family, cw):       1983 def print_kernel_op_table_hdr(family, cw):
2240     print_kernel_op_table_fwd(family, cw, ter    1984     print_kernel_op_table_fwd(family, cw, terminate=True)
2241                                                  1985 
2242                                                  1986 
2243 def print_kernel_op_table(family, cw):           1987 def print_kernel_op_table(family, cw):
2244     print_kernel_op_table_fwd(family, cw, ter    1988     print_kernel_op_table_fwd(family, cw, terminate=False)
2245     if family.kernel_policy == 'global' or fa    1989     if family.kernel_policy == 'global' or family.kernel_policy == 'per-op':
2246         for op_name, op in family.ops.items()    1990         for op_name, op in family.ops.items():
2247             if op.is_async:                      1991             if op.is_async:
2248                 continue                         1992                 continue
2249                                                  1993 
2250             cw.ifdef_block(op.get('config-con << 
2251             cw.block_start()                     1994             cw.block_start()
2252             members = [('cmd', op.enum_name)]    1995             members = [('cmd', op.enum_name)]
2253             if 'dont-validate' in op:            1996             if 'dont-validate' in op:
2254                 members.append(('validate',      1997                 members.append(('validate',
2255                                 ' | '.join([c    1998                                 ' | '.join([c_upper('genl-dont-validate-' + x)
2256                                             f    1999                                             for x in op['dont-validate']])), )
2257             for op_mode in ['do', 'dump']:       2000             for op_mode in ['do', 'dump']:
2258                 if op_mode in op:                2001                 if op_mode in op:
2259                     name = c_lower(f"{family. !! 2002                     name = c_lower(f"{family.name}-nl-{op_name}-{op_mode}it")
2260                     members.append((op_mode +    2003                     members.append((op_mode + 'it', name))
2261             if family.kernel_policy == 'per-o    2004             if family.kernel_policy == 'per-op':
2262                 struct = Struct(family, op['a    2005                 struct = Struct(family, op['attribute-set'],
2263                                 type_list=op[    2006                                 type_list=op['do']['request']['attributes'])
2264                                                  2007 
2265                 name = c_lower(f"{family.iden !! 2008                 name = c_lower(f"{family.name}-{op_name}-nl-policy")
2266                 members.append(('policy', nam    2009                 members.append(('policy', name))
2267                 members.append(('maxattr', st    2010                 members.append(('maxattr', struct.attr_max_val.enum_name))
2268             if 'flags' in op:                    2011             if 'flags' in op:
2269                 members.append(('flags', ' |     2012                 members.append(('flags', ' | '.join([c_upper('genl-' + x) for x in op['flags']])))
2270             cw.write_struct_init(members)        2013             cw.write_struct_init(members)
2271             cw.block_end(line=',')               2014             cw.block_end(line=',')
2272     elif family.kernel_policy == 'split':        2015     elif family.kernel_policy == 'split':
2273         cb_names = {'do':   {'pre': 'pre_doit    2016         cb_names = {'do':   {'pre': 'pre_doit', 'post': 'post_doit'},
2274                     'dump': {'pre': 'start',     2017                     'dump': {'pre': 'start', 'post': 'done'}}
2275                                                  2018 
2276         for op_name, op in family.ops.items()    2019         for op_name, op in family.ops.items():
2277             for op_mode in ['do', 'dump']:       2020             for op_mode in ['do', 'dump']:
2278                 if op.is_async or op_mode not    2021                 if op.is_async or op_mode not in op:
2279                     continue                     2022                     continue
2280                                                  2023 
2281                 cw.ifdef_block(op.get('config << 
2282                 cw.block_start()                 2024                 cw.block_start()
2283                 members = [('cmd', op.enum_na    2025                 members = [('cmd', op.enum_name)]
2284                 if 'dont-validate' in op:        2026                 if 'dont-validate' in op:
2285                     dont_validate = []           2027                     dont_validate = []
2286                     for x in op['dont-validat    2028                     for x in op['dont-validate']:
2287                         if op_mode == 'do' an    2029                         if op_mode == 'do' and x in ['dump', 'dump-strict']:
2288                             continue             2030                             continue
2289                         if op_mode == "dump"     2031                         if op_mode == "dump" and x == 'strict':
2290                             continue             2032                             continue
2291                         dont_validate.append(    2033                         dont_validate.append(x)
2292                                                  2034 
2293                     if dont_validate:            2035                     if dont_validate:
2294                         members.append(('vali    2036                         members.append(('validate',
2295                                         ' | '    2037                                         ' | '.join([c_upper('genl-dont-validate-' + x)
2296                                                  2038                                                     for x in dont_validate])), )
2297                 name = c_lower(f"{family.iden !! 2039                 name = c_lower(f"{family.name}-nl-{op_name}-{op_mode}it")
2298                 if 'pre' in op[op_mode]:         2040                 if 'pre' in op[op_mode]:
2299                     members.append((cb_names[    2041                     members.append((cb_names[op_mode]['pre'], c_lower(op[op_mode]['pre'])))
2300                 members.append((op_mode + 'it    2042                 members.append((op_mode + 'it', name))
2301                 if 'post' in op[op_mode]:        2043                 if 'post' in op[op_mode]:
2302                     members.append((cb_names[    2044                     members.append((cb_names[op_mode]['post'], c_lower(op[op_mode]['post'])))
2303                 if 'request' in op[op_mode]:     2045                 if 'request' in op[op_mode]:
2304                     struct = Struct(family, o    2046                     struct = Struct(family, op['attribute-set'],
2305                                     type_list    2047                                     type_list=op[op_mode]['request']['attributes'])
2306                                                  2048 
2307                     if op.dual_policy:           2049                     if op.dual_policy:
2308                         name = c_lower(f"{fam !! 2050                         name = c_lower(f"{family.name}-{op_name}-{op_mode}-nl-policy")
2309                     else:                        2051                     else:
2310                         name = c_lower(f"{fam !! 2052                         name = c_lower(f"{family.name}-{op_name}-nl-policy")
2311                     members.append(('policy',    2053                     members.append(('policy', name))
2312                     members.append(('maxattr'    2054                     members.append(('maxattr', struct.attr_max_val.enum_name))
2313                 flags = (op['flags'] if 'flag    2055                 flags = (op['flags'] if 'flags' in op else []) + ['cmd-cap-' + op_mode]
2314                 members.append(('flags', ' |     2056                 members.append(('flags', ' | '.join([c_upper('genl-' + x) for x in flags])))
2315                 cw.write_struct_init(members)    2057                 cw.write_struct_init(members)
2316                 cw.block_end(line=',')           2058                 cw.block_end(line=',')
2317     cw.ifdef_block(None)                      << 
2318                                                  2059 
2319     cw.block_end(line=';')                       2060     cw.block_end(line=';')
2320     cw.nl()                                      2061     cw.nl()
2321                                                  2062 
2322                                                  2063 
2323 def print_kernel_mcgrp_hdr(family, cw):          2064 def print_kernel_mcgrp_hdr(family, cw):
2324     if not family.mcgrps['list']:                2065     if not family.mcgrps['list']:
2325         return                                   2066         return
2326                                                  2067 
2327     cw.block_start('enum')                       2068     cw.block_start('enum')
2328     for grp in family.mcgrps['list']:            2069     for grp in family.mcgrps['list']:
2329         grp_id = c_upper(f"{family.ident_name !! 2070         grp_id = c_upper(f"{family.name}-nlgrp-{grp['name']},")
2330         cw.p(grp_id)                             2071         cw.p(grp_id)
2331     cw.block_end(';')                            2072     cw.block_end(';')
2332     cw.nl()                                      2073     cw.nl()
2333                                                  2074 
2334                                                  2075 
2335 def print_kernel_mcgrp_src(family, cw):          2076 def print_kernel_mcgrp_src(family, cw):
2336     if not family.mcgrps['list']:                2077     if not family.mcgrps['list']:
2337         return                                   2078         return
2338                                                  2079 
2339     cw.block_start('static const struct genl_ !! 2080     cw.block_start('static const struct genl_multicast_group ' + family.name + '_nl_mcgrps[] =')
2340     for grp in family.mcgrps['list']:            2081     for grp in family.mcgrps['list']:
2341         name = grp['name']                       2082         name = grp['name']
2342         grp_id = c_upper(f"{family.ident_name !! 2083         grp_id = c_upper(f"{family.name}-nlgrp-{name}")
2343         cw.p('[' + grp_id + '] = { "' + name     2084         cw.p('[' + grp_id + '] = { "' + name + '", },')
2344     cw.block_end(';')                            2085     cw.block_end(';')
2345     cw.nl()                                      2086     cw.nl()
2346                                                  2087 
2347                                                  2088 
2348 def print_kernel_family_struct_hdr(family, cw    2089 def print_kernel_family_struct_hdr(family, cw):
2349     if not kernel_can_gen_family_struct(famil    2090     if not kernel_can_gen_family_struct(family):
2350         return                                   2091         return
2351                                                  2092 
2352     cw.p(f"extern struct genl_family {family. !! 2093     cw.p(f"extern struct genl_family {family.name}_nl_family;")
2353     cw.nl()                                      2094     cw.nl()
2354     if 'sock-priv' in family.kernel_family:   << 
2355         cw.p(f'void {family.c_name}_nl_sock_p << 
2356         cw.p(f'void {family.c_name}_nl_sock_p << 
2357         cw.nl()                               << 
2358                                                  2095 
2359                                                  2096 
2360 def print_kernel_family_struct_src(family, cw    2097 def print_kernel_family_struct_src(family, cw):
2361     if not kernel_can_gen_family_struct(famil    2098     if not kernel_can_gen_family_struct(family):
2362         return                                   2099         return
2363                                                  2100 
2364     cw.block_start(f"struct genl_family {fami !! 2101     cw.block_start(f"struct genl_family {family.name}_nl_family __ro_after_init =")
2365     cw.p('.name\t\t= ' + family.fam_key + ','    2102     cw.p('.name\t\t= ' + family.fam_key + ',')
2366     cw.p('.version\t= ' + family.ver_key + ',    2103     cw.p('.version\t= ' + family.ver_key + ',')
2367     cw.p('.netnsok\t= true,')                    2104     cw.p('.netnsok\t= true,')
2368     cw.p('.parallel_ops\t= true,')               2105     cw.p('.parallel_ops\t= true,')
2369     cw.p('.module\t\t= THIS_MODULE,')            2106     cw.p('.module\t\t= THIS_MODULE,')
2370     if family.kernel_policy == 'per-op':         2107     if family.kernel_policy == 'per-op':
2371         cw.p(f'.ops\t\t= {family.c_name}_nl_o !! 2108         cw.p(f'.ops\t\t= {family.name}_nl_ops,')
2372         cw.p(f'.n_ops\t\t= ARRAY_SIZE({family !! 2109         cw.p(f'.n_ops\t\t= ARRAY_SIZE({family.name}_nl_ops),')
2373     elif family.kernel_policy == 'split':        2110     elif family.kernel_policy == 'split':
2374         cw.p(f'.split_ops\t= {family.c_name}_ !! 2111         cw.p(f'.split_ops\t= {family.name}_nl_ops,')
2375         cw.p(f'.n_split_ops\t= ARRAY_SIZE({fa !! 2112         cw.p(f'.n_split_ops\t= ARRAY_SIZE({family.name}_nl_ops),')
2376     if family.mcgrps['list']:                    2113     if family.mcgrps['list']:
2377         cw.p(f'.mcgrps\t\t= {family.c_name}_n !! 2114         cw.p(f'.mcgrps\t\t= {family.name}_nl_mcgrps,')
2378         cw.p(f'.n_mcgrps\t= ARRAY_SIZE({famil !! 2115         cw.p(f'.n_mcgrps\t= ARRAY_SIZE({family.name}_nl_mcgrps),')
2379     if 'sock-priv' in family.kernel_family:   << 
2380         cw.p(f'.sock_priv_size\t= sizeof({fam << 
2381         # Force cast here, actual helpers tak << 
2382         cw.p(f'.sock_priv_init\t= (void *){fa << 
2383         cw.p(f'.sock_priv_destroy = (void *){ << 
2384     cw.block_end(';')                            2116     cw.block_end(';')
2385                                                  2117 
2386                                                  2118 
2387 def uapi_enum_start(family, cw, obj, ckey='',    2119 def uapi_enum_start(family, cw, obj, ckey='', enum_name='enum-name'):
2388     start_line = 'enum'                          2120     start_line = 'enum'
2389     if enum_name in obj:                         2121     if enum_name in obj:
2390         if obj[enum_name]:                       2122         if obj[enum_name]:
2391             start_line = 'enum ' + c_lower(ob    2123             start_line = 'enum ' + c_lower(obj[enum_name])
2392     elif ckey and ckey in obj:                   2124     elif ckey and ckey in obj:
2393         start_line = 'enum ' + family.c_name  !! 2125         start_line = 'enum ' + family.name + '_' + c_lower(obj[ckey])
2394     cw.block_start(line=start_line)              2126     cw.block_start(line=start_line)
2395                                                  2127 
2396                                                  2128 
2397 def render_uapi(family, cw):                     2129 def render_uapi(family, cw):
2398     hdr_prot = f"_UAPI_LINUX_{c_upper(family. !! 2130     hdr_prot = f"_UAPI_LINUX_{family.name.upper()}_H"
2399     cw.p('#ifndef ' + hdr_prot)                  2131     cw.p('#ifndef ' + hdr_prot)
2400     cw.p('#define ' + hdr_prot)                  2132     cw.p('#define ' + hdr_prot)
2401     cw.nl()                                      2133     cw.nl()
2402                                                  2134 
2403     defines = [(family.fam_key, family["name"    2135     defines = [(family.fam_key, family["name"]),
2404                (family.ver_key, family.get('v    2136                (family.ver_key, family.get('version', 1))]
2405     cw.writes_defines(defines)                   2137     cw.writes_defines(defines)
2406     cw.nl()                                      2138     cw.nl()
2407                                                  2139 
2408     defines = []                                 2140     defines = []
2409     for const in family['definitions']:          2141     for const in family['definitions']:
2410         if const['type'] != 'const':             2142         if const['type'] != 'const':
2411             cw.writes_defines(defines)           2143             cw.writes_defines(defines)
2412             defines = []                         2144             defines = []
2413             cw.nl()                              2145             cw.nl()
2414                                                  2146 
2415         # Write kdoc for enum and flags (one     2147         # Write kdoc for enum and flags (one day maybe also structs)
2416         if const['type'] == 'enum' or const['    2148         if const['type'] == 'enum' or const['type'] == 'flags':
2417             enum = family.consts[const['name'    2149             enum = family.consts[const['name']]
2418                                                  2150 
2419             if enum.has_doc():                   2151             if enum.has_doc():
2420                 cw.p('/**')                      2152                 cw.p('/**')
2421                 doc = ''                         2153                 doc = ''
2422                 if 'doc' in enum:                2154                 if 'doc' in enum:
2423                     doc = ' - ' + enum['doc']    2155                     doc = ' - ' + enum['doc']
2424                 cw.write_doc_line(enum.enum_n    2156                 cw.write_doc_line(enum.enum_name + doc)
2425                 for entry in enum.entries.val    2157                 for entry in enum.entries.values():
2426                     if entry.has_doc():          2158                     if entry.has_doc():
2427                         doc = '@' + entry.c_n    2159                         doc = '@' + entry.c_name + ': ' + entry['doc']
2428                         cw.write_doc_line(doc    2160                         cw.write_doc_line(doc)
2429                 cw.p(' */')                      2161                 cw.p(' */')
2430                                                  2162 
2431             uapi_enum_start(family, cw, const    2163             uapi_enum_start(family, cw, const, 'name')
2432             name_pfx = const.get('name-prefix !! 2164             name_pfx = const.get('name-prefix', f"{family.name}-{const['name']}-")
2433             for entry in enum.entries.values(    2165             for entry in enum.entries.values():
2434                 suffix = ','                     2166                 suffix = ','
2435                 if entry.value_change:           2167                 if entry.value_change:
2436                     suffix = f" = {entry.user    2168                     suffix = f" = {entry.user_value()}" + suffix
2437                 cw.p(entry.c_name + suffix)      2169                 cw.p(entry.c_name + suffix)
2438                                                  2170 
2439             if const.get('render-max', False)    2171             if const.get('render-max', False):
2440                 cw.nl()                          2172                 cw.nl()
2441                 cw.p('/* private: */')           2173                 cw.p('/* private: */')
2442                 if const['type'] == 'flags':     2174                 if const['type'] == 'flags':
2443                     max_name = c_upper(name_p    2175                     max_name = c_upper(name_pfx + 'mask')
2444                     max_val = f' = {enum.get_    2176                     max_val = f' = {enum.get_mask()},'
2445                     cw.p(max_name + max_val)     2177                     cw.p(max_name + max_val)
2446                 else:                            2178                 else:
2447                     max_name = c_upper(name_p    2179                     max_name = c_upper(name_pfx + 'max')
2448                     cw.p('__' + max_name + ',    2180                     cw.p('__' + max_name + ',')
2449                     cw.p(max_name + ' = (__'     2181                     cw.p(max_name + ' = (__' + max_name + ' - 1)')
2450             cw.block_end(line=';')               2182             cw.block_end(line=';')
2451             cw.nl()                              2183             cw.nl()
2452         elif const['type'] == 'const':           2184         elif const['type'] == 'const':
2453             defines.append([c_upper(family.ge    2185             defines.append([c_upper(family.get('c-define-name',
2454                                               !! 2186                                                f"{family.name}-{const['name']}")),
2455                             const['value']])     2187                             const['value']])
2456                                                  2188 
2457     if defines:                                  2189     if defines:
2458         cw.writes_defines(defines)               2190         cw.writes_defines(defines)
2459         cw.nl()                                  2191         cw.nl()
2460                                                  2192 
2461     max_by_define = family.get('max-by-define    2193     max_by_define = family.get('max-by-define', False)
2462                                                  2194 
2463     for _, attr_set in family.attr_sets.items    2195     for _, attr_set in family.attr_sets.items():
2464         if attr_set.subset_of:                   2196         if attr_set.subset_of:
2465             continue                             2197             continue
2466                                                  2198 
2467         max_value = f"({attr_set.cnt_name} -  !! 2199         cnt_name = c_upper(family.get('attr-cnt-name', f"__{attr_set.name_prefix}MAX"))
                                                   >> 2200         max_value = f"({cnt_name} - 1)"
2468                                                  2201 
2469         val = 0                                  2202         val = 0
2470         uapi_enum_start(family, cw, attr_set.    2203         uapi_enum_start(family, cw, attr_set.yaml, 'enum-name')
2471         for _, attr in attr_set.items():         2204         for _, attr in attr_set.items():
2472             suffix = ','                         2205             suffix = ','
2473             if attr.value != val:                2206             if attr.value != val:
2474                 suffix = f" = {attr.value},"     2207                 suffix = f" = {attr.value},"
2475                 val = attr.value                 2208                 val = attr.value
2476             val += 1                             2209             val += 1
2477             cw.p(attr.enum_name + suffix)        2210             cw.p(attr.enum_name + suffix)
2478         cw.nl()                                  2211         cw.nl()
2479         cw.p(attr_set.cnt_name + ('' if max_b !! 2212         cw.p(cnt_name + ('' if max_by_define else ','))
2480         if not max_by_define:                    2213         if not max_by_define:
2481             cw.p(f"{attr_set.max_name} = {max    2214             cw.p(f"{attr_set.max_name} = {max_value}")
2482         cw.block_end(line=';')                   2215         cw.block_end(line=';')
2483         if max_by_define:                        2216         if max_by_define:
2484             cw.p(f"#define {attr_set.max_name    2217             cw.p(f"#define {attr_set.max_name} {max_value}")
2485         cw.nl()                                  2218         cw.nl()
2486                                                  2219 
2487     # Commands                                   2220     # Commands
2488     separate_ntf = 'async-prefix' in family['    2221     separate_ntf = 'async-prefix' in family['operations']
2489                                                  2222 
2490     max_name = c_upper(family.get('cmd-max-na    2223     max_name = c_upper(family.get('cmd-max-name', f"{family.op_prefix}MAX"))
2491     cnt_name = c_upper(family.get('cmd-cnt-na    2224     cnt_name = c_upper(family.get('cmd-cnt-name', f"__{family.op_prefix}MAX"))
2492     max_value = f"({cnt_name} - 1)"              2225     max_value = f"({cnt_name} - 1)"
2493                                                  2226 
2494     uapi_enum_start(family, cw, family['opera    2227     uapi_enum_start(family, cw, family['operations'], 'enum-name')
2495     val = 0                                      2228     val = 0
2496     for op in family.msgs.values():              2229     for op in family.msgs.values():
2497         if separate_ntf and ('notify' in op o    2230         if separate_ntf and ('notify' in op or 'event' in op):
2498             continue                             2231             continue
2499                                                  2232 
2500         suffix = ','                             2233         suffix = ','
2501         if op.value != val:                      2234         if op.value != val:
2502             suffix = f" = {op.value},"           2235             suffix = f" = {op.value},"
2503             val = op.value                       2236             val = op.value
2504         cw.p(op.enum_name + suffix)              2237         cw.p(op.enum_name + suffix)
2505         val += 1                                 2238         val += 1
2506     cw.nl()                                      2239     cw.nl()
2507     cw.p(cnt_name + ('' if max_by_define else    2240     cw.p(cnt_name + ('' if max_by_define else ','))
2508     if not max_by_define:                        2241     if not max_by_define:
2509         cw.p(f"{max_name} = {max_value}")        2242         cw.p(f"{max_name} = {max_value}")
2510     cw.block_end(line=';')                       2243     cw.block_end(line=';')
2511     if max_by_define:                            2244     if max_by_define:
2512         cw.p(f"#define {max_name} {max_value}    2245         cw.p(f"#define {max_name} {max_value}")
2513     cw.nl()                                      2246     cw.nl()
2514                                                  2247 
2515     if separate_ntf:                             2248     if separate_ntf:
2516         uapi_enum_start(family, cw, family['o    2249         uapi_enum_start(family, cw, family['operations'], enum_name='async-enum')
2517         for op in family.msgs.values():          2250         for op in family.msgs.values():
2518             if separate_ntf and not ('notify'    2251             if separate_ntf and not ('notify' in op or 'event' in op):
2519                 continue                         2252                 continue
2520                                                  2253 
2521             suffix = ','                         2254             suffix = ','
2522             if 'value' in op:                    2255             if 'value' in op:
2523                 suffix = f" = {op['value']},"    2256                 suffix = f" = {op['value']},"
2524             cw.p(op.enum_name + suffix)          2257             cw.p(op.enum_name + suffix)
2525         cw.block_end(line=';')                   2258         cw.block_end(line=';')
2526         cw.nl()                                  2259         cw.nl()
2527                                                  2260 
2528     # Multicast                                  2261     # Multicast
2529     defines = []                                 2262     defines = []
2530     for grp in family.mcgrps['list']:            2263     for grp in family.mcgrps['list']:
2531         name = grp['name']                       2264         name = grp['name']
2532         defines.append([c_upper(grp.get('c-de !! 2265         defines.append([c_upper(grp.get('c-define-name', f"{family.name}-mcgrp-{name}")),
2533                         f'{name}'])              2266                         f'{name}'])
2534     cw.nl()                                      2267     cw.nl()
2535     if defines:                                  2268     if defines:
2536         cw.writes_defines(defines)               2269         cw.writes_defines(defines)
2537         cw.nl()                                  2270         cw.nl()
2538                                                  2271 
2539     cw.p(f'#endif /* {hdr_prot} */')             2272     cw.p(f'#endif /* {hdr_prot} */')
2540                                                  2273 
2541                                                  2274 
2542 def _render_user_ntf_entry(ri, op):              2275 def _render_user_ntf_entry(ri, op):
2543     ri.cw.block_start(line=f"[{op.enum_name}]    2276     ri.cw.block_start(line=f"[{op.enum_name}] = ")
2544     ri.cw.p(f".alloc_sz\t= sizeof({type_name(    2277     ri.cw.p(f".alloc_sz\t= sizeof({type_name(ri, 'event')}),")
2545     ri.cw.p(f".cb\t\t= {op_prefix(ri, 'reply'    2278     ri.cw.p(f".cb\t\t= {op_prefix(ri, 'reply', deref=True)}_parse,")
2546     ri.cw.p(f".policy\t\t= &{ri.struct['reply    2279     ri.cw.p(f".policy\t\t= &{ri.struct['reply'].render_name}_nest,")
2547     ri.cw.p(f".free\t\t= (void *){op_prefix(r    2280     ri.cw.p(f".free\t\t= (void *){op_prefix(ri, 'notify')}_free,")
2548     ri.cw.block_end(line=',')                    2281     ri.cw.block_end(line=',')
2549                                                  2282 
2550                                                  2283 
2551 def render_user_family(family, cw, prototype)    2284 def render_user_family(family, cw, prototype):
2552     symbol = f'const struct ynl_family ynl_{f    2285     symbol = f'const struct ynl_family ynl_{family.c_name}_family'
2553     if prototype:                                2286     if prototype:
2554         cw.p(f'extern {symbol};')                2287         cw.p(f'extern {symbol};')
2555         return                                   2288         return
2556                                                  2289 
2557     if family.ntfs:                              2290     if family.ntfs:
2558         cw.block_start(line=f"static const st    2291         cw.block_start(line=f"static const struct ynl_ntf_info {family['name']}_ntf_info[] = ")
2559         for ntf_op_name, ntf_op in family.ntf    2292         for ntf_op_name, ntf_op in family.ntfs.items():
2560             if 'notify' in ntf_op:               2293             if 'notify' in ntf_op:
2561                 op = family.ops[ntf_op['notif    2294                 op = family.ops[ntf_op['notify']]
2562                 ri = RenderInfo(cw, family, "    2295                 ri = RenderInfo(cw, family, "user", op, "notify")
2563             elif 'event' in ntf_op:              2296             elif 'event' in ntf_op:
2564                 ri = RenderInfo(cw, family, "    2297                 ri = RenderInfo(cw, family, "user", ntf_op, "event")
2565             else:                                2298             else:
2566                 raise Exception('Invalid noti    2299                 raise Exception('Invalid notification ' + ntf_op_name)
2567             _render_user_ntf_entry(ri, ntf_op    2300             _render_user_ntf_entry(ri, ntf_op)
2568         for op_name, op in family.ops.items()    2301         for op_name, op in family.ops.items():
2569             if 'event' not in op:                2302             if 'event' not in op:
2570                 continue                         2303                 continue
2571             ri = RenderInfo(cw, family, "user    2304             ri = RenderInfo(cw, family, "user", op, "event")
2572             _render_user_ntf_entry(ri, op)       2305             _render_user_ntf_entry(ri, op)
2573         cw.block_end(line=";")                   2306         cw.block_end(line=";")
2574         cw.nl()                                  2307         cw.nl()
2575                                                  2308 
2576     cw.block_start(f'{symbol} = ')               2309     cw.block_start(f'{symbol} = ')
2577     cw.p(f'.name\t\t= "{family.c_name}",')    !! 2310     cw.p(f'.name\t\t= "{family.name}",')
2578     if family.fixed_header:                   << 
2579         cw.p(f'.hdr_len\t= sizeof(struct genl << 
2580     else:                                     << 
2581         cw.p('.hdr_len\t= sizeof(struct genlm << 
2582     if family.ntfs:                              2311     if family.ntfs:
2583         cw.p(f".ntf_info\t= {family['name']}_    2312         cw.p(f".ntf_info\t= {family['name']}_ntf_info,")
2584         cw.p(f".ntf_info_size\t= YNL_ARRAY_SI !! 2313         cw.p(f".ntf_info_size\t= MNL_ARRAY_SIZE({family['name']}_ntf_info),")
2585     cw.block_end(line=';')                       2314     cw.block_end(line=';')
2586                                                  2315 
2587                                                  2316 
2588 def family_contains_bitfield32(family):       << 
2589     for _, attr_set in family.attr_sets.items << 
2590         if attr_set.subset_of:                << 
2591             continue                          << 
2592         for _, attr in attr_set.items():      << 
2593             if attr.type == "bitfield32":     << 
2594                 return True                   << 
2595     return False                              << 
2596                                               << 
2597                                               << 
2598 def find_kernel_root(full_path):                 2317 def find_kernel_root(full_path):
2599     sub_path = ''                                2318     sub_path = ''
2600     while True:                                  2319     while True:
2601         sub_path = os.path.join(os.path.basen    2320         sub_path = os.path.join(os.path.basename(full_path), sub_path)
2602         full_path = os.path.dirname(full_path    2321         full_path = os.path.dirname(full_path)
2603         maintainers = os.path.join(full_path,    2322         maintainers = os.path.join(full_path, "MAINTAINERS")
2604         if os.path.exists(maintainers):          2323         if os.path.exists(maintainers):
2605             return full_path, sub_path[:-1]      2324             return full_path, sub_path[:-1]
2606                                                  2325 
2607                                                  2326 
2608 def main():                                      2327 def main():
2609     parser = argparse.ArgumentParser(descript    2328     parser = argparse.ArgumentParser(description='Netlink simple parsing generator')
2610     parser.add_argument('--mode', dest='mode'    2329     parser.add_argument('--mode', dest='mode', type=str, required=True)
2611     parser.add_argument('--spec', dest='spec'    2330     parser.add_argument('--spec', dest='spec', type=str, required=True)
2612     parser.add_argument('--header', dest='hea    2331     parser.add_argument('--header', dest='header', action='store_true', default=None)
2613     parser.add_argument('--source', dest='hea    2332     parser.add_argument('--source', dest='header', action='store_false')
2614     parser.add_argument('--user-header', narg    2333     parser.add_argument('--user-header', nargs='+', default=[])
2615     parser.add_argument('--cmp-out', action=' << 
2616                         help='Do not overwrit << 
2617     parser.add_argument('--exclude-op', actio    2334     parser.add_argument('--exclude-op', action='append', default=[])
2618     parser.add_argument('-o', dest='out_file'    2335     parser.add_argument('-o', dest='out_file', type=str, default=None)
2619     args = parser.parse_args()                   2336     args = parser.parse_args()
2620                                                  2337 
2621     if args.header is None:                      2338     if args.header is None:
2622         parser.error("--header or --source is    2339         parser.error("--header or --source is required")
2623                                                  2340 
2624     exclude_ops = [re.compile(expr) for expr     2341     exclude_ops = [re.compile(expr) for expr in args.exclude_op]
2625                                                  2342 
2626     try:                                         2343     try:
2627         parsed = Family(args.spec, exclude_op    2344         parsed = Family(args.spec, exclude_ops)
2628         if parsed.license != '((GPL-2.0 WITH     2345         if parsed.license != '((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)':
2629             print('Spec license:', parsed.lic    2346             print('Spec license:', parsed.license)
2630             print('License must be: ((GPL-2.0    2347             print('License must be: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)')
2631             os.sys.exit(1)                       2348             os.sys.exit(1)
2632     except yaml.YAMLError as exc:                2349     except yaml.YAMLError as exc:
2633         print(exc)                               2350         print(exc)
2634         os.sys.exit(1)                           2351         os.sys.exit(1)
2635         return                                   2352         return
2636                                                  2353 
2637     supported_models = ['unified']               2354     supported_models = ['unified']
2638     if args.mode in ['user', 'kernel']:          2355     if args.mode in ['user', 'kernel']:
2639         supported_models += ['directional']      2356         supported_models += ['directional']
2640     if parsed.msg_id_model not in supported_m    2357     if parsed.msg_id_model not in supported_models:
2641         print(f'Message enum-model {parsed.ms    2358         print(f'Message enum-model {parsed.msg_id_model} not supported for {args.mode} generation')
2642         os.sys.exit(1)                           2359         os.sys.exit(1)
2643                                                  2360 
2644     cw = CodeWriter(BaseNlLib(), args.out_fil !! 2361     cw = CodeWriter(BaseNlLib(), args.out_file)
2645                                                  2362 
2646     _, spec_kernel = find_kernel_root(args.sp    2363     _, spec_kernel = find_kernel_root(args.spec)
2647     if args.mode == 'uapi' or args.header:       2364     if args.mode == 'uapi' or args.header:
2648         cw.p(f'/* SPDX-License-Identifier: {p    2365         cw.p(f'/* SPDX-License-Identifier: {parsed.license} */')
2649     else:                                        2366     else:
2650         cw.p(f'// SPDX-License-Identifier: {p    2367         cw.p(f'// SPDX-License-Identifier: {parsed.license}')
2651     cw.p("/* Do not edit directly, auto-gener    2368     cw.p("/* Do not edit directly, auto-generated from: */")
2652     cw.p(f"/*\t{spec_kernel} */")                2369     cw.p(f"/*\t{spec_kernel} */")
2653     cw.p(f"/* YNL-GEN {args.mode} {'header' i    2370     cw.p(f"/* YNL-GEN {args.mode} {'header' if args.header else 'source'} */")
2654     if args.exclude_op or args.user_header:      2371     if args.exclude_op or args.user_header:
2655         line = ''                                2372         line = ''
2656         line += ' --user-header '.join([''] +    2373         line += ' --user-header '.join([''] + args.user_header)
2657         line += ' --exclude-op '.join([''] +     2374         line += ' --exclude-op '.join([''] + args.exclude_op)
2658         cw.p(f'/* YNL-ARG{line} */')             2375         cw.p(f'/* YNL-ARG{line} */')
2659     cw.nl()                                      2376     cw.nl()
2660                                                  2377 
2661     if args.mode == 'uapi':                      2378     if args.mode == 'uapi':
2662         render_uapi(parsed, cw)                  2379         render_uapi(parsed, cw)
2663         return                                   2380         return
2664                                                  2381 
2665     hdr_prot = f"_LINUX_{parsed.c_name.upper( !! 2382     hdr_prot = f"_LINUX_{parsed.name.upper()}_GEN_H"
2666     if args.header:                              2383     if args.header:
2667         cw.p('#ifndef ' + hdr_prot)              2384         cw.p('#ifndef ' + hdr_prot)
2668         cw.p('#define ' + hdr_prot)              2385         cw.p('#define ' + hdr_prot)
2669         cw.nl()                                  2386         cw.nl()
2670                                                  2387 
2671     hdr_file=os.path.basename(args.out_file[: << 
2672                                               << 
2673     if args.mode == 'kernel':                    2388     if args.mode == 'kernel':
2674         cw.p('#include <net/netlink.h>')         2389         cw.p('#include <net/netlink.h>')
2675         cw.p('#include <net/genetlink.h>')       2390         cw.p('#include <net/genetlink.h>')
2676         cw.nl()                                  2391         cw.nl()
2677         if not args.header:                      2392         if not args.header:
2678             if args.out_file:                    2393             if args.out_file:
2679                 cw.p(f'#include "{hdr_file}"' !! 2394                 cw.p(f'#include "{os.path.basename(args.out_file[:-2])}.h"')
2680             cw.nl()                              2395             cw.nl()
2681         headers = ['uapi/' + parsed.uapi_head    2396         headers = ['uapi/' + parsed.uapi_header]
2682         headers += parsed.kernel_family.get(' << 
2683     else:                                        2397     else:
2684         cw.p('#include <stdlib.h>')              2398         cw.p('#include <stdlib.h>')
2685         cw.p('#include <string.h>')              2399         cw.p('#include <string.h>')
2686         if args.header:                          2400         if args.header:
2687             cw.p('#include <linux/types.h>')     2401             cw.p('#include <linux/types.h>')
2688             if family_contains_bitfield32(par << 
2689                 cw.p('#include <linux/netlink << 
2690         else:                                    2402         else:
2691             cw.p(f'#include "{hdr_file}"')    !! 2403             cw.p(f'#include "{parsed.name}-user.h"')
2692             cw.p('#include "ynl.h"')             2404             cw.p('#include "ynl.h"')
2693         headers = [parsed.uapi_header]           2405         headers = [parsed.uapi_header]
2694     for definition in parsed['definitions']:     2406     for definition in parsed['definitions']:
2695         if 'header' in definition:               2407         if 'header' in definition:
2696             headers.append(definition['header    2408             headers.append(definition['header'])
2697     for one in headers:                          2409     for one in headers:
2698         cw.p(f"#include <{one}>")                2410         cw.p(f"#include <{one}>")
2699     cw.nl()                                      2411     cw.nl()
2700                                                  2412 
2701     if args.mode == "user":                      2413     if args.mode == "user":
2702         if not args.header:                      2414         if not args.header:
                                                   >> 2415             cw.p("#include <libmnl/libmnl.h>")
2703             cw.p("#include <linux/genetlink.h    2416             cw.p("#include <linux/genetlink.h>")
2704             cw.nl()                              2417             cw.nl()
2705             for one in args.user_header:         2418             for one in args.user_header:
2706                 cw.p(f'#include "{one}"')        2419                 cw.p(f'#include "{one}"')
2707         else:                                    2420         else:
2708             cw.p('struct ynl_sock;')             2421             cw.p('struct ynl_sock;')
2709             cw.nl()                              2422             cw.nl()
2710             render_user_family(parsed, cw, Tr    2423             render_user_family(parsed, cw, True)
2711         cw.nl()                                  2424         cw.nl()
2712                                                  2425 
2713     if args.mode == "kernel":                    2426     if args.mode == "kernel":
2714         if args.header:                          2427         if args.header:
2715             for _, struct in sorted(parsed.pu    2428             for _, struct in sorted(parsed.pure_nested_structs.items()):
2716                 if struct.request:               2429                 if struct.request:
2717                     cw.p('/* Common nested ty    2430                     cw.p('/* Common nested types */')
2718                     break                        2431                     break
2719             for attr_set, struct in sorted(pa    2432             for attr_set, struct in sorted(parsed.pure_nested_structs.items()):
2720                 if struct.request:               2433                 if struct.request:
2721                     print_req_policy_fwd(cw,     2434                     print_req_policy_fwd(cw, struct)
2722             cw.nl()                              2435             cw.nl()
2723                                                  2436 
2724             if parsed.kernel_policy == 'globa    2437             if parsed.kernel_policy == 'global':
2725                 cw.p(f"/* Global operation po    2438                 cw.p(f"/* Global operation policy for {parsed.name} */")
2726                                                  2439 
2727                 struct = Struct(parsed, parse    2440                 struct = Struct(parsed, parsed.global_policy_set, type_list=parsed.global_policy)
2728                 print_req_policy_fwd(cw, stru    2441                 print_req_policy_fwd(cw, struct)
2729                 cw.nl()                          2442                 cw.nl()
2730                                                  2443 
2731             if parsed.kernel_policy in {'per-    2444             if parsed.kernel_policy in {'per-op', 'split'}:
2732                 for op_name, op in parsed.ops    2445                 for op_name, op in parsed.ops.items():
2733                     if 'do' in op and 'event'    2446                     if 'do' in op and 'event' not in op:
2734                         ri = RenderInfo(cw, p    2447                         ri = RenderInfo(cw, parsed, args.mode, op, "do")
2735                         print_req_policy_fwd(    2448                         print_req_policy_fwd(cw, ri.struct['request'], ri=ri)
2736                         cw.nl()                  2449                         cw.nl()
2737                                                  2450 
2738             print_kernel_op_table_hdr(parsed,    2451             print_kernel_op_table_hdr(parsed, cw)
2739             print_kernel_mcgrp_hdr(parsed, cw    2452             print_kernel_mcgrp_hdr(parsed, cw)
2740             print_kernel_family_struct_hdr(pa    2453             print_kernel_family_struct_hdr(parsed, cw)
2741         else:                                    2454         else:
2742             print_kernel_policy_ranges(parsed << 
2743                                               << 
2744             for _, struct in sorted(parsed.pu    2455             for _, struct in sorted(parsed.pure_nested_structs.items()):
2745                 if struct.request:               2456                 if struct.request:
2746                     cw.p('/* Common nested ty    2457                     cw.p('/* Common nested types */')
2747                     break                        2458                     break
2748             for attr_set, struct in sorted(pa    2459             for attr_set, struct in sorted(parsed.pure_nested_structs.items()):
2749                 if struct.request:               2460                 if struct.request:
2750                     print_req_policy(cw, stru    2461                     print_req_policy(cw, struct)
2751             cw.nl()                              2462             cw.nl()
2752                                                  2463 
2753             if parsed.kernel_policy == 'globa    2464             if parsed.kernel_policy == 'global':
2754                 cw.p(f"/* Global operation po    2465                 cw.p(f"/* Global operation policy for {parsed.name} */")
2755                                                  2466 
2756                 struct = Struct(parsed, parse    2467                 struct = Struct(parsed, parsed.global_policy_set, type_list=parsed.global_policy)
2757                 print_req_policy(cw, struct)     2468                 print_req_policy(cw, struct)
2758                 cw.nl()                          2469                 cw.nl()
2759                                                  2470 
2760             for op_name, op in parsed.ops.ite    2471             for op_name, op in parsed.ops.items():
2761                 if parsed.kernel_policy in {'    2472                 if parsed.kernel_policy in {'per-op', 'split'}:
2762                     for op_mode in ['do', 'du    2473                     for op_mode in ['do', 'dump']:
2763                         if op_mode in op and     2474                         if op_mode in op and 'request' in op[op_mode]:
2764                             cw.p(f"/* {op.enu    2475                             cw.p(f"/* {op.enum_name} - {op_mode} */")
2765                             ri = RenderInfo(c    2476                             ri = RenderInfo(cw, parsed, args.mode, op, op_mode)
2766                             print_req_policy(    2477                             print_req_policy(cw, ri.struct['request'], ri=ri)
2767                             cw.nl()              2478                             cw.nl()
2768                                                  2479 
2769             print_kernel_op_table(parsed, cw)    2480             print_kernel_op_table(parsed, cw)
2770             print_kernel_mcgrp_src(parsed, cw    2481             print_kernel_mcgrp_src(parsed, cw)
2771             print_kernel_family_struct_src(pa    2482             print_kernel_family_struct_src(parsed, cw)
2772                                                  2483 
2773     if args.mode == "user":                      2484     if args.mode == "user":
2774         if args.header:                          2485         if args.header:
2775             cw.p('/* Enums */')                  2486             cw.p('/* Enums */')
2776             put_op_name_fwd(parsed, cw)          2487             put_op_name_fwd(parsed, cw)
2777                                                  2488 
2778             for name, const in parsed.consts.    2489             for name, const in parsed.consts.items():
2779                 if isinstance(const, EnumSet)    2490                 if isinstance(const, EnumSet):
2780                     put_enum_to_str_fwd(parse    2491                     put_enum_to_str_fwd(parsed, cw, const)
2781             cw.nl()                              2492             cw.nl()
2782                                                  2493 
2783             cw.p('/* Common nested types */')    2494             cw.p('/* Common nested types */')
2784             for attr_set, struct in parsed.pu    2495             for attr_set, struct in parsed.pure_nested_structs.items():
2785                 ri = RenderInfo(cw, parsed, a    2496                 ri = RenderInfo(cw, parsed, args.mode, "", "", attr_set)
2786                 print_type_full(ri, struct)      2497                 print_type_full(ri, struct)
2787                                                  2498 
2788             for op_name, op in parsed.ops.ite    2499             for op_name, op in parsed.ops.items():
2789                 cw.p(f"/* ============== {op.    2500                 cw.p(f"/* ============== {op.enum_name} ============== */")
2790                                                  2501 
2791                 if 'do' in op and 'event' not    2502                 if 'do' in op and 'event' not in op:
2792                     cw.p(f"/* {op.enum_name}     2503                     cw.p(f"/* {op.enum_name} - do */")
2793                     ri = RenderInfo(cw, parse    2504                     ri = RenderInfo(cw, parsed, args.mode, op, "do")
2794                     print_req_type(ri)           2505                     print_req_type(ri)
2795                     print_req_type_helpers(ri    2506                     print_req_type_helpers(ri)
2796                     cw.nl()                      2507                     cw.nl()
2797                     print_rsp_type(ri)           2508                     print_rsp_type(ri)
2798                     print_rsp_type_helpers(ri    2509                     print_rsp_type_helpers(ri)
2799                     cw.nl()                      2510                     cw.nl()
2800                     print_req_prototype(ri)      2511                     print_req_prototype(ri)
2801                     cw.nl()                      2512                     cw.nl()
2802                                                  2513 
2803                 if 'dump' in op:                 2514                 if 'dump' in op:
2804                     cw.p(f"/* {op.enum_name}     2515                     cw.p(f"/* {op.enum_name} - dump */")
2805                     ri = RenderInfo(cw, parse    2516                     ri = RenderInfo(cw, parsed, args.mode, op, 'dump')
2806                     print_req_type(ri)        !! 2517                     if 'request' in op['dump']:
2807                     print_req_type_helpers(ri !! 2518                         print_req_type(ri)
                                                   >> 2519                         print_req_type_helpers(ri)
2808                     if not ri.type_consistent    2520                     if not ri.type_consistent:
2809                         print_rsp_type(ri)       2521                         print_rsp_type(ri)
2810                     print_wrapped_type(ri)       2522                     print_wrapped_type(ri)
2811                     print_dump_prototype(ri)     2523                     print_dump_prototype(ri)
2812                     cw.nl()                      2524                     cw.nl()
2813                                                  2525 
2814                 if op.has_ntf:                   2526                 if op.has_ntf:
2815                     cw.p(f"/* {op.enum_name}     2527                     cw.p(f"/* {op.enum_name} - notify */")
2816                     ri = RenderInfo(cw, parse    2528                     ri = RenderInfo(cw, parsed, args.mode, op, 'notify')
2817                     if not ri.type_consistent    2529                     if not ri.type_consistent:
2818                         raise Exception(f'Onl    2530                         raise Exception(f'Only notifications with consistent types supported ({op.name})')
2819                     print_wrapped_type(ri)       2531                     print_wrapped_type(ri)
2820                                                  2532 
2821             for op_name, op in parsed.ntfs.it    2533             for op_name, op in parsed.ntfs.items():
2822                 if 'event' in op:                2534                 if 'event' in op:
2823                     ri = RenderInfo(cw, parse    2535                     ri = RenderInfo(cw, parsed, args.mode, op, 'event')
2824                     cw.p(f"/* {op.enum_name}     2536                     cw.p(f"/* {op.enum_name} - event */")
2825                     print_rsp_type(ri)           2537                     print_rsp_type(ri)
2826                     cw.nl()                      2538                     cw.nl()
2827                     print_wrapped_type(ri)       2539                     print_wrapped_type(ri)
2828             cw.nl()                              2540             cw.nl()
2829         else:                                    2541         else:
2830             cw.p('/* Enums */')                  2542             cw.p('/* Enums */')
2831             put_op_name(parsed, cw)              2543             put_op_name(parsed, cw)
2832                                                  2544 
2833             for name, const in parsed.consts.    2545             for name, const in parsed.consts.items():
2834                 if isinstance(const, EnumSet)    2546                 if isinstance(const, EnumSet):
2835                     put_enum_to_str(parsed, c    2547                     put_enum_to_str(parsed, cw, const)
2836             cw.nl()                              2548             cw.nl()
2837                                                  2549 
2838             has_recursive_nests = False       << 
2839             cw.p('/* Policies */')               2550             cw.p('/* Policies */')
2840             for struct in parsed.pure_nested_ << 
2841                 if struct.recursive:          << 
2842                     put_typol_fwd(cw, struct) << 
2843                     has_recursive_nests = Tru << 
2844             if has_recursive_nests:           << 
2845                 cw.nl()                       << 
2846             for name in parsed.pure_nested_st    2551             for name in parsed.pure_nested_structs:
2847                 struct = Struct(parsed, name)    2552                 struct = Struct(parsed, name)
2848                 put_typol(cw, struct)            2553                 put_typol(cw, struct)
2849             for name in parsed.root_sets:        2554             for name in parsed.root_sets:
2850                 struct = Struct(parsed, name)    2555                 struct = Struct(parsed, name)
2851                 put_typol(cw, struct)            2556                 put_typol(cw, struct)
2852                                                  2557 
2853             cw.p('/* Common nested types */')    2558             cw.p('/* Common nested types */')
2854             if has_recursive_nests:           << 
2855                 for attr_set, struct in parse << 
2856                     ri = RenderInfo(cw, parse << 
2857                     free_rsp_nested_prototype << 
2858                     if struct.request:        << 
2859                         put_req_nested_protot << 
2860                     if struct.reply:          << 
2861                         parse_rsp_nested_prot << 
2862                 cw.nl()                       << 
2863             for attr_set, struct in parsed.pu    2559             for attr_set, struct in parsed.pure_nested_structs.items():
2864                 ri = RenderInfo(cw, parsed, a    2560                 ri = RenderInfo(cw, parsed, args.mode, "", "", attr_set)
2865                                                  2561 
2866                 free_rsp_nested(ri, struct)      2562                 free_rsp_nested(ri, struct)
2867                 if struct.request:               2563                 if struct.request:
2868                     put_req_nested(ri, struct    2564                     put_req_nested(ri, struct)
2869                 if struct.reply:                 2565                 if struct.reply:
2870                     parse_rsp_nested(ri, stru    2566                     parse_rsp_nested(ri, struct)
2871                                                  2567 
2872             for op_name, op in parsed.ops.ite    2568             for op_name, op in parsed.ops.items():
2873                 cw.p(f"/* ============== {op.    2569                 cw.p(f"/* ============== {op.enum_name} ============== */")
2874                 if 'do' in op and 'event' not    2570                 if 'do' in op and 'event' not in op:
2875                     cw.p(f"/* {op.enum_name}     2571                     cw.p(f"/* {op.enum_name} - do */")
2876                     ri = RenderInfo(cw, parse    2572                     ri = RenderInfo(cw, parsed, args.mode, op, "do")
2877                     print_req_free(ri)           2573                     print_req_free(ri)
2878                     print_rsp_free(ri)           2574                     print_rsp_free(ri)
2879                     parse_rsp_msg(ri)            2575                     parse_rsp_msg(ri)
2880                     print_req(ri)                2576                     print_req(ri)
2881                     cw.nl()                      2577                     cw.nl()
2882                                                  2578 
2883                 if 'dump' in op:                 2579                 if 'dump' in op:
2884                     cw.p(f"/* {op.enum_name}     2580                     cw.p(f"/* {op.enum_name} - dump */")
2885                     ri = RenderInfo(cw, parse    2581                     ri = RenderInfo(cw, parsed, args.mode, op, "dump")
2886                     if not ri.type_consistent    2582                     if not ri.type_consistent:
2887                         parse_rsp_msg(ri, der    2583                         parse_rsp_msg(ri, deref=True)
2888                     print_req_free(ri)        << 
2889                     print_dump_type_free(ri)     2584                     print_dump_type_free(ri)
2890                     print_dump(ri)               2585                     print_dump(ri)
2891                     cw.nl()                      2586                     cw.nl()
2892                                                  2587 
2893                 if op.has_ntf:                   2588                 if op.has_ntf:
2894                     cw.p(f"/* {op.enum_name}     2589                     cw.p(f"/* {op.enum_name} - notify */")
2895                     ri = RenderInfo(cw, parse    2590                     ri = RenderInfo(cw, parsed, args.mode, op, 'notify')
2896                     if not ri.type_consistent    2591                     if not ri.type_consistent:
2897                         raise Exception(f'Onl    2592                         raise Exception(f'Only notifications with consistent types supported ({op.name})')
2898                     print_ntf_type_free(ri)      2593                     print_ntf_type_free(ri)
2899                                                  2594 
2900             for op_name, op in parsed.ntfs.it    2595             for op_name, op in parsed.ntfs.items():
2901                 if 'event' in op:                2596                 if 'event' in op:
2902                     cw.p(f"/* {op.enum_name}     2597                     cw.p(f"/* {op.enum_name} - event */")
2903                                                  2598 
2904                     ri = RenderInfo(cw, parse    2599                     ri = RenderInfo(cw, parsed, args.mode, op, "do")
2905                     parse_rsp_msg(ri)            2600                     parse_rsp_msg(ri)
2906                                                  2601 
2907                     ri = RenderInfo(cw, parse    2602                     ri = RenderInfo(cw, parsed, args.mode, op, "event")
2908                     print_ntf_type_free(ri)      2603                     print_ntf_type_free(ri)
2909             cw.nl()                              2604             cw.nl()
2910             render_user_family(parsed, cw, Fa    2605             render_user_family(parsed, cw, False)
2911                                                  2606 
2912     if args.header:                              2607     if args.header:
2913         cw.p(f'#endif /* {hdr_prot} */')         2608         cw.p(f'#endif /* {hdr_prot} */')
2914                                                  2609 
2915                                                  2610 
2916 if __name__ == "__main__":                       2611 if __name__ == "__main__":
2917     main()                                       2612     main()
                                                      

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php