From e8543149287856e83017ee0d726a20f355bc14c4 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Sun, 8 Jan 2023 12:13:23 +0100 Subject: [PATCH] net: l2: ieee802154: fix double address swap As we have to provide LL addresses in big endian to userspace to be POSIX compliant and we also do not want to reserve extra space for such addresses, bff6a5cce5083eba23b227fa224a6243e63b4bc6 introduced a change that swaps address bytes in place in the packet before returning the packet with LL address pointers to userspace. Unfortunately a regression sneaked into the code base while doing so: The byte swapping was duplicated when using 6LoWPAN compression and the byte swapping caused decryption to fail in some cases, see #53630. This commit fixes the problem. Fixes: #53630 Signed-off-by: Florian Grandel --- subsys/net/l2/ieee802154/ieee802154.c | 31 +++++++++++++---------- subsys/net/l2/ieee802154/ieee802154_6lo.c | 13 ---------- 2 files changed, 18 insertions(+), 26 deletions(-) diff --git a/subsys/net/l2/ieee802154/ieee802154.c b/subsys/net/l2/ieee802154/ieee802154.c index 2cc36eb2fb1..c8338f66d05 100644 --- a/subsys/net/l2/ieee802154/ieee802154.c +++ b/subsys/net/l2/ieee802154/ieee802154.c @@ -94,9 +94,9 @@ static inline void ieee802154_acknowledge(struct net_if *iface, struct ieee80215 #define ieee802154_acknowledge(...) #endif /* CONFIG_NET_L2_IEEE802154_ACK_REPLY */ -static inline void set_pkt_ll_addr(struct net_linkaddr *addr, bool comp, - enum ieee802154_addressing_mode mode, - struct ieee802154_address_field *ll) +static inline void swap_and_set_pkt_ll_addr(struct net_linkaddr *addr, bool comp, + enum ieee802154_addressing_mode mode, + struct ieee802154_address_field *ll) { addr->type = NET_LINK_IEEE802154; @@ -127,8 +127,9 @@ static inline void set_pkt_ll_addr(struct net_linkaddr *addr, bool comp, addr->addr = NULL; } - /* Swap address byte order in place from little to big endian. - * This is ok as the ll address field comes from the header + /* The net stack expects link layer addresses to be in + * big endian format for posix compliance so we must swap it. + * This is ok as the L2 address field comes from the header * part of the packet buffer which will not be directly accessible * once the packet reaches the upper layers. */ @@ -238,18 +239,22 @@ static enum net_verdict ieee802154_recv(struct net_if *iface, struct net_pkt *pk ieee802154_acknowledge(iface, &mpdu); - net_pkt_set_ll_proto_type(pkt, ETH_P_IEEE802154); - - set_pkt_ll_addr(net_pkt_lladdr_src(pkt), mpdu.mhr.fs->fc.pan_id_comp, - mpdu.mhr.fs->fc.src_addr_mode, mpdu.mhr.src_addr); - - set_pkt_ll_addr(net_pkt_lladdr_dst(pkt), false, mpdu.mhr.fs->fc.dst_addr_mode, - mpdu.mhr.dst_addr); - if (!ieee802154_decipher_data_frame(iface, pkt, &mpdu)) { return NET_DROP; } + /* Setting L2 addresses must be done after packet authentication and internal + * packet handling as it will mangle the package header to comply with upper + * network layers' (POSIX) requirement to represent network addresses in big endian. + */ + swap_and_set_pkt_ll_addr(net_pkt_lladdr_src(pkt), mpdu.mhr.fs->fc.pan_id_comp, + mpdu.mhr.fs->fc.src_addr_mode, mpdu.mhr.src_addr); + + swap_and_set_pkt_ll_addr(net_pkt_lladdr_dst(pkt), false, mpdu.mhr.fs->fc.dst_addr_mode, + mpdu.mhr.dst_addr); + + net_pkt_set_ll_proto_type(pkt, ETH_P_IEEE802154); + pkt_hexdump(RX_PKT_TITLE " (with ll)", pkt, true); hdr_len = (uint8_t *)mpdu.payload - net_pkt_data(pkt); diff --git a/subsys/net/l2/ieee802154/ieee802154_6lo.c b/subsys/net/l2/ieee802154/ieee802154_6lo.c index 9d36ee55d47..3899ff7db6d 100644 --- a/subsys/net/l2/ieee802154/ieee802154_6lo.c +++ b/subsys/net/l2/ieee802154/ieee802154_6lo.c @@ -24,19 +24,6 @@ LOG_MODULE_REGISTER(net_ieee802154_6lo, CONFIG_NET_L2_IEEE802154_LOG_LEVEL); enum net_verdict ieee802154_6lo_decode_pkt(struct net_if *iface, struct net_pkt *pkt) { - /* Upper IP stack expects the link layer address to be in - * big endian format so we must swap it here. - */ - if (net_pkt_lladdr_src(pkt)->addr && - net_pkt_lladdr_src(pkt)->len == IEEE802154_EXT_ADDR_LENGTH) { - sys_mem_swap(net_pkt_lladdr_src(pkt)->addr, net_pkt_lladdr_src(pkt)->len); - } - - if (net_pkt_lladdr_dst(pkt)->addr && - net_pkt_lladdr_dst(pkt)->len == IEEE802154_EXT_ADDR_LENGTH) { - sys_mem_swap(net_pkt_lladdr_dst(pkt)->addr, net_pkt_lladdr_dst(pkt)->len); - } - #ifdef CONFIG_NET_L2_IEEE802154_FRAGMENT return ieee802154_6lo_reassemble(pkt); #else