~ [ 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.4.16)


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