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