aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--include/uapi/linux/rtnetlink.h2
-rw-r--r--net/ipv6/addrconf.c77
2 files changed, 79 insertions, 0 deletions
diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h
index 0043b413b8bc..a4d75ea868ed 100644
--- a/include/uapi/linux/rtnetlink.h
+++ b/include/uapi/linux/rtnetlink.h
@@ -592,6 +592,8 @@ enum rtnetlink_groups {
592#define RTNLGRP_PHONET_ROUTE RTNLGRP_PHONET_ROUTE 592#define RTNLGRP_PHONET_ROUTE RTNLGRP_PHONET_ROUTE
593 RTNLGRP_DCB, 593 RTNLGRP_DCB,
594#define RTNLGRP_DCB RTNLGRP_DCB 594#define RTNLGRP_DCB RTNLGRP_DCB
595 RTNLGRP_IPV6_NETCONF,
596#define RTNLGRP_IPV6_NETCONF RTNLGRP_IPV6_NETCONF
595 __RTNLGRP_MAX 597 __RTNLGRP_MAX
596}; 598};
597#define RTNLGRP_MAX (__RTNLGRP_MAX - 1) 599#define RTNLGRP_MAX (__RTNLGRP_MAX - 1)
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();