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;
}