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
This commit is contained in:
wbokslag 2022-07-29 16:28:59 +02:00
parent a5bc24792b
commit 3fba49ead4
2 changed files with 70 additions and 11 deletions

View File

@ -82,42 +82,98 @@ const char *tetra_get_llc_pdut_dec_name(enum tllc_pdut_dec pdut)
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 */

View File

@ -72,8 +72,11 @@ struct tetra_llc_pdu {
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 */
};