mirror of
				https://github.com/brmlab/osmo-tetra.git
				synced 2025-10-31 15:33:59 +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 | ||||
| 	$(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 | ||||
|  |  | |||
							
								
								
									
										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_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; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Harald Welte
						Harald Welte