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()
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.