net: l2: ieee802154: mgmt: allow beacon payload

The standard does allow for a optional beacon payload, which gets lost
during scan, that could be interesting for the application to access
in the NET_EVENT_IEEE802154_SCAN_RESULT callback.

See section 7.3.1.6 in IEEE Std 802.15.4 for more information about
the beacon payload field. And section 7.3.1 and figure 7-5 about general
beacon frame format.

Signed-off-by: Fabian Pflug <fabian.pflug@grandcentrix.net>
This commit is contained in:
Fabian Pflug 2024-07-23 07:39:27 +02:00 committed by Anas Nashif
commit ca53d2bf80
5 changed files with 42 additions and 10 deletions

View file

@ -330,6 +330,11 @@ struct ieee802154_req_params {
uint8_t len; uint8_t len;
/** Link quality information, between 0 and 255 */ /** Link quality information, between 0 and 255 */
uint8_t lqi; uint8_t lqi;
/** Additional payload of the beacon if any.*/
uint8_t *beacon_payload;
/** Length of the additional payload. */
size_t beacon_payload_len;
}; };
/** /**

View file

@ -194,30 +194,32 @@ ieee802154_validate_aux_security_hdr(uint8_t *buf, uint8_t **p_buf, uint8_t *len
} }
#endif /* CONFIG_NET_L2_IEEE802154_SECURITY */ #endif /* CONFIG_NET_L2_IEEE802154_SECURITY */
static inline bool validate_beacon(struct ieee802154_mpdu *mpdu, uint8_t *buf, uint8_t length) int ieee802514_beacon_header_length(uint8_t *buf, uint8_t length)
{ {
struct ieee802154_beacon *beacon = (struct ieee802154_beacon *)buf; struct ieee802154_beacon *beacon = (struct ieee802154_beacon *)buf;
struct ieee802154_pas_spec *pas; struct ieee802154_pas_spec *pas;
uint8_t len = IEEE802154_BEACON_SF_SIZE + IEEE802154_BEACON_GTS_SPEC_SIZE; uint8_t len = IEEE802154_BEACON_SF_SIZE + IEEE802154_BEACON_GTS_SPEC_SIZE;
if (length < len) { if (length < len) {
return false; return -EINVAL;
} }
/* see section 7.3.1.5 on how to calculate GTS length */
if (beacon->gts.desc_count) { if (beacon->gts.desc_count) {
len += IEEE802154_BEACON_GTS_DIR_SIZE + len += IEEE802154_BEACON_GTS_DIR_SIZE +
beacon->gts.desc_count * IEEE802154_BEACON_GTS_SIZE; beacon->gts.desc_count * IEEE802154_BEACON_GTS_SIZE;
} }
if (length < len) { if (length < len) {
return false; return -EINVAL;
} }
/* see section 7.3.1.6 on how to calculate pending address length */
pas = (struct ieee802154_pas_spec *)buf + len; pas = (struct ieee802154_pas_spec *)buf + len;
len += IEEE802154_BEACON_PAS_SPEC_SIZE; len += IEEE802154_BEACON_PAS_SPEC_SIZE;
if (length < len) { if (length < len) {
return false; return -EINVAL;
} }
if (pas->nb_sap || pas->nb_eap) { if (pas->nb_sap || pas->nb_eap) {
@ -226,12 +228,10 @@ static inline bool validate_beacon(struct ieee802154_mpdu *mpdu, uint8_t *buf, u
} }
if (length < len) { if (length < len) {
return false; return -EINVAL;
} }
mpdu->beacon = beacon; return len;
return true;
} }
static inline bool validate_mac_command_cfi_to_mhr(struct ieee802154_mhr *mhr, static inline bool validate_mac_command_cfi_to_mhr(struct ieee802154_mhr *mhr,
@ -376,7 +376,7 @@ static inline bool validate_payload_and_mfr(struct ieee802154_mpdu *mpdu, uint8_
NET_DBG("Header size: %u, payload size %u", (uint32_t)(p_buf - buf), length); NET_DBG("Header size: %u, payload size %u", (uint32_t)(p_buf - buf), length);
if (type == IEEE802154_FRAME_TYPE_BEACON) { if (type == IEEE802154_FRAME_TYPE_BEACON) {
if (!validate_beacon(mpdu, p_buf, length)) { if (ieee802514_beacon_header_length(p_buf, length) < 0) {
return false; return false;
} }
} else if (type == IEEE802154_FRAME_TYPE_DATA) { } else if (type == IEEE802154_FRAME_TYPE_DATA) {

View file

@ -472,6 +472,20 @@ ieee802154_validate_aux_security_hdr(uint8_t *buf, uint8_t **p_buf, uint8_t *len
struct ieee802154_fcf_seq *ieee802154_validate_fc_seq(uint8_t *buf, uint8_t **p_buf, struct ieee802154_fcf_seq *ieee802154_validate_fc_seq(uint8_t *buf, uint8_t **p_buf,
uint8_t *length); uint8_t *length);
/**
* @brief Calculate the beacon header length.
*
* @details Returns the length of the MAC payload without the beacon payload,
* see section 7.3.1.1, figure 7-5.
*
* @param buf pointer to the MAC payload
* @param length buffer length
*
* @retval -EINVAL The header is invalid.
* @return the length of the beacon header
*/
int ieee802514_beacon_header_length(uint8_t *buf, uint8_t length);
bool ieee802154_validate_frame(uint8_t *buf, uint8_t length, struct ieee802154_mpdu *mpdu); bool ieee802154_validate_frame(uint8_t *buf, uint8_t length, struct ieee802154_mpdu *mpdu);
void ieee802154_compute_header_and_authtag_len(struct net_if *iface, struct net_linkaddr *dst, void ieee802154_compute_header_and_authtag_len(struct net_if *iface, struct net_linkaddr *dst,

View file

@ -37,6 +37,7 @@ enum net_verdict ieee802154_handle_beacon(struct net_if *iface,
uint8_t lqi) uint8_t lqi)
{ {
struct ieee802154_context *ctx = net_if_l2_data(iface); struct ieee802154_context *ctx = net_if_l2_data(iface);
int beacon_hdr_len;
NET_DBG("Beacon received"); NET_DBG("Beacon received");
@ -64,6 +65,10 @@ enum net_verdict ieee802154_handle_beacon(struct net_if *iface,
IEEE802154_EXT_ADDR_LENGTH); IEEE802154_EXT_ADDR_LENGTH);
} }
beacon_hdr_len = ieee802514_beacon_header_length(mpdu->payload, mpdu->payload_length);
ctx->scan_ctx->beacon_payload_len = mpdu->payload_length - beacon_hdr_len;
ctx->scan_ctx->beacon_payload = (uint8_t *)mpdu->payload + beacon_hdr_len;
net_mgmt_event_notify(NET_EVENT_IEEE802154_SCAN_RESULT, iface); net_mgmt_event_notify(NET_EVENT_IEEE802154_SCAN_RESULT, iface);
k_sem_give(&ctx->scan_ctx_lock); k_sem_give(&ctx->scan_ctx_lock);

View file

@ -45,12 +45,16 @@ K_SEM_DEFINE(scan_lock, 0, 1);
#define EXPECTED_ENDDEVICE_EXT_ADDR_STR "08:07:06:05:04:03:02:01" #define EXPECTED_ENDDEVICE_EXT_ADDR_STR "08:07:06:05:04:03:02:01"
#define EXPECTED_ENDDEVICE_SHORT_ADDR 0xaaaa #define EXPECTED_ENDDEVICE_SHORT_ADDR 0xaaaa
#define EXPECTED_PAYLOAD_DATA EXPECTED_ENDDEVICE_EXT_ADDR_LE
#define EXPECTED_PAYLOAD_LEN 8
static void scan_result_cb(struct net_mgmt_event_callback *cb, uint32_t mgmt_event, static void scan_result_cb(struct net_mgmt_event_callback *cb, uint32_t mgmt_event,
struct net_if *iface) struct net_if *iface)
{ {
struct ieee802154_context *ctx = net_if_l2_data(iface); struct ieee802154_context *ctx = net_if_l2_data(iface);
struct ieee802154_req_params *scan_ctx = ctx->scan_ctx; struct ieee802154_req_params *scan_ctx = ctx->scan_ctx;
uint8_t expected_coordinator_address[] = {EXPECTED_COORDINATOR_ADDR_BE}; uint8_t expected_coordinator_address[] = {EXPECTED_COORDINATOR_ADDR_BE};
uint8_t expected_payload_data[] = {EXPECTED_PAYLOAD_DATA};
/* No need for scan_ctx locking as we should execute exclusively. */ /* No need for scan_ctx locking as we should execute exclusively. */
@ -63,6 +67,10 @@ static void scan_result_cb(struct net_mgmt_event_callback *cb, uint32_t mgmt_eve
zassert_equal(scan_ctx->lqi, EXPECTED_COORDINATOR_LQI, zassert_equal(scan_ctx->lqi, EXPECTED_COORDINATOR_LQI,
"Scan did not receive correct link quality indicator."); "Scan did not receive correct link quality indicator.");
zassert_equal(scan_ctx->beacon_payload_len, EXPECTED_PAYLOAD_LEN,
"Scan did not include the payload");
zassert_mem_equal(scan_ctx->beacon_payload, expected_payload_data, EXPECTED_PAYLOAD_LEN);
k_sem_give(&scan_lock); k_sem_give(&scan_lock);
} }
@ -201,7 +209,7 @@ ZTEST(ieee802154_l2_shell, test_active_scan)
0x00, 0xc0, /* Superframe Specification: PAN coordinator + association permitted */ 0x00, 0xc0, /* Superframe Specification: PAN coordinator + association permitted */
0x00, /* GTS */ 0x00, /* GTS */
0x00, /* Pending Addresses */ 0x00, /* Pending Addresses */
0x00, 0x00 /* Payload */ EXPECTED_PAYLOAD_DATA /* Layer 3 payload */
}; };
struct net_pkt *pkt; struct net_pkt *pkt;