Commit a84e9345 authored by Jukka Rissanen's avatar Jukka Rissanen
Browse files

net: arp: Use proper dest hw address after receiving a request



If a packet is received with Ethernet source address different
from ARP's sender hardware address field, then DUT must use the
latter address in response packets.

Fixes #16098

Signed-off-by: default avatarJukka Rissanen <jukka.rissanen@linux.intel.com>
parent 58e9ac68
Loading
Loading
Loading
Loading
+28 −6
Original line number Diff line number Diff line
@@ -440,6 +440,23 @@ static void arp_update(struct net_if *iface,
			if (entry) {
				memcpy(&entry->eth, hwaddr,
				       sizeof(struct net_eth_addr));
			} else {
				/* Add new entry as it was not found and force
				 * was set.
				 */
				entry = arp_entry_get_free();
				if (!entry) {
					/* Then let's take one from table? */
					entry = arp_entry_get_last_from_table();
				}

				if (entry) {
					entry->req_start = k_uptime_get();
					entry->iface = iface;
					net_ipaddr_copy(&entry->ip, src);
					memcpy(&entry->eth, hwaddr, sizeof(entry->eth));
					sys_slist_prepend(&arp_table, &entry->node);
				}
			}
		}

@@ -468,7 +485,8 @@ static void arp_update(struct net_if *iface,

static inline struct net_pkt *arp_prepare_reply(struct net_if *iface,
						struct net_pkt *req,
						struct net_eth_hdr *eth_query)
						struct net_eth_hdr *eth_query,
						struct net_eth_addr *dst_addr)
{
	struct net_arp_hdr *hdr, *query;
	struct net_pkt *pkt;
@@ -492,7 +510,7 @@ static inline struct net_pkt *arp_prepare_reply(struct net_if *iface,
	hdr->protolen = sizeof(struct in_addr);
	hdr->opcode = htons(NET_ARP_REPLY);

	memcpy(&hdr->dst_hwaddr.addr, &eth_query->src.addr,
	memcpy(&hdr->dst_hwaddr.addr, &dst_addr->addr,
	       sizeof(struct net_eth_addr));
	memcpy(&hdr->src_hwaddr.addr, net_if_get_link_addr(iface)->addr,
	       sizeof(struct net_eth_addr));
@@ -526,6 +544,7 @@ static bool arp_hdr_check(struct net_arp_hdr *arp_hdr)
enum net_verdict net_arp_input(struct net_pkt *pkt,
			       struct net_eth_hdr *eth_hdr)
{
	struct net_eth_addr *dst_hw_addr;
	struct net_arp_hdr *arp_hdr;
	struct net_pkt *reply;
	struct in_addr *addr;
@@ -594,9 +613,7 @@ enum net_verdict net_arp_input(struct net_pkt *pkt,
		 * changed. In this case the target MAC address is all zeros
		 * and the target IP address is our address.
		 */
		if (memcmp(&eth_hdr->src, &arp_hdr->src_hwaddr,
			   sizeof(struct net_eth_addr)) == 0 &&
		    net_eth_is_addr_unspecified(&arp_hdr->dst_hwaddr)) {
		if (net_eth_is_addr_unspecified(&arp_hdr->dst_hwaddr)) {
			NET_DBG("Updating ARP cache for %s [%s]",
				log_strdup(net_sprint_ipv4_addr(
						 &arp_hdr->src_ipaddr)),
@@ -608,10 +625,15 @@ enum net_verdict net_arp_input(struct net_pkt *pkt,
				   &arp_hdr->src_ipaddr,
				   &arp_hdr->src_hwaddr,
				   false, true);

			dst_hw_addr = &arp_hdr->src_hwaddr;
		} else {
			dst_hw_addr = &eth_hdr->src;
		}

		/* Send reply */
		reply = arp_prepare_reply(net_pkt_iface(pkt), pkt, eth_hdr);
		reply = arp_prepare_reply(net_pkt_iface(pkt), pkt, eth_hdr,
					  dst_hw_addr);
		if (reply) {
			net_if_queue_tx(net_pkt_iface(reply), reply);
		} else {