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


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