aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/addrconf.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/addrconf.c')
-rw-r--r--net/ipv6/addrconf.c114
1 files changed, 82 insertions, 32 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 848b35591042..99d1888af363 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -3838,6 +3838,15 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
3838 array[DEVCONF_FORCE_TLLAO] = cnf->force_tllao; 3838 array[DEVCONF_FORCE_TLLAO] = cnf->force_tllao;
3839} 3839}
3840 3840
3841static inline size_t inet6_ifla6_size(void)
3842{
3843 return nla_total_size(4) /* IFLA_INET6_FLAGS */
3844 + nla_total_size(sizeof(struct ifla_cacheinfo))
3845 + nla_total_size(DEVCONF_MAX * 4) /* IFLA_INET6_CONF */
3846 + nla_total_size(IPSTATS_MIB_MAX * 8) /* IFLA_INET6_STATS */
3847 + nla_total_size(ICMP6_MIB_MAX * 8); /* IFLA_INET6_ICMP6STATS */
3848}
3849
3841static inline size_t inet6_if_nlmsg_size(void) 3850static inline size_t inet6_if_nlmsg_size(void)
3842{ 3851{
3843 return NLMSG_ALIGN(sizeof(struct ifinfomsg)) 3852 return NLMSG_ALIGN(sizeof(struct ifinfomsg))
@@ -3845,13 +3854,7 @@ static inline size_t inet6_if_nlmsg_size(void)
3845 + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */ 3854 + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */
3846 + nla_total_size(4) /* IFLA_MTU */ 3855 + nla_total_size(4) /* IFLA_MTU */
3847 + nla_total_size(4) /* IFLA_LINK */ 3856 + nla_total_size(4) /* IFLA_LINK */
3848 + nla_total_size( /* IFLA_PROTINFO */ 3857 + nla_total_size(inet6_ifla6_size()); /* IFLA_PROTINFO */
3849 nla_total_size(4) /* IFLA_INET6_FLAGS */
3850 + nla_total_size(sizeof(struct ifla_cacheinfo))
3851 + nla_total_size(DEVCONF_MAX * 4) /* IFLA_INET6_CONF */
3852 + nla_total_size(IPSTATS_MIB_MAX * 8) /* IFLA_INET6_STATS */
3853 + nla_total_size(ICMP6_MIB_MAX * 8) /* IFLA_INET6_ICMP6STATS */
3854 );
3855} 3858}
3856 3859
3857static inline void __snmp6_fill_stats(u64 *stats, void __percpu **mib, 3860static inline void __snmp6_fill_stats(u64 *stats, void __percpu **mib,
@@ -3898,15 +3901,70 @@ static void snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype,
3898 } 3901 }
3899} 3902}
3900 3903
3904static int inet6_fill_ifla6_attrs(struct sk_buff *skb, struct inet6_dev *idev)
3905{
3906 struct nlattr *nla;
3907 struct ifla_cacheinfo ci;
3908
3909 NLA_PUT_U32(skb, IFLA_INET6_FLAGS, idev->if_flags);
3910
3911 ci.max_reasm_len = IPV6_MAXPLEN;
3912 ci.tstamp = cstamp_delta(idev->tstamp);
3913 ci.reachable_time = jiffies_to_msecs(idev->nd_parms->reachable_time);
3914 ci.retrans_time = jiffies_to_msecs(idev->nd_parms->retrans_time);
3915 NLA_PUT(skb, IFLA_INET6_CACHEINFO, sizeof(ci), &ci);
3916
3917 nla = nla_reserve(skb, IFLA_INET6_CONF, DEVCONF_MAX * sizeof(s32));
3918 if (nla == NULL)
3919 goto nla_put_failure;
3920 ipv6_store_devconf(&idev->cnf, nla_data(nla), nla_len(nla));
3921
3922 /* XXX - MC not implemented */
3923
3924 nla = nla_reserve(skb, IFLA_INET6_STATS, IPSTATS_MIB_MAX * sizeof(u64));
3925 if (nla == NULL)
3926 goto nla_put_failure;
3927 snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_STATS, nla_len(nla));
3928
3929 nla = nla_reserve(skb, IFLA_INET6_ICMP6STATS, ICMP6_MIB_MAX * sizeof(u64));
3930 if (nla == NULL)
3931 goto nla_put_failure;
3932 snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_ICMP6STATS, nla_len(nla));
3933
3934 return 0;
3935
3936nla_put_failure:
3937 return -EMSGSIZE;
3938}
3939
3940static size_t inet6_get_link_af_size(const struct net_device *dev)
3941{
3942 if (!__in6_dev_get(dev))
3943 return 0;
3944
3945 return inet6_ifla6_size();
3946}
3947
3948static int inet6_fill_link_af(struct sk_buff *skb, const struct net_device *dev)
3949{
3950 struct inet6_dev *idev = __in6_dev_get(dev);
3951
3952 if (!idev)
3953 return -ENODATA;
3954
3955 if (inet6_fill_ifla6_attrs(skb, idev) < 0)
3956 return -EMSGSIZE;
3957
3958 return 0;
3959}
3960
3901static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, 3961static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev,
3902 u32 pid, u32 seq, int event, unsigned int flags) 3962 u32 pid, u32 seq, int event, unsigned int flags)
3903{ 3963{
3904 struct net_device *dev = idev->dev; 3964 struct net_device *dev = idev->dev;
3905 struct nlattr *nla;
3906 struct ifinfomsg *hdr; 3965 struct ifinfomsg *hdr;
3907 struct nlmsghdr *nlh; 3966 struct nlmsghdr *nlh;
3908 void *protoinfo; 3967 void *protoinfo;
3909 struct ifla_cacheinfo ci;
3910 3968
3911 nlh = nlmsg_put(skb, pid, seq, event, sizeof(*hdr), flags); 3969 nlh = nlmsg_put(skb, pid, seq, event, sizeof(*hdr), flags);
3912 if (nlh == NULL) 3970 if (nlh == NULL)
@@ -3933,30 +3991,8 @@ static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev,
3933 if (protoinfo == NULL) 3991 if (protoinfo == NULL)
3934 goto nla_put_failure; 3992 goto nla_put_failure;
3935 3993
3936 NLA_PUT_U32(skb, IFLA_INET6_FLAGS, idev->if_flags); 3994 if (inet6_fill_ifla6_attrs(skb, idev) < 0)
3937
3938 ci.max_reasm_len = IPV6_MAXPLEN;
3939 ci.tstamp = cstamp_delta(idev->tstamp);
3940 ci.reachable_time = jiffies_to_msecs(idev->nd_parms->reachable_time);
3941 ci.retrans_time = jiffies_to_msecs(idev->nd_parms->retrans_time);
3942 NLA_PUT(skb, IFLA_INET6_CACHEINFO, sizeof(ci), &ci);
3943
3944 nla = nla_reserve(skb, IFLA_INET6_CONF, DEVCONF_MAX * sizeof(s32));
3945 if (nla == NULL)
3946 goto nla_put_failure;
3947 ipv6_store_devconf(&idev->cnf, nla_data(nla), nla_len(nla));
3948
3949 /* XXX - MC not implemented */
3950
3951 nla = nla_reserve(skb, IFLA_INET6_STATS, IPSTATS_MIB_MAX * sizeof(u64));
3952 if (nla == NULL)
3953 goto nla_put_failure;
3954 snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_STATS, nla_len(nla));
3955
3956 nla = nla_reserve(skb, IFLA_INET6_ICMP6STATS, ICMP6_MIB_MAX * sizeof(u64));
3957 if (nla == NULL)
3958 goto nla_put_failure; 3995 goto nla_put_failure;
3959 snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_ICMP6STATS, nla_len(nla));
3960 3996
3961 nla_nest_end(skb, protoinfo); 3997 nla_nest_end(skb, protoinfo);
3962 return nlmsg_end(skb, nlh); 3998 return nlmsg_end(skb, nlh);
@@ -4627,6 +4663,12 @@ int unregister_inet6addr_notifier(struct notifier_block *nb)
4627} 4663}
4628EXPORT_SYMBOL(unregister_inet6addr_notifier); 4664EXPORT_SYMBOL(unregister_inet6addr_notifier);
4629 4665
4666static struct rtnl_af_ops inet6_ops = {
4667 .family = AF_INET6,
4668 .fill_link_af = inet6_fill_link_af,
4669 .get_link_af_size = inet6_get_link_af_size,
4670};
4671
4630/* 4672/*
4631 * Init / cleanup code 4673 * Init / cleanup code
4632 */ 4674 */
@@ -4678,6 +4720,10 @@ int __init addrconf_init(void)
4678 4720
4679 addrconf_verify(0); 4721 addrconf_verify(0);
4680 4722
4723 err = rtnl_af_register(&inet6_ops);
4724 if (err < 0)
4725 goto errout_af;
4726
4681 err = __rtnl_register(PF_INET6, RTM_GETLINK, NULL, inet6_dump_ifinfo); 4727 err = __rtnl_register(PF_INET6, RTM_GETLINK, NULL, inet6_dump_ifinfo);
4682 if (err < 0) 4728 if (err < 0)
4683 goto errout; 4729 goto errout;
@@ -4693,6 +4739,8 @@ int __init addrconf_init(void)
4693 4739
4694 return 0; 4740 return 0;
4695errout: 4741errout:
4742 rtnl_af_unregister(&inet6_ops);
4743errout_af:
4696 unregister_netdevice_notifier(&ipv6_dev_notf); 4744 unregister_netdevice_notifier(&ipv6_dev_notf);
4697errlo: 4745errlo:
4698 unregister_pernet_subsys(&addrconf_ops); 4746 unregister_pernet_subsys(&addrconf_ops);
@@ -4713,6 +4761,8 @@ void addrconf_cleanup(void)
4713 4761
4714 rtnl_lock(); 4762 rtnl_lock();
4715 4763
4764 __rtnl_af_unregister(&inet6_ops);
4765
4716 /* clean dev list */ 4766 /* clean dev list */
4717 for_each_netdev(&init_net, dev) { 4767 for_each_netdev(&init_net, dev) {
4718 if (__in6_dev_get(dev) == NULL) 4768 if (__in6_dev_get(dev) == NULL)