diff --git a/src/Makefile b/src/Makefile index 0806d5c..cafed6d 100644 --- a/src/Makefile +++ b/src/Makefile @@ -9,7 +9,7 @@ all: conv_enc_test crc_test tetra-rx float_to_bits libosmo-tetra-phy.a: phy/tetra_burst_sync.o phy/tetra_burst.o $(AR) r $@ $^ -libosmo-tetra-mac.a: lower_mac/tetra_conv_enc.o tetra_tdma.o lower_mac/tetra_scramb.o lower_mac/tetra_rm3014.o lower_mac/tetra_interleave.o lower_mac/crc_simple.o tetra_common.o lower_mac/viterbi.o lower_mac/viterbi_cch.o lower_mac/viterbi_tch.o lower_mac/tetra_lower_mac.o tetra_upper_mac.o tetra_mac_pdu.o tetra_mle_pdu.o tetra_mm_pdu.o tetra_cmce_pdu.o tetra_sndcp_pdu.o tetra_gsmtap.o +libosmo-tetra-mac.a: lower_mac/tetra_conv_enc.o tetra_tdma.o lower_mac/tetra_scramb.o lower_mac/tetra_rm3014.o lower_mac/tetra_interleave.o lower_mac/crc_simple.o tetra_common.o lower_mac/viterbi.o lower_mac/viterbi_cch.o lower_mac/viterbi_tch.o lower_mac/tetra_lower_mac.o tetra_upper_mac.o tetra_mac_pdu.o tetra_llc_pdu.o tetra_mle_pdu.o tetra_mm_pdu.o tetra_cmce_pdu.o tetra_sndcp_pdu.o tetra_gsmtap.o $(AR) r $@ $^ float_to_bits: float_to_bits.o diff --git a/src/tetra_llc_pdu.c b/src/tetra_llc_pdu.c new file mode 100644 index 0000000..e77764d --- /dev/null +++ b/src/tetra_llc_pdu.c @@ -0,0 +1,166 @@ +/* Implementation of some PDU parsing of the TETRA LLC */ + +/* (C) 2011 by Harald Welte + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + +#include +#include +#include +#include +#include + +#include + +#include "tetra_common.h" +#include "tetra_llc_pdu.h" + +static const struct value_string tetra_llc_pdut_names[] = { + { TLLC_PDUT_BL_ADATA, "BL-ADATA" }, + { TLLC_PDUT_BL_DATA, "BL-DATA" }, + { TLLC_PDUT_BL_UDATA, "BL-UDATA" }, + { TLLC_PDUT_BL_ACK, "BL-ACK" }, + { TLLC_PDUT_BL_ADATA_FCS, "BL-ADATA-FCS" }, + { TLLC_PDUT_BL_DATA_FCS, "BL-DATA-FCS" }, + { TLLC_PDUT_BL_UDATA_FCS, "BL-UDATA-FCS" }, + { TLLC_PDUT_BL_ACK_FCS, "BL-ACK-FCS" }, + { TLLC_PDUT_AL_SETUP, "AL-SETUP" }, + { TLLC_PDUT_AL_DATA_FINAL, "AL-DATA/FINAL" }, + { TLLC_PDUT_AL_UDATA_UFINAL, "AL-UDATA/FINAL" }, + { TLLC_PDUT_AL_ACK_RNR, "AL-ACK/AL-RNR" }, + { TLLC_PDUT_AL_RECONNECT, "AL-RECONNECT" }, + { TLLC_PDUT_SUPPL, "AL-SUPPLEMENTARY" }, + { TLLC_PDUT_L2SIG, "AL-L2SIG" }, + { TLLD_PDUT_AL_DISC, "AL-DISC" }, + { 0, NULL } +}; +const char *tetra_get_llc_pdut_name(uint8_t pdut) +{ + return get_value_string(tetra_llc_pdut_names, pdut); +} + +static const struct value_string pdut_dec_names[] = { + { TLLC_PDUT_DEC_BL_ADATA, "BL-ADATA" }, + { TLLC_PDUT_DEC_BL_DATA, "BL-DATA" }, + { TLLC_PDUT_DEC_BL_UDATA, "BL-UDATA" }, + { TLLC_PDUT_DEC_BL_ACK, "BL-ACK" }, + { TLLC_PDUT_DEC_AL_SETUP, "AL-SETUP" }, + { TLLC_PDUT_DEC_AL_DATA, "AL-DATA" }, + { TLLC_PDUT_DEC_AL_FINAL, "AL-FINAL" }, + { TLLC_PDUT_DEC_AL_UDATA, "AL-UDATA" }, + { TLLC_PDUT_DEC_AL_UFINAL, "AL-UFINAL" }, + { TLLC_PDUT_DEC_AL_ACK, "AL-ACK" }, + { TLLC_PDUT_DEC_AL_RNR, "AL-RNR" }, + { TLLC_PDUT_DEC_AL_RECONNECT, "AL-RECONNECT" }, + { TLLC_PDUT_DEC_AL_DISC, "AL-DISC" }, + { TLLC_PDUT_DEC_ALX_DATA, "ALX-DATA" }, + { TLLC_PDUT_DEC_ALX_FINAL, "ALX-FINAL" }, + { TLLC_PDUT_DEC_ALX_UDATA, "ALX-UDATA" }, + { TLLC_PDUT_DEC_ALX_UFINAL, "ALX-UFINAL" }, + { TLLC_PDUT_DEC_ALX_ACK, "ALX-ACK" }, + { TLLC_PDUT_DEC_ALX_RNR, "ALX-RNR" }, + { 0, NULL } +}; + +const char *tetra_get_llc_pdut_dec_name(enum tllc_pdut_dec pdut) +{ + return get_value_string(pdut_dec_names, pdut); +} + +int tetra_llc_pdu_parse(struct tetra_llc_pdu *lpp, uint8_t *buf, int len) +{ + uint8_t *cur = buf; + uint8_t pdu_type; + + 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: + 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; + break; + case TLLC_PDUT_BL_DATA_FCS: + /* FIXME */ + len -= 32; + case TLLC_PDUT_BL_DATA: + lpp->ns = *cur++; + lpp->tl_sdu = cur; + lpp->tl_sdu_len = len - (cur - buf); + lpp->pdu_type = TLLC_PDUT_DEC_BL_DATA; + break; + case TLLC_PDUT_BL_UDATA_FCS: + /* FIXME */ + len -= 32; + case TLLC_PDUT_BL_UDATA: + lpp->tl_sdu = cur; + lpp->tl_sdu_len = len - (cur - buf); + lpp->pdu_type = TLLC_PDUT_DEC_BL_UDATA; + break; + case TLLC_PDUT_AL_DATA_FINAL: + if (*cur++) { + /* FINAL */ + cur++; + cur += 2; + lpp->ns = bits_to_uint(cur, 5); cur += 5; + lpp->ss = bits_to_uint(cur, 8); cur += 8; + if (*cur++) { + /* FIXME: FCS */ + len -= 32; + } + lpp->tl_sdu = cur; + lpp->tl_sdu_len = len - (cur - buf); + lpp->pdu_type = TLLC_PDUT_DEC_AL_FINAL; + } else { + /* DATA Table 21.19 */ + cur++; + lpp->ns = bits_to_uint(cur, 3); cur += 3; + lpp->ss = bits_to_uint(cur, 8); cur += 8; + lpp->tl_sdu = cur; + lpp->tl_sdu_len = len - (cur - buf); + lpp->pdu_type = TLLC_PDUT_DEC_AL_DATA; + } + break; + case TLLC_PDUT_AL_UDATA_UFINAL: + if (*cur++) { + /* UFINAL 21.2.3.7 / Table 21.26 */ + lpp->ns = bits_to_uint(cur, 8); cur+= 8; + lpp->ss = bits_to_uint(cur, 8); cur+= 8; + lpp->tl_sdu = cur; + /* FIXME: FCS */ + len -= 32; + lpp->tl_sdu_len = len - (cur - buf); + lpp->pdu_type = TLLC_PDUT_DEC_AL_UFINAL; + } else { + /* UDATA 21.2.3.6 / Table 21.24 */ + lpp->ns = bits_to_uint(cur, 8); cur+= 8; + lpp->ss = bits_to_uint(cur, 8); cur+= 8; + lpp->tl_sdu = cur; + lpp->tl_sdu_len = len - (cur - buf); + lpp->pdu_type = TLLC_PDUT_DEC_AL_UDATA; + } + break; + } + return (cur - buf); +} diff --git a/src/tetra_llc_pdu.h b/src/tetra_llc_pdu.h new file mode 100644 index 0000000..c96bdcf --- /dev/null +++ b/src/tetra_llc_pdu.h @@ -0,0 +1,80 @@ +#ifndef TETRA_LLC_PDU_H +#define TETRA_LLC_PDU_H + +/* Table 21.1 */ +enum tetra_llc_pdu_t { + TLLC_PDUT_BL_ADATA = 0, + TLLC_PDUT_BL_DATA = 1, + TLLC_PDUT_BL_UDATA = 2, + TLLC_PDUT_BL_ACK = 3, + TLLC_PDUT_BL_ADATA_FCS = 4, + TLLC_PDUT_BL_DATA_FCS = 5, + TLLC_PDUT_BL_UDATA_FCS = 6, + TLLC_PDUT_BL_ACK_FCS = 7, + TLLC_PDUT_AL_SETUP = 8, + TLLC_PDUT_AL_DATA_FINAL = 9, + TLLC_PDUT_AL_UDATA_UFINAL = 10, + TLLC_PDUT_AL_ACK_RNR = 11, + TLLC_PDUT_AL_RECONNECT = 12, + TLLC_PDUT_SUPPL = 13, + TLLC_PDUT_L2SIG = 14, + TLLD_PDUT_AL_DISC = 15 +}; +const char *tetra_get_llc_pdut_name(uint8_t pdut); + +/* Table 21.2 */ +enum tetra_llc_l2sig_pdu_t { + TLLC_PDUT_L2_DATA_PRIO = 0, + TLLC_PDUT_L2_SCHEDULE_SYNC = 1, + TLLC_PDUT_L2_LINK_FB_CTRL = 2, + TLLC_PDUT_L2_LINK_FB_INFO = 3, + TLLC_PDUT_L2_LINK_FB_INFO_RD_PRIO = 4 +}; + +/* Table 21.3 */ +enum tetra_llc_suppl_pdu_t { + TLLC_PDUT_SUPPL_ALX_DATA_FINAL = 0, + TLLC_PDUT_SUPPL_ALX_UDATA_UFINAL = 1, + TLLC_PDUT_SUPPL_ALX_ACK_RNR = 2 +}; + +/* Decoded */ + +enum tllc_pdut_dec { + TLLC_PDUT_DEC_UNKNOWN, + TLLC_PDUT_DEC_BL_ADATA, + TLLC_PDUT_DEC_BL_DATA, + TLLC_PDUT_DEC_BL_UDATA, + TLLC_PDUT_DEC_BL_ACK, + TLLC_PDUT_DEC_AL_SETUP, + TLLC_PDUT_DEC_AL_DATA, + TLLC_PDUT_DEC_AL_FINAL, + TLLC_PDUT_DEC_AL_UDATA, + TLLC_PDUT_DEC_AL_UFINAL, + TLLC_PDUT_DEC_AL_ACK, + TLLC_PDUT_DEC_AL_RNR, + TLLC_PDUT_DEC_AL_RECONNECT, + TLLC_PDUT_DEC_AL_DISC, + TLLC_PDUT_DEC_ALX_DATA, + TLLC_PDUT_DEC_ALX_FINAL, + TLLC_PDUT_DEC_ALX_UDATA, + TLLC_PDUT_DEC_ALX_UFINAL, + TLLC_PDUT_DEC_ALX_ACK, + TLLC_PDUT_DEC_ALX_RNR, +}; +const char *tetra_get_llc_pdut_dec_name(enum tllc_pdut_dec pdut); + +struct tetra_llc_pdu { + enum tllc_pdut_dec pdu_type; + uint8_t nr; + uint8_t ns; + uint8_t ss; + uint32_t _fcs; + uint32_t *fcs; + uint8_t *tl_sdu; /* pointer to bitbuf */ + uint8_t tl_sdu_len; /* in bits */ +}; + +int tetra_llc_pdu_parse(struct tetra_llc_pdu *lpp, uint8_t *buf, int len); + +#endif /* TETRA_LLC_PDU_H */ diff --git a/src/tetra_upper_mac.c b/src/tetra_upper_mac.c index 8271610..7e98c41 100644 --- a/src/tetra_upper_mac.c +++ b/src/tetra_upper_mac.c @@ -29,7 +29,7 @@ #include "tetra_prim.h" #include "tetra_upper_mac.h" #include "tetra_mac_pdu.h" -#include "tetra_mle_pdu.h" +#include "tetra_llc_pdu.h" #include "tetra_mm_pdu.h" #include "tetra_cmce_pdu.h" #include "tetra_sndcp_pdu.h" @@ -95,11 +95,11 @@ const char *tetra_alloc_dump(const struct tetra_chan_alloc_decoded *cad) return buf; } -static int rx_tm_sdu(uint8_t *bits, unsigned int len) +static int rx_tl_sdu(uint8_t *bits, unsigned int len) { uint8_t mle_pdisc = bits_to_uint(bits, 3); - printf("TM-SDU(%s): %s", tetra_get_mle_pdisc_name(mle_pdisc), + printf("TL-SDU(%s): %s", tetra_get_mle_pdisc_name(mle_pdisc), ubit_dump(bits, len)); switch (mle_pdisc) { case TMLE_PDISC_MM: @@ -120,6 +120,20 @@ static int rx_tm_sdu(uint8_t *bits, unsigned int len) return len; } +static int rx_tm_sdu(uint8_t *bits, unsigned int len) +{ + struct tetra_llc_pdu lpp; + + memset(&lpp, 0, sizeof(lpp)); + tetra_llc_pdu_parse(&lpp, bits, len); + + printf("TM-SDU(%s): ", tetra_get_llc_pdut_dec_name(lpp.pdu_type)); + if (lpp.tl_sdu) { + rx_tl_sdu(lpp.tl_sdu, lpp.tl_sdu_len); + } + return len; +} + static void rx_resrc(struct tetra_tmvsap_prim *tmvp) { struct tmv_unitdata_param *tup = &tmvp->u.unitdata;