/** * netlink_policy_dump_get_policy_idx - retrieve policy index * @state: the policy dump state * @policy: the policy to find * @maxtype: the policy's maxattr * * Returns: the index of the given policy in the dump state * * Call this to find a policy index when you've added multiple and e.g. * need to tell userspace which command has which policy (by index). * * Note: this will WARN and return 0 if the policy isn't found, which * means it wasn't added in the first place, which would be an * internal consistency bug.
*/ int netlink_policy_dump_get_policy_idx(struct netlink_policy_dump_state *state, conststruct nla_policy *policy, unsignedint maxtype)
{ unsignedint i;
if (WARN_ON(!policy || !maxtype)) return 0;
for (i = 0; i < state->n_alloc; i++) { if (state->policies[i].policy == policy &&
state->policies[i].maxtype == maxtype) return i;
}
state = kzalloc(struct_size(state, policies, INITIAL_POLICIES_ALLOC),
GFP_KERNEL); if (!state) return ERR_PTR(-ENOMEM);
state->n_alloc = INITIAL_POLICIES_ALLOC;
return state;
}
/** * netlink_policy_dump_add_policy - add a policy to the dump * @pstate: state to add to, may be reallocated, must be %NULL the first time * @policy: the new policy to add to the dump * @maxtype: the new policy's max attr type * * Returns: 0 on success, a negative error code otherwise. * * Call this to allocate a policy dump state, and to add policies to it. This * should be called from the dump start() callback. * * Note: on failures, any previously allocated state is freed.
*/ int netlink_policy_dump_add_policy(struct netlink_policy_dump_state **pstate, conststruct nla_policy *policy, unsignedint maxtype)
{ struct netlink_policy_dump_state *state = *pstate; unsignedint policy_idx; int err;
if (!state) {
state = alloc_state(); if (IS_ERR(state)) return PTR_ERR(state);
}
/* * walk the policies and nested ones first, and build * a linear list of them.
*/
err = add_policy(&state, policy, maxtype); if (err) goto err_try_undo;
for (type = 0;
type <= state->policies[policy_idx].maxtype;
type++) { switch (policy[type].type) { case NLA_NESTED: case NLA_NESTED_ARRAY:
err = add_policy(&state,
policy[type].nested_policy,
policy[type].len); if (err) goto err_try_undo; break; default: break;
}
}
}
*pstate = state; return 0;
err_try_undo: /* Try to preserve reasonable unwind semantics - if we're starting from * scratch clean up fully, otherwise record what we got and caller will.
*/ if (!*pstate)
netlink_policy_dump_free(state); else
*pstate = state; return err;
}
/** * netlink_policy_dump_loop - dumping loop indicator * @state: the policy dump state * * Returns: %true if the dump continues, %false otherwise * * Note: this frees the dump state when finishing
*/ bool netlink_policy_dump_loop(struct netlink_policy_dump_state *state)
{ return !netlink_policy_dump_finished(state);
}
int netlink_policy_dump_attr_size_estimate(conststruct nla_policy *pt)
{ /* nested + type */ int common = 2 * nla_attr_size(sizeof(u32));
switch (pt->type) { case NLA_UNSPEC: case NLA_REJECT: /* these actually don't need any space */ return 0; case NLA_NESTED: case NLA_NESTED_ARRAY: /* common, policy idx, policy maxattr */ return common + 2 * nla_attr_size(sizeof(u32)); case NLA_U8: case NLA_U16: case NLA_U32: case NLA_U64: case NLA_MSECS: case NLA_S8: case NLA_S16: case NLA_S32: case NLA_S64: case NLA_SINT: case NLA_UINT: /* maximum is common, u64 min/max with padding */ return common +
2 * (nla_attr_size(0) + nla_attr_size(sizeof(u64))); case NLA_BITFIELD32: return common + nla_attr_size(sizeof(u32)); case NLA_STRING: case NLA_NUL_STRING: case NLA_BINARY: /* maximum is common, u32 min-length/max-length */ return common + 2 * nla_attr_size(sizeof(u32)); case NLA_FLAG: return common;
}
/* this should then cause a warning later */ return 0;
}
attr = nla_nest_start(skb, nestattr); if (!attr) return -ENOBUFS;
switch (pt->type) { default: case NLA_UNSPEC: case NLA_REJECT: /* skip - use NLA_MIN_LEN to advertise such */
nla_nest_cancel(skb, attr); return -ENODATA; case NLA_NESTED:
type = NL_ATTR_TYPE_NESTED;
fallthrough; case NLA_NESTED_ARRAY: if (pt->type == NLA_NESTED_ARRAY)
type = NL_ATTR_TYPE_NESTED_ARRAY; if (state && pt->nested_policy && pt->len &&
(nla_put_u32(skb, NL_POLICY_TYPE_ATTR_POLICY_IDX,
netlink_policy_dump_get_policy_idx(state,
pt->nested_policy,
pt->len)) ||
nla_put_u32(skb, NL_POLICY_TYPE_ATTR_POLICY_MAXTYPE,
pt->len))) goto nla_put_failure; break; case NLA_U8: case NLA_U16: case NLA_U32: case NLA_U64: case NLA_UINT: case NLA_MSECS: { struct netlink_range_validation range;
if (pt->type == NLA_U8)
type = NL_ATTR_TYPE_U8; elseif (pt->type == NLA_U16)
type = NL_ATTR_TYPE_U16; elseif (pt->type == NLA_U32)
type = NL_ATTR_TYPE_U32; elseif (pt->type == NLA_U64)
type = NL_ATTR_TYPE_U64; else
type = NL_ATTR_TYPE_UINT;
if (nla_put_u64_64bit(skb, NL_POLICY_TYPE_ATTR_MIN_VALUE_U,
range.min, NL_POLICY_TYPE_ATTR_PAD) ||
nla_put_u64_64bit(skb, NL_POLICY_TYPE_ATTR_MAX_VALUE_U,
range.max, NL_POLICY_TYPE_ATTR_PAD)) goto nla_put_failure; break;
} case NLA_S8: case NLA_S16: case NLA_S32: case NLA_S64: case NLA_SINT: { struct netlink_range_validation_signed range;
if (pt->type == NLA_S8)
type = NL_ATTR_TYPE_S8; elseif (pt->type == NLA_S16)
type = NL_ATTR_TYPE_S16; elseif (pt->type == NLA_S32)
type = NL_ATTR_TYPE_S32; elseif (pt->type == NLA_S64)
type = NL_ATTR_TYPE_S64; else
type = NL_ATTR_TYPE_SINT;
if (pt->validation_type == NLA_VALIDATE_FUNCTION) break;
nla_get_range_signed(pt, &range);
if (nla_put_s64(skb, NL_POLICY_TYPE_ATTR_MIN_VALUE_S,
range.min, NL_POLICY_TYPE_ATTR_PAD) ||
nla_put_s64(skb, NL_POLICY_TYPE_ATTR_MAX_VALUE_S,
range.max, NL_POLICY_TYPE_ATTR_PAD)) goto nla_put_failure; break;
} case NLA_BITFIELD32:
type = NL_ATTR_TYPE_BITFIELD32; if (nla_put_u32(skb, NL_POLICY_TYPE_ATTR_BITFIELD32_MASK,
pt->bitfield32_valid)) goto nla_put_failure; break; case NLA_STRING: case NLA_NUL_STRING: case NLA_BINARY: if (pt->type == NLA_STRING)
type = NL_ATTR_TYPE_STRING; elseif (pt->type == NLA_NUL_STRING)
type = NL_ATTR_TYPE_NUL_STRING; else
type = NL_ATTR_TYPE_BINARY;
/** * netlink_policy_dump_write_attr - write a given attribute policy * @skb: the message skb to write to * @pt: the attribute's policy * @nestattr: the nested attribute ID to use * * Returns: 0 on success, an error code otherwise; -%ENODATA is * special, indicating that there's no policy data and * the attribute is generally rejected.
*/ int netlink_policy_dump_write_attr(struct sk_buff *skb, conststruct nla_policy *pt, int nestattr)
{ return __netlink_policy_dump_write_attr(NULL, skb, pt, nestattr);
}
/** * netlink_policy_dump_write - write current policy dump attributes * @skb: the message skb to write to * @state: the policy dump state * * Returns: 0 on success, an error code otherwise
*/ int netlink_policy_dump_write(struct sk_buff *skb, struct netlink_policy_dump_state *state)
{ conststruct nla_policy *pt; struct nlattr *policy; bool again; int err;
/** * netlink_policy_dump_free - free policy dump state * @state: the policy dump state to free * * Call this from the done() method to ensure dump state is freed.
*/ void netlink_policy_dump_free(struct netlink_policy_dump_state *state)
{
kfree(state);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.