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