Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 92 additions & 43 deletions subsys/net/l2/ieee802154/ieee802154_frame.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ const u8_t level_2_tag_size[4] = {
};
#endif

struct ieee802154_fcf_seq *ieee802154_validate_fc_seq(u8_t *buf, u8_t **p_buf)
struct ieee802154_fcf_seq *ieee802154_validate_fc_seq(u8_t *buf, u8_t **p_buf,
u8_t *length)
{
struct ieee802154_fcf_seq *fs = (struct ieee802154_fcf_seq *)buf;

Expand Down Expand Up @@ -81,17 +82,20 @@ struct ieee802154_fcf_seq *ieee802154_validate_fc_seq(u8_t *buf, u8_t **p_buf)
#endif

if (p_buf) {
*p_buf = buf + 3;
*length -= IEEE802154_FCF_SEQ_LENGTH;
*p_buf = buf + IEEE802154_FCF_SEQ_LENGTH;
}

return fs;
}

static inline struct ieee802154_address_field *
validate_addr(u8_t *buf, u8_t **p_buf,
validate_addr(u8_t *buf, u8_t **p_buf, u8_t *length,
enum ieee802154_addressing_mode mode,
bool pan_id_compression)
{
u8_t len = 0;

*p_buf = buf;

NET_DBG("Buf %p - mode %d - pan id comp %d",
Expand All @@ -102,59 +106,76 @@ validate_addr(u8_t *buf, u8_t **p_buf,
}

if (!pan_id_compression) {
*p_buf += IEEE802154_PAN_ID_LENGTH;
len = IEEE802154_PAN_ID_LENGTH;
}

if (mode == IEEE802154_ADDR_MODE_SHORT) {
*p_buf += IEEE802154_SHORT_ADDR_LENGTH;
len += IEEE802154_SHORT_ADDR_LENGTH;
} else {
/* IEEE802154_ADDR_MODE_EXTENDED */
*p_buf += IEEE802154_EXT_ADDR_LENGTH;
len += IEEE802154_EXT_ADDR_LENGTH;
}

if (len > *length) {
return NULL;
}

*p_buf += len;
*length -= len;

return (struct ieee802154_address_field *)buf;
}

#ifdef CONFIG_NET_L2_IEEE802154_SECURITY
struct ieee802154_aux_security_hdr *
ieee802154_validate_aux_security_hdr(u8_t *buf, u8_t **p_buf)
ieee802154_validate_aux_security_hdr(u8_t *buf, u8_t **p_buf, u8_t *length)
{
struct ieee802154_aux_security_hdr *ash =
(struct ieee802154_aux_security_hdr *)buf;
u8_t len = IEEE802154_SECURITY_CF_LENGTH +
IEEE802154_SECURITY_FRAME_COUNTER_LENGTH;

*p_buf = buf;
/* At least the asf is sized of: control field + frame counter */
if (*length < len) {
return NULL;
}

/* Only implicit key mode is supported for now */
if (ash->control.key_id_mode != IEEE802154_KEY_ID_MODE_IMPLICIT) {
return NULL;
}

/* At least the asf is sized of: control field + frame counter */
*p_buf += sizeof(struct ieee802154_security_control_field) +
sizeof(u32_t);

/* Explicit key must have a key index != 0x00, see Section 7.4.3.2 */
switch (ash->control.key_id_mode) {
case IEEE802154_KEY_ID_MODE_IMPLICIT:
break;
case IEEE802154_KEY_ID_MODE_INDEX:
*p_buf += IEEE8021254_KEY_ID_FIELD_INDEX_LENGTH;
len += IEEE8021254_KEY_ID_FIELD_INDEX_LENGTH;
if (*length < len) {
return NULL;
}

if (!ash->kif.mode_1.key_index) {
return NULL;
}

break;
case IEEE802154_KEY_ID_MODE_SRC_4_INDEX:
*p_buf += IEEE8021254_KEY_ID_FIELD_SRC_4_INDEX_LENGTH;
len += IEEE8021254_KEY_ID_FIELD_SRC_4_INDEX_LENGTH;
if (*length < len) {
return NULL;
}

if (!ash->kif.mode_2.key_index) {
return NULL;
}

break;
case IEEE802154_KEY_ID_MODE_SRC_8_INDEX:
*p_buf += IEEE8021254_KEY_ID_FIELD_SRC_8_INDEX_LENGTH;
len += IEEE8021254_KEY_ID_FIELD_SRC_8_INDEX_LENGTH;
if (*length < len) {
return NULL;
}

if (!ash->kif.mode_3.key_index) {
return NULL;
Expand All @@ -163,44 +184,52 @@ ieee802154_validate_aux_security_hdr(u8_t *buf, u8_t **p_buf)
break;
}

*p_buf = buf + len;
*length -= len;

return ash;
}
#endif /* CONFIG_NET_L2_IEEE802154_SECURITY */

static inline bool
validate_beacon(struct ieee802154_mpdu *mpdu, u8_t *buf, u8_t length)
validate_beacon(struct ieee802154_mpdu *mpdu, u8_t *buf, u8_t *length)
{
struct ieee802154_beacon *b = (struct ieee802154_beacon *)buf;
u8_t *p_buf = buf;
struct ieee802154_pas_spec *pas;
u8_t len = IEEE802154_BEACON_SF_SIZE +
IEEE802154_BEACON_GTS_SPEC_SIZE;


if (length < IEEE802154_BEACON_MIN_SIZE) {
if (*length < len) {
return false;
}

p_buf += IEEE802154_BEACON_SF_SIZE + IEEE802154_BEACON_GTS_SPEC_SIZE;

if (b->gts.desc_count) {
p_buf += IEEE802154_BEACON_GTS_DIR_SIZE +
len += IEEE802154_BEACON_GTS_DIR_SIZE +
b->gts.desc_count * IEEE802154_BEACON_GTS_SIZE;
}

if (length < (p_buf - buf)) {
if (*length < len) {
return false;
}

pas = (struct ieee802154_pas_spec *)p_buf;
p_buf += IEEE802154_BEACON_PAS_SPEC_SIZE;
pas = (struct ieee802154_pas_spec *)buf + len;

len += IEEE802154_BEACON_PAS_SPEC_SIZE;
if (*length < len) {
return false;
}

if (pas->nb_sap || pas->nb_eap) {
p_buf += (pas->nb_sap * IEEE802154_SHORT_ADDR_LENGTH) +
len += (pas->nb_sap * IEEE802154_SHORT_ADDR_LENGTH) +
(pas->nb_eap * IEEE802154_EXT_ADDR_LENGTH);
}

if (length < (p_buf - buf)) {
if (*length < len) {
return false;
}

*length -= len;
mpdu->beacon = b;

return true;
Expand Down Expand Up @@ -241,26 +270,37 @@ validate_mac_command_cfi_to_mhr(struct ieee802154_mhr *mhr,
}

static inline bool
validate_mac_command(struct ieee802154_mpdu *mpdu, u8_t *buf, u8_t length)
validate_mac_command(struct ieee802154_mpdu *mpdu, u8_t *buf, u8_t *length)
{
struct ieee802154_command *c = (struct ieee802154_command *)buf;
u8_t len = IEEE802154_CMD_CFI_LENGTH;
bool src_pan_brdcst_chk = false;
bool dst_brdcst_chk = false;
u8_t comp = 0U;
u8_t ar = 0U;
u8_t src, dst;

if (*length < len) {
return false;
}

switch (c->cfi) {
case IEEE802154_CFI_UNKNOWN:
return false;
case IEEE802154_CFI_ASSOCIATION_REQUEST:
len += IEEE802154_CMD_ASSOC_REQ_LENGTH;
src = IEEE802154_EXT_ADDR_LENGTH;
src_pan_brdcst_chk = true;
dst = IEEE802154_ADDR_MODE_SHORT |
IEEE802154_ADDR_MODE_EXTENDED;

break;
case IEEE802154_CFI_ASSOCIATION_RESPONSE:
len += IEEE802154_CMD_ASSOC_RES_LENGTH;
case IEEE802154_CFI_DISASSOCIATION_NOTIFICATION:
if (c->cfi == IEEE802154_CFI_DISASSOCIATION_NOTIFICATION) {
len += IEEE802154_CMD_DISASSOC_NOTE_LENGTH;
}
case IEEE802154_CFI_PAN_ID_CONLICT_NOTIFICATION:
ar = 1U;
comp = 1U;
Expand Down Expand Up @@ -296,6 +336,7 @@ validate_mac_command(struct ieee802154_mpdu *mpdu, u8_t *buf, u8_t length)

break;
case IEEE802154_CFI_COORDINATOR_REALIGNEMENT:
len += IEEE802154_CMD_COORD_REALIGN_LENGTH;
src = IEEE802154_EXT_ADDR_LENGTH;

if (mpdu->mhr.fs->fc.dst_addr_mode ==
Expand All @@ -308,6 +349,7 @@ validate_mac_command(struct ieee802154_mpdu *mpdu, u8_t *buf, u8_t length)

break;
case IEEE802154_CFI_GTS_REQUEST:
len += IEEE802154_GTS_REQUEST_LENGTH;
ar = 1U;
src = IEEE802154_ADDR_MODE_SHORT;
dst = IEEE802154_ADDR_MODE_NONE;
Expand All @@ -317,54 +359,60 @@ validate_mac_command(struct ieee802154_mpdu *mpdu, u8_t *buf, u8_t length)
return false;
}

if (*length < len) {
return false;
}

if (!validate_mac_command_cfi_to_mhr(&mpdu->mhr, ar, comp,
src, src_pan_brdcst_chk,
dst, dst_brdcst_chk)) {
return false;
}

*length -= len;
mpdu->command = c;

return true;
}

static inline bool
validate_payload_and_mfr(struct ieee802154_mpdu *mpdu,
u8_t *buf, u8_t *p_buf, u8_t length)
u8_t *buf, u8_t *p_buf, u8_t *length)
{
u8_t type = mpdu->mhr.fs->fc.frame_type;
u8_t payload_length;

payload_length = length - (p_buf - buf);

NET_DBG("Header size: %u, vs total length %u: payload size %u",
(u32_t)(p_buf - buf), length, payload_length);
NET_DBG("Header size: %u, payload size %u",
(u32_t)(p_buf - buf), *length);

if (type == IEEE802154_FRAME_TYPE_BEACON) {
if (!validate_beacon(mpdu, p_buf, payload_length)) {
if (!validate_beacon(mpdu, p_buf, length)) {
return false;
}
} else if (type == IEEE802154_FRAME_TYPE_DATA) {
/** A data frame embeds a payload */
if (payload_length == 0U) {
if (*length == 0U) {
return false;
}

mpdu->payload = (void *)p_buf;
} else if (type == IEEE802154_FRAME_TYPE_ACK) {
/** An ACK frame has no payload */
if (payload_length) {
if (*length) {
return false;
}

mpdu->payload = NULL;
} else {
if (!validate_mac_command(mpdu, p_buf, payload_length)) {
if (!validate_mac_command(mpdu, p_buf, length)) {
return false;
}
}

mpdu->mfr = (struct ieee802154_mfr *)(p_buf + payload_length);
if (*length) {
mpdu->mfr = (struct ieee802154_mfr *)(p_buf + *length);
} else {
mpdu->mfr = NULL;
}

return true;
}
Expand All @@ -379,7 +427,7 @@ bool ieee802154_validate_frame(u8_t *buf, u8_t length,
return false;
}

mpdu->mhr.fs = ieee802154_validate_fc_seq(buf, &p_buf);
mpdu->mhr.fs = ieee802154_validate_fc_seq(buf, &p_buf, &length);
if (!mpdu->mhr.fs) {
return false;
}
Expand All @@ -389,25 +437,26 @@ bool ieee802154_validate_frame(u8_t *buf, u8_t length,
return false;
}

mpdu->mhr.dst_addr = validate_addr(p_buf, &p_buf,
mpdu->mhr.dst_addr = validate_addr(p_buf, &p_buf, &length,
mpdu->mhr.fs->fc.dst_addr_mode,
false);

mpdu->mhr.src_addr = validate_addr(p_buf, &p_buf,
mpdu->mhr.src_addr = validate_addr(p_buf, &p_buf, &length,
mpdu->mhr.fs->fc.src_addr_mode,
(mpdu->mhr.fs->fc.pan_id_comp));

#ifdef CONFIG_NET_L2_IEEE802154_SECURITY
if (mpdu->mhr.fs->fc.security_enabled) {
mpdu->mhr.aux_sec =
ieee802154_validate_aux_security_hdr(p_buf, &p_buf);
ieee802154_validate_aux_security_hdr(p_buf, &p_buf,
&length);
if (!mpdu->mhr.aux_sec) {
return false;
}
}
#endif

return validate_payload_and_mfr(mpdu, buf, p_buf, length);
return validate_payload_and_mfr(mpdu, buf, p_buf, &length);
}

u8_t ieee802154_compute_header_size(struct net_if *iface,
Expand Down
Loading