diff options
author | Nicolas Dichtel <nicolas.dichtel@6wind.com> | 2012-10-25 18:28:51 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-10-28 19:05:00 -0400 |
commit | 76f8f6cb76b110aaace90b6208b1ceb46bd78b7f (patch) | |
tree | 0b70420e29479970155518d8ac3f147bf652328e /net/ipv6/addrconf.c | |
parent | f3a1bfb11ccbc72d44f0b58c92115a40128979c3 (diff) |
rtnl/ipv6: add support of RTM_GETNETCONF
This message allows to get the devconf for an interface.
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/addrconf.c')
-rw-r--r-- | net/ipv6/addrconf.c | 75 |
1 files changed, 73 insertions, 2 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 0c57a8f67715..8f0b12a67131 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -466,7 +466,8 @@ static int inet6_netconf_msgsize_devconf(int type) | |||
466 | int size = NLMSG_ALIGN(sizeof(struct netconfmsg)) | 466 | int size = NLMSG_ALIGN(sizeof(struct netconfmsg)) |
467 | + nla_total_size(4); /* NETCONFA_IFINDEX */ | 467 | + nla_total_size(4); /* NETCONFA_IFINDEX */ |
468 | 468 | ||
469 | if (type == NETCONFA_FORWARDING) | 469 | /* type -1 is used for ALL */ |
470 | if (type == -1 || type == NETCONFA_FORWARDING) | ||
470 | size += nla_total_size(4); | 471 | size += nla_total_size(4); |
471 | 472 | ||
472 | return size; | 473 | return size; |
@@ -491,7 +492,8 @@ static int inet6_netconf_fill_devconf(struct sk_buff *skb, int ifindex, | |||
491 | if (nla_put_s32(skb, NETCONFA_IFINDEX, ifindex) < 0) | 492 | if (nla_put_s32(skb, NETCONFA_IFINDEX, ifindex) < 0) |
492 | goto nla_put_failure; | 493 | goto nla_put_failure; |
493 | 494 | ||
494 | if (type == NETCONFA_FORWARDING && | 495 | /* type -1 is used for ALL */ |
496 | if ((type == -1 || type == NETCONFA_FORWARDING) && | ||
495 | nla_put_s32(skb, NETCONFA_FORWARDING, devconf->forwarding) < 0) | 497 | nla_put_s32(skb, NETCONFA_FORWARDING, devconf->forwarding) < 0) |
496 | goto nla_put_failure; | 498 | goto nla_put_failure; |
497 | 499 | ||
@@ -527,6 +529,73 @@ errout: | |||
527 | rtnl_set_sk_err(net, RTNLGRP_IPV6_NETCONF, err); | 529 | rtnl_set_sk_err(net, RTNLGRP_IPV6_NETCONF, err); |
528 | } | 530 | } |
529 | 531 | ||
532 | static const struct nla_policy devconf_ipv6_policy[NETCONFA_MAX+1] = { | ||
533 | [NETCONFA_IFINDEX] = { .len = sizeof(int) }, | ||
534 | [NETCONFA_FORWARDING] = { .len = sizeof(int) }, | ||
535 | }; | ||
536 | |||
537 | static int inet6_netconf_get_devconf(struct sk_buff *in_skb, | ||
538 | struct nlmsghdr *nlh, | ||
539 | void *arg) | ||
540 | { | ||
541 | struct net *net = sock_net(in_skb->sk); | ||
542 | struct nlattr *tb[NETCONFA_MAX+1]; | ||
543 | struct netconfmsg *ncm; | ||
544 | struct sk_buff *skb; | ||
545 | struct ipv6_devconf *devconf; | ||
546 | struct inet6_dev *in6_dev; | ||
547 | struct net_device *dev; | ||
548 | int ifindex; | ||
549 | int err; | ||
550 | |||
551 | err = nlmsg_parse(nlh, sizeof(*ncm), tb, NETCONFA_MAX, | ||
552 | devconf_ipv6_policy); | ||
553 | if (err < 0) | ||
554 | goto errout; | ||
555 | |||
556 | err = EINVAL; | ||
557 | if (!tb[NETCONFA_IFINDEX]) | ||
558 | goto errout; | ||
559 | |||
560 | ifindex = nla_get_s32(tb[NETCONFA_IFINDEX]); | ||
561 | switch (ifindex) { | ||
562 | case NETCONFA_IFINDEX_ALL: | ||
563 | devconf = net->ipv6.devconf_all; | ||
564 | break; | ||
565 | case NETCONFA_IFINDEX_DEFAULT: | ||
566 | devconf = net->ipv6.devconf_dflt; | ||
567 | break; | ||
568 | default: | ||
569 | dev = __dev_get_by_index(net, ifindex); | ||
570 | if (dev == NULL) | ||
571 | goto errout; | ||
572 | in6_dev = __in6_dev_get(dev); | ||
573 | if (in6_dev == NULL) | ||
574 | goto errout; | ||
575 | devconf = &in6_dev->cnf; | ||
576 | break; | ||
577 | } | ||
578 | |||
579 | err = -ENOBUFS; | ||
580 | skb = nlmsg_new(inet6_netconf_msgsize_devconf(-1), GFP_ATOMIC); | ||
581 | if (skb == NULL) | ||
582 | goto errout; | ||
583 | |||
584 | err = inet6_netconf_fill_devconf(skb, ifindex, devconf, | ||
585 | NETLINK_CB(in_skb).portid, | ||
586 | nlh->nlmsg_seq, RTM_NEWNETCONF, 0, | ||
587 | -1); | ||
588 | if (err < 0) { | ||
589 | /* -EMSGSIZE implies BUG in inet6_netconf_msgsize_devconf() */ | ||
590 | WARN_ON(err == -EMSGSIZE); | ||
591 | kfree_skb(skb); | ||
592 | goto errout; | ||
593 | } | ||
594 | err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid); | ||
595 | errout: | ||
596 | return err; | ||
597 | } | ||
598 | |||
530 | #ifdef CONFIG_SYSCTL | 599 | #ifdef CONFIG_SYSCTL |
531 | static void dev_forward_change(struct inet6_dev *idev) | 600 | static void dev_forward_change(struct inet6_dev *idev) |
532 | { | 601 | { |
@@ -4861,6 +4930,8 @@ int __init addrconf_init(void) | |||
4861 | inet6_dump_ifmcaddr, NULL); | 4930 | inet6_dump_ifmcaddr, NULL); |
4862 | __rtnl_register(PF_INET6, RTM_GETANYCAST, NULL, | 4931 | __rtnl_register(PF_INET6, RTM_GETANYCAST, NULL, |
4863 | inet6_dump_ifacaddr, NULL); | 4932 | inet6_dump_ifacaddr, NULL); |
4933 | __rtnl_register(PF_INET6, RTM_GETNETCONF, inet6_netconf_get_devconf, | ||
4934 | NULL, NULL); | ||
4864 | 4935 | ||
4865 | ipv6_addr_label_rtnl_register(); | 4936 | ipv6_addr_label_rtnl_register(); |
4866 | 4937 | ||