laforge has submitted this change. ( https://gerrit.osmocom.org/c/osmo-tetra/+/28851 )
Change subject: Added basic link FCS validation in LLC ......................................................................
Added basic link FCS validation in LLC
tetra_llc_pdu.c now parses the FCS (Frame Check Sequence) for basic link pdus that use it. Some changes were made to the tetra_resrc_decoded struct definition. The have_fcs field designates the FCS was present, while the FCS field holds the extracted FCS, and FCS_invalid designates an FCS was present but differs from the computed value.
Change-Id: I81941110801d00ca06bdafdcc0a7afaf7b7617d3 --- M src/tetra_llc_pdu.c M src/tetra_llc_pdu.h 2 files changed, 70 insertions(+), 11 deletions(-)
Approvals: Jenkins Builder: Verified laforge: Looks good to me, approved
diff --git a/src/tetra_llc_pdu.c b/src/tetra_llc_pdu.c index 9f7880c..5bd1688 100644 --- a/src/tetra_llc_pdu.c +++ b/src/tetra_llc_pdu.c @@ -82,42 +82,98 @@ return get_value_string(pdut_dec_names, pdut); }
+static uint32_t tetra_llc_compute_fcs(const uint8_t *buf, int len) +{ + uint32_t crc = 0xFFFFFFFF; + if (len < 32) { + crc <<= (32 - len); + } + + for (size_t i = 0; i < len; i++) { + uint8_t bit = (buf[i] ^ (crc >> 31)) & 1; + crc <<= 1; + if (bit) { + crc = crc ^ 0x04C11DB7; + } + } + return ~crc; +} + +static int tetra_llc_check_fcs(struct tetra_llc_pdu *lpp, uint8_t *buf, int len) +{ + uint32_t computed_fcs = tetra_llc_compute_fcs(buf, len); + return lpp->fcs == computed_fcs; +} + int tetra_llc_pdu_parse(struct tetra_llc_pdu *lpp, uint8_t *buf, int len) { uint8_t *cur = buf; uint8_t pdu_type; + lpp->have_fcs = 0; + lpp->fcs = 0;
pdu_type = bits_to_uint(cur, 4); cur += 4;
switch (pdu_type) { - case TLLC_PDUT_BL_ADATA_FCS: - /* FIXME */ - len -= 32; + case TLLC_PDUT_BL_ADATA: + case TLLC_PDUT_BL_ADATA_FCS: lpp->nr = *cur++; lpp->ns = *cur++; lpp->tl_sdu = cur; lpp->tl_sdu_len = len - (cur - buf); lpp->pdu_type = TLLC_PDUT_DEC_BL_ADATA; + + if (pdu_type == TLLC_PDUT_BL_ADATA_FCS) { + if (lpp->tl_sdu_len < 32) { + printf("\nWARNING frame too small for FCS (%d)\n", lpp->tl_sdu_len); + return cur-buf; + } + lpp->tl_sdu_len -= 32; + lpp->have_fcs = 1; + lpp->fcs = bits_to_uint(buf + len - 32, 32); + lpp->fcs_invalid = !tetra_llc_check_fcs(lpp, cur, lpp->tl_sdu_len); + } break; - case TLLC_PDUT_BL_DATA_FCS: - /* FIXME */ - len -= 32; + case TLLC_PDUT_BL_DATA: + case TLLC_PDUT_BL_DATA_FCS: lpp->ns = *cur++; lpp->tl_sdu = cur; lpp->tl_sdu_len = len - (cur - buf); lpp->pdu_type = TLLC_PDUT_DEC_BL_DATA; + + if (pdu_type == TLLC_PDUT_BL_DATA_FCS) { + if (lpp->tl_sdu_len < 32) { + printf("\nWARNING frame too small for FCS (%d)\n", lpp->tl_sdu_len); + return cur-buf; + } + lpp->tl_sdu_len -= 32; + lpp->have_fcs = 1; + lpp->fcs = bits_to_uint(buf + len - 32, 32); + lpp->fcs_invalid = !tetra_llc_check_fcs(lpp, cur, lpp->tl_sdu_len); + } break; - case TLLC_PDUT_BL_UDATA_FCS: - /* FIXME */ - len -= 32; + case TLLC_PDUT_BL_UDATA: + case TLLC_PDUT_BL_UDATA_FCS: lpp->tl_sdu = cur; lpp->tl_sdu_len = len - (cur - buf); lpp->pdu_type = TLLC_PDUT_DEC_BL_UDATA; + + if (pdu_type == TLLC_PDUT_BL_UDATA_FCS) { + if (lpp->tl_sdu_len < 32) { + printf("\nWARNING frame too small for FCS (%d)\n", lpp->tl_sdu_len); + return cur-buf; + } + lpp->tl_sdu_len -= 32; + lpp->have_fcs = 1; + lpp->fcs = bits_to_uint(buf + len - 32, 32); + lpp->fcs_invalid = !tetra_llc_check_fcs(lpp, cur, lpp->tl_sdu_len); + } break; + case TLLC_PDUT_AL_DATA_FINAL: if (*cur++) { /* FINAL */ diff --git a/src/tetra_llc_pdu.h b/src/tetra_llc_pdu.h index e2ce6fd..4d260c7 100644 --- a/src/tetra_llc_pdu.h +++ b/src/tetra_llc_pdu.h @@ -72,8 +72,11 @@ uint8_t nr; /* N(R) PDU number (receive) */ uint8_t ns; /* N(S) PDU number (sent) */ uint8_t ss; /* S(S) Segment (sent) */ - uint32_t _fcs; - uint32_t *fcs; + + uint8_t have_fcs; /* 1 if LLC PDU defines FCS is present */ + uint32_t fcs; /* FCS value extracted from pdu */ + uint8_t fcs_invalid; /* 1 if extracted FCS does not match computed FCS */ + uint8_t *tl_sdu; /* pointer to bitbuf */ uint8_t tl_sdu_len; /* in bits */ };