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