Commit 0cc526e0 authored by Alexey Kuznetsov's avatar Alexey Kuznetsov Committed by David S. Miller

[IPV6]: Fix anycast usage.

- Recognition of reserved anycasts is removed from ipv6_addr_type()
  Flag IPV6_ADDR_ANYCAST is removed as well.
- Some meaningless noop code checking for anycast which are not
  going to happen is removed from ndisc.c
- ipv6_unicast_destination() replaces suboptimal ipv6_chk_acast_addr()
  in data paths
parent 2135f3fb
......@@ -45,7 +45,8 @@ extern int ip6_del_rt(struct rt6_info *,
void *rtattr);
extern int ip6_rt_addr_add(struct in6_addr *addr,
struct net_device *dev);
struct net_device *dev,
int anycast);
extern int ip6_rt_addr_del(struct in6_addr *addr,
struct net_device *dev);
......@@ -118,5 +119,12 @@ static inline void ip6_dst_store(struct sock *sk, struct dst_entry *dst,
write_unlock(&sk->sk_dst_lock);
}
static inline int ipv6_unicast_destination(struct sk_buff *skb)
{
struct rt6_info *rt = (struct rt6_info *) skb->dst;
return rt->rt6i_flags & RTF_LOCAL;
}
#endif
#endif
......@@ -51,7 +51,7 @@
/*
* Addr type
*
* type - unicast | multicast | anycast
* type - unicast | multicast
* scope - local | site | global
* v4 - compat
* v4mapped
......@@ -63,7 +63,6 @@
#define IPV6_ADDR_UNICAST 0x0001U
#define IPV6_ADDR_MULTICAST 0x0002U
#define IPV6_ADDR_ANYCAST 0x0004U
#define IPV6_ADDR_LOOPBACK 0x0010U
#define IPV6_ADDR_LINKLOCAL 0x0020U
......
......@@ -209,15 +209,8 @@ int ipv6_addr_type(const struct in6_addr *addr)
};
return type;
}
/* check for reserved anycast addresses */
if ((st & htonl(0xE0000000)) &&
((addr->s6_addr32[2] == htonl(0xFDFFFFFF) &&
(addr->s6_addr32[3] | htonl(0x7F)) == (u32)~0) ||
(addr->s6_addr32[2] == 0 && addr->s6_addr32[3] == 0)))
type = IPV6_ADDR_ANYCAST;
else
type = IPV6_ADDR_UNICAST;
type = IPV6_ADDR_UNICAST;
/* Consider all addresses with the first three bits different of
000 and 111 as finished.
......@@ -2552,7 +2545,7 @@ static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
switch (event) {
case RTM_NEWADDR:
ip6_rt_addr_add(&ifp->addr, ifp->idev->dev);
ip6_rt_addr_add(&ifp->addr, ifp->idev->dev, 0);
break;
case RTM_DELADDR:
addrconf_leave_solict(ifp->idev->dev, &ifp->addr);
......
......@@ -96,7 +96,6 @@ ip6_onlink(struct in6_addr *addr, struct net_device *dev)
return onlink;
}
/*
* socket join an anycast group
*/
......@@ -110,8 +109,12 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, struct in6_addr *addr)
int ishost = !ipv6_devconf.forwarding;
int err = 0;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
if (ipv6_addr_type(addr) & IPV6_ADDR_MULTICAST)
return -EINVAL;
if (ipv6_chk_addr(addr, NULL))
return -EINVAL;
pac = sock_kmalloc(sk, sizeof(struct ipv6_ac_socklist), GFP_KERNEL);
if (pac == NULL)
......@@ -161,21 +164,12 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, struct in6_addr *addr)
* For hosts, allow link-local or matching prefix anycasts.
* This obviates the need for propagating anycast routes while
* still allowing some non-router anycast participation.
*
* allow anyone to join anycasts that don't require a special route
* and can't be spoofs of unicast addresses (reserved anycast only)
*/
if (!ip6_onlink(addr, dev)) {
if (ishost)
err = -EADDRNOTAVAIL;
else if (!capable(CAP_NET_ADMIN))
err = -EPERM;
if (err)
goto out_dev_put;
} else if (!(ipv6_addr_type(addr) & IPV6_ADDR_ANYCAST) &&
!capable(CAP_NET_ADMIN)) {
err = -EPERM;
goto out_dev_put;
}
err = ipv6_dev_ac_inc(dev, addr);
......@@ -266,6 +260,13 @@ void ipv6_sock_ac_close(struct sock *sk)
dev_put(dev);
}
#if 0
/* The function is not used, which is funny. Apparently, author
* supposed to use it to filter out datagrams inside udp/raw but forgot.
*
* It is OK, anycasts are not special comparing to delivery to unicasts.
*/
int inet6_ac_check(struct sock *sk, struct in6_addr *addr, int ifindex)
{
struct ipv6_ac_socklist *pac;
......@@ -286,6 +287,8 @@ int inet6_ac_check(struct sock *sk, struct in6_addr *addr, int ifindex)
return found;
}
#endif
static void aca_put(struct ifacaddr6 *ac)
{
if (atomic_dec_and_test(&ac->aca_refcnt)) {
......@@ -347,7 +350,7 @@ int ipv6_dev_ac_inc(struct net_device *dev, struct in6_addr *addr)
idev->ac_list = aca;
write_unlock_bh(&idev->lock);
ip6_rt_addr_add(&aca->aca_addr, dev);
ip6_rt_addr_add(&aca->aca_addr, dev, 1);
addrconf_join_solict(dev, &aca->aca_addr);
......
......@@ -415,8 +415,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
saddr = &skb->nh.ipv6h->daddr;
if (ipv6_addr_type(saddr) & IPV6_ADDR_MULTICAST ||
ipv6_chk_acast_addr(0, saddr))
if (!ipv6_unicast_destination(skb))
saddr = NULL;
memcpy(&tmp_hdr, icmph, sizeof(tmp_hdr));
......
......@@ -785,8 +785,7 @@ static void ndisc_recv_ns(struct sk_buff *skb)
ipv6_addr_all_nodes(&maddr);
ndisc_send_na(dev, NULL, &maddr, &ifp->addr,
ifp->idev->cnf.forwarding, 0,
ipv6_addr_type(&ifp->addr)&IPV6_ADDR_ANYCAST ? 0 : 1,
1);
1, 1);
in6_ifa_put(ifp);
return;
}
......@@ -809,8 +808,7 @@ static void ndisc_recv_ns(struct sk_buff *skb)
if (neigh || !dev->hard_header) {
ndisc_send_na(dev, neigh, saddr, &ifp->addr,
ifp->idev->cnf.forwarding, 1,
ipv6_addr_type(&ifp->addr)&IPV6_ADDR_ANYCAST ? 0 : 1,
1);
1, 1);
if (neigh)
neigh_release(neigh);
}
......
......@@ -1261,7 +1261,7 @@ int ip6_pkt_discard(struct sk_buff *skb)
* Add address
*/
int ip6_rt_addr_add(struct in6_addr *addr, struct net_device *dev)
int ip6_rt_addr_add(struct in6_addr *addr, struct net_device *dev, int anycast)
{
struct rt6_info *rt = ip6_dst_alloc();
......@@ -1280,6 +1280,8 @@ int ip6_rt_addr_add(struct in6_addr *addr, struct net_device *dev)
rt->u.dst.obsolete = -1;
rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP;
if (!anycast)
rt->rt6i_flags |= RTF_LOCAL;
rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_gateway);
if (rt->rt6i_nexthop == NULL) {
dst_free((struct dst_entry *) rt);
......
......@@ -971,7 +971,7 @@ static void tcp_v6_send_reset(struct sk_buff *skb)
if (th->rst)
return;
if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr))
if (!ipv6_unicast_destination(skb))
return;
/*
......@@ -1175,8 +1175,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
if (skb->protocol == htons(ETH_P_IP))
return tcp_v4_conn_request(sk, skb);
/* FIXME: do the same check for anycast */
if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr))
if (!ipv6_unicast_destination(skb))
goto drop;
/*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment