2011-01-19 09:39:59 +00:00
/* TETRA upper MAC layer main routine, above TMV-SAP */
/* (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 <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <unistd.h>
2014-11-26 18:20:41 +00:00
# include <ctype.h>
2011-04-17 18:21:41 +00:00
# include <osmocom/core/utils.h>
2011-04-24 14:55:42 +00:00
# include <osmocom/core/msgb.h>
# include <osmocom/core/talloc.h>
2011-01-19 09:39:59 +00:00
# include "tetra_common.h"
# include "tetra_prim.h"
# include "tetra_upper_mac.h"
# include "tetra_mac_pdu.h"
2011-04-24 09:10:52 +00:00
# include "tetra_llc_pdu.h"
2011-01-19 09:39:59 +00:00
# include "tetra_mm_pdu.h"
2011-04-23 15:00:01 +00:00
# include "tetra_cmce_pdu.h"
2011-04-24 03:12:16 +00:00
# include "tetra_sndcp_pdu.h"
2011-04-24 07:24:13 +00:00
# include "tetra_mle_pdu.h"
2011-01-19 09:39:59 +00:00
# include "tetra_gsmtap.h"
2014-11-26 18:20:41 +00:00
# include "tetra_sds.h"
2011-01-19 09:39:59 +00:00
2011-05-27 07:37:06 +00:00
static int rx_tm_sdu ( struct tetra_mac_state * tms , struct msgb * msg , unsigned int len ) ;
2011-05-27 06:44:12 +00:00
static void rx_bcast ( struct tetra_tmvsap_prim * tmvp , struct tetra_mac_state * tms )
2011-01-19 09:39:59 +00:00
{
2011-04-24 14:55:42 +00:00
struct msgb * msg = tmvp - > oph . msg ;
2011-01-19 09:39:59 +00:00
struct tetra_si_decoded sid ;
uint32_t dl_freq , ul_freq ;
int i ;
memset ( & sid , 0 , sizeof ( sid ) ) ;
2011-04-24 14:55:42 +00:00
macpdu_decode_sysinfo ( & sid , msg - > l1h ) ;
2013-12-30 19:58:30 +00:00
tmvp - > u . unitdata . tdma_time . hn = sid . hyperframe_number ;
2011-01-19 09:39:59 +00:00
dl_freq = tetra_dl_carrier_hz ( sid . freq_band ,
2015-02-23 16:01:06 +00:00
sid . main_carrier ,
sid . freq_offset ) ;
2011-01-19 09:39:59 +00:00
ul_freq = tetra_ul_carrier_hz ( sid . freq_band ,
2015-02-23 16:01:06 +00:00
sid . main_carrier ,
sid . freq_offset ,
sid . duplex_spacing ,
sid . reverse_operation ) ;
2011-01-19 09:39:59 +00:00
2014-12-27 21:50:33 +00:00
printf ( " BNCH SYSINFO (DL %u Hz, UL %u Hz), service_details 0x%04x LA:%u " ,
2015-02-23 16:01:06 +00:00
dl_freq , ul_freq , sid . mle_si . bs_service_details , sid . mle_si . la ) ;
2014-11-26 18:20:41 +00:00
/* sq5bpf */
2015-06-03 19:58:50 +00:00
tetra_hack_freq_band = sid . freq_band ;
tetra_hack_freq_offset = sid . freq_offset ;
2014-11-26 18:20:41 +00:00
tetra_hack_dl_freq = dl_freq ;
tetra_hack_ul_freq = ul_freq ;
2014-12-27 21:50:33 +00:00
tetra_hack_la = sid . mle_si . la ;
2015-02-23 16:01:06 +00:00
2011-01-19 09:39:59 +00:00
if ( sid . cck_valid_no_hf )
printf ( " CCK ID %u " , sid . cck_id ) ;
else
printf ( " Hyperframe %u " , sid . hyperframe_number ) ;
printf ( " \n " ) ;
for ( i = 0 ; i < 12 ; i + + )
printf ( " \t %s: %u \n " , tetra_get_bs_serv_det_name ( 1 < < i ) ,
2015-02-23 16:01:06 +00:00
sid . mle_si . bs_service_details & ( 1 < < i ) ? 1 : 0 ) ;
2011-01-19 09:39:59 +00:00
2012-12-01 13:48:52 +00:00
memcpy ( & tms - > last_sid , & sid , sizeof ( sid ) ) ;
2011-01-19 09:39:59 +00:00
}
2015-06-09 14:03:50 +00:00
const char * tetra_alloc_dump ( const struct tetra_chan_alloc_decoded * cad , struct tetra_mac_state * tms , int send_telive_msg )
2011-01-19 09:39:59 +00:00
{
static char buf [ 64 ] ;
char * cur = buf ;
2011-04-24 08:00:37 +00:00
unsigned int freq_band , freq_offset ;
2015-06-09 14:03:50 +00:00
char freqinfo [ 128 ] ;
2011-04-24 08:00:37 +00:00
if ( cad - > ext_carr_pres ) {
freq_band = cad - > ext_carr . freq_band ;
freq_offset = cad - > ext_carr . freq_offset ;
} else {
2012-12-01 13:48:52 +00:00
freq_band = tms - > last_sid . freq_band ;
freq_offset = tms - > last_sid . freq_offset ;
2011-04-24 08:00:37 +00:00
}
2011-01-19 09:39:59 +00:00
cur + = sprintf ( cur , " %s (TN%u/%s/%uHz) " ,
2015-02-23 16:01:06 +00:00
tetra_get_alloc_t_name ( cad - > type ) , cad - > timeslot ,
tetra_get_ul_dl_name ( cad - > ul_dl ) ,
tetra_dl_carrier_hz ( freq_band , cad - > carrier_nr , freq_offset ) ) ;
2015-06-09 14:03:50 +00:00
if ( send_telive_msg ) {
switch ( cad - > ul_dl ) {
case 3 : /* uplink + downlink */
sprintf ( freqinfo , " TETMON_begin FUNC:FREQINFO2 DLF:%i RX:%i TETMON_end " , tetra_dl_carrier_hz ( freq_band , cad - > carrier_nr , freq_offset ) , tetra_hack_rxid ) ;
sendto ( tetra_hack_live_socket , ( char * ) & freqinfo , 128 , 0 , ( struct sockaddr * ) & tetra_hack_live_sockaddr , tetra_hack_socklen ) ;
break ;
2011-01-19 09:39:59 +00:00
2015-06-09 14:03:50 +00:00
default :
break ;
}
}
2011-01-19 09:39:59 +00:00
return buf ;
}
2014-11-26 18:20:41 +00:00
/* sq5bpf */
int parse_d_release ( struct tetra_mac_state * tms , struct msgb * msg , unsigned int len )
{
uint8_t * bits = msg - > l3h + 3 ;
int n = 0 ;
int m = 0 ;
2015-03-09 02:23:12 +00:00
char tmpstr2 [ 1024 ] ;
2015-03-12 21:39:09 +00:00
char * nis ;
int tmpdu_offset ;
struct tetra_resrc_decoded rsd ;
2014-11-26 18:20:41 +00:00
2015-03-12 21:39:09 +00:00
memset ( & rsd , 0 , sizeof ( rsd ) ) ;
tmpdu_offset = macpdu_decode_resource ( & rsd , msg - > l1h ) ;
2014-11-26 18:20:41 +00:00
/* strona 270 */
m = 5 ; uint8_t pdu_type = bits_to_uint ( bits + n , m ) ; n = n + m ;
m = 14 ; uint16_t callident = bits_to_uint ( bits + n , m ) ; n = n + m ;
2015-03-12 21:39:09 +00:00
m = 5 ; uint16_t disccause = bits_to_uint ( bits + n , m ) ; n = n + m ;
2014-11-26 18:20:41 +00:00
m = 6 ; uint16_t notifindic = bits_to_uint ( bits + n , m ) ; n = n + m ;
2015-03-12 21:39:09 +00:00
nis = ( notifindic < 28 ) ? notification_indicator_strings [ notifindic ] : " Reserved " ;
printf ( " \n Call identifier:%i Discconnect cause:%i NotificationID:%i (%s) \n " , callident , disccause , notifindic , nis ) ;
sprintf ( tmpstr2 , " TETMON_begin FUNC:DRELEASEDEC SSI:%i CID:%i NID:%i [%s] RX:%i TETMON_end " , rsd . addr . ssi , callident , notifindic , nis , tetra_hack_rxid ) ;
2015-03-09 02:23:12 +00:00
sendto ( tetra_hack_live_socket , ( char * ) & tmpstr2 , strlen ( ( char * ) & tmpstr2 ) + 1 , 0 , ( struct sockaddr * ) & tetra_hack_live_sockaddr , tetra_hack_socklen ) ;
2014-11-26 18:20:41 +00:00
}
2016-03-20 17:24:11 +00:00
/* sq5bpf */
int parse_d_connect ( struct tetra_mac_state * tms , struct msgb * msg , unsigned int len ) {
uint8_t * bits = msg - > l3h + 3 ;
int n = 0 ;
int m = 0 ;
char * nis ;
int tmpdu_offset ;
struct tetra_resrc_decoded rsd ;
char buf [ 1024 ] ;
char buf2 [ 128 ] ;
2014-11-26 18:20:41 +00:00
2016-03-20 17:24:11 +00:00
memset ( & rsd , 0 , sizeof ( rsd ) ) ;
tmpdu_offset = macpdu_decode_resource ( & rsd , msg - > l1h ) ;
/* strona 266 */
m = 5 ; uint8_t pdu_type = bits_to_uint ( bits + n , m ) ; n = n + m ;
m = 14 ; uint16_t callident = bits_to_uint ( bits + n , m ) ; n = n + m ;
m = 4 ; uint8_t call_timeout = bits_to_uint ( bits + n , m ) ; n = n + m ;
m = 1 ; uint8_t hook_method_sel = bits_to_uint ( bits + n , m ) ; n = n + m ;
m = 1 ; uint8_t duplex_sel = bits_to_uint ( bits + n , m ) ; n = n + m ;
m = 2 ; uint8_t tx_grant = bits_to_uint ( bits + n , m ) ; n = n + m ;
m = 1 ; uint8_t tx_req_permission = bits_to_uint ( bits + n , m ) ; n = n + m ;
m = 1 ; uint8_t call_ownership = bits_to_uint ( bits + n , m ) ; n = n + m ;
m = 1 ; uint8_t o_bit = bits_to_uint ( bits + n , m ) ; n = n + m ;
printf ( " \n Call Identifier:%i Call timeout:%i hook_method:%i Duplex:%i TX_Grant:%i TX_Request_permission:%i Call ownership:%i \n " , callident , call_timeout , hook_method_sel , duplex_sel , tx_grant , tx_req_permission , call_ownership ) ;
sprintf ( buf , " TETMON_begin FUNC:DCONNECTDEC SSI:%i IDX:%i CID:%i CALLOWN:%i " , rsd . addr . ssi , rsd . addr . usage_marker , callident , call_ownership ) ;
if ( o_bit ) {
m = 1 ; uint8_t pbit_callpri = bits_to_uint ( bits + n , m ) ; n = n + m ;
if ( pbit_callpri ) {
m = 4 ; uint8_t callpri = bits_to_uint ( bits + n , m ) ; n = n + m ;
printf ( " Call priority:%i " , callpri ) ;
}
m = 1 ; uint8_t pbit_bsi = bits_to_uint ( bits + n , m ) ; n = n + m ;
if ( pbit_bsi ) {
m = 8 ; uint8_t basic_service_information = bits_to_uint ( bits + n , m ) ; n = n + m ;
printf ( " Basic service information:%i " , basic_service_information ) ;
}
m = 1 ; uint8_t pbit_tmpaddr = bits_to_uint ( bits + n , m ) ; n = n + m ;
if ( pbit_tmpaddr ) {
m = 24 ; uint32_t temp_addr = bits_to_uint ( bits + n , m ) ; n = n + m ;
printf ( " Temp address:%i " , temp_addr ) ;
sprintf ( buf2 , " SSI2:%i " , temp_addr ) ;
strcat ( buf , buf2 ) ;
}
m = 1 ; uint8_t pbit_nid = bits_to_uint ( bits + n , m ) ; n = n + m ;
if ( pbit_nid ) {
m = 6 ; uint8_t notifindic = bits_to_uint ( bits + n , m ) ; n = n + m ;
nis = ( notifindic < 28 ) ? notification_indicator_strings [ notifindic ] : " Reserved " ;
printf ( " Notification indicator:%i [%s] " , notifindic , nis ) ;
sprintf ( buf2 , " NID:%i [%s] " , notifindic , nis ) ;
strcat ( buf , buf2 ) ;
}
printf ( " \n " ) ;
}
sprintf ( buf2 , " RX:%i TETMON_end " , tetra_hack_rxid ) ;
strcat ( buf , buf2 ) ;
sendto ( tetra_hack_live_socket , ( char * ) & buf , strlen ( ( char * ) & buf ) + 1 , 0 , ( struct sockaddr * ) & tetra_hack_live_sockaddr , tetra_hack_socklen ) ;
}
int parse_d_txgranted ( struct tetra_mac_state * tms , struct msgb * msg , unsigned int len ) {
uint8_t * bits = msg - > l3h + 3 ;
int n = 0 ;
int m = 0 ;
char * nis ;
int tmpdu_offset ;
struct tetra_resrc_decoded rsd ;
char buf [ 1024 ] ;
char buf2 [ 128 ] ;
memset ( & rsd , 0 , sizeof ( rsd ) ) ;
tmpdu_offset = macpdu_decode_resource ( & rsd , msg - > l1h ) ;
/* strona 271 */
m = 5 ; uint8_t pdu_type = bits_to_uint ( bits + n , m ) ; n = n + m ;
m = 14 ; uint16_t callident = bits_to_uint ( bits + n , m ) ; n = n + m ;
m = 2 ; uint8_t tx_grant = bits_to_uint ( bits + n , m ) ; n = n + m ;
m = 1 ; uint8_t tx_req_permission = bits_to_uint ( bits + n , m ) ; n = n + m ;
m = 1 ; uint8_t enc_control = bits_to_uint ( bits + n , m ) ; n = n + m ;
m = 1 ; uint8_t reserved = bits_to_uint ( bits + n , m ) ; n = n + m ;
m = 1 ; uint8_t o_bit = bits_to_uint ( bits + n , m ) ; n = n + m ;
printf ( " \n Call Identifier:%i TX_Grant:%i TX_Request_permission:%i Encryption control:%i \n " , callident , tx_grant , tx_req_permission , enc_control ) ;
sprintf ( buf , " TETMON_begin FUNC:DTXGRANTDEC SSI:%i IDX:%i CID:%i TXGRANT:%i TXPERM:%i ENCC:%i " , rsd . addr . ssi , rsd . addr . usage_marker , callident , tx_grant , tx_req_permission , enc_control ) ;
if ( o_bit ) {
m = 1 ; uint8_t pbit_nid = bits_to_uint ( bits + n , m ) ; n = n + m ;
if ( pbit_nid ) {
m = 6 ; uint8_t notifindic = bits_to_uint ( bits + n , m ) ; n = n + m ;
nis = ( notifindic < 28 ) ? notification_indicator_strings [ notifindic ] : " Reserved " ;
printf ( " Notification indicator:%i [%s] " , notifindic , nis ) ;
sprintf ( buf2 , " NID:%i [%s] " , notifindic , nis ) ;
strcat ( buf , buf2 ) ;
}
m = 1 ; uint8_t pbit_tpti = bits_to_uint ( bits + n , m ) ; n = n + m ;
if ( pbit_tpti ) {
m = 2 ; uint8_t tpti = bits_to_uint ( bits + n , m ) ; n = n + m ;
uint32_t txssi ;
uint32_t txssiext ;
sprintf ( buf2 , " TPTI:%i " , tpti ) ;
strcat ( buf , buf2 ) ;
switch ( tpti )
{
case 0 : /* SNA , this isn't defined for D-TX GRANTED */
m = 8 ; txssi = bits_to_uint ( bits + n , m ) ; n = n + m ;
sprintf ( buf2 , " SSI2:%i " , txssi ) ;
strcat ( buf , buf2 ) ;
break ;
case 1 : /* SSI */
m = 24 ; txssi = bits_to_uint ( bits + n , m ) ; n = n + m ;
sprintf ( buf2 , " SSI2:%i " , txssi ) ;
strcat ( buf , buf2 ) ;
break ;
case 2 : /* TETRA Subscriber Identity (TSI) */
m = 24 ; txssi = bits_to_uint ( bits + n , m ) ; n = n + m ;
m = 24 ; txssiext = bits_to_uint ( bits + n , m ) ; n = n + m ;
sprintf ( buf2 , " SSI2:%i SSIEXT:%i " , txssi , txssiext ) ;
strcat ( buf , buf2 ) ;
break ;
case 3 : /* reserved ? */
break ;
}
}
/* TODO: type 3/4 elements */
printf ( " \n " ) ;
}
sprintf ( buf2 , " RX:%i TETMON_end " , tetra_hack_rxid ) ;
strcat ( buf , buf2 ) ;
sendto ( tetra_hack_live_socket , ( char * ) & buf , strlen ( ( char * ) & buf ) + 1 , 0 , ( struct sockaddr * ) & tetra_hack_live_sockaddr , tetra_hack_socklen ) ;
}
2014-11-26 18:20:41 +00:00
uint parse_d_setup ( struct tetra_mac_state * tms , struct msgb * msg , unsigned int len )
{
uint8_t * bits = msg - > l3h + 3 ;
int n = 0 ;
int m = 0 ;
uint32_t callingssi = 0 ;
uint32_t callingext = 0 ;
char tmpstr2 [ 1024 ] ;
struct tetra_resrc_decoded rsd ;
int tmpdu_offset ;
2016-11-16 20:36:50 +00:00
uint16_t notifindic = 0 ;
uint32_t tempaddr = 0 ;
uint16_t cpti = 0 ;
2014-11-26 18:20:41 +00:00
memset ( & rsd , 0 , sizeof ( rsd ) ) ;
tmpdu_offset = macpdu_decode_resource ( & rsd , msg - > l1h ) ;
/* strona 270, opisy strona 280 */
m = 5 ; uint8_t pdu_type = bits_to_uint ( bits + n , m ) ; n = n + m ;
m = 14 ; uint16_t callident = bits_to_uint ( bits + n , m ) ; n = n + m ;
m = 4 ; uint16_t calltimeout = bits_to_uint ( bits + n , m ) ; n = n + m ;
m = 1 ; uint16_t hookmethod = bits_to_uint ( bits + n , m ) ; n = n + m ;
m = 1 ; uint16_t duplex = bits_to_uint ( bits + n , m ) ; n = n + m ;
m = 8 ; uint8_t basicinfo = bits_to_uint ( bits + n , m ) ; n = n + m ;
m = 2 ; uint16_t txgrant = bits_to_uint ( bits + n , m ) ; n = n + m ;
m = 1 ; uint16_t txperm = bits_to_uint ( bits + n , m ) ; n = n + m ;
m = 4 ; uint16_t callprio = bits_to_uint ( bits + n , m ) ; n = n + m ;
2016-11-16 20:36:50 +00:00
m = 1 ; uint8_t obit = bits_to_uint ( bits + n , m ) ; n = n + m ;
if ( obit )
2014-11-26 18:20:41 +00:00
{
2016-11-16 20:36:50 +00:00
m = 1 ; uint8_t pbit_notifindic = bits_to_uint ( bits + n , m ) ; n = n + m ;
if ( pbit_notifindic ) {
m = 6 ; notifindic = bits_to_uint ( bits + n , m ) ; n = n + m ;
}
m = 1 ; uint8_t pbit_tempaddr = bits_to_uint ( bits + n , m ) ; n = n + m ;
if ( pbit_tempaddr ) {
m = 24 ; tempaddr = bits_to_uint ( bits + n , m ) ; n = n + m ;
}
m = 1 ; uint8_t pbit_cpti = bits_to_uint ( bits + n , m ) ; n = n + m ;
if ( pbit_cpti ) {
m = 2 ; cpti = bits_to_uint ( bits + n , m ) ; n = n + m ;
switch ( cpti )
{
case 0 : /* SNA */
m = 8 ; callingssi = bits_to_uint ( bits + n , m ) ; n = n + m ;
break ;
case 1 : /* SSI */
m = 24 ; callingssi = bits_to_uint ( bits + n , m ) ; n = n + m ;
break ;
case 2 : /* TETRA Subscriber Identity (TSI) */
m = 24 ; callingssi = bits_to_uint ( bits + n , m ) ; n = n + m ;
m = 24 ; callingext = bits_to_uint ( bits + n , m ) ; n = n + m ;
break ;
case 3 : /* reserved ? */
break ;
}
}
2014-11-26 18:20:41 +00:00
2016-11-16 20:36:50 +00:00
}
2014-11-26 18:20:41 +00:00
printf ( " \n Call identifier:%i Call timeout:%i Hookmethod:%i Duplex:%i \n " , callident , calltimeout , hookmethod , duplex ) ;
printf ( " Basicinfo:0x%2.2X Txgrant:%i TXperm:%i Callprio:%i \n " , basicinfo , txgrant , txperm , callprio ) ;
printf ( " NotificationID:%i Tempaddr:%i CPTI:%i CallingSSI:%i CallingExt:%i \n " , notifindic , tempaddr , cpti , callingssi , callingext ) ;
2016-11-16 20:36:50 +00:00
sprintf ( tmpstr2 , " TETMON_begin FUNC:DSETUPDEC IDX:%i SSI:%i SSI2:%i CID:%i NID:%i RX:%i TETMON_end " , rsd . addr . usage_marker , rsd . addr . ssi , callingssi , callident , notifindic , tetra_hack_rxid ) ;
2014-11-26 18:20:41 +00:00
sendto ( tetra_hack_live_socket , ( char * ) & tmpstr2 , strlen ( ( char * ) & tmpstr2 ) + 1 , 0 , ( struct sockaddr * ) & tetra_hack_live_sockaddr , tetra_hack_socklen ) ;
}
2015-06-03 19:58:50 +00:00
/* decode 18.5.17 Neighbour cell information for CA */
/* str 535, przyklad str 1294 */
int parse_nci_ca ( uint8_t * bits )
{
int n , m ;
char buf [ 1024 ] ;
char buf2 [ 128 ] ;
char freqinfo [ 128 ] ;
n = 0 ;
m = 5 ; uint8_t cell_id = bits_to_uint ( bits + n , m ) ; n = n + m ;
m = 2 ; uint8_t cell_reselection = bits_to_uint ( bits + n , m ) ; n = n + m ;
m = 1 ; uint8_t neig_cell_synced = bits_to_uint ( bits + n , m ) ; n = n + m ;
m = 2 ; uint8_t cell_load = bits_to_uint ( bits + n , m ) ; n = n + m ;
m = 12 ; uint16_t main_carrier_num = bits_to_uint ( bits + n , m ) ; n = n + m ;
/* the band and offset info is from the sysinfo message, not sure if this is correct */
sprintf ( buf , " NCI:[cell_id:%i cell_resel:%i neigh_synced:%i cell_load:%i carrier:%i %iHz " , cell_id , cell_reselection , neig_cell_synced , cell_load , main_carrier_num , tetra_dl_carrier_hz ( tetra_hack_freq_band , main_carrier_num , tetra_hack_freq_offset ) ) ;
2015-06-09 14:03:50 +00:00
sprintf ( freqinfo , " TETMON_begin FUNC:FREQINFO1 DLF:%i " , tetra_dl_carrier_hz ( tetra_hack_freq_band , main_carrier_num , tetra_hack_freq_offset ) ) ;
2015-06-03 19:58:50 +00:00
m = 1 ; uint8_t obit = bits_to_uint ( bits + n , m ) ; n = n + m ;
if ( obit ) {
m = 1 ; uint8_t pbit_main_carrier_num_ext = bits_to_uint ( bits + n , m ) ; n = n + m ;
if ( pbit_main_carrier_num_ext ) {
m = 4 ; uint8_t freq_band = bits_to_uint ( bits + n , m ) ; n = n + m ;
m = 2 ; uint8_t freq_offset = bits_to_uint ( bits + n , m ) ; n = n + m ;
m = 3 ; uint8_t duplex_spacing = bits_to_uint ( bits + n , m ) ; n = n + m ;
m = 1 ; uint8_t reverse = bits_to_uint ( bits + n , m ) ; n = n + m ;
uint32_t dlfext = tetra_dl_carrier_hz ( freq_band , main_carrier_num , freq_offset ) ;
uint32_t ulfext = tetra_ul_carrier_hz ( freq_band , main_carrier_num , freq_offset , duplex_spacing , reverse ) ;
sprintf ( buf2 , " band:%i offset:%i freq:%iHz uplink:%iHz (duplex:%i rev:%i) " , freq_band , freq_offset , dlfext , ulfext , duplex_spacing , reverse ) ;
strcat ( buf , buf2 ) ;
2015-06-09 14:03:50 +00:00
sprintf ( buf2 , " TETMON_begin FUNC:FREQINFO1 DLF:%i ULF:%i " , dlfext , ulfext ) ;
2015-06-03 19:58:50 +00:00
strcat ( freqinfo , buf2 ) ;
}
m = 1 ; uint8_t pbit_mcc = bits_to_uint ( bits + n , m ) ; n = n + m ;
if ( pbit_mcc ) {
m = 10 ; uint16_t mcc = bits_to_uint ( bits + n , m ) ; n = n + m ;
sprintf ( buf2 , " MCC:%i " , mcc ) ;
strcat ( buf , buf2 ) ;
sprintf ( buf2 , " MCC:%4.4x " , mcc ) ;
strcat ( freqinfo , buf2 ) ;
}
m = 1 ; uint8_t pbit_mnc = bits_to_uint ( bits + n , m ) ; n = n + m ;
if ( pbit_mnc ) {
m = 14 ; uint16_t mnc = bits_to_uint ( bits + n , m ) ; n = n + m ;
sprintf ( buf2 , " MNC:%i " , mnc ) ;
strcat ( buf , buf2 ) ;
sprintf ( buf2 , " MNC:%4.4x " , mnc ) ;
strcat ( freqinfo , buf2 ) ;
}
m = 1 ; uint8_t pbit_la = bits_to_uint ( bits + n , m ) ; n = n + m ;
if ( pbit_la ) {
m = 14 ; uint16_t la = bits_to_uint ( bits + n , m ) ; n = n + m ;
sprintf ( buf2 , " LA:%i " , la ) ;
strcat ( buf , buf2 ) ;
strcat ( freqinfo , buf2 ) ;
}
m = 1 ; uint8_t pbit_max_ms_txpower = bits_to_uint ( bits + n , m ) ; n = n + m ;
if ( pbit_max_ms_txpower ) {
m = 3 ; uint8_t max_ms_txpower = bits_to_uint ( bits + n , m ) ; n = n + m ;
}
m = 1 ; uint8_t pbit_min_rx_level = bits_to_uint ( bits + n , m ) ; n = n + m ;
if ( pbit_min_rx_level ) {
m = 4 ; uint8_t min_rx_level = bits_to_uint ( bits + n , m ) ; n = n + m ;
}
m = 1 ; uint8_t pbit_subscr_class = bits_to_uint ( bits + n , m ) ; n = n + m ;
if ( pbit_subscr_class ) {
m = 16 ; uint16_t subscr_class = bits_to_uint ( bits + n , m ) ; n = n + m ;
}
m = 1 ; uint8_t pbit_bs_srv_details = bits_to_uint ( bits + n , m ) ; n = n + m ;
if ( pbit_bs_srv_details ) {
m = 12 ; uint16_t bs_srv_details = bits_to_uint ( bits + n , m ) ; n = n + m ;
}
m = 1 ; uint8_t pbit_timeshare_info = bits_to_uint ( bits + n , m ) ; n = n + m ;
if ( pbit_timeshare_info ) {
m = 5 ; uint8_t timeshare_info = bits_to_uint ( bits + n , m ) ; n = n + m ;
}
m = 1 ; uint8_t pbit_tdma_frame_offset = bits_to_uint ( bits + n , m ) ; n = n + m ;
if ( pbit_tdma_frame_offset ) {
m = 6 ; uint8_t tdma_frame_offset = bits_to_uint ( bits + n , m ) ; n = n + m ;
}
}
sprintf ( buf2 , " ] " ) ;
strcat ( buf , buf2 ) ;
printf ( " %s " , buf ) ;
sprintf ( buf2 , " RX:%i TETMON_end " , tetra_hack_rxid ) ;
strcat ( freqinfo , buf2 ) ;
sendto ( tetra_hack_live_socket , ( char * ) & freqinfo , 128 , 0 , ( struct sockaddr * ) & tetra_hack_live_sockaddr , tetra_hack_socklen ) ;
return ( n ) ;
}
uint parse_d_nwrk_broadcast ( struct tetra_mac_state * tms , struct msgb * msg , unsigned int len )
{
uint8_t * bits = msg - > l3h ;
int n , m , i ;
/* TMLE_PDISC_MLE 3 bits
* TMLE_PDUT_D_NWRK_BROADCAST 3 bits */
n = 3 + 3 ;
m = 16 ; uint16_t cell_reselect_parms = bits_to_uint ( bits + n , m ) ; n = n + m ;
m = 2 ; uint16_t cell_load = bits_to_uint ( bits + n , m ) ; n = n + m ;
m = 1 ; uint16_t optional_elements = bits_to_uint ( bits + n , m ) ; n = n + m ;
printf ( " \n D_NWRK_BROADCAST:[ cell_reselect:0x%4.4x cell_load:%i " , cell_reselect_parms , cell_load ) ;
if ( optional_elements ) {
m = 1 ; uint16_t pbit_tetra_time = bits_to_uint ( bits + n , m ) ; n = n + m ;
if ( pbit_tetra_time )
{
m = 24 ; uint32_t tetra_time_utc = bits_to_uint ( bits + n , m ) ; n = n + m ;
m = 1 ; uint8_t tetra_time_offset_sign = bits_to_uint ( bits + n , m ) ; n = n + m ;
m = 6 ; uint8_t tetra_time_offset = bits_to_uint ( bits + n , m ) ; n = n + m ;
m = 6 ; uint8_t tetra_time_year = bits_to_uint ( bits + n , m ) ; n = n + m ;
m = 11 ; uint16_t tetra_time_reserved = bits_to_uint ( bits + n , m ) ; n = n + m ; /* must be 0x7ff */
printf ( " time[secs:%i offset:%c%imin year:%i reserved:0x%4.4x] " , tetra_time_utc , tetra_time_offset_sign ? ' - ' : ' + ' , tetra_time_offset * 15 , 2000 + tetra_time_year , tetra_time_reserved ) ;
/* we could decode the time here, but it is not accurate on the networks that i see anyway */
}
m = 1 ; uint16_t pbit_neigh_cells = bits_to_uint ( bits + n , m ) ; n = n + m ;
// printf(" pbit_tetra_time:%i pbit_neigh_cells:%i",pbit_tetra_time,pbit_neigh_cells);
if ( pbit_neigh_cells )
{
m = 3 ; uint16_t num_neigh_cells = bits_to_uint ( bits + n , m ) ; n = n + m ;
printf ( " num_cells:%i " , num_neigh_cells ) ;
for ( i = 0 ; i < num_neigh_cells ; i + + ) {
m = parse_nci_ca ( bits + n ) ; n = n + m ;
}
}
2014-11-26 18:20:41 +00:00
2015-06-03 19:58:50 +00:00
}
printf ( " ] RX:%i \n " , tetra_hack_rxid ) ;
}
2011-05-27 07:37:06 +00:00
/* Receive TL-SDU (LLC SDU == MLE PDU) */
static int rx_tl_sdu ( struct tetra_mac_state * tms , struct msgb * msg , unsigned int len )
2011-01-19 09:39:59 +00:00
{
2011-05-27 07:37:06 +00:00
uint8_t * bits = msg - > l3h ;
2011-01-19 09:39:59 +00:00
uint8_t mle_pdisc = bits_to_uint ( bits , 3 ) ;
2014-11-26 18:20:41 +00:00
char tmpstr [ 1024 ] ;
2011-04-24 09:10:52 +00:00
printf ( " TL-SDU(%s): %s " , tetra_get_mle_pdisc_name ( mle_pdisc ) ,
2014-11-26 18:20:41 +00:00
osmo_ubit_dump ( bits , len ) ) ;
2011-01-19 09:39:59 +00:00
switch ( mle_pdisc ) {
2014-11-26 18:20:41 +00:00
case TMLE_PDISC_MM :
printf ( " %s " , tetra_get_mm_pdut_name ( bits_to_uint ( bits + 3 , 4 ) , 0 ) ) ;
break ;
case TMLE_PDISC_CMCE :
printf ( " %s " , tetra_get_cmce_pdut_name ( bits_to_uint ( bits + 3 , 5 ) , 0 ) ) ;
/* sq5bpf */
switch ( bits_to_uint ( bits + 3 , 5 ) ) {
case TCMCE_PDU_T_D_SETUP :
parse_d_setup ( tms , msg , len ) ;
break ;
2016-03-20 17:24:11 +00:00
case TCMCE_PDU_T_D_CONNECT :
parse_d_connect ( tms , msg , len ) ;
break ;
2014-11-26 18:20:41 +00:00
case TCMCE_PDU_T_D_RELEASE :
parse_d_release ( tms , msg , len ) ;
break ;
2016-03-20 17:24:11 +00:00
case TCMCE_PDU_T_D_TX_GRANTED :
parse_d_txgranted ( tms , msg , len ) ;
break ;
2014-11-26 18:20:41 +00:00
case TCMCE_PDU_T_D_SDS_DATA :
sprintf ( tmpstr , " TETMON_begin FUNC:SDS [%s] TETMON_end " , osmo_ubit_dump ( bits , len ) ) ;
sendto ( tetra_hack_live_socket , ( char * ) & tmpstr , strlen ( ( char * ) & tmpstr ) + 1 , 0 , ( struct sockaddr * ) & tetra_hack_live_sockaddr , tetra_hack_socklen ) ;
parse_d_sds_data ( tms , msg , len ) ;
break ;
/* case TCMCE_PDU_T_U_SDS_DATA:
sprintf ( tmpstr , " TETMON_begin FUNC:D-SDS [%s] TETMON_end " , osmo_ubit_dump ( bits , len ) ) ;
sendto ( tetra_hack_live_socket , ( char * ) & tmpstr , strlen ( ( char * ) & tmpstr ) + 1 , 0 , ( struct sockaddr * ) & tetra_hack_live_sockaddr , tetra_hack_socklen ) ;
break ;
*/
}
break ;
case TMLE_PDISC_SNDCP :
printf ( " %s " , tetra_get_sndcp_pdut_name ( bits_to_uint ( bits + 3 , 4 ) , 0 ) ) ;
printf ( " NSAPI=%u PCOMP=%u, DCOMP=%u " ,
bits_to_uint ( bits + 3 + 4 , 4 ) ,
bits_to_uint ( bits + 3 + 4 + 4 , 4 ) ,
bits_to_uint ( bits + 3 + 4 + 4 + 4 , 4 ) ) ;
printf ( " V%u, IHL=%u " ,
bits_to_uint ( bits + 3 + 4 + 4 + 4 + 4 , 4 ) ,
4 * bits_to_uint ( bits + 3 + 4 + 4 + 4 + 4 + 4 , 4 ) ) ;
printf ( " Proto=%u " ,
bits_to_uint ( bits + 3 + 4 + 4 + 4 + 4 + 4 + 4 + 64 , 8 ) ) ;
break ;
case TMLE_PDISC_MLE :
printf ( " %s " , tetra_get_mle_pdut_name ( bits_to_uint ( bits + 3 , 3 ) , 0 ) ) ;
2015-06-03 19:58:50 +00:00
/* parse d-nwrk-broadcast */
switch ( bits_to_uint ( bits + 3 , 3 ) )
{
case TMLE_PDUT_D_NWRK_BROADCAST :
parse_d_nwrk_broadcast ( tms , msg , len ) ;
default :
break ;
}
2014-11-26 18:20:41 +00:00
break ;
default :
break ;
2011-01-19 09:39:59 +00:00
}
return len ;
}
2011-05-27 07:37:06 +00:00
static int rx_tm_sdu ( struct tetra_mac_state * tms , struct msgb * msg , unsigned int len )
2011-04-24 09:10:52 +00:00
{
struct tetra_llc_pdu lpp ;
2011-05-27 07:37:06 +00:00
uint8_t * bits = msg - > l2h ;
2011-04-24 09:10:52 +00:00
memset ( & lpp , 0 , sizeof ( lpp ) ) ;
tetra_llc_pdu_parse ( & lpp , bits , len ) ;
2011-04-24 09:45:20 +00:00
printf ( " TM-SDU(%s,%u,%u): " ,
2014-11-26 18:20:41 +00:00
tetra_get_llc_pdut_dec_name ( lpp . pdu_type ) , lpp . ns , lpp . ss ) ;
2011-04-24 09:45:20 +00:00
if ( lpp . tl_sdu & & lpp . ss = = 0 ) {
2011-05-27 07:37:06 +00:00
msg - > l3h = lpp . tl_sdu ;
rx_tl_sdu ( tms , msg , lpp . tl_sdu_len ) ;
2011-04-24 09:10:52 +00:00
}
return len ;
}
2016-10-19 06:51:01 +00:00
/* add bits to a fragment. these should really be bit operations and not stuffing one bit per byte */
void append_frag_bits ( int slot , uint8_t * bits , int bitlen , int fillbits )
{
int i = bitlen ;
int l = fragslots [ slot ] . length ;
struct msgb * fragmsgb ;
uint8_t bit ;
int zeroes = 0 ;
fragmsgb = fragslots [ slot ] . msgb ;
while ( i ) {
bit = bits_to_uint ( bits , 1 ) ;
msgb_put_u8 ( fragmsgb , bit ) ;
if ( bit ) { zeroes = 0 ; } else { zeroes + + ; }
bits + + ;
i - - ;
l + + ;
if ( l > 4095 ) { printf ( " \n FRAG LENGTH ERROR! \n " ) ; return ; } /* limit hardcoded for now, the buffer allocated is twice the size just in case */
}
fragslots [ slot ] . length = fragslots [ slot ] . length + bitlen ;
if ( fillbits ) {
fragslots [ slot ] . length = fragslots [ slot ] . length - zeroes ;
msgb_get ( fragmsgb , zeroes ) ;
}
fragslots [ slot ] . fragments + + ;
fragslots [ slot ] . fragtimer = 0 ;
/*
* printf ( " \n append_frag slot=%i len=%i totallen=%i fillbits=%i \n " , slot , bitlen , fragslots [ slot ] . length , fillbits ) ;
* printf ( " \n FRAGDUMP: %s \n " , osmo_ubit_dump ( ( unsigned char * ) fragmsgb - > l3h , msgb_l3len ( fragmsgb ) ) ) ;
*/
}
/* MAC-FRAG PDU */
static void rx_macfrag ( struct tetra_tmvsap_prim * tmvp , struct tetra_mac_state * tms , int slot )
{
struct msgb * msg = tmvp - > oph . msg ;
struct tetra_resrc_decoded rsd ;
uint8_t * bits = msg - > l1h ;
int n = 0 ;
int m = 0 ;
memset ( & rsd , 0 , sizeof ( rsd ) ) ;
m = 2 ; uint8_t macpdu_type = bits_to_uint ( bits + n , m ) ; n = n + m ; /* MAC-FRAG/END */
m = 1 ; uint8_t macpdu_subtype = bits_to_uint ( bits + n , m ) ; n = n + m ; /* 0 - MAC-FRAG */
m = 1 ; uint8_t fillbits_present = bits_to_uint ( bits + n , m ) ; n = n + m ;
int len = msgb_l1len ( msg ) - n ;
if ( fragslots [ slot ] . active ) {
append_frag_bits ( slot , bits + n , len , fillbits_present ) ;
} else {
printf ( " \n FRAG: got fragment without start packet for slot=%i \n " , slot ) ;
}
}
/* 21.4.3.3 MAC-END PDU page 618 */
static void rx_macend ( struct tetra_tmvsap_prim * tmvp , struct tetra_mac_state * tms , int slot )
{
struct msgb * msg = tmvp - > oph . msg ;
struct tetra_resrc_decoded rsd ;
int tmpdu_offset ;
uint8_t * bits = msg - > l1h ;
struct msgb * fragmsgb ;
int n = 0 ;
int m = 0 ;
memset ( & rsd , 0 , sizeof ( rsd ) ) ;
m = 2 ; uint8_t macpdu_type = bits_to_uint ( bits + n , m ) ; n = n + m ;
m = 1 ; uint8_t macpdu_subtype = bits_to_uint ( bits + n , m ) ; n = n + m ;
m = 1 ; uint8_t fillbits_present = bits_to_uint ( bits + n , m ) ; n = n + m ;
m = 6 ; uint8_t length_indicator = bits_to_uint ( bits + n , m ) ; n = n + m ;
/* FIXME: we should really look at the modulation and handle d8psk and qam */
/* m=1; uint8_t napping=bits_to_uint(bits+n, m); n=n+m; // only in d8psk and qam */
m = 1 ; uint8_t slot_granting = bits_to_uint ( bits + n , m ) ; n = n + m ;
if ( slot_granting ) {
/* m=1; uint8_t multiple=bits_to_uint(bits+n, m); n=n+m; // only in qam */
m = 8 ; /* basic slot granting */ n = n + m ;
/* multiple slot granting in qam */
}
m = 1 ; uint8_t chanalloc = bits_to_uint ( bits + n , m ) ; n = n + m ;
if ( chanalloc ) {
m = decode_chan_alloc ( & rsd . cad , bits + n ) ; n = n + m ;
}
int len = msgb_l1len ( msg ) - n ;
fragmsgb = fragslots [ slot ] . msgb ;
fragslots [ slot ] . fragments + + ;
if ( fragslots [ slot ] . active ) {
append_frag_bits ( slot , bits + n , len , fillbits_present ) ;
/* for now filter out just SDS messages to hide the fact that the fragment stuff doesn't work 100% correctly :) */
uint8_t * b = fragmsgb - > l3h ;
2016-10-25 05:54:32 +00:00
if ( b ) {
uint8_t mle_pdisc = bits_to_uint ( b , 3 ) ;
uint8_t proto = bits_to_uint ( b + 3 , 5 ) ;
if ( ( mle_pdisc = = TMLE_PDISC_CMCE ) & & ( proto = = TCMCE_PDU_T_D_SDS_DATA ) ) {
printf ( " \n FRAGMENT DECODE fragments=%i len=%i slot=%i Encr=%i " , fragslots [ slot ] . fragments , fragslots [ slot ] . length , slot , fragslots [ slot ] . encryption ) ;
fflush ( stdout ) ; /* TODO: remove this in the future, for now leave it so that the printf() is shown if rx_tl_sdu segfaults for somee reason */
rx_tl_sdu ( tms , fragmsgb , fragslots [ slot ] . length ) ;
}
2016-10-19 06:51:01 +00:00
}
2016-10-25 05:54:32 +00:00
else
{
printf ( " \n FRAG: got end frag without start packet for slot=%i \n " , slot ) ;
}
} else {
printf ( " \n FRAGMENT without l3 header dropped slot=%i \n " , slot ) ;
2016-10-19 06:51:01 +00:00
}
2016-10-25 05:54:32 +00:00
2016-10-19 06:51:01 +00:00
msgb_reset ( fragmsgb ) ;
fragslots [ slot ] . fragments = 0 ;
fragslots [ slot ] . active = 0 ;
fragslots [ slot ] . length = 0 ;
fragslots [ slot ] . fragtimer = 0 ;
}
void hexdump ( unsigned char * c , int i )
{
printf ( " \n HEXDUMP_%i: [ " , i ) ;
while ( i ) {
printf ( " %2.2x " , ( unsigned char ) * c ) ;
c + + ;
i - - ;
fflush ( stdout ) ;
}
printf ( " ] \n " ) ;
}
static void rx_resrc ( struct tetra_tmvsap_prim * tmvp , struct tetra_mac_state * tms , int slot )
2011-01-19 09:39:59 +00:00
{
2011-04-24 14:55:42 +00:00
struct msgb * msg = tmvp - > oph . msg ;
2011-01-19 09:39:59 +00:00
struct tetra_resrc_decoded rsd ;
int tmpdu_offset ;
2016-10-19 06:51:01 +00:00
struct msgb * fragmsgb ;
int tmplen ;
2014-11-26 18:20:41 +00:00
char tmpstr [ 1380 ] ;
2011-01-19 09:39:59 +00:00
memset ( & rsd , 0 , sizeof ( rsd ) ) ;
2011-04-24 14:55:42 +00:00
tmpdu_offset = macpdu_decode_resource ( & rsd , msg - > l1h ) ;
msg - > l2h = msg - > l1h + tmpdu_offset ;
2011-01-19 09:39:59 +00:00
2011-04-24 06:07:27 +00:00
printf ( " RESOURCE Encr=%u, Length=%d Addr=%s " ,
2014-11-26 18:20:41 +00:00
rsd . encryption_mode , rsd . macpdu_length ,
tetra_addr_dump ( & rsd . addr ) ) ;
2011-01-19 09:39:59 +00:00
2011-04-24 09:45:20 +00:00
if ( rsd . addr . type = = ADDR_TYPE_NULL )
goto out ;
2011-01-19 09:39:59 +00:00
if ( rsd . chan_alloc_pres )
2015-06-09 14:03:50 +00:00
printf ( " ChanAlloc=%s " , tetra_alloc_dump ( & rsd . cad , tms , ( rsd . encryption_mode = = 0 ) ) ) ;
2011-04-24 05:52:06 +00:00
if ( rsd . slot_granting . pres )
2011-04-24 07:54:02 +00:00
printf ( " SlotGrant=%u/%u " , rsd . slot_granting . nr_slots ,
2014-11-26 18:20:41 +00:00
rsd . slot_granting . delay ) ;
2011-04-24 05:52:06 +00:00
2016-10-25 05:54:32 +00:00
if ( ( tetra_hack_allow_encrypted ) | | ( rsd . encryption_mode = = 0 ) ) {
2011-04-24 06:07:27 +00:00
int len_bits = rsd . macpdu_length * 8 ;
2011-04-24 14:55:42 +00:00
if ( msg - > l2h + len_bits > msg - > l1h + msgb_l1len ( msg ) )
len_bits = msgb_l1len ( msg ) - tmpdu_offset ;
2016-10-19 06:51:01 +00:00
if ( rsd . macpdu_length > 0 ) {
rx_tm_sdu ( tms , msg , len_bits ) ;
}
else
{
if ( ( tetra_hack_reassemble_fragments ) & & ( rsd . macpdu_length = = MACPDU_LEN_START_FRAG ) ) {
int len = msgb_l1len ( msg ) - tmpdu_offset ;
if ( fragslots [ slot ] . active ) printf ( " \n WARNING: leftover fragment slot \n " ) ;
fragmsgb = fragslots [ slot ] . msgb ;
/* printf ("\nFRAGMENT START slot=%i msgb=%p\n",slot,fragmsgb); */
msgb_reset ( fragmsgb ) ;
fragslots [ slot ] . active = 1 ;
fragslots [ slot ] . fragments = 0 ;
/* copy the original msgb */
tmplen = msg - > tail - msg - > data ;
memcpy ( msgb_put ( fragmsgb , tmplen ) , msg - > data , tmplen ) ;
if ( msg - > l1h ) {
fragmsgb - > l1h = ( ( void * ) msg - > l1h - ( void * ) msg ) + ( void * ) fragmsgb ;
} else {
fragmsgb - > l1h = 0 ;
}
if ( msg - > l2h ) {
fragmsgb - > l2h = ( ( void * ) msg - > l2h - ( void * ) msg ) + ( void * ) fragmsgb ;
} else {
fragmsgb - > l2h = 0 ;
}
struct tetra_llc_pdu lpp ;
memset ( & lpp , 0 , sizeof ( lpp ) ) ;
tetra_llc_pdu_parse ( & lpp , ( uint8_t * ) fragmsgb - > l2h , msgb_l2len ( fragmsgb ) ) ;
if ( lpp . tl_sdu & & lpp . ss = = 0 ) {
fragmsgb - > l3h = lpp . tl_sdu ;
} else {
fragmsgb - > l3h = 0 ;
}
fragslots [ slot ] . length = lpp . tl_sdu_len ; /* not sure if this is the correct way to get the accurate length */
fragslots [ slot ] . encryption = rsd . encryption_mode ;
fragslots [ slot ] . active = 1 ;
fragslots [ slot ] . fragments = 1 ;
return ;
}
}
2011-01-19 09:39:59 +00:00
}
2011-04-24 09:45:20 +00:00
out :
2014-11-26 18:20:41 +00:00
/* sq5bpf */
//if (rsd.encryption_mode==0)
{
uint8_t * bits = msg - > l3h ;
uint8_t mle_pdisc = 0 ;
uint8_t req_type = 0 ;
uint16_t callident = 0 ;
if ( bits ) {
mle_pdisc = bits_to_uint ( bits , 3 ) ;
req_type = bits_to_uint ( bits + 3 , 5 ) ;
callident = bits_to_uint ( bits + 8 , 14 ) ;
}
printf ( " sq5bpf req mle_pdisc=%i req=%i " , mle_pdisc , req_type ) ;
if ( mle_pdisc = = TMLE_PDISC_CMCE ) {
sprintf ( tmpstr , " TETMON_begin FUNC:%s SSI:%8.8i IDX:%3.3i IDT:%i ENCR:%i RX:%i TETMON_end " , tetra_get_cmce_pdut_name ( req_type , 0 ) , rsd . addr . ssi , rsd . addr . usage_marker , rsd . addr . type , rsd . encryption_mode , tetra_hack_rxid ) ;
sendto ( tetra_hack_live_socket , ( char * ) & tmpstr , 128 , 0 , ( struct sockaddr * ) & tetra_hack_live_sockaddr , tetra_hack_socklen ) ;
//printf("\nSQ5BPF KOMUNIKAT: [%s]\n",tmpstr);
}
}
2011-01-19 09:39:59 +00:00
printf ( " \n " ) ;
}
2011-05-27 06:44:12 +00:00
static void rx_suppl ( struct tetra_tmvsap_prim * tmvp , struct tetra_mac_state * tms )
2011-04-24 07:15:28 +00:00
{
2011-04-24 14:55:42 +00:00
//struct tmv_unitdata_param *tup = &tmvp->u.unitdata;
struct msgb * msg = tmvp - > oph . msg ;
2011-04-24 07:15:28 +00:00
//struct tetra_suppl_decoded sud;
int tmpdu_offset ;
#if 0
memset ( & sud , 0 , sizeof ( sud ) ) ;
2011-04-24 14:55:42 +00:00
tmpdu_offset = macpdu_decode_suppl ( & sud , msg - > l1h , tup - > lchan ) ;
2011-04-24 07:15:28 +00:00
# else
{
2011-04-24 14:55:42 +00:00
uint8_t slot_granting = * ( msg - > l1h + 17 ) ;
2011-04-24 07:15:28 +00:00
if ( slot_granting )
tmpdu_offset = 17 + 1 + 8 ;
else
tmpdu_offset = 17 + 1 ;
}
# endif
printf ( " SUPPLEMENTARY MAC-D-BLOCK " ) ;
//if (sud.encryption_mode == 0)
2014-11-26 18:20:41 +00:00
msg - > l2h = msg - > l1h + tmpdu_offset ;
rx_tm_sdu ( tms , msg , 100 ) ;
2011-04-24 07:15:28 +00:00
printf ( " \n " ) ;
}
2011-01-19 09:39:59 +00:00
static void dump_access ( struct tetra_access_field * acc , unsigned int num )
{
printf ( " ACCESS%u: %c/%u " , num , ' A ' + acc - > access_code , acc - > base_frame_len ) ;
}
2011-05-27 06:44:12 +00:00
static void rx_aach ( struct tetra_tmvsap_prim * tmvp , struct tetra_mac_state * tms )
2011-01-19 09:39:59 +00:00
{
struct tmv_unitdata_param * tup = & tmvp - > u . unitdata ;
struct tetra_acc_ass_decoded aad ;
printf ( " ACCESS-ASSIGN PDU: " ) ;
memset ( & aad , 0 , sizeof ( aad ) ) ;
2011-04-24 14:55:42 +00:00
macpdu_decode_access_assign ( & aad , tmvp - > oph . msg - > l1h ,
2014-11-26 18:20:41 +00:00
tup - > tdma_time . fn = = 18 ? 1 : 0 ) ;
2011-01-19 09:39:59 +00:00
if ( aad . pres & TETRA_ACC_ASS_PRES_ACCESS1 )
dump_access ( & aad . access [ 0 ] , 1 ) ;
if ( aad . pres & TETRA_ACC_ASS_PRES_ACCESS2 )
dump_access ( & aad . access [ 1 ] , 2 ) ;
if ( aad . pres & TETRA_ACC_ASS_PRES_DL_USAGE )
printf ( " DL_USAGE: %s " , tetra_get_dl_usage_name ( aad . dl_usage ) ) ;
if ( aad . pres & TETRA_ACC_ASS_PRES_UL_USAGE )
printf ( " UL_USAGE: %s " , tetra_get_ul_usage_name ( aad . ul_usage ) ) ;
2011-05-28 18:10:56 +00:00
/* save the state whether the current burst is traffic or not */
if ( aad . dl_usage > 3 )
2014-11-26 18:20:41 +00:00
//sq5bpf tms->cur_burst.is_traffic = 1;
tms - > cur_burst . is_traffic = aad . dl_usage ;
2011-05-28 18:10:56 +00:00
else
tms - > cur_burst . is_traffic = 0 ;
2011-01-19 09:39:59 +00:00
printf ( " \n " ) ;
}
2011-05-27 06:44:12 +00:00
static int rx_tmv_unitdata_ind ( struct tetra_tmvsap_prim * tmvp , struct tetra_mac_state * tms )
2011-01-19 09:39:59 +00:00
{
struct tmv_unitdata_param * tup = & tmvp - > u . unitdata ;
2011-04-24 14:55:42 +00:00
struct msgb * msg = tmvp - > oph . msg ;
uint8_t pdu_type = bits_to_uint ( msg - > l1h , 2 ) ;
2011-01-19 09:39:59 +00:00
const char * pdu_name ;
struct msgb * gsmtap_msg ;
2016-10-19 06:51:01 +00:00
uint8_t pdu_frag_subtype ;
2011-01-19 09:39:59 +00:00
if ( tup - > lchan = = TETRA_LC_BSCH )
pdu_name = " SYNC " ;
else if ( tup - > lchan = = TETRA_LC_AACH )
pdu_name = " ACCESS-ASSIGN " ;
else {
2011-04-24 14:55:42 +00:00
pdu_type = bits_to_uint ( msg - > l1h , 2 ) ;
2011-01-19 09:39:59 +00:00
pdu_name = tetra_get_macpdu_name ( pdu_type ) ;
}
printf ( " TMV-UNITDATA.ind %s %s CRC=%u %s \n " ,
2014-11-26 18:20:41 +00:00
tetra_tdma_time_dump ( & tup - > tdma_time ) ,
tetra_get_lchan_name ( tup - > lchan ) ,
tup - > crc_ok , pdu_name ) ;
2011-01-19 09:39:59 +00:00
if ( ! tup - > crc_ok )
return 0 ;
2011-04-24 14:55:42 +00:00
gsmtap_msg = tetra_gsmtap_makemsg ( & tup - > tdma_time , tup - > lchan ,
2014-11-26 18:20:41 +00:00
tup - > tdma_time . tn ,
/* FIXME: */ 0 , 0 , 0 ,
msg - > l1h , msgb_l1len ( msg ) ) ;
2011-01-19 09:39:59 +00:00
if ( gsmtap_msg )
tetra_gsmtap_sendmsg ( gsmtap_msg ) ;
2016-10-19 06:51:01 +00:00
int slot = tup - > tdma_time . tn ;
/* age out old fragments */
if ( ( tetra_hack_reassemble_fragments ) & & ( tup - > tdma_time . fn = = 18 ) ) {
int i ;
for ( i = 0 ; i < FRAGSLOT_NR_SLOTS ; i + + ) {
if ( fragslots [ i ] . active ) {
fragslots [ i ] . fragtimer + + ;
if ( fragslots [ i ] . fragtimer > N203 ) {
printf ( " \n FRAG: aged out old fragments for slot=%i fragments=%i length=%i timer=%i \n " , i , fragslots [ i ] . fragments , fragslots [ i ] . length , fragslots [ i ] . fragtimer ) ;
msgb_reset ( fragslots [ i ] . msgb ) ;
fragslots [ i ] . fragments = 0 ;
fragslots [ i ] . active = 0 ;
fragslots [ i ] . length = 0 ;
fragslots [ i ] . fragtimer = 0 ;
}
}
}
}
2011-01-19 09:39:59 +00:00
switch ( tup - > lchan ) {
2014-11-26 18:20:41 +00:00
case TETRA_LC_AACH :
rx_aach ( tmvp , tms ) ;
2011-04-24 07:15:28 +00:00
break ;
2014-11-26 18:20:41 +00:00
case TETRA_LC_BNCH :
case TETRA_LC_UNKNOWN :
case TETRA_LC_SCH_F :
switch ( pdu_type ) {
case TETRA_PDU_T_BROADCAST :
rx_bcast ( tmvp , tms ) ;
break ;
case TETRA_PDU_T_MAC_RESOURCE :
2016-10-19 06:51:01 +00:00
rx_resrc ( tmvp , tms , slot ) ;
2014-11-26 18:20:41 +00:00
break ;
case TETRA_PDU_T_MAC_SUPPL :
rx_suppl ( tmvp , tms ) ;
break ;
case TETRA_PDU_T_MAC_FRAG_END :
2016-10-19 06:51:01 +00:00
pdu_frag_subtype = bits_to_uint ( msg - > l1h + 2 , 1 ) ;
2014-11-26 18:20:41 +00:00
if ( msg - > l1h [ 3 ] = = TETRA_MAC_FRAGE_FRAG ) {
printf ( " FRAG/END FRAG: " ) ;
msg - > l2h = msg - > l1h + 4 ;
2016-10-19 06:51:01 +00:00
if ( tetra_hack_reassemble_fragments ) {
rx_macfrag ( tmvp , tms , slot ) ;
} else {
rx_tm_sdu ( tms , msg , 100 /*FIXME*/ ) ;
}
2014-11-26 18:20:41 +00:00
printf ( " \n " ) ;
} else
printf ( " FRAG/END END \n " ) ;
2016-10-19 06:51:01 +00:00
if ( tetra_hack_reassemble_fragments ) rx_macend ( tmvp , tms , slot ) ;
2014-11-26 18:20:41 +00:00
break ;
default :
printf ( " STRANGE pdu=%u \n " , pdu_type ) ;
break ;
}
2011-04-24 07:15:28 +00:00
break ;
2014-11-26 18:20:41 +00:00
case TETRA_LC_BSCH :
2011-04-24 07:54:02 +00:00
break ;
default :
2014-11-26 18:20:41 +00:00
printf ( " STRANGE lchan=%u \n " , tup - > lchan ) ;
2011-04-24 07:15:28 +00:00
break ;
2011-01-19 09:39:59 +00:00
}
return 0 ;
}
int upper_mac_prim_recv ( struct osmo_prim_hdr * op , void * priv )
{
struct tetra_tmvsap_prim * tmvp ;
2011-05-27 06:44:12 +00:00
struct tetra_mac_state * tms = priv ;
2011-01-19 09:39:59 +00:00
int rc ;
switch ( op - > sap ) {
2014-11-26 18:20:41 +00:00
case TETRA_SAP_TMV :
tmvp = ( struct tetra_tmvsap_prim * ) op ;
rc = rx_tmv_unitdata_ind ( tmvp , tms ) ;
break ;
default :
printf ( " primitive on unknown sap \n " ) ;
break ;
2011-01-19 09:39:59 +00:00
}
2011-04-24 14:55:42 +00:00
talloc_free ( op - > msg ) ;
talloc_free ( op ) ;
2011-01-19 09:39:59 +00:00
return rc ;
}