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.c169
1 files changed, 108 insertions, 61 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index e048ec62d109..5b189c97c2fc 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -98,7 +98,11 @@
98#endif 98#endif
99 99
100#define INFINITY_LIFE_TIME 0xFFFFFFFF 100#define INFINITY_LIFE_TIME 0xFFFFFFFF
101#define TIME_DELTA(a, b) ((unsigned long)((long)(a) - (long)(b))) 101
102static inline u32 cstamp_delta(unsigned long cstamp)
103{
104 return (cstamp - INITIAL_JIFFIES) * 100UL / HZ;
105}
102 106
103#define ADDRCONF_TIMER_FUZZ_MINUS (HZ > 50 ? HZ/50 : 1) 107#define ADDRCONF_TIMER_FUZZ_MINUS (HZ > 50 ? HZ/50 : 1)
104#define ADDRCONF_TIMER_FUZZ (HZ / 4) 108#define ADDRCONF_TIMER_FUZZ (HZ / 4)
@@ -2665,8 +2669,9 @@ static int addrconf_ifdown(struct net_device *dev, int how)
2665 2669
2666 ASSERT_RTNL(); 2670 ASSERT_RTNL();
2667 2671
2668 rt6_ifdown(net, dev); 2672 /* Flush routes if device is being removed or it is not loopback */
2669 neigh_ifdown(&nd_tbl, dev); 2673 if (how || !(dev->flags & IFF_LOOPBACK))
2674 rt6_ifdown(net, dev);
2670 2675
2671 idev = __in6_dev_get(dev); 2676 idev = __in6_dev_get(dev);
2672 if (idev == NULL) 2677 if (idev == NULL)
@@ -2740,10 +2745,6 @@ static int addrconf_ifdown(struct net_device *dev, int how)
2740 /* Flag it for later restoration when link comes up */ 2745 /* Flag it for later restoration when link comes up */
2741 ifa->flags |= IFA_F_TENTATIVE; 2746 ifa->flags |= IFA_F_TENTATIVE;
2742 ifa->state = INET6_IFADDR_STATE_DAD; 2747 ifa->state = INET6_IFADDR_STATE_DAD;
2743
2744 write_unlock_bh(&idev->lock);
2745
2746 in6_ifa_hold(ifa);
2747 } else { 2748 } else {
2748 list_del(&ifa->if_list); 2749 list_del(&ifa->if_list);
2749 2750
@@ -2758,19 +2759,15 @@ static int addrconf_ifdown(struct net_device *dev, int how)
2758 ifa->state = INET6_IFADDR_STATE_DEAD; 2759 ifa->state = INET6_IFADDR_STATE_DEAD;
2759 spin_unlock_bh(&ifa->state_lock); 2760 spin_unlock_bh(&ifa->state_lock);
2760 2761
2761 if (state == INET6_IFADDR_STATE_DEAD) 2762 if (state != INET6_IFADDR_STATE_DEAD) {
2762 goto put_ifa; 2763 __ipv6_ifa_notify(RTM_DELADDR, ifa);
2763 } 2764 atomic_notifier_call_chain(&inet6addr_chain,
2764 2765 NETDEV_DOWN, ifa);
2765 __ipv6_ifa_notify(RTM_DELADDR, ifa); 2766 }
2766 if (ifa->state == INET6_IFADDR_STATE_DEAD)
2767 atomic_notifier_call_chain(&inet6addr_chain,
2768 NETDEV_DOWN, ifa);
2769
2770put_ifa:
2771 in6_ifa_put(ifa);
2772 2767
2773 write_lock_bh(&idev->lock); 2768 in6_ifa_put(ifa);
2769 write_lock_bh(&idev->lock);
2770 }
2774 } 2771 }
2775 2772
2776 list_splice(&keep_list, &idev->addr_list); 2773 list_splice(&keep_list, &idev->addr_list);
@@ -3452,10 +3449,8 @@ static int put_cacheinfo(struct sk_buff *skb, unsigned long cstamp,
3452{ 3449{
3453 struct ifa_cacheinfo ci; 3450 struct ifa_cacheinfo ci;
3454 3451
3455 ci.cstamp = (u32)(TIME_DELTA(cstamp, INITIAL_JIFFIES) / HZ * 100 3452 ci.cstamp = cstamp_delta(cstamp);
3456 + TIME_DELTA(cstamp, INITIAL_JIFFIES) % HZ * 100 / HZ); 3453 ci.tstamp = cstamp_delta(tstamp);
3457 ci.tstamp = (u32)(TIME_DELTA(tstamp, INITIAL_JIFFIES) / HZ * 100
3458 + TIME_DELTA(tstamp, INITIAL_JIFFIES) % HZ * 100 / HZ);
3459 ci.ifa_prefered = preferred; 3454 ci.ifa_prefered = preferred;
3460 ci.ifa_valid = valid; 3455 ci.ifa_valid = valid;
3461 3456
@@ -3806,8 +3801,10 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
3806 array[DEVCONF_AUTOCONF] = cnf->autoconf; 3801 array[DEVCONF_AUTOCONF] = cnf->autoconf;
3807 array[DEVCONF_DAD_TRANSMITS] = cnf->dad_transmits; 3802 array[DEVCONF_DAD_TRANSMITS] = cnf->dad_transmits;
3808 array[DEVCONF_RTR_SOLICITS] = cnf->rtr_solicits; 3803 array[DEVCONF_RTR_SOLICITS] = cnf->rtr_solicits;
3809 array[DEVCONF_RTR_SOLICIT_INTERVAL] = cnf->rtr_solicit_interval; 3804 array[DEVCONF_RTR_SOLICIT_INTERVAL] =
3810 array[DEVCONF_RTR_SOLICIT_DELAY] = cnf->rtr_solicit_delay; 3805 jiffies_to_msecs(cnf->rtr_solicit_interval);
3806 array[DEVCONF_RTR_SOLICIT_DELAY] =
3807 jiffies_to_msecs(cnf->rtr_solicit_delay);
3811 array[DEVCONF_FORCE_MLD_VERSION] = cnf->force_mld_version; 3808 array[DEVCONF_FORCE_MLD_VERSION] = cnf->force_mld_version;
3812#ifdef CONFIG_IPV6_PRIVACY 3809#ifdef CONFIG_IPV6_PRIVACY
3813 array[DEVCONF_USE_TEMPADDR] = cnf->use_tempaddr; 3810 array[DEVCONF_USE_TEMPADDR] = cnf->use_tempaddr;
@@ -3821,7 +3818,8 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
3821 array[DEVCONF_ACCEPT_RA_PINFO] = cnf->accept_ra_pinfo; 3818 array[DEVCONF_ACCEPT_RA_PINFO] = cnf->accept_ra_pinfo;
3822#ifdef CONFIG_IPV6_ROUTER_PREF 3819#ifdef CONFIG_IPV6_ROUTER_PREF
3823 array[DEVCONF_ACCEPT_RA_RTR_PREF] = cnf->accept_ra_rtr_pref; 3820 array[DEVCONF_ACCEPT_RA_RTR_PREF] = cnf->accept_ra_rtr_pref;
3824 array[DEVCONF_RTR_PROBE_INTERVAL] = cnf->rtr_probe_interval; 3821 array[DEVCONF_RTR_PROBE_INTERVAL] =
3822 jiffies_to_msecs(cnf->rtr_probe_interval);
3825#ifdef CONFIG_IPV6_ROUTE_INFO 3823#ifdef CONFIG_IPV6_ROUTE_INFO
3826 array[DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN] = cnf->accept_ra_rt_info_max_plen; 3824 array[DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN] = cnf->accept_ra_rt_info_max_plen;
3827#endif 3825#endif
@@ -3839,6 +3837,15 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
3839 array[DEVCONF_FORCE_TLLAO] = cnf->force_tllao; 3837 array[DEVCONF_FORCE_TLLAO] = cnf->force_tllao;
3840} 3838}
3841 3839
3840static inline size_t inet6_ifla6_size(void)
3841{
3842 return nla_total_size(4) /* IFLA_INET6_FLAGS */
3843 + nla_total_size(sizeof(struct ifla_cacheinfo))
3844 + nla_total_size(DEVCONF_MAX * 4) /* IFLA_INET6_CONF */
3845 + nla_total_size(IPSTATS_MIB_MAX * 8) /* IFLA_INET6_STATS */
3846 + nla_total_size(ICMP6_MIB_MAX * 8); /* IFLA_INET6_ICMP6STATS */
3847}
3848
3842static inline size_t inet6_if_nlmsg_size(void) 3849static inline size_t inet6_if_nlmsg_size(void)
3843{ 3850{
3844 return NLMSG_ALIGN(sizeof(struct ifinfomsg)) 3851 return NLMSG_ALIGN(sizeof(struct ifinfomsg))
@@ -3846,13 +3853,7 @@ static inline size_t inet6_if_nlmsg_size(void)
3846 + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */ 3853 + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */
3847 + nla_total_size(4) /* IFLA_MTU */ 3854 + nla_total_size(4) /* IFLA_MTU */
3848 + nla_total_size(4) /* IFLA_LINK */ 3855 + nla_total_size(4) /* IFLA_LINK */
3849 + nla_total_size( /* IFLA_PROTINFO */ 3856 + nla_total_size(inet6_ifla6_size()); /* IFLA_PROTINFO */
3850 nla_total_size(4) /* IFLA_INET6_FLAGS */
3851 + nla_total_size(sizeof(struct ifla_cacheinfo))
3852 + nla_total_size(DEVCONF_MAX * 4) /* IFLA_INET6_CONF */
3853 + nla_total_size(IPSTATS_MIB_MAX * 8) /* IFLA_INET6_STATS */
3854 + nla_total_size(ICMP6_MIB_MAX * 8) /* IFLA_INET6_ICMP6STATS */
3855 );
3856} 3857}
3857 3858
3858static inline void __snmp6_fill_stats(u64 *stats, void __percpu **mib, 3859static inline void __snmp6_fill_stats(u64 *stats, void __percpu **mib,
@@ -3899,15 +3900,70 @@ static void snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype,
3899 } 3900 }
3900} 3901}
3901 3902
3903static int inet6_fill_ifla6_attrs(struct sk_buff *skb, struct inet6_dev *idev)
3904{
3905 struct nlattr *nla;
3906 struct ifla_cacheinfo ci;
3907
3908 NLA_PUT_U32(skb, IFLA_INET6_FLAGS, idev->if_flags);
3909
3910 ci.max_reasm_len = IPV6_MAXPLEN;
3911 ci.tstamp = cstamp_delta(idev->tstamp);
3912 ci.reachable_time = jiffies_to_msecs(idev->nd_parms->reachable_time);
3913 ci.retrans_time = jiffies_to_msecs(idev->nd_parms->retrans_time);
3914 NLA_PUT(skb, IFLA_INET6_CACHEINFO, sizeof(ci), &ci);
3915
3916 nla = nla_reserve(skb, IFLA_INET6_CONF, DEVCONF_MAX * sizeof(s32));
3917 if (nla == NULL)
3918 goto nla_put_failure;
3919 ipv6_store_devconf(&idev->cnf, nla_data(nla), nla_len(nla));
3920
3921 /* XXX - MC not implemented */
3922
3923 nla = nla_reserve(skb, IFLA_INET6_STATS, IPSTATS_MIB_MAX * sizeof(u64));
3924 if (nla == NULL)
3925 goto nla_put_failure;
3926 snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_STATS, nla_len(nla));
3927
3928 nla = nla_reserve(skb, IFLA_INET6_ICMP6STATS, ICMP6_MIB_MAX * sizeof(u64));
3929 if (nla == NULL)
3930 goto nla_put_failure;
3931 snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_ICMP6STATS, nla_len(nla));
3932
3933 return 0;
3934
3935nla_put_failure:
3936 return -EMSGSIZE;
3937}
3938
3939static size_t inet6_get_link_af_size(const struct net_device *dev)
3940{
3941 if (!__in6_dev_get(dev))
3942 return 0;
3943
3944 return inet6_ifla6_size();
3945}
3946
3947static int inet6_fill_link_af(struct sk_buff *skb, const struct net_device *dev)
3948{
3949 struct inet6_dev *idev = __in6_dev_get(dev);
3950
3951 if (!idev)
3952 return -ENODATA;
3953
3954 if (inet6_fill_ifla6_attrs(skb, idev) < 0)
3955 return -EMSGSIZE;
3956
3957 return 0;
3958}
3959
3902static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, 3960static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev,
3903 u32 pid, u32 seq, int event, unsigned int flags) 3961 u32 pid, u32 seq, int event, unsigned int flags)
3904{ 3962{
3905 struct net_device *dev = idev->dev; 3963 struct net_device *dev = idev->dev;
3906 struct nlattr *nla;
3907 struct ifinfomsg *hdr; 3964 struct ifinfomsg *hdr;
3908 struct nlmsghdr *nlh; 3965 struct nlmsghdr *nlh;
3909 void *protoinfo; 3966 void *protoinfo;
3910 struct ifla_cacheinfo ci;
3911 3967
3912 nlh = nlmsg_put(skb, pid, seq, event, sizeof(*hdr), flags); 3968 nlh = nlmsg_put(skb, pid, seq, event, sizeof(*hdr), flags);
3913 if (nlh == NULL) 3969 if (nlh == NULL)
@@ -3934,31 +3990,8 @@ static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev,
3934 if (protoinfo == NULL) 3990 if (protoinfo == NULL)
3935 goto nla_put_failure; 3991 goto nla_put_failure;
3936 3992
3937 NLA_PUT_U32(skb, IFLA_INET6_FLAGS, idev->if_flags); 3993 if (inet6_fill_ifla6_attrs(skb, idev) < 0)
3938
3939 ci.max_reasm_len = IPV6_MAXPLEN;
3940 ci.tstamp = (__u32)(TIME_DELTA(idev->tstamp, INITIAL_JIFFIES) / HZ * 100
3941 + TIME_DELTA(idev->tstamp, INITIAL_JIFFIES) % HZ * 100 / HZ);
3942 ci.reachable_time = idev->nd_parms->reachable_time;
3943 ci.retrans_time = idev->nd_parms->retrans_time;
3944 NLA_PUT(skb, IFLA_INET6_CACHEINFO, sizeof(ci), &ci);
3945
3946 nla = nla_reserve(skb, IFLA_INET6_CONF, DEVCONF_MAX * sizeof(s32));
3947 if (nla == NULL)
3948 goto nla_put_failure;
3949 ipv6_store_devconf(&idev->cnf, nla_data(nla), nla_len(nla));
3950
3951 /* XXX - MC not implemented */
3952
3953 nla = nla_reserve(skb, IFLA_INET6_STATS, IPSTATS_MIB_MAX * sizeof(u64));
3954 if (nla == NULL)
3955 goto nla_put_failure; 3994 goto nla_put_failure;
3956 snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_STATS, nla_len(nla));
3957
3958 nla = nla_reserve(skb, IFLA_INET6_ICMP6STATS, ICMP6_MIB_MAX * sizeof(u64));
3959 if (nla == NULL)
3960 goto nla_put_failure;
3961 snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_ICMP6STATS, nla_len(nla));
3962 3995
3963 nla_nest_end(skb, protoinfo); 3996 nla_nest_end(skb, protoinfo);
3964 return nlmsg_end(skb, nlh); 3997 return nlmsg_end(skb, nlh);
@@ -4025,11 +4058,11 @@ void inet6_ifinfo_notify(int event, struct inet6_dev *idev)
4025 kfree_skb(skb); 4058 kfree_skb(skb);
4026 goto errout; 4059 goto errout;
4027 } 4060 }
4028 rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC); 4061 rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFINFO, NULL, GFP_ATOMIC);
4029 return; 4062 return;
4030errout: 4063errout:
4031 if (err < 0) 4064 if (err < 0)
4032 rtnl_set_sk_err(net, RTNLGRP_IPV6_IFADDR, err); 4065 rtnl_set_sk_err(net, RTNLGRP_IPV6_IFINFO, err);
4033} 4066}
4034 4067
4035static inline size_t inet6_prefix_nlmsg_size(void) 4068static inline size_t inet6_prefix_nlmsg_size(void)
@@ -4629,6 +4662,12 @@ int unregister_inet6addr_notifier(struct notifier_block *nb)
4629} 4662}
4630EXPORT_SYMBOL(unregister_inet6addr_notifier); 4663EXPORT_SYMBOL(unregister_inet6addr_notifier);
4631 4664
4665static struct rtnl_af_ops inet6_ops = {
4666 .family = AF_INET6,
4667 .fill_link_af = inet6_fill_link_af,
4668 .get_link_af_size = inet6_get_link_af_size,
4669};
4670
4632/* 4671/*
4633 * Init / cleanup code 4672 * Init / cleanup code
4634 */ 4673 */
@@ -4680,6 +4719,10 @@ int __init addrconf_init(void)
4680 4719
4681 addrconf_verify(0); 4720 addrconf_verify(0);
4682 4721
4722 err = rtnl_af_register(&inet6_ops);
4723 if (err < 0)
4724 goto errout_af;
4725
4683 err = __rtnl_register(PF_INET6, RTM_GETLINK, NULL, inet6_dump_ifinfo); 4726 err = __rtnl_register(PF_INET6, RTM_GETLINK, NULL, inet6_dump_ifinfo);
4684 if (err < 0) 4727 if (err < 0)
4685 goto errout; 4728 goto errout;
@@ -4695,6 +4738,8 @@ int __init addrconf_init(void)
4695 4738
4696 return 0; 4739 return 0;
4697errout: 4740errout:
4741 rtnl_af_unregister(&inet6_ops);
4742errout_af:
4698 unregister_netdevice_notifier(&ipv6_dev_notf); 4743 unregister_netdevice_notifier(&ipv6_dev_notf);
4699errlo: 4744errlo:
4700 unregister_pernet_subsys(&addrconf_ops); 4745 unregister_pernet_subsys(&addrconf_ops);
@@ -4715,6 +4760,8 @@ void addrconf_cleanup(void)
4715 4760
4716 rtnl_lock(); 4761 rtnl_lock();
4717 4762
4763 __rtnl_af_unregister(&inet6_ops);
4764
4718 /* clean dev list */ 4765 /* clean dev list */
4719 for_each_netdev(&init_net, dev) { 4766 for_each_netdev(&init_net, dev) {
4720 if (__in6_dev_get(dev) == NULL) 4767 if (__in6_dev_get(dev) == NULL)