WIP: BSSGP related hepler functions; towards tests

This commit is contained in:
Harald Welte 2017-07-22 17:07:51 +02:00
parent b2f94c4baa
commit 3a1944091e
6 changed files with 488 additions and 0 deletions

96
gprs_gb/BSSGP_Helper.cc Normal file
View File

@ -0,0 +1,96 @@
#include "Octetstring.hh"
#include "Error.hh"
#include "Logger.hh"
#include <stdint.h>
namespace BSSGP__Helper__Functions {
/* convert a buffer filled with TLVs that have variable-length "length" fields (Osmocom TvLV) into a
* buffer filled with TLVs that have fixed 16-bit length values (TL16V format) */
static OCTETSTRING transcode_tlv_part(OCTETSTRING const &in)
{
const unsigned char *in_ptr = (const unsigned char *)in;
int in_len = in.lengthof();
int ofs = 0;
uint16_t data_len;
OCTETSTRING out(0, (const unsigned char *)"");
while (ofs < in_len) {
int remain_len = in_len - ofs;
int tl_length;
if (remain_len < 2) {
TTCN_error("Remaining input length (%d) insufficient for Tag+Length", remain_len);
break;
}
/* copy over tag */
if (in_ptr[ofs+1] & 0x80) {
/* E bit is set, 7-bit length field */
data_len = in_ptr[ofs+1] & 0x7F;
tl_length = 2;
} else {
/* E bit is not set, 15 bit length field */
if (in_len < 3) {
TTCN_error("Remaining input length insufficient for 2-octet length");
break;
}
data_len = in_ptr[ofs+1] << 8 | in_ptr[ofs+2];
tl_length = 3;
}
if (in_len < tl_length + data_len) {
TTCN_error("Remaining input length insufficient for TLV value length");
break;
}
/* Tag + 16bit length */
uint8_t hdr_buf[3];
hdr_buf[0] = in_ptr[ofs+0];
hdr_buf[1] = data_len >> 8;
hdr_buf[2] = data_len & 0xff;
OCTETSTRING tlv_hdr(3, hdr_buf);
out += tlv_hdr;
if (data_len) {
/* append octet string of current TLV to output octetstring */
OCTETSTRING tlv_val(data_len, in_ptr + ofs + tl_length);
out += tlv_val;
}
/* advance input offset*/
ofs += data_len + tl_length;
}
return out;
}
#define BSSGP_PDUT_DL_UNITDATA 0x00
#define BSSGP_PDUT_UL_UNITDATA 0x01
/* expand all the variable-length "length" fields of a BSSGP message (Osmocom TvLV) into
* statlc TL16V format */
OCTETSTRING f__BSSGP__preprocess__pdu(OCTETSTRING const &in)
{
const unsigned char *in_ptr = (const unsigned char *)in;
int in_len = in.lengthof();
uint8_t pdu_type = in_ptr[0];
uint8_t static_hdr_len = 1;
if (pdu_type == BSSGP_PDUT_DL_UNITDATA || pdu_type == BSSGP_PDUT_UL_UNITDATA)
static_hdr_len = 8;
if (in_len < static_hdr_len)
TTCN_error("BSSGP message is shorter (%u bytes) than minimum header length (%u bytes) for msg_type 0x%02x",
in_len, static_hdr_len, pdu_type);
/* prefix = non-TLV section of header */
OCTETSTRING prefix(static_hdr_len, in_ptr);
OCTETSTRING tlv_part_in(in_len - static_hdr_len, in_ptr + static_hdr_len);
return prefix + transcode_tlv_part(tlv_part_in);
}
}

View File

@ -0,0 +1,3 @@
module BSSGP_Helper_Functions {
external function f_BSSGP_preprocess_pdu(in octetstring inp) return octetstring;
};

279
gprs_gb/BSSGP_Types.ttcn Normal file
View File

@ -0,0 +1,279 @@
module BSSGP_Types {
import from General_Types all;
import from Osmocom_Types all;
import from GSM_Types all;
type enumerated BssgpPduType {
DL_UNITDATA ('00'H),
UL_UNITDATA ('01'H),
RA_CAPABILITY ('02'H),
DL_MBMS_UNITDATA ('04'H),
UL_MBMS_UNITDATA ('05'H),
/* between GMM SAPs */
PAGING_PS ('06'H),
PAGING_CS ('07'H),
RA_CAPABILITY_UPDATE ('08'H),
RA_CAPABILITY_UPDATE_ACK ('09'H),
RADIO_STATUS ('0A'H),
SUSPEND ('0B'H),
SUSPEND_ACK ('0C'H),
SUSPEND_NACK ('0D'H),
RESUME ('0E'H),
RESUME_ACK ('0F'H),
RESUME_NACK ('10'H),
/* between NM SAPs */
BVC_BLOCK ('20'H),
BVC_BLOCK_ACK ('21'H),
BVC_RESET ('22'H),
BVC_RESET_ACK ('23'H),
BVC_UNBLOCK ('24'H),
BVC_UNBLOCK_ACK ('25'H),
FLOW_CONTROL_BVC ('26'H),
FLOW_CONTROL_BVC_ACK ('27'H),
FLOW_CONTROL_MS ('28'H),
FLOW_CONTROL_MS_ACK ('29'H),
FLUSH_LL ('2A'H),
FLUSH_LL_ACK ('2B'H),
LLC_DISCARDED ('2C'H),
FLOW_CONTROL_PFC ('2D'H),
FLOW_CONTROL_PFC_ACK ('2E'H),
SGSN_INVOKE_TRACE ('40'H),
STATUS ('41'H)
/* between PFM SAPs : TODO */
/* between LCS SAPs : TODO */
/* between RIM SAPs : TODO */
/* between MBMS SAPs : TODO */
} with { variant "FIELDLENGTH(8)" };
type enumerated BssgpIEI {
ALIGNMENT_OCTETS ('00'H),
BMAX_DEFAULT_MS ('01'H),
BSS_AREA_INDICATION ('02'H),
BUCKET_LEAK_RATE ('03'H),
BVCI ('04'H),
BVC_BUCKET_SIZE ('05'H),
BVC_MEASUREMENT ('06'H),
CAUSE ('07'H),
CELL_ID ('08'H),
CHENNEL_NEEDED ('09'H),
DRX_PARAMETERS ('0A'H),
EMLPP_PRIORITY ('0B'H),
FLUSH_ACTION ('0C'H),
IMSI ('0D'H),
LLC_PDU ('0E'H),
LLC_FRAMES_DISCARDED ('0F'H),
LOCATION_AREA ('10'H),
MOBILE_IDENTITY ('11'H),
MS_BUCKET_SIZE ('12'H),
MS_RADIO_ACCESS_CAPABILITY ('13'H),
OMC_ID ('14'H),
PDU_IN_ERROR ('15'H),
PDU_LIFETIME ('16'H),
PRIORITY ('17'H),
QOS_PROFILE ('18'H),
RADIO_CAUSE ('19'H),
RA_CAP_UPD_CAUSE ('1A'H),
ROUTEING_AREA ('1B'H),
R_DEFAULT_MS ('1C'H),
SUSPE_DN_REFERENCE_NR ('1D'H),
TAG ('1E'H),
TLLI ('1F'H),
TMSI ('20'H),
TRACE_REFERENCE ('21'H),
TRACE_TYPE ('22'H),
TRANSACTION_ID ('23'H),
TRIGGER_ID ('24'H),
NUMBER_OF_OCTETS_AFFECTED ('25'H),
LSA_IDENTIFIER_LIST ('26'H),
LSA_INFORMATION ('27'H),
PACKET_FLOW_IDENTIFIER ('28'H),
PACKET_FLOW_TIMER ('29'H),
AGGREGATE_BSS_QOS_PROFILE ('3a'H),
FEATURE_BITMAP ('3b'H),
BUCKET_FILL_RATIO ('3c'H),
SERVICE_UTRAN_CCO ('3d'H),
NSEI ('3e'H),
RRLP_APDU ('3f'H),
LCS_QOS ('40'H),
LCS_CLIENT_TYPE ('41'H),
REQUESTED_GPS_ASSIST_DATA ('42'H),
LOCATION_TYPE ('43'H),
LOCATION_ESTIMATE ('44'H),
POSITIONING_DATA ('45'H),
DECIPHERING_KEYS ('46'H),
LCS_PRIORITY ('47'H),
LCS_CAUSE ('48'H),
LCS_CAPABILITY ('49'H),
RRLP_FLAGS ('4a'H),
RIM_APPLICATION_IDENTITY ('4b'H),
RIM_SEQUENCE_NUMBER ('4c'H),
RAN_INFO_REUEST_AC ('4d'H),
RAN_INFO_AC ('4e'H),
RIM_PDU_INDICATIONS ('4f'H),
PFC_FLOC_CONTROL_PARAMETERS ('52'H),
GLOBAL_CN_ID ('53'H),
RIM_ROUTING_INFORMATION ('54'H),
RIM_PROTOCOL_VERSION_NUMBER ('55'H),
APP_ERROR_CONTAINER ('56'H),
/* FIXME */
EXTENDED_FEATURE_BITMAP ('69'H)
} with { variant "FIELDLENGTH(8)" };
/* 11.3.28 */
type record BssgpQosProfile {
uint16_t r,
BIT2 spare,
boolean c_r,
boolean t,
boolean a,
uint3_t precedence
} with { variant (c_r) "FIELDLENGTH(1)"
variant (t) "FIELDLENGTH(1)"
variant (a) "FIELDLENGTH(1)"
};
/* 11.3.84 */
type record BssgpFeatureBitmap {
boolean mbms,
boolean enh_radio_status,
boolean pfc_fc,
boolean rim,
boolean lcs,
boolean inr,
boolean cbl,
boolean pfc
} with { variant "" };
/* 11.3.47 */
type record BssgpServiceUtranCco {
uint5_t spare,
uint3_t value_part
} with { variant "" };
/* 11.3.84 */
type record BssgpExtendedFeatureBitmap {
BIT7 spare,
BIT1 ps_handover
} with { variant "" };
type uint16_t BssgpPduLifetime;
/* TS 48.008 3.2.2.18 */
type record BssmapPriority {
BIT1 spare,
boolean pci,
uint4_t level,
boolean qa,
boolean pvi
} with { variant "" };
type BssmapPriority BssgpPriority;
type uint32_t BssgpTlli;
type uint16_t BssgpBvci;
type uint8_t BssgpCause;
type record BssgpCellId {
RoutingAreaIdentification ra_id,
CellIdentity cell_id
} with { variant "" };
type union BssgpIeUnion {
uint16_t bmax_default_ms, /* 11.3.2 */
uint16_t bucket_leak_rate, /* 11.3.4 */
uint16_t bvc_bucket_size, /* 11.3.5 */
BssgpBvci bvci, /* 11.3.6 */
uint16_t bvc_measurement, /* 11.3.7 */
BssgpCause cause, /* 11.3.8 */
BssgpCellId cell_id, /* 11.3.9 */
DrxParameter drx_parameter, /* 11.3.11 */
LocationAreaIdentification lai, /* 11.3.17 */
MobileIdentity mobile_id, /* 11.3.20 */
BssgpPduLifetime pdu_lifetime, /* 11.3.25 */
BssgpPriority priority, /* 11.3.27 */
BssgpQosProfile qos_profile, /* 11.3.28 */
BssgpTlli tlli, /* 11.3.25 */
uint16_t r_default_ms, /* 11.3.32 */
BssgpServiceUtranCco svc_utran_cco, /* 11.3.47 */
BssgpFeatureBitmap feature_bitmap, /* 11.3.40 */
BssgpExtendedFeatureBitmap ext_feature_bitmap, /* 11.3.84 */
octetstring other
};
type record BssgpTLV {
BssgpIEI iei,
/* we cannot express a variable-length "length" field with extension octets in the TTCN-3
* syntax, so we simply assume a plain 16 bit length value here and have a 'pseudl-BSSGP'
* translator in front which explands all variable-length "length" fields to 16bits */
uint16_t len,
BssgpIeUnion u
} with {
variant (u) "CROSSTAG(
bmax_default_ms, iei = BMAX_DEFAULT_MS;
bucket_leak_rate, iei = BUCKET_LEAK_RATE;
bvc_bucket_size, iei = BVC_BUCKET_SIZE;
bvci, iei = BVCI;
bvc_measurement, iei = BVC_MEASUREMENT;
cause, iei = CAUSE;
cell_id, iei = CELL_ID;
drx_parameter, iei = DRX_PARAMETERS;
lai, iei = LOCATION_AREA;
priority, iei = PRIORITY;
mobile_id, iei = MOBILE_IDENTITY;
pdu_lifetime, iei = PDU_LIFETIME;
qos_profile, iei = QOS_PROFILE;
tlli, iei = TLLI;
r_default_ms, iei = R_DEFAULT_MS;
svc_utran_cco, iei = SERVICE_UTRAN_CCO;
feature_bitmap, iei = FEATURE_BITMAP;
ext_feature_bitmap, iei = EXTENDED_FEATURE_BITMAP;
other, OTHERWISE)"
variant (len) "LENGTHTO(u)"
};
type record of BssgpTLV BssgpTLVs;
/* 10.2.1 */
type record BssgpDlUnitdata {
BssgpTlli tlli,
BssgpQosProfile qos_profile,
BssgpTLV pdu_lifetime,
/* optional parts */
BssgpTLVs tlvs
} with { variant "" };
/* 10.2.2 */
type record BssgpUlUnitdata {
BssgpTlli tlli,
BssgpQosProfile qos_profile,
BssgpTLV cell_id,
/* optional parts */
BssgpTLVs tlvs
} with { variant "" };
type record BssgpNormalPdu {
BssgpTLVs tlvs optional
} with { variant "" };
type union BssgpPduUnion {
BssgpDlUnitdata dl_unitdata,
BssgpUlUnitdata ul_unitdata,
BssgpNormalPdu other
};
type record BssgpPdu {
BssgpPduType pdu_type,
BssgpPduUnion u
} with {
variant (u) "CROSSTAG(
dl_unitdata, pdu_type = DL_UNITDATA;
ul_unitdata, pdu_type = UL_UNITDATA;
other, OTHERWISE)"
}
external function dec_BssgpPdu(in octetstring stream) return BssgpPdu
with { extension "prototype(convert) decode(RAW)" };
} with { encode "RAW" };

79
gprs_gb/Test.ttcn Normal file
View File

@ -0,0 +1,79 @@
module Test {
import from BSSGP_Helper_Functions all;
import from BSSGP_Types all;
type component dummy_CT {
}
function f_assert_prepr(in octetstring a, in octetstring b) {
log ("Input: ", a);
log ("Expected: ", b);
var octetstring a_preprocessed := f_BSSGP_preprocess_pdu(a);
log ("Preprocessed: ", a_preprocessed);
if (a_preprocessed != b) {
setverdict(fail);
} else {
setverdict(pass);
}
}
function f_dec_and_log(in octetstring inp) {
log("Input: ", inp);
var octetstring inp_p := f_BSSGP_preprocess_pdu(inp);
log ("Preprocessed: ", inp_p);
var BssgpPdu dec := dec_BssgpPdu(inp_p);
log("Decoded: ", dec);
}
testcase TC_selftest() runs on dummy_CT {
const octetstring c_bvc_reset_pcu := '2204820000078108088832f44000c80051e0'O;
const octetstring c_bvc_reset_q := '2204820000078100'O;
const octetstring c_status_pcu := '4107810515882204820000078103'O;
const octetstring c_reset_ack_q := '2304820000'O;
const octetstring c_reset_ack_pcu := '23048200c4'O;
const octetstring c_unblock_pcu := '24048200c4'O;
const octetstring c_unblock_ack_q := '25048200c4'O;
const octetstring c_fc_bvc_pcu := '261e8101058200fa038200c8018200fa1c8200c806820000'O;
const octetstring c_fc_bvc_ack_q := '271e8101'O;
const octetstring c_gmm_mo_att_req := '01bb146ddd000004088832f44000c80051e000800e003b01c001080103e5e000110a0005f4fb146ddd32f44000c8001d1b53432b37159ef9090070000dd9c6321200e00019b32c642401c0002017057bf0ec'O;
const octetstring c_gmm_mt_ac_req := '00bb146ddd0050001682ffff0a8204030e9c41c001081200102198c72477ea104895e8b959acc58b108182f4d045'O;
const octetstring c_gmm_mo_ac_resp := '01bb146ddd000004088832f44000c80051e000800e000e01c00508130122fa361f5fdd623d'O;
const octetstring c_gmm_mt_att_acc := '00bb146ddd0050001682ffff0a8204030e9841c005080201340432f44000c8001805f4fb146ddd0967d0'O;
const octetstring c_gmm_mt_det_req := '00bb146ddd0050001682ffff0a8204030e8941c00908050215f0b6'O;
const octetstring c_gmm_mo_att_cpl := '01fb146ddd000004088832f44000c80051e000800e000801c009080339d7bc'O;
/* single byte length to two byte length */
f_assert_prepr('04058101'O, '0405000101'O);
f_assert_prepr('040589000102030405060708'O, '04050009000102030405060708'O);
/* two byte length to two byte length */
f_assert_prepr('0405000101'O, '0405000101'O);
/* special case: DL-UD + UL-UD */
f_assert_prepr('00aabbccddeeffaa29822342'O, '00aabbccddeeffaa2900022342'O);
f_assert_prepr('01aabbccddeeffaa29822342'O, '01aabbccddeeffaa2900022342'O);
/* multiple TLVs */
f_assert_prepr('234281aa4382bbbb'O, '23420001aa430002bbbb'O);
f_assert_prepr('230080'O, '23000000'O);
f_dec_and_log(c_bvc_reset_pcu);
f_dec_and_log(c_bvc_reset_q);
f_dec_and_log(c_status_pcu);
f_dec_and_log(c_reset_ack_q);
f_dec_and_log(c_reset_ack_pcu);
f_dec_and_log(c_unblock_pcu);
f_dec_and_log(c_unblock_ack_q);
f_dec_and_log(c_fc_bvc_pcu);
f_dec_and_log(c_fc_bvc_ack_q);
f_dec_and_log(c_gmm_mo_att_req);
f_dec_and_log(c_gmm_mt_ac_req);
f_dec_and_log(c_gmm_mo_ac_resp);
f_dec_and_log(c_gmm_mt_att_acc);
f_dec_and_log(c_gmm_mt_det_req);
f_dec_and_log(c_gmm_mo_att_cpl);
}
control {
execute(TC_selftest());
}
};

22
gprs_gb/gen_links.sh Executable file
View File

@ -0,0 +1,22 @@
#!/bin/sh
BASEDIR=~/projects/git
gen_links() {
DIR=$1
FILES=$*
for f in $FILES; do
echo "Linking $f"
ln -sf $DIR/$f $f
done
}
#DIR=$BASEDIR/titan.TestPorts.UNIX_DOMAIN_SOCKETasp/src
#FILES="UD_PT.cc UD_PT.hh UD_PortType.ttcn UD_Types.ttcn"
#gen_links $DIR $FILES
DIR=../library
FILES="General_Types.ttcn GSM_Types.ttcn Osmocom_Types.ttcn"
gen_links $DIR $FILES

9
gprs_gb/regen_makefile.sh Executable file
View File

@ -0,0 +1,9 @@
#!/bin/sh
FILES="*.ttcn BSSGP_Helper.cc"
ttcn3_makefilegen -f Test.ttcn $FILES
sed -i -e 's/# TTCN3_DIR = /TTCN3_DIR = \/usr/' Makefile
sed -i -e 's/LDFLAGS = /LDFLAGS = -L \/usr\/lib\/titan `pkg-config --libs libnetfilter_conntrack`/' Makefile
sed -i -e 's/TTCN3_LIB = ttcn3-parallel/TTCN3_LIB = ttcn3/' Makefile
sed -i -e 's/CPPFLAGS = -D$(PLATFORM) -I$(TTCN3_DIR)\/include/CPPFLAGS = -D$(PLATFORM) -I$(TTCN3_DIR)\/include -I\/usr\/include\/titan/' Makefile