mirror of
				https://github.com/brmlab/osmo-tetra.git
				synced 2025-10-30 23:14:00 +01:00 
			
		
		
		
	Introduce LLC layer that has been completely missign so far
All our MM/CMCE/SNDCP 'decodes' were broken previously, as they assumed that the MM/CMCE/SNDCP message follows immediately after the MAC header. However, there's the LLC layer in between. This is just simple LLC decoding and does not do re-assembly yet.
This commit is contained in:
		
							parent
							
								
									2c6eab8f48
								
							
						
					
					
						commit
						b5d6edbb82
					
				
					 4 changed files with 264 additions and 4 deletions
				
			
		|  | @ -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 | libosmo-tetra-phy.a: phy/tetra_burst_sync.o phy/tetra_burst.o | ||||||
| 	$(AR) r $@ $^ | 	$(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 $@ $^ | 	$(AR) r $@ $^ | ||||||
| 
 | 
 | ||||||
| float_to_bits: float_to_bits.o | float_to_bits: float_to_bits.o | ||||||
|  |  | ||||||
							
								
								
									
										166
									
								
								src/tetra_llc_pdu.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										166
									
								
								src/tetra_llc_pdu.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,166 @@ | ||||||
|  | /* Implementation of some PDU parsing of the TETRA LLC */ | ||||||
|  | 
 | ||||||
|  | /* (C) 2011 by Harald Welte <laforge@gnumonks.org>
 | ||||||
|  |  * 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 <http://www.gnu.org/licenses/>.
 | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | #include <stdint.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <string.h> | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <errno.h> | ||||||
|  | 
 | ||||||
|  | #include <osmocom/core/utils.h> | ||||||
|  | 
 | ||||||
|  | #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); | ||||||
|  | } | ||||||
							
								
								
									
										80
									
								
								src/tetra_llc_pdu.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								src/tetra_llc_pdu.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -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 */ | ||||||
|  | @ -29,7 +29,7 @@ | ||||||
| #include "tetra_prim.h" | #include "tetra_prim.h" | ||||||
| #include "tetra_upper_mac.h" | #include "tetra_upper_mac.h" | ||||||
| #include "tetra_mac_pdu.h" | #include "tetra_mac_pdu.h" | ||||||
| #include "tetra_mle_pdu.h" | #include "tetra_llc_pdu.h" | ||||||
| #include "tetra_mm_pdu.h" | #include "tetra_mm_pdu.h" | ||||||
| #include "tetra_cmce_pdu.h" | #include "tetra_cmce_pdu.h" | ||||||
| #include "tetra_sndcp_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; | 	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); | 	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)); | 		ubit_dump(bits, len)); | ||||||
| 	switch (mle_pdisc) { | 	switch (mle_pdisc) { | ||||||
| 	case TMLE_PDISC_MM: | 	case TMLE_PDISC_MM: | ||||||
|  | @ -120,6 +120,20 @@ static int rx_tm_sdu(uint8_t *bits, unsigned int len) | ||||||
| 	return 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) | static void rx_resrc(struct tetra_tmvsap_prim *tmvp) | ||||||
| { | { | ||||||
| 	struct tmv_unitdata_param *tup = &tmvp->u.unitdata; | 	struct tmv_unitdata_param *tup = &tmvp->u.unitdata; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Harald Welte
						Harald Welte