net: l2: ieee802154: don't use net_context->local for AF_PACKET sockets

There is an issue with AF_PACKET sockets bound to ieee802154 l2 iface.
The socket keeps track of the iface link_addr with a sockaddr_ll_ptr
structure, with sll_addr pointing to the iface link_addr address, and
sll_halen being a copy of the iface link_addr length.

The iface link address for ieee802154 can change during association
between extended address (8 bytes) and short address (2 bytes). The
iface link_addr s correctly updated, but the sll_halen of already bound
sockets is not, as it's a out of sync local copy.

This commit fixes #99711 by replacing all the sll_halen usage for
AF_PACKET socket with the iface link_addr length directly on recv and
send paths.

Signed-off-by: Simon Piriou <spiriou31@gmail.com>
diff --git a/subsys/net/ip/net_context.c b/subsys/net/ip/net_context.c
index f8049d6..9364dbb 100644
--- a/subsys/net/ip/net_context.c
+++ b/subsys/net/ip/net_context.c
@@ -3251,6 +3251,23 @@
 				net_sll_ptr(&context->local)->sll_halen;
 
 			if (net_sll_ptr(&context->local)->sll_addr != NULL) {
+				/* NET_AF_PACKET socket is bound to an iface as
+				 * context->local->sll_addr is valid.  Although the sll_addr
+				 * pointer correctly links to the iface net_linkaddr, the
+				 * sll_halen is a copy and doesn't track properly the iface
+				 * linkaddr len. For example, the linkaddr len can change
+				 * depending on the link address format with 802.15.4, between
+				 * extended (8 bytes) or short (2 bytes).
+				 *
+				 * Instead, use the iface link_addr directly. The socket is
+				 * bound to an interface as context->local->sll_addr is valid.
+				 */
+				struct net_linkaddr *link_addr = CONTAINER_OF(
+						(uint8_t(*)[NET_LINK_ADDR_MAX_LENGTH])
+						net_sll_ptr(&context->local)->sll_addr,
+						struct net_linkaddr, addr);
+
+				addr.sll_halen = link_addr->len;
 				memcpy(addr.sll_addr,
 				       net_sll_ptr(&context->local)->sll_addr,
 				       MIN(addr.sll_halen, sizeof(addr.sll_addr)));
diff --git a/subsys/net/l2/ieee802154/ieee802154.c b/subsys/net/l2/ieee802154/ieee802154.c
index 10e639c..525c9d7 100644
--- a/subsys/net/l2/ieee802154/ieee802154.c
+++ b/subsys/net/l2/ieee802154/ieee802154.c
@@ -509,16 +509,25 @@
 			   socket_type == NET_SOCK_DGRAM) {
 			struct net_sockaddr_ll *dst_addr =
 				(struct net_sockaddr_ll *)&context->remote;
-			struct net_sockaddr_ll_ptr *src_addr =
-				(struct net_sockaddr_ll_ptr *)&context->local;
 
 			(void)net_linkaddr_set(net_pkt_lladdr_dst(pkt),
 					       dst_addr->sll_addr,
 					       dst_addr->sll_halen);
 
+			/* context->local sockaddr_ll_ptr is not supported for
+			 * NET_AF_PACKET sockets (raw packets from l2).
+			 *
+			 * Although the sll_addr pointer correctly links to the iface
+			 * net_linkaddr, the sll_halen is a copy and doesn't track properly
+			 * the iface linkaddr len. For example, the linkaddr len can change
+			 * depending on the link address format with 802.15.4, between
+			 * extended (8 bytes) or short (2 bytes).
+			 *
+			 * Instead, use the iface link_addr directly.
+			 */
 			(void)net_linkaddr_set(net_pkt_lladdr_src(pkt),
-					       src_addr->sll_addr,
-					       src_addr->sll_halen);
+					       iface->if_dev->link_addr.addr,
+					       iface->if_dev->link_addr.len);
 		} else {
 			return -EINVAL;
 		}