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.c82
1 files changed, 65 insertions, 17 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index f7c8bbeb27b7..98e4a63d72bb 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -201,6 +201,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
201 .disable_ipv6 = 0, 201 .disable_ipv6 = 0,
202 .accept_dad = 1, 202 .accept_dad = 1,
203 .suppress_frag_ndisc = 1, 203 .suppress_frag_ndisc = 1,
204 .accept_ra_mtu = 1,
204}; 205};
205 206
206static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { 207static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
@@ -238,6 +239,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
238 .disable_ipv6 = 0, 239 .disable_ipv6 = 0,
239 .accept_dad = 1, 240 .accept_dad = 1,
240 .suppress_frag_ndisc = 1, 241 .suppress_frag_ndisc = 1,
242 .accept_ra_mtu = 1,
241}; 243};
242 244
243/* Check if a valid qdisc is available */ 245/* Check if a valid qdisc is available */
@@ -489,7 +491,8 @@ static int inet6_netconf_fill_devconf(struct sk_buff *skb, int ifindex,
489 nla_put_s32(skb, NETCONFA_PROXY_NEIGH, devconf->proxy_ndp) < 0) 491 nla_put_s32(skb, NETCONFA_PROXY_NEIGH, devconf->proxy_ndp) < 0)
490 goto nla_put_failure; 492 goto nla_put_failure;
491 493
492 return nlmsg_end(skb, nlh); 494 nlmsg_end(skb, nlh);
495 return 0;
493 496
494nla_put_failure: 497nla_put_failure:
495 nlmsg_cancel(skb, nlh); 498 nlmsg_cancel(skb, nlh);
@@ -619,7 +622,7 @@ static int inet6_netconf_dump_devconf(struct sk_buff *skb,
619 cb->nlh->nlmsg_seq, 622 cb->nlh->nlmsg_seq,
620 RTM_NEWNETCONF, 623 RTM_NEWNETCONF,
621 NLM_F_MULTI, 624 NLM_F_MULTI,
622 -1) <= 0) { 625 -1) < 0) {
623 rcu_read_unlock(); 626 rcu_read_unlock();
624 goto done; 627 goto done;
625 } 628 }
@@ -635,7 +638,7 @@ cont:
635 NETLINK_CB(cb->skb).portid, 638 NETLINK_CB(cb->skb).portid,
636 cb->nlh->nlmsg_seq, 639 cb->nlh->nlmsg_seq,
637 RTM_NEWNETCONF, NLM_F_MULTI, 640 RTM_NEWNETCONF, NLM_F_MULTI,
638 -1) <= 0) 641 -1) < 0)
639 goto done; 642 goto done;
640 else 643 else
641 h++; 644 h++;
@@ -646,7 +649,7 @@ cont:
646 NETLINK_CB(cb->skb).portid, 649 NETLINK_CB(cb->skb).portid,
647 cb->nlh->nlmsg_seq, 650 cb->nlh->nlmsg_seq,
648 RTM_NEWNETCONF, NLM_F_MULTI, 651 RTM_NEWNETCONF, NLM_F_MULTI,
649 -1) <= 0) 652 -1) < 0)
650 goto done; 653 goto done;
651 else 654 else
652 h++; 655 h++;
@@ -1519,15 +1522,30 @@ static int ipv6_count_addresses(struct inet6_dev *idev)
1519int ipv6_chk_addr(struct net *net, const struct in6_addr *addr, 1522int ipv6_chk_addr(struct net *net, const struct in6_addr *addr,
1520 const struct net_device *dev, int strict) 1523 const struct net_device *dev, int strict)
1521{ 1524{
1525 return ipv6_chk_addr_and_flags(net, addr, dev, strict, IFA_F_TENTATIVE);
1526}
1527EXPORT_SYMBOL(ipv6_chk_addr);
1528
1529int ipv6_chk_addr_and_flags(struct net *net, const struct in6_addr *addr,
1530 const struct net_device *dev, int strict,
1531 u32 banned_flags)
1532{
1522 struct inet6_ifaddr *ifp; 1533 struct inet6_ifaddr *ifp;
1523 unsigned int hash = inet6_addr_hash(addr); 1534 unsigned int hash = inet6_addr_hash(addr);
1535 u32 ifp_flags;
1524 1536
1525 rcu_read_lock_bh(); 1537 rcu_read_lock_bh();
1526 hlist_for_each_entry_rcu(ifp, &inet6_addr_lst[hash], addr_lst) { 1538 hlist_for_each_entry_rcu(ifp, &inet6_addr_lst[hash], addr_lst) {
1527 if (!net_eq(dev_net(ifp->idev->dev), net)) 1539 if (!net_eq(dev_net(ifp->idev->dev), net))
1528 continue; 1540 continue;
1541 /* Decouple optimistic from tentative for evaluation here.
1542 * Ban optimistic addresses explicitly, when required.
1543 */
1544 ifp_flags = (ifp->flags&IFA_F_OPTIMISTIC)
1545 ? (ifp->flags&~IFA_F_TENTATIVE)
1546 : ifp->flags;
1529 if (ipv6_addr_equal(&ifp->addr, addr) && 1547 if (ipv6_addr_equal(&ifp->addr, addr) &&
1530 !(ifp->flags&IFA_F_TENTATIVE) && 1548 !(ifp_flags&banned_flags) &&
1531 (dev == NULL || ifp->idev->dev == dev || 1549 (dev == NULL || ifp->idev->dev == dev ||
1532 !(ifp->scope&(IFA_LINK|IFA_HOST) || strict))) { 1550 !(ifp->scope&(IFA_LINK|IFA_HOST) || strict))) {
1533 rcu_read_unlock_bh(); 1551 rcu_read_unlock_bh();
@@ -1538,7 +1556,7 @@ int ipv6_chk_addr(struct net *net, const struct in6_addr *addr,
1538 rcu_read_unlock_bh(); 1556 rcu_read_unlock_bh();
1539 return 0; 1557 return 0;
1540} 1558}
1541EXPORT_SYMBOL(ipv6_chk_addr); 1559EXPORT_SYMBOL(ipv6_chk_addr_and_flags);
1542 1560
1543static bool ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr, 1561static bool ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr,
1544 struct net_device *dev) 1562 struct net_device *dev)
@@ -4047,7 +4065,8 @@ static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa,
4047 if (nla_put_u32(skb, IFA_FLAGS, ifa->flags) < 0) 4065 if (nla_put_u32(skb, IFA_FLAGS, ifa->flags) < 0)
4048 goto error; 4066 goto error;
4049 4067
4050 return nlmsg_end(skb, nlh); 4068 nlmsg_end(skb, nlh);
4069 return 0;
4051 4070
4052error: 4071error:
4053 nlmsg_cancel(skb, nlh); 4072 nlmsg_cancel(skb, nlh);
@@ -4076,7 +4095,8 @@ static int inet6_fill_ifmcaddr(struct sk_buff *skb, struct ifmcaddr6 *ifmca,
4076 return -EMSGSIZE; 4095 return -EMSGSIZE;
4077 } 4096 }
4078 4097
4079 return nlmsg_end(skb, nlh); 4098 nlmsg_end(skb, nlh);
4099 return 0;
4080} 4100}
4081 4101
4082static int inet6_fill_ifacaddr(struct sk_buff *skb, struct ifacaddr6 *ifaca, 4102static int inet6_fill_ifacaddr(struct sk_buff *skb, struct ifacaddr6 *ifaca,
@@ -4101,7 +4121,8 @@ static int inet6_fill_ifacaddr(struct sk_buff *skb, struct ifacaddr6 *ifaca,
4101 return -EMSGSIZE; 4121 return -EMSGSIZE;
4102 } 4122 }
4103 4123
4104 return nlmsg_end(skb, nlh); 4124 nlmsg_end(skb, nlh);
4125 return 0;
4105} 4126}
4106 4127
4107enum addr_type_t { 4128enum addr_type_t {
@@ -4134,7 +4155,7 @@ static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb,
4134 cb->nlh->nlmsg_seq, 4155 cb->nlh->nlmsg_seq,
4135 RTM_NEWADDR, 4156 RTM_NEWADDR,
4136 NLM_F_MULTI); 4157 NLM_F_MULTI);
4137 if (err <= 0) 4158 if (err < 0)
4138 break; 4159 break;
4139 nl_dump_check_consistent(cb, nlmsg_hdr(skb)); 4160 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
4140 } 4161 }
@@ -4151,7 +4172,7 @@ static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb,
4151 cb->nlh->nlmsg_seq, 4172 cb->nlh->nlmsg_seq,
4152 RTM_GETMULTICAST, 4173 RTM_GETMULTICAST,
4153 NLM_F_MULTI); 4174 NLM_F_MULTI);
4154 if (err <= 0) 4175 if (err < 0)
4155 break; 4176 break;
4156 } 4177 }
4157 break; 4178 break;
@@ -4166,7 +4187,7 @@ static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb,
4166 cb->nlh->nlmsg_seq, 4187 cb->nlh->nlmsg_seq,
4167 RTM_GETANYCAST, 4188 RTM_GETANYCAST,
4168 NLM_F_MULTI); 4189 NLM_F_MULTI);
4169 if (err <= 0) 4190 if (err < 0)
4170 break; 4191 break;
4171 } 4192 }
4172 break; 4193 break;
@@ -4209,7 +4230,7 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb,
4209 goto cont; 4230 goto cont;
4210 4231
4211 if (in6_dump_addrs(idev, skb, cb, type, 4232 if (in6_dump_addrs(idev, skb, cb, type,
4212 s_ip_idx, &ip_idx) <= 0) 4233 s_ip_idx, &ip_idx) < 0)
4213 goto done; 4234 goto done;
4214cont: 4235cont:
4215 idx++; 4236 idx++;
@@ -4376,6 +4397,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
4376 array[DEVCONF_NDISC_NOTIFY] = cnf->ndisc_notify; 4397 array[DEVCONF_NDISC_NOTIFY] = cnf->ndisc_notify;
4377 array[DEVCONF_SUPPRESS_FRAG_NDISC] = cnf->suppress_frag_ndisc; 4398 array[DEVCONF_SUPPRESS_FRAG_NDISC] = cnf->suppress_frag_ndisc;
4378 array[DEVCONF_ACCEPT_RA_FROM_LOCAL] = cnf->accept_ra_from_local; 4399 array[DEVCONF_ACCEPT_RA_FROM_LOCAL] = cnf->accept_ra_from_local;
4400 array[DEVCONF_ACCEPT_RA_MTU] = cnf->accept_ra_mtu;
4379} 4401}
4380 4402
4381static inline size_t inet6_ifla6_size(void) 4403static inline size_t inet6_ifla6_size(void)
@@ -4572,6 +4594,22 @@ static int inet6_set_iftoken(struct inet6_dev *idev, struct in6_addr *token)
4572 return 0; 4594 return 0;
4573} 4595}
4574 4596
4597static const struct nla_policy inet6_af_policy[IFLA_INET6_MAX + 1] = {
4598 [IFLA_INET6_ADDR_GEN_MODE] = { .type = NLA_U8 },
4599 [IFLA_INET6_TOKEN] = { .len = sizeof(struct in6_addr) },
4600};
4601
4602static int inet6_validate_link_af(const struct net_device *dev,
4603 const struct nlattr *nla)
4604{
4605 struct nlattr *tb[IFLA_INET6_MAX + 1];
4606
4607 if (dev && !__in6_dev_get(dev))
4608 return -EAFNOSUPPORT;
4609
4610 return nla_parse_nested(tb, IFLA_INET6_MAX, nla, inet6_af_policy);
4611}
4612
4575static int inet6_set_link_af(struct net_device *dev, const struct nlattr *nla) 4613static int inet6_set_link_af(struct net_device *dev, const struct nlattr *nla)
4576{ 4614{
4577 int err = -EINVAL; 4615 int err = -EINVAL;
@@ -4638,7 +4676,8 @@ static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev,
4638 goto nla_put_failure; 4676 goto nla_put_failure;
4639 4677
4640 nla_nest_end(skb, protoinfo); 4678 nla_nest_end(skb, protoinfo);
4641 return nlmsg_end(skb, nlh); 4679 nlmsg_end(skb, nlh);
4680 return 0;
4642 4681
4643nla_put_failure: 4682nla_put_failure:
4644 nlmsg_cancel(skb, nlh); 4683 nlmsg_cancel(skb, nlh);
@@ -4670,7 +4709,7 @@ static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
4670 if (inet6_fill_ifinfo(skb, idev, 4709 if (inet6_fill_ifinfo(skb, idev,
4671 NETLINK_CB(cb->skb).portid, 4710 NETLINK_CB(cb->skb).portid,
4672 cb->nlh->nlmsg_seq, 4711 cb->nlh->nlmsg_seq,
4673 RTM_NEWLINK, NLM_F_MULTI) <= 0) 4712 RTM_NEWLINK, NLM_F_MULTI) < 0)
4674 goto out; 4713 goto out;
4675cont: 4714cont:
4676 idx++; 4715 idx++;
@@ -4747,7 +4786,8 @@ static int inet6_fill_prefix(struct sk_buff *skb, struct inet6_dev *idev,
4747 ci.valid_time = ntohl(pinfo->valid); 4786 ci.valid_time = ntohl(pinfo->valid);
4748 if (nla_put(skb, PREFIX_CACHEINFO, sizeof(ci), &ci)) 4787 if (nla_put(skb, PREFIX_CACHEINFO, sizeof(ci), &ci))
4749 goto nla_put_failure; 4788 goto nla_put_failure;
4750 return nlmsg_end(skb, nlh); 4789 nlmsg_end(skb, nlh);
4790 return 0;
4751 4791
4752nla_put_failure: 4792nla_put_failure:
4753 nlmsg_cancel(skb, nlh); 4793 nlmsg_cancel(skb, nlh);
@@ -5253,6 +5293,13 @@ static struct addrconf_sysctl_table
5253 .proc_handler = proc_dointvec, 5293 .proc_handler = proc_dointvec,
5254 }, 5294 },
5255 { 5295 {
5296 .procname = "accept_ra_mtu",
5297 .data = &ipv6_devconf.accept_ra_mtu,
5298 .maxlen = sizeof(int),
5299 .mode = 0644,
5300 .proc_handler = proc_dointvec,
5301 },
5302 {
5256 /* sentinel */ 5303 /* sentinel */
5257 } 5304 }
5258 }, 5305 },
@@ -5389,10 +5436,11 @@ static struct pernet_operations addrconf_ops = {
5389 .exit = addrconf_exit_net, 5436 .exit = addrconf_exit_net,
5390}; 5437};
5391 5438
5392static struct rtnl_af_ops inet6_ops = { 5439static struct rtnl_af_ops inet6_ops __read_mostly = {
5393 .family = AF_INET6, 5440 .family = AF_INET6,
5394 .fill_link_af = inet6_fill_link_af, 5441 .fill_link_af = inet6_fill_link_af,
5395 .get_link_af_size = inet6_get_link_af_size, 5442 .get_link_af_size = inet6_get_link_af_size,
5443 .validate_link_af = inet6_validate_link_af,
5396 .set_link_af = inet6_set_link_af, 5444 .set_link_af = inet6_set_link_af,
5397}; 5445};
5398 5446