Commit f8696133 authored by Kuniyuki Iwashima's avatar Kuniyuki Iwashima Committed by Jakub Kicinski
Browse files

arp: Factorise ip_route_output() call in arp_req_set() and arp_req_delete().



When ioctl(SIOCDARP/SIOCSARP) is issued for non-proxy entry (no ATF_COM)
without arpreq.arp_dev[] set, arp_req_set() and arp_req_delete() looks up
dev based on IPv4 address by ip_route_output().

Let's factorise the same code as arp_req_dev().

Signed-off-by: default avatarKuniyuki Iwashima <kuniyu@amazon.com>
Link: https://lore.kernel.org/r/20240430015813.71143-4-kuniyu@amazon.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 05923674
Loading
Loading
Loading
Loading
+30 −20
Original line number Diff line number Diff line
@@ -1003,6 +1003,27 @@ static int arp_rcv(struct sk_buff *skb, struct net_device *dev,
 *	User level interface (ioctl)
 */

static struct net_device *arp_req_dev(struct net *net, struct arpreq *r)
{
	struct net_device *dev;
	struct rtable *rt;
	__be32 ip;

	ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr;

	rt = ip_route_output(net, ip, 0, 0, 0, RT_SCOPE_LINK);
	if (IS_ERR(rt))
		return ERR_CAST(rt);

	dev = rt->dst.dev;
	ip_rt_put(rt);

	if (!dev)
		return ERR_PTR(-EINVAL);

	return dev;
}

/*
 *	Set (create) an ARP cache entry.
 */
@@ -1045,25 +1066,17 @@ static int arp_req_set_public(struct net *net, struct arpreq *r,
static int arp_req_set(struct net *net, struct arpreq *r,
		       struct net_device *dev)
{
	__be32 ip;
	struct neighbour *neigh;
	__be32 ip;
	int err;

	if (r->arp_flags & ATF_PUBL)
		return arp_req_set_public(net, r, dev);

	ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr;

	if (!dev) {
		struct rtable *rt = ip_route_output(net, ip, 0, 0, 0,
						    RT_SCOPE_LINK);

		if (IS_ERR(rt))
			return PTR_ERR(rt);
		dev = rt->dst.dev;
		ip_rt_put(rt);
		if (!dev)
			return -EINVAL;
		dev = arp_req_dev(net, r);
		if (IS_ERR(dev))
			return PTR_ERR(dev);
	}
	switch (dev->type) {
#if IS_ENABLED(CONFIG_FDDI)
@@ -1086,6 +1099,8 @@ static int arp_req_set(struct net *net, struct arpreq *r,
		break;
	}

	ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr;

	neigh = __neigh_lookup_errno(&arp_tbl, &ip, dev);
	err = PTR_ERR(neigh);
	if (!IS_ERR(neigh)) {
@@ -1191,14 +1206,9 @@ static int arp_req_delete(struct net *net, struct arpreq *r,

	ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr;
	if (!dev) {
		struct rtable *rt = ip_route_output(net, ip, 0, 0, 0,
						    RT_SCOPE_LINK);
		if (IS_ERR(rt))
			return PTR_ERR(rt);
		dev = rt->dst.dev;
		ip_rt_put(rt);
		if (!dev)
			return -EINVAL;
		dev = arp_req_dev(net, r);
		if (IS_ERR(dev))
			return PTR_ERR(dev);
	}
	return arp_invalidate(dev, ip, true);
}