@@ -225,10 +225,11 @@ def _attr_policy(self, policy):
225225 return '{ .type = ' + policy + ', }'
226226
227227 def attr_policy (self , cw ):
228- policy = f'NLA_{ c_upper (self .type )} '
228+ policy_type = self .attr .get ('nla-policy-type' , self .type )
229+ policy = f'NLA_{ c_upper (policy_type )} '
229230 if self .attr .get ('byte-order' ) == 'big-endian' :
230- if self . type in {'u16' , 'u32' }:
231- policy = f'NLA_BE{ self . type [1 :]} '
231+ if policy_type in {'u16' , 'u32' }:
232+ policy = f'NLA_BE{ policy_type [1 :]} '
232233
233234 spec = self ._attr_policy (policy )
234235 cw .p (f"\t [{ self .enum_name } ] = { spec } ," )
@@ -3415,6 +3416,255 @@ def find_kernel_root(full_path):
34153416 return full_path , sub_path [:- 1 ]
34163417
34173418
3419+ def _struct_c_type (attr_type ):
3420+ """Map YNL attribute type to C type for struct field declarations."""
3421+ type_map = {
3422+ 'u8' : 'unsigned char' , 'u16' : '__u16' , 'u32' : '__u32' , 'u64' : '__u64' ,
3423+ 's8' : '__s8' , 's16' : '__s16' , 's32' : '__s32' , 's64' : '__s64' ,
3424+ }
3425+ return type_map .get (attr_type )
3426+
3427+
3428+ def _nested_attr_sets (family ):
3429+ """Yield (name, attr_set) for non-root attr-sets in spec order.
3430+
3431+ The root attr-set (same name as family) contains nest-type attributes
3432+ that point to the nested sets. Only the nested sets have scalar/array
3433+ fields that translate to struct members.
3434+ """
3435+ root_name = family ['name' ]
3436+ for name , attr_set in family .attr_sets .items ():
3437+ if name == root_name or attr_set .subset_of :
3438+ continue
3439+ yield name , attr_set
3440+
3441+
3442+ def render_struct_decl (family , cw ):
3443+ """Generate C struct declarations from nested attribute sets."""
3444+ for set_name , attr_set in _nested_attr_sets (family ):
3445+ s_name = c_lower (set_name )
3446+ cw .p (f"struct { s_name } {{" )
3447+ for _ , attr in attr_set .items ():
3448+ c_name = c_lower (attr .name )
3449+ c_type = _struct_c_type (attr ['type' ])
3450+ if c_type :
3451+ cw .p (f"\t { c_type } { c_name } ;" )
3452+ elif attr ['type' ] in ('string' , 'binary' ):
3453+ maxlen = attr .get ('checks' , {}).get ('max-len' , 0 )
3454+ cw .p (f"\t char { c_name } [{ maxlen } ];" )
3455+ cw .p (f"\t __u32 { c_name } _len;" )
3456+ cw .p ('};' )
3457+ cw .nl ()
3458+
3459+
3460+ def _nla_get_fn (attr_type ):
3461+ """Return the nla_get function name for a scalar type."""
3462+ fn_map = {
3463+ 'u8' : 'nla_get_u8' , 'u16' : 'nla_get_u16' ,
3464+ 'u32' : 'nla_get_u32' , 'u64' : 'nla_get_u64' ,
3465+ 's8' : 'nla_get_s8' , 's16' : 'nla_get_s16' ,
3466+ 's32' : 'nla_get_s32' , 's64' : 'nla_get_s64' ,
3467+ }
3468+ return fn_map .get (attr_type )
3469+
3470+
3471+ def _nla_put_fn (attr_type ):
3472+ """Return (function_name, extra_args) for a scalar nla_put."""
3473+ fn_map = {
3474+ 'u8' : ('nla_put_u8' , '' ),
3475+ 'u16' : ('nla_put_u16' , '' ),
3476+ 'u32' : ('nla_put_u32' , '' ),
3477+ 'u64' : ('nla_put_u64_64bit' , ', 0' ),
3478+ 's8' : ('nla_put_s8' , '' ),
3479+ 's16' : ('nla_put_s16' , '' ),
3480+ 's32' : ('nla_put_s32' , '' ),
3481+ 's64' : ('nla_put_s64' , '' ),
3482+ }
3483+ return fn_map .get (attr_type )
3484+
3485+
3486+ def render_from_attrs (family , cw ):
3487+ """Generate from_attrs() deserialization functions."""
3488+ root_set = family .attr_sets .get (family ['name' ])
3489+
3490+ for set_name , attr_set in _nested_attr_sets (family ):
3491+ s_name = c_lower (set_name )
3492+ struct = family .pure_nested_structs .get (set_name )
3493+ if not struct or not struct .request :
3494+ continue
3495+ tla_name = None
3496+ if root_set :
3497+ for _ , tla_attr in root_set .items ():
3498+ if tla_attr .attr .get ('nested-attributes' ) == set_name :
3499+ tla_name = tla_attr .enum_name
3500+ break
3501+ if tla_name is None :
3502+ continue
3503+
3504+ policy_name = f"{ struct .render_name } _nl_policy"
3505+ max_attr = struct .attr_max_val .enum_name
3506+ cw .p (f"static int __{ s_name } _from_attrs(struct { s_name } *s," )
3507+ cw .p (f"\t \t struct nlattr ***ret_nested_attribute_table," )
3508+ cw .p (f"\t \t struct genl_info *info)" )
3509+ cw .block_start ()
3510+ cw .p (f"const int maxtype = { max_attr } ;" )
3511+ cw .p (f"struct nlattr *tla = info->attrs[{ tla_name } ];" )
3512+ cw .p ('struct nlattr **ntb;' )
3513+ cw .p ('struct nlattr *nla;' )
3514+ cw .p ('int err = 0;' )
3515+ cw .nl ()
3516+ cw .p ('if (ret_nested_attribute_table)' )
3517+ cw .p ('*ret_nested_attribute_table = NULL;' )
3518+ cw .p ('if (!tla)' )
3519+ cw .p ('return -ENOMSG;' )
3520+ cw .p (f"ntb = kcalloc({ max_attr } + 1, sizeof(*ntb), GFP_KERNEL);" )
3521+ cw .p ('if (!ntb)' )
3522+ cw .p ('return -ENOMEM;' )
3523+ cw .p (f"err = nla_parse_nested_deprecated(ntb, maxtype, tla, { policy_name } , NULL);" )
3524+ cw .p ('if (err)' )
3525+ cw .p ('goto out;' )
3526+ cw .nl ()
3527+
3528+ for _ , attr in attr_set .items ():
3529+ c_name = c_lower (attr .name )
3530+ is_required = attr .attr .get ('required' , False )
3531+ get_fn = _nla_get_fn (attr ['type' ])
3532+
3533+ cw .p (f"nla = ntb[{ attr .enum_name } ];" )
3534+ if is_required :
3535+ cw .block_start (line = 'if (nla)' )
3536+ if get_fn :
3537+ cw .p ('if (s)' )
3538+ cw .p (f"s->{ c_name } = { get_fn } (nla);" )
3539+ elif attr ['type' ] == 'string' :
3540+ maxlen = attr .get ('checks' , {}).get ('max-len' , 0 )
3541+ cw .p ('if (s)' )
3542+ cw .p (f"s->{ c_name } _len = nla_strscpy(s->{ c_name } , nla, { maxlen } );" )
3543+ elif attr ['type' ] == 'binary' :
3544+ maxlen = attr .get ('checks' , {}).get ('max-len' , 0 )
3545+ cw .p ('if (s)' )
3546+ cw .p (f"s->{ c_name } _len = nla_memcpy(s->{ c_name } , nla, { maxlen } );" )
3547+ cw .block_end ()
3548+ cw .block_start (line = 'else' )
3549+ cw .p (f'pr_info("<< missing required attr: { c_name } \\ n");' )
3550+ cw .p ('err = -ENOMSG;' )
3551+ cw .block_end ()
3552+ else :
3553+ if get_fn :
3554+ cw .p ('if (nla && s)' )
3555+ cw .p (f"s->{ c_name } = { get_fn } (nla);" )
3556+ elif attr ['type' ] == 'string' :
3557+ maxlen = attr .get ('checks' , {}).get ('max-len' , 0 )
3558+ cw .p ('if (nla && s)' )
3559+ cw .p (f"s->{ c_name } _len = nla_strscpy(s->{ c_name } , nla, { maxlen } );" )
3560+ elif attr ['type' ] == 'binary' :
3561+ maxlen = attr .get ('checks' , {}).get ('max-len' , 0 )
3562+ cw .p ('if (nla && s)' )
3563+ cw .p (f"s->{ c_name } _len = nla_memcpy(s->{ c_name } , nla, { maxlen } );" )
3564+ cw .nl ()
3565+
3566+ cw .p ('out:' )
3567+ cw .p ('if (ret_nested_attribute_table && (!err || err == -ENOMSG))' )
3568+ cw .p ('*ret_nested_attribute_table = ntb;' )
3569+ cw .p ('else' )
3570+ cw .p ('kfree(ntb);' )
3571+ cw .p ('return err;' )
3572+ cw .block_end ()
3573+ cw .nl ()
3574+
3575+ cw .p (f"int { s_name } _from_attrs(struct { s_name } *s," )
3576+ cw .p (f"\t \t \t \t struct genl_info *info)" )
3577+ cw .block_start ()
3578+ cw .p (f"return __{ s_name } _from_attrs(s, NULL, info);" )
3579+ cw .block_end ()
3580+ cw .nl ()
3581+
3582+ cw .p (f"int { s_name } _ntb_from_attrs(" )
3583+ cw .p (f"\t \t \t struct nlattr ***ret_nested_attribute_table," )
3584+ cw .p (f"\t \t \t struct genl_info *info)" )
3585+ cw .block_start ()
3586+ cw .p (f"return __{ s_name } _from_attrs(NULL, ret_nested_attribute_table, info);" )
3587+ cw .block_end ()
3588+ cw .nl ()
3589+
3590+
3591+ def render_to_skb (family , cw ):
3592+ """Generate to_skb() serialization functions."""
3593+ root_set = family .attr_sets .get (family ['name' ])
3594+
3595+ for set_name , attr_set in _nested_attr_sets (family ):
3596+ s_name = c_lower (set_name )
3597+ tla_name = None
3598+ if root_set :
3599+ for _ , tla_attr in root_set .items ():
3600+ if tla_attr .attr .get ('nested-attributes' ) == set_name :
3601+ tla_name = tla_attr .enum_name
3602+ break
3603+ if tla_name is None :
3604+ continue
3605+
3606+ cw .p (f"int { s_name } _to_skb(struct sk_buff *skb, struct { s_name } *s)" )
3607+ cw .block_start ()
3608+ cw .p (f"struct nlattr *tla = nla_nest_start(skb, { tla_name } );" )
3609+ cw .nl ()
3610+ cw .p ('if (!tla)' )
3611+ cw .p ('goto nla_put_failure;' )
3612+ cw .nl ()
3613+
3614+ for _ , attr in attr_set .items ():
3615+ c_name = c_lower (attr .name )
3616+ put = _nla_put_fn (attr ['type' ])
3617+
3618+ if put :
3619+ fn , extra = put
3620+ cw .p (f"if ({ fn } (skb, { attr .enum_name } , s->{ c_name } { extra } ))" )
3621+ cw .p ('goto nla_put_failure;' )
3622+ elif attr ['type' ] in ('string' , 'binary' ):
3623+ maxlen = attr .get ('checks' , {}).get ('max-len' , 0 )
3624+ nul_adj = f" + (s->{ c_name } _len < { maxlen } )" if attr ['type' ] == 'string' else ''
3625+ cw .p (f"if (nla_put(skb, { attr .enum_name } , min_t(int, { maxlen } ," )
3626+ cw .p (f"\t \t s->{ c_name } _len{ nul_adj } ), s->{ c_name } ))" )
3627+ cw .p ('goto nla_put_failure;' , add_ind = 1 )
3628+
3629+ cw .nl ()
3630+ cw .p ('nla_nest_end(skb, tla);' )
3631+ cw .p ('return 0;' )
3632+ cw .nl ()
3633+ cw .p ('nla_put_failure:' )
3634+ cw .p ('if (tla)' )
3635+ cw .p ('nla_nest_cancel(skb, tla);' )
3636+ cw .p ('return -EMSGSIZE;' )
3637+ cw .block_end ()
3638+ cw .nl ()
3639+
3640+
3641+ def render_set_defaults (family , cw ):
3642+ """Generate set_defaults() initialization functions."""
3643+ for set_name , attr_set in _nested_attr_sets (family ):
3644+ s_name = c_lower (set_name )
3645+ has_defaults = any (
3646+ 'default' in attr .attr for _ , attr in attr_set .items ()
3647+ )
3648+ if not has_defaults :
3649+ continue
3650+
3651+ cw .p (f"void set_{ s_name } _defaults(struct { s_name } *x)" )
3652+ cw .block_start ()
3653+ for _ , attr in attr_set .items ():
3654+ c_name = c_lower (attr .name )
3655+ default = attr .attr .get ('default' )
3656+ if default is None :
3657+ continue
3658+
3659+ if attr ['type' ] in ('string' , 'binary' ):
3660+ cw .p (f"memset(x->{ c_name } , 0, sizeof(x->{ c_name } ));" )
3661+ cw .p (f"x->{ c_name } _len = 0;" )
3662+ else :
3663+ cw .p (f"x->{ c_name } = { default } ;" )
3664+ cw .block_end ()
3665+ cw .nl ()
3666+
3667+
34183668def main ():
34193669 parser = argparse .ArgumentParser (description = 'Netlink simple parsing generator' )
34203670 parser .add_argument ('--mode' , dest = 'mode' , type = str , required = True ,
@@ -3487,6 +3737,9 @@ def main():
34873737 cw .p ('#include <net/genetlink.h>' )
34883738 cw .nl ()
34893739 if not args .header :
3740+ if parsed .kernel_family .get ('emit-structs' ):
3741+ cw .p ('#include <linux/kernel.h>' )
3742+ cw .p ('#include <linux/slab.h>' )
34903743 if args .out_file :
34913744 cw .p (f'#include "{ hdr_file } "' )
34923745 cw .nl ()
@@ -3555,6 +3808,31 @@ def main():
35553808 print_kernel_op_table_hdr (parsed , cw )
35563809 print_kernel_mcgrp_hdr (parsed , cw )
35573810 print_kernel_family_struct_hdr (parsed , cw )
3811+
3812+ if parsed .kernel_family .get ('emit-structs' ):
3813+ cw .nl ()
3814+ render_struct_decl (parsed , cw )
3815+ # Function prototypes
3816+ root_set = parsed .attr_sets .get (parsed ['name' ])
3817+ for set_name , attr_set in _nested_attr_sets (parsed ):
3818+ s_name = c_lower (set_name )
3819+ struct = parsed .pure_nested_structs .get (set_name )
3820+ has_tla = False
3821+ if root_set :
3822+ for _ , tla_attr in root_set .items ():
3823+ if tla_attr .attr .get ('nested-attributes' ) == set_name :
3824+ has_tla = True
3825+ break
3826+ if not has_tla :
3827+ continue
3828+ if struct and struct .request :
3829+ cw .p (f"int { s_name } _from_attrs(struct { s_name } *s, struct genl_info *info);" )
3830+ cw .p (f"int { s_name } _ntb_from_attrs(struct nlattr ***ret_nested_attribute_table, struct genl_info *info);" )
3831+ cw .p (f"int { s_name } _to_skb(struct sk_buff *skb, struct { s_name } *s);" )
3832+ has_defaults = any ('default' in a .attr for _ , a in attr_set .items ())
3833+ if has_defaults :
3834+ cw .p (f"void set_{ s_name } _defaults(struct { s_name } *x);" )
3835+ cw .nl ()
35583836 else :
35593837 print_kernel_policy_ranges (parsed , cw )
35603838 print_kernel_policy_sparse_enum_validates (parsed , cw )
@@ -3588,6 +3866,15 @@ def main():
35883866 print_kernel_mcgrp_src (parsed , cw )
35893867 print_kernel_family_struct_src (parsed , cw )
35903868
3869+ if parsed .kernel_family .get ('emit-structs' ):
3870+ cw .nl ()
3871+ render_from_attrs (parsed , cw )
3872+ render_to_skb (parsed , cw )
3873+ render_set_defaults (parsed , cw )
3874+ if cw ._block_end :
3875+ cw ._block_end = False
3876+ cw ._out .write ('}\n ' )
3877+
35913878 if args .mode == "user" :
35923879 if args .header :
35933880 cw .p ('/* Enums */' )
0 commit comments