diff options
Diffstat (limited to 'net/ipv6/addrconf.c')
-rw-r--r-- | net/ipv6/addrconf.c | 208 |
1 files changed, 197 insertions, 11 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index dae802c0af7c..d1ab6ab29a55 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -70,6 +70,7 @@ | |||
70 | #include <net/snmp.h> | 70 | #include <net/snmp.h> |
71 | 71 | ||
72 | #include <net/af_ieee802154.h> | 72 | #include <net/af_ieee802154.h> |
73 | #include <net/firewire.h> | ||
73 | #include <net/ipv6.h> | 74 | #include <net/ipv6.h> |
74 | #include <net/protocol.h> | 75 | #include <net/protocol.h> |
75 | #include <net/ndisc.h> | 76 | #include <net/ndisc.h> |
@@ -419,6 +420,7 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev) | |||
419 | ipv6_regen_rndid((unsigned long) ndev); | 420 | ipv6_regen_rndid((unsigned long) ndev); |
420 | } | 421 | } |
421 | #endif | 422 | #endif |
423 | ndev->token = in6addr_any; | ||
422 | 424 | ||
423 | if (netif_running(dev) && addrconf_qdisc_ok(dev)) | 425 | if (netif_running(dev) && addrconf_qdisc_ok(dev)) |
424 | ndev->if_flags |= IF_READY; | 426 | ndev->if_flags |= IF_READY; |
@@ -542,8 +544,7 @@ static const struct nla_policy devconf_ipv6_policy[NETCONFA_MAX+1] = { | |||
542 | }; | 544 | }; |
543 | 545 | ||
544 | static int inet6_netconf_get_devconf(struct sk_buff *in_skb, | 546 | static int inet6_netconf_get_devconf(struct sk_buff *in_skb, |
545 | struct nlmsghdr *nlh, | 547 | struct nlmsghdr *nlh) |
546 | void *arg) | ||
547 | { | 548 | { |
548 | struct net *net = sock_net(in_skb->sk); | 549 | struct net *net = sock_net(in_skb->sk); |
549 | struct nlattr *tb[NETCONFA_MAX+1]; | 550 | struct nlattr *tb[NETCONFA_MAX+1]; |
@@ -603,6 +604,77 @@ errout: | |||
603 | return err; | 604 | return err; |
604 | } | 605 | } |
605 | 606 | ||
607 | static int inet6_netconf_dump_devconf(struct sk_buff *skb, | ||
608 | struct netlink_callback *cb) | ||
609 | { | ||
610 | struct net *net = sock_net(skb->sk); | ||
611 | int h, s_h; | ||
612 | int idx, s_idx; | ||
613 | struct net_device *dev; | ||
614 | struct inet6_dev *idev; | ||
615 | struct hlist_head *head; | ||
616 | |||
617 | s_h = cb->args[0]; | ||
618 | s_idx = idx = cb->args[1]; | ||
619 | |||
620 | for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { | ||
621 | idx = 0; | ||
622 | head = &net->dev_index_head[h]; | ||
623 | rcu_read_lock(); | ||
624 | cb->seq = atomic_read(&net->ipv6.dev_addr_genid) ^ | ||
625 | net->dev_base_seq; | ||
626 | hlist_for_each_entry_rcu(dev, head, index_hlist) { | ||
627 | if (idx < s_idx) | ||
628 | goto cont; | ||
629 | idev = __in6_dev_get(dev); | ||
630 | if (!idev) | ||
631 | goto cont; | ||
632 | |||
633 | if (inet6_netconf_fill_devconf(skb, dev->ifindex, | ||
634 | &idev->cnf, | ||
635 | NETLINK_CB(cb->skb).portid, | ||
636 | cb->nlh->nlmsg_seq, | ||
637 | RTM_NEWNETCONF, | ||
638 | NLM_F_MULTI, | ||
639 | -1) <= 0) { | ||
640 | rcu_read_unlock(); | ||
641 | goto done; | ||
642 | } | ||
643 | nl_dump_check_consistent(cb, nlmsg_hdr(skb)); | ||
644 | cont: | ||
645 | idx++; | ||
646 | } | ||
647 | rcu_read_unlock(); | ||
648 | } | ||
649 | if (h == NETDEV_HASHENTRIES) { | ||
650 | if (inet6_netconf_fill_devconf(skb, NETCONFA_IFINDEX_ALL, | ||
651 | net->ipv6.devconf_all, | ||
652 | NETLINK_CB(cb->skb).portid, | ||
653 | cb->nlh->nlmsg_seq, | ||
654 | RTM_NEWNETCONF, NLM_F_MULTI, | ||
655 | -1) <= 0) | ||
656 | goto done; | ||
657 | else | ||
658 | h++; | ||
659 | } | ||
660 | if (h == NETDEV_HASHENTRIES + 1) { | ||
661 | if (inet6_netconf_fill_devconf(skb, NETCONFA_IFINDEX_DEFAULT, | ||
662 | net->ipv6.devconf_dflt, | ||
663 | NETLINK_CB(cb->skb).portid, | ||
664 | cb->nlh->nlmsg_seq, | ||
665 | RTM_NEWNETCONF, NLM_F_MULTI, | ||
666 | -1) <= 0) | ||
667 | goto done; | ||
668 | else | ||
669 | h++; | ||
670 | } | ||
671 | done: | ||
672 | cb->args[0] = h; | ||
673 | cb->args[1] = idx; | ||
674 | |||
675 | return skb->len; | ||
676 | } | ||
677 | |||
606 | #ifdef CONFIG_SYSCTL | 678 | #ifdef CONFIG_SYSCTL |
607 | static void dev_forward_change(struct inet6_dev *idev) | 679 | static void dev_forward_change(struct inet6_dev *idev) |
608 | { | 680 | { |
@@ -804,6 +876,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, | |||
804 | ifa->prefix_len = pfxlen; | 876 | ifa->prefix_len = pfxlen; |
805 | ifa->flags = flags | IFA_F_TENTATIVE; | 877 | ifa->flags = flags | IFA_F_TENTATIVE; |
806 | ifa->cstamp = ifa->tstamp = jiffies; | 878 | ifa->cstamp = ifa->tstamp = jiffies; |
879 | ifa->tokenized = false; | ||
807 | 880 | ||
808 | ifa->rt = rt; | 881 | ifa->rt = rt; |
809 | 882 | ||
@@ -1666,6 +1739,20 @@ static int addrconf_ifid_eui64(u8 *eui, struct net_device *dev) | |||
1666 | return 0; | 1739 | return 0; |
1667 | } | 1740 | } |
1668 | 1741 | ||
1742 | static int addrconf_ifid_ieee1394(u8 *eui, struct net_device *dev) | ||
1743 | { | ||
1744 | union fwnet_hwaddr *ha; | ||
1745 | |||
1746 | if (dev->addr_len != FWNET_ALEN) | ||
1747 | return -1; | ||
1748 | |||
1749 | ha = (union fwnet_hwaddr *)dev->dev_addr; | ||
1750 | |||
1751 | memcpy(eui, &ha->uc.uniq_id, sizeof(ha->uc.uniq_id)); | ||
1752 | eui[0] ^= 2; | ||
1753 | return 0; | ||
1754 | } | ||
1755 | |||
1669 | static int addrconf_ifid_arcnet(u8 *eui, struct net_device *dev) | 1756 | static int addrconf_ifid_arcnet(u8 *eui, struct net_device *dev) |
1670 | { | 1757 | { |
1671 | /* XXX: inherit EUI-64 from other interface -- yoshfuji */ | 1758 | /* XXX: inherit EUI-64 from other interface -- yoshfuji */ |
@@ -1730,6 +1817,8 @@ static int ipv6_generate_eui64(u8 *eui, struct net_device *dev) | |||
1730 | return addrconf_ifid_gre(eui, dev); | 1817 | return addrconf_ifid_gre(eui, dev); |
1731 | case ARPHRD_IEEE802154: | 1818 | case ARPHRD_IEEE802154: |
1732 | return addrconf_ifid_eui64(eui, dev); | 1819 | return addrconf_ifid_eui64(eui, dev); |
1820 | case ARPHRD_IEEE1394: | ||
1821 | return addrconf_ifid_ieee1394(eui, dev); | ||
1733 | } | 1822 | } |
1734 | return -1; | 1823 | return -1; |
1735 | } | 1824 | } |
@@ -2044,11 +2133,19 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao) | |||
2044 | struct inet6_ifaddr *ifp; | 2133 | struct inet6_ifaddr *ifp; |
2045 | struct in6_addr addr; | 2134 | struct in6_addr addr; |
2046 | int create = 0, update_lft = 0; | 2135 | int create = 0, update_lft = 0; |
2136 | bool tokenized = false; | ||
2047 | 2137 | ||
2048 | if (pinfo->prefix_len == 64) { | 2138 | if (pinfo->prefix_len == 64) { |
2049 | memcpy(&addr, &pinfo->prefix, 8); | 2139 | memcpy(&addr, &pinfo->prefix, 8); |
2050 | if (ipv6_generate_eui64(addr.s6_addr + 8, dev) && | 2140 | |
2051 | ipv6_inherit_eui64(addr.s6_addr + 8, in6_dev)) { | 2141 | if (!ipv6_addr_any(&in6_dev->token)) { |
2142 | read_lock_bh(&in6_dev->lock); | ||
2143 | memcpy(addr.s6_addr + 8, | ||
2144 | in6_dev->token.s6_addr + 8, 8); | ||
2145 | read_unlock_bh(&in6_dev->lock); | ||
2146 | tokenized = true; | ||
2147 | } else if (ipv6_generate_eui64(addr.s6_addr + 8, dev) && | ||
2148 | ipv6_inherit_eui64(addr.s6_addr + 8, in6_dev)) { | ||
2052 | in6_dev_put(in6_dev); | 2149 | in6_dev_put(in6_dev); |
2053 | return; | 2150 | return; |
2054 | } | 2151 | } |
@@ -2089,6 +2186,7 @@ ok: | |||
2089 | 2186 | ||
2090 | update_lft = create = 1; | 2187 | update_lft = create = 1; |
2091 | ifp->cstamp = jiffies; | 2188 | ifp->cstamp = jiffies; |
2189 | ifp->tokenized = tokenized; | ||
2092 | addrconf_dad_start(ifp); | 2190 | addrconf_dad_start(ifp); |
2093 | } | 2191 | } |
2094 | 2192 | ||
@@ -2598,7 +2696,8 @@ static void addrconf_dev_config(struct net_device *dev) | |||
2598 | (dev->type != ARPHRD_FDDI) && | 2696 | (dev->type != ARPHRD_FDDI) && |
2599 | (dev->type != ARPHRD_ARCNET) && | 2697 | (dev->type != ARPHRD_ARCNET) && |
2600 | (dev->type != ARPHRD_INFINIBAND) && | 2698 | (dev->type != ARPHRD_INFINIBAND) && |
2601 | (dev->type != ARPHRD_IEEE802154)) { | 2699 | (dev->type != ARPHRD_IEEE802154) && |
2700 | (dev->type != ARPHRD_IEEE1394)) { | ||
2602 | /* Alas, we support only Ethernet autoconfiguration. */ | 2701 | /* Alas, we support only Ethernet autoconfiguration. */ |
2603 | return; | 2702 | return; |
2604 | } | 2703 | } |
@@ -3535,7 +3634,7 @@ static const struct nla_policy ifa_ipv6_policy[IFA_MAX+1] = { | |||
3535 | }; | 3634 | }; |
3536 | 3635 | ||
3537 | static int | 3636 | static int |
3538 | inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 3637 | inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh) |
3539 | { | 3638 | { |
3540 | struct net *net = sock_net(skb->sk); | 3639 | struct net *net = sock_net(skb->sk); |
3541 | struct ifaddrmsg *ifm; | 3640 | struct ifaddrmsg *ifm; |
@@ -3601,7 +3700,7 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags, | |||
3601 | } | 3700 | } |
3602 | 3701 | ||
3603 | static int | 3702 | static int |
3604 | inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 3703 | inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh) |
3605 | { | 3704 | { |
3606 | struct net *net = sock_net(skb->sk); | 3705 | struct net *net = sock_net(skb->sk); |
3607 | struct ifaddrmsg *ifm; | 3706 | struct ifaddrmsg *ifm; |
@@ -3832,6 +3931,7 @@ static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb, | |||
3832 | NLM_F_MULTI); | 3931 | NLM_F_MULTI); |
3833 | if (err <= 0) | 3932 | if (err <= 0) |
3834 | break; | 3933 | break; |
3934 | nl_dump_check_consistent(cb, nlmsg_hdr(skb)); | ||
3835 | } | 3935 | } |
3836 | break; | 3936 | break; |
3837 | } | 3937 | } |
@@ -3889,6 +3989,7 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, | |||
3889 | s_ip_idx = ip_idx = cb->args[2]; | 3989 | s_ip_idx = ip_idx = cb->args[2]; |
3890 | 3990 | ||
3891 | rcu_read_lock(); | 3991 | rcu_read_lock(); |
3992 | cb->seq = atomic_read(&net->ipv6.dev_addr_genid) ^ net->dev_base_seq; | ||
3892 | for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { | 3993 | for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { |
3893 | idx = 0; | 3994 | idx = 0; |
3894 | head = &net->dev_index_head[h]; | 3995 | head = &net->dev_index_head[h]; |
@@ -3940,8 +4041,7 @@ static int inet6_dump_ifacaddr(struct sk_buff *skb, struct netlink_callback *cb) | |||
3940 | return inet6_dump_addr(skb, cb, type); | 4041 | return inet6_dump_addr(skb, cb, type); |
3941 | } | 4042 | } |
3942 | 4043 | ||
3943 | static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr *nlh, | 4044 | static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr *nlh) |
3944 | void *arg) | ||
3945 | { | 4045 | { |
3946 | struct net *net = sock_net(in_skb->sk); | 4046 | struct net *net = sock_net(in_skb->sk); |
3947 | struct ifaddrmsg *ifm; | 4047 | struct ifaddrmsg *ifm; |
@@ -4074,7 +4174,8 @@ static inline size_t inet6_ifla6_size(void) | |||
4074 | + nla_total_size(sizeof(struct ifla_cacheinfo)) | 4174 | + nla_total_size(sizeof(struct ifla_cacheinfo)) |
4075 | + nla_total_size(DEVCONF_MAX * 4) /* IFLA_INET6_CONF */ | 4175 | + nla_total_size(DEVCONF_MAX * 4) /* IFLA_INET6_CONF */ |
4076 | + nla_total_size(IPSTATS_MIB_MAX * 8) /* IFLA_INET6_STATS */ | 4176 | + nla_total_size(IPSTATS_MIB_MAX * 8) /* IFLA_INET6_STATS */ |
4077 | + nla_total_size(ICMP6_MIB_MAX * 8); /* IFLA_INET6_ICMP6STATS */ | 4177 | + nla_total_size(ICMP6_MIB_MAX * 8) /* IFLA_INET6_ICMP6STATS */ |
4178 | + nla_total_size(sizeof(struct in6_addr)); /* IFLA_INET6_TOKEN */ | ||
4078 | } | 4179 | } |
4079 | 4180 | ||
4080 | static inline size_t inet6_if_nlmsg_size(void) | 4181 | static inline size_t inet6_if_nlmsg_size(void) |
@@ -4161,6 +4262,13 @@ static int inet6_fill_ifla6_attrs(struct sk_buff *skb, struct inet6_dev *idev) | |||
4161 | goto nla_put_failure; | 4262 | goto nla_put_failure; |
4162 | snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_ICMP6STATS, nla_len(nla)); | 4263 | snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_ICMP6STATS, nla_len(nla)); |
4163 | 4264 | ||
4265 | nla = nla_reserve(skb, IFLA_INET6_TOKEN, sizeof(struct in6_addr)); | ||
4266 | if (nla == NULL) | ||
4267 | goto nla_put_failure; | ||
4268 | read_lock_bh(&idev->lock); | ||
4269 | memcpy(nla_data(nla), idev->token.s6_addr, nla_len(nla)); | ||
4270 | read_unlock_bh(&idev->lock); | ||
4271 | |||
4164 | return 0; | 4272 | return 0; |
4165 | 4273 | ||
4166 | nla_put_failure: | 4274 | nla_put_failure: |
@@ -4188,6 +4296,80 @@ static int inet6_fill_link_af(struct sk_buff *skb, const struct net_device *dev) | |||
4188 | return 0; | 4296 | return 0; |
4189 | } | 4297 | } |
4190 | 4298 | ||
4299 | static int inet6_set_iftoken(struct inet6_dev *idev, struct in6_addr *token) | ||
4300 | { | ||
4301 | struct inet6_ifaddr *ifp; | ||
4302 | struct net_device *dev = idev->dev; | ||
4303 | bool update_rs = false; | ||
4304 | |||
4305 | if (token == NULL) | ||
4306 | return -EINVAL; | ||
4307 | if (ipv6_addr_any(token)) | ||
4308 | return -EINVAL; | ||
4309 | if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) | ||
4310 | return -EINVAL; | ||
4311 | if (!ipv6_accept_ra(idev)) | ||
4312 | return -EINVAL; | ||
4313 | if (idev->cnf.rtr_solicits <= 0) | ||
4314 | return -EINVAL; | ||
4315 | |||
4316 | write_lock_bh(&idev->lock); | ||
4317 | |||
4318 | BUILD_BUG_ON(sizeof(token->s6_addr) != 16); | ||
4319 | memcpy(idev->token.s6_addr + 8, token->s6_addr + 8, 8); | ||
4320 | |||
4321 | write_unlock_bh(&idev->lock); | ||
4322 | |||
4323 | if (!idev->dead && (idev->if_flags & IF_READY)) { | ||
4324 | struct in6_addr ll_addr; | ||
4325 | |||
4326 | ipv6_get_lladdr(dev, &ll_addr, IFA_F_TENTATIVE | | ||
4327 | IFA_F_OPTIMISTIC); | ||
4328 | |||
4329 | /* If we're not ready, then normal ifup will take care | ||
4330 | * of this. Otherwise, we need to request our rs here. | ||
4331 | */ | ||
4332 | ndisc_send_rs(dev, &ll_addr, &in6addr_linklocal_allrouters); | ||
4333 | update_rs = true; | ||
4334 | } | ||
4335 | |||
4336 | write_lock_bh(&idev->lock); | ||
4337 | |||
4338 | if (update_rs) | ||
4339 | idev->if_flags |= IF_RS_SENT; | ||
4340 | |||
4341 | /* Well, that's kinda nasty ... */ | ||
4342 | list_for_each_entry(ifp, &idev->addr_list, if_list) { | ||
4343 | spin_lock(&ifp->lock); | ||
4344 | if (ifp->tokenized) { | ||
4345 | ifp->valid_lft = 0; | ||
4346 | ifp->prefered_lft = 0; | ||
4347 | } | ||
4348 | spin_unlock(&ifp->lock); | ||
4349 | } | ||
4350 | |||
4351 | write_unlock_bh(&idev->lock); | ||
4352 | return 0; | ||
4353 | } | ||
4354 | |||
4355 | static int inet6_set_link_af(struct net_device *dev, const struct nlattr *nla) | ||
4356 | { | ||
4357 | int err = -EINVAL; | ||
4358 | struct inet6_dev *idev = __in6_dev_get(dev); | ||
4359 | struct nlattr *tb[IFLA_INET6_MAX + 1]; | ||
4360 | |||
4361 | if (!idev) | ||
4362 | return -EAFNOSUPPORT; | ||
4363 | |||
4364 | if (nla_parse_nested(tb, IFLA_INET6_MAX, nla, NULL) < 0) | ||
4365 | BUG(); | ||
4366 | |||
4367 | if (tb[IFLA_INET6_TOKEN]) | ||
4368 | err = inet6_set_iftoken(idev, nla_data(tb[IFLA_INET6_TOKEN])); | ||
4369 | |||
4370 | return err; | ||
4371 | } | ||
4372 | |||
4191 | static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, | 4373 | static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, |
4192 | u32 portid, u32 seq, int event, unsigned int flags) | 4374 | u32 portid, u32 seq, int event, unsigned int flags) |
4193 | { | 4375 | { |
@@ -4366,6 +4548,8 @@ errout: | |||
4366 | 4548 | ||
4367 | static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) | 4549 | static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) |
4368 | { | 4550 | { |
4551 | struct net *net = dev_net(ifp->idev->dev); | ||
4552 | |||
4369 | inet6_ifa_notify(event ? : RTM_NEWADDR, ifp); | 4553 | inet6_ifa_notify(event ? : RTM_NEWADDR, ifp); |
4370 | 4554 | ||
4371 | switch (event) { | 4555 | switch (event) { |
@@ -4391,6 +4575,7 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) | |||
4391 | dst_free(&ifp->rt->dst); | 4575 | dst_free(&ifp->rt->dst); |
4392 | break; | 4576 | break; |
4393 | } | 4577 | } |
4578 | atomic_inc(&net->ipv6.dev_addr_genid); | ||
4394 | } | 4579 | } |
4395 | 4580 | ||
4396 | static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) | 4581 | static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) |
@@ -4871,6 +5056,7 @@ static struct rtnl_af_ops inet6_ops = { | |||
4871 | .family = AF_INET6, | 5056 | .family = AF_INET6, |
4872 | .fill_link_af = inet6_fill_link_af, | 5057 | .fill_link_af = inet6_fill_link_af, |
4873 | .get_link_af_size = inet6_get_link_af_size, | 5058 | .get_link_af_size = inet6_get_link_af_size, |
5059 | .set_link_af = inet6_set_link_af, | ||
4874 | }; | 5060 | }; |
4875 | 5061 | ||
4876 | /* | 5062 | /* |
@@ -4943,7 +5129,7 @@ int __init addrconf_init(void) | |||
4943 | __rtnl_register(PF_INET6, RTM_GETANYCAST, NULL, | 5129 | __rtnl_register(PF_INET6, RTM_GETANYCAST, NULL, |
4944 | inet6_dump_ifacaddr, NULL); | 5130 | inet6_dump_ifacaddr, NULL); |
4945 | __rtnl_register(PF_INET6, RTM_GETNETCONF, inet6_netconf_get_devconf, | 5131 | __rtnl_register(PF_INET6, RTM_GETNETCONF, inet6_netconf_get_devconf, |
4946 | NULL, NULL); | 5132 | inet6_netconf_dump_devconf, NULL); |
4947 | 5133 | ||
4948 | ipv6_addr_label_rtnl_register(); | 5134 | ipv6_addr_label_rtnl_register(); |
4949 | 5135 | ||