aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
authorNicolas Dichtel <nicolas.dichtel@6wind.com>2012-10-25 18:28:50 -0400
committerDavid S. Miller <davem@davemloft.net>2012-10-28 19:05:00 -0400
commitf3a1bfb11ccbc72d44f0b58c92115a40128979c3 (patch)
treead32461b8d2cc759260eec13d20f6a82729e69b4 /net/ipv6
parentd900082bd9060dc955b181dae2f2adf86e27d747 (diff)
rtnl/ipv6: use netconf msg to advertise forwarding status
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/addrconf.c77
1 files changed, 77 insertions, 0 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 0424e4e27414..0c57a8f67715 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -81,6 +81,7 @@
81#include <net/pkt_sched.h> 81#include <net/pkt_sched.h>
82#include <linux/if_tunnel.h> 82#include <linux/if_tunnel.h>
83#include <linux/rtnetlink.h> 83#include <linux/rtnetlink.h>
84#include <linux/netconf.h>
84 85
85#ifdef CONFIG_IPV6_PRIVACY 86#ifdef CONFIG_IPV6_PRIVACY
86#include <linux/random.h> 87#include <linux/random.h>
@@ -460,6 +461,72 @@ static struct inet6_dev *ipv6_find_idev(struct net_device *dev)
460 return idev; 461 return idev;
461} 462}
462 463
464static int inet6_netconf_msgsize_devconf(int type)
465{
466 int size = NLMSG_ALIGN(sizeof(struct netconfmsg))
467 + nla_total_size(4); /* NETCONFA_IFINDEX */
468
469 if (type == NETCONFA_FORWARDING)
470 size += nla_total_size(4);
471
472 return size;
473}
474
475static int inet6_netconf_fill_devconf(struct sk_buff *skb, int ifindex,
476 struct ipv6_devconf *devconf, u32 portid,
477 u32 seq, int event, unsigned int flags,
478 int type)
479{
480 struct nlmsghdr *nlh;
481 struct netconfmsg *ncm;
482
483 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct netconfmsg),
484 flags);
485 if (nlh == NULL)
486 return -EMSGSIZE;
487
488 ncm = nlmsg_data(nlh);
489 ncm->ncm_family = AF_INET6;
490
491 if (nla_put_s32(skb, NETCONFA_IFINDEX, ifindex) < 0)
492 goto nla_put_failure;
493
494 if (type == NETCONFA_FORWARDING &&
495 nla_put_s32(skb, NETCONFA_FORWARDING, devconf->forwarding) < 0)
496 goto nla_put_failure;
497
498 return nlmsg_end(skb, nlh);
499
500nla_put_failure:
501 nlmsg_cancel(skb, nlh);
502 return -EMSGSIZE;
503}
504
505static void inet6_netconf_notify_devconf(struct net *net, int type, int ifindex,
506 struct ipv6_devconf *devconf)
507{
508 struct sk_buff *skb;
509 int err = -ENOBUFS;
510
511 skb = nlmsg_new(inet6_netconf_msgsize_devconf(type), GFP_ATOMIC);
512 if (skb == NULL)
513 goto errout;
514
515 err = inet6_netconf_fill_devconf(skb, ifindex, devconf, 0, 0,
516 RTM_NEWNETCONF, 0, type);
517 if (err < 0) {
518 /* -EMSGSIZE implies BUG in inet6_netconf_msgsize_devconf() */
519 WARN_ON(err == -EMSGSIZE);
520 kfree_skb(skb);
521 goto errout;
522 }
523 rtnl_notify(skb, net, 0, RTNLGRP_IPV6_NETCONF, NULL, GFP_ATOMIC);
524 return;
525errout:
526 if (err < 0)
527 rtnl_set_sk_err(net, RTNLGRP_IPV6_NETCONF, err);
528}
529
463#ifdef CONFIG_SYSCTL 530#ifdef CONFIG_SYSCTL
464static void dev_forward_change(struct inet6_dev *idev) 531static void dev_forward_change(struct inet6_dev *idev)
465{ 532{
@@ -486,6 +553,8 @@ static void dev_forward_change(struct inet6_dev *idev)
486 else 553 else
487 addrconf_leave_anycast(ifa); 554 addrconf_leave_anycast(ifa);
488 } 555 }
556 inet6_netconf_notify_devconf(dev_net(dev), NETCONFA_FORWARDING,
557 dev->ifindex, &idev->cnf);
489} 558}
490 559
491 560
@@ -518,6 +587,10 @@ static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int newf)
518 *p = newf; 587 *p = newf;
519 588
520 if (p == &net->ipv6.devconf_dflt->forwarding) { 589 if (p == &net->ipv6.devconf_dflt->forwarding) {
590 if ((!newf) ^ (!old))
591 inet6_netconf_notify_devconf(net, NETCONFA_FORWARDING,
592 NETCONFA_IFINDEX_DEFAULT,
593 net->ipv6.devconf_dflt);
521 rtnl_unlock(); 594 rtnl_unlock();
522 return 0; 595 return 0;
523 } 596 }
@@ -525,6 +598,10 @@ static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int newf)
525 if (p == &net->ipv6.devconf_all->forwarding) { 598 if (p == &net->ipv6.devconf_all->forwarding) {
526 net->ipv6.devconf_dflt->forwarding = newf; 599 net->ipv6.devconf_dflt->forwarding = newf;
527 addrconf_forward_change(net, newf); 600 addrconf_forward_change(net, newf);
601 if ((!newf) ^ (!old))
602 inet6_netconf_notify_devconf(net, NETCONFA_FORWARDING,
603 NETCONFA_IFINDEX_ALL,
604 net->ipv6.devconf_all);
528 } else if ((!newf) ^ (!old)) 605 } else if ((!newf) ^ (!old))
529 dev_forward_change((struct inet6_dev *)table->extra1); 606 dev_forward_change((struct inet6_dev *)table->extra1);
530 rtnl_unlock(); 607 rtnl_unlock();