diff options
Diffstat (limited to 'net/netlink/genetlink.c')
-rw-r--r-- | net/netlink/genetlink.c | 40 |
1 files changed, 40 insertions, 0 deletions
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index 3ac942cdb677..49bc2db7982b 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c | |||
@@ -387,7 +387,10 @@ static void genl_rcv(struct sock *sk, int len) | |||
387 | static int ctrl_fill_info(struct genl_family *family, u32 pid, u32 seq, | 387 | static int ctrl_fill_info(struct genl_family *family, u32 pid, u32 seq, |
388 | u32 flags, struct sk_buff *skb, u8 cmd) | 388 | u32 flags, struct sk_buff *skb, u8 cmd) |
389 | { | 389 | { |
390 | struct nlattr *nla_ops; | ||
391 | struct genl_ops *ops; | ||
390 | void *hdr; | 392 | void *hdr; |
393 | int idx = 1; | ||
391 | 394 | ||
392 | hdr = genlmsg_put(skb, pid, seq, GENL_ID_CTRL, 0, flags, cmd, | 395 | hdr = genlmsg_put(skb, pid, seq, GENL_ID_CTRL, 0, flags, cmd, |
393 | family->version); | 396 | family->version); |
@@ -396,6 +399,37 @@ static int ctrl_fill_info(struct genl_family *family, u32 pid, u32 seq, | |||
396 | 399 | ||
397 | NLA_PUT_STRING(skb, CTRL_ATTR_FAMILY_NAME, family->name); | 400 | NLA_PUT_STRING(skb, CTRL_ATTR_FAMILY_NAME, family->name); |
398 | NLA_PUT_U16(skb, CTRL_ATTR_FAMILY_ID, family->id); | 401 | NLA_PUT_U16(skb, CTRL_ATTR_FAMILY_ID, family->id); |
402 | NLA_PUT_U32(skb, CTRL_ATTR_VERSION, family->version); | ||
403 | NLA_PUT_U32(skb, CTRL_ATTR_HDRSIZE, family->hdrsize); | ||
404 | NLA_PUT_U32(skb, CTRL_ATTR_MAXATTR, family->maxattr); | ||
405 | |||
406 | nla_ops = nla_nest_start(skb, CTRL_ATTR_OPS); | ||
407 | if (nla_ops == NULL) | ||
408 | goto nla_put_failure; | ||
409 | |||
410 | list_for_each_entry(ops, &family->ops_list, ops_list) { | ||
411 | struct nlattr *nest; | ||
412 | |||
413 | nest = nla_nest_start(skb, idx++); | ||
414 | if (nest == NULL) | ||
415 | goto nla_put_failure; | ||
416 | |||
417 | NLA_PUT_U32(skb, CTRL_ATTR_OP_ID, ops->cmd); | ||
418 | NLA_PUT_U32(skb, CTRL_ATTR_OP_FLAGS, ops->flags); | ||
419 | |||
420 | if (ops->policy) | ||
421 | NLA_PUT_FLAG(skb, CTRL_ATTR_OP_POLICY); | ||
422 | |||
423 | if (ops->doit) | ||
424 | NLA_PUT_FLAG(skb, CTRL_ATTR_OP_DOIT); | ||
425 | |||
426 | if (ops->dumpit) | ||
427 | NLA_PUT_FLAG(skb, CTRL_ATTR_OP_DUMPIT); | ||
428 | |||
429 | nla_nest_end(skb, nest); | ||
430 | } | ||
431 | |||
432 | nla_nest_end(skb, nla_ops); | ||
399 | 433 | ||
400 | return genlmsg_end(skb, hdr); | 434 | return genlmsg_end(skb, hdr); |
401 | 435 | ||
@@ -411,6 +445,9 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb) | |||
411 | int chains_to_skip = cb->args[0]; | 445 | int chains_to_skip = cb->args[0]; |
412 | int fams_to_skip = cb->args[1]; | 446 | int fams_to_skip = cb->args[1]; |
413 | 447 | ||
448 | if (chains_to_skip != 0) | ||
449 | genl_lock(); | ||
450 | |||
414 | for (i = 0; i < GENL_FAM_TAB_SIZE; i++) { | 451 | for (i = 0; i < GENL_FAM_TAB_SIZE; i++) { |
415 | if (i < chains_to_skip) | 452 | if (i < chains_to_skip) |
416 | continue; | 453 | continue; |
@@ -428,6 +465,9 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb) | |||
428 | } | 465 | } |
429 | 466 | ||
430 | errout: | 467 | errout: |
468 | if (chains_to_skip != 0) | ||
469 | genl_unlock(); | ||
470 | |||
431 | cb->args[0] = i; | 471 | cb->args[0] = i; |
432 | cb->args[1] = n; | 472 | cb->args[1] = n; |
433 | 473 | ||