Hello Jenkins Builder,

I'd like you to reexamine a change.  Please visit

    https://gerrit.osmocom.org/6536

to look at the new patch set (#4).

First actual SGSN test case

Change-Id: Id66ddf8dbe1c5cfa96a087235588ba67763b7f05
---
D gprs_gb/LLC_Types.ttcn
M gprs_gb/Test.ttcn
M gprs_gb/gen_links.sh
M gprs_gb/regen_makefile.sh
M library/BSSGP_Emulation.ttcn
A library/LLC_Templates.ttcn
M sgsn/SGSN_Tests.ttcn
M sgsn/gen_links.sh
M sgsn/regen_makefile.sh
9 files changed, 857 insertions(+), 301 deletions(-)


  git pull ssh://gerrit.osmocom.org:29418/osmo-ttcn3-hacks 
refs/changes/36/6536/4

diff --git a/gprs_gb/LLC_Types.ttcn b/gprs_gb/LLC_Types.ttcn
deleted file mode 100644
index 8ca8f39..0000000
--- a/gprs_gb/LLC_Types.ttcn
+++ /dev/null
@@ -1,165 +0,0 @@
-module LLC_Types {
-       import from General_Types all;
-       import from Osmocom_Types all;
-
-       /* TS 44.064 Chapter 6.2 */
-       type record LlcAddressField {
-               BIT1 pd ('0'B),
-               boolean c_r,
-               BIT2 reserved,
-               LlcSapi sapi
-       } with {
-               variant (c_r) "FIELDLENGTH(1)"
-       };
-
-       template LlcAddressField t_LLC_Addr(template boolean c_r, template 
LlcSapi sapi) := {
-               pd := '0'B,
-               c_r := c_r,
-               reserved := '00'B,
-               sapi := sapi
-       };
-
-       const boolean LLC_CR_DL_CMD := true;
-       const boolean LLC_CR_DL_RSP := false;
-       const boolean LLC_CR_UL_CMD := false;
-       const boolean LLC_CR_UL_RSP := true;
-
-       template LlcAddressField t_LLC_Addr_DlCmd(template LlcSapi sapi) := 
t_LLC_Addr(true, sapi);
-       template LlcAddressField t_LLC_Addr_DlRsp(template LlcSapi sapi) := 
t_LLC_Addr(false, sapi);
-       template LlcAddressField t_LLC_Addr_UlCmd(template LlcSapi sapi) := 
t_LLC_Addr(false, sapi);
-       template LlcAddressField t_LLC_Addr_UlRsp(template LlcSapi sapi) := 
t_LLC_Addr(true, sapi);
-
-       type enumerated LlcSapi {
-               LLC_SAPI_RESERVED_0     ('0000'B),
-               LLC_SAPI_GMM            ('0001'B),
-               LLC_SAPI_TOM2           ('0010'B),
-               LLC_SAPI_LL3            ('0011'B),
-               LLC_SAPI_RESERVED_4     ('0100'B),
-               LLC_SAPI_LL5            ('0101'B),
-               LLC_SAPI_RESERVED_6     ('0110'B),
-               LLC_SAPI_SMS            ('0111'B),
-               LLC_SAPI_TOM8           ('1000'B),
-               LLC_SAPI_LL9            ('1001'B),
-               LLC_SAPI_RESERVED_10    ('1010'B),
-               LLC_SAPI_LL11           ('1011'B),
-               LLC_SAPI_RESERVED_12    ('1100'B),
-               LLC_SAPI_RESERVED_13    ('1101'B),
-               LLC_SAPI_RESERVED_14    ('1110'B),
-               LLC_SAPI_RESERVED_15    ('1111'B)
-       } with { variant "FIELDLENGTH(4)" };
-
-       /* TS 44.064 Chapter 6.3 */
-       type record LlcCtrlFieldI {
-               BIT1 presence ('0'B),
-               boolean a,
-               BIT1 spare,
-               uint9_t n_s,
-               BIT1 spare2,
-               uint9_t n_r,
-               LlcCtrlS s
-       } with { variant
-               (a) "FIELDLENGTH(1)"
-       };
-
-       /* TS 44.064 Chapter 6.3 */
-       type record LlcCtrlFieldS {
-               BIT2 presence ('10'B),
-               boolean a,
-               BIT2 spare,
-               uint9_t  n_r,
-               LlcCtrlS s
-       } with {
-               variant (a) "FIELDLENGTH(1)"
-       };
-
-       /* TS 44.064 Chapter 6.3 */
-       type record LlcCtrlFieldUI {
-               BIT3 presence ('110'B),
-               BIT2 spare,
-               uint9_t n_u,
-               boolean e,
-               boolean pm
-       } with {
-               variant (e) "FIELDLENGTH(1)"
-               variant (pm) "FIELDLENGTH(1)"
-       };
-
-       template LlcCtrlFieldUI t_LlcCtrlUI(template uint8_t n_u) := {
-               presence := '110'B,
-               spare := '00'B,
-               n_u := n_u,
-               e := false,
-               pm := true
-       };
-
-       /* TS 44.064 Chapter 6.3 */
-       type record LlcCtrlFieldU {
-               BIT3 presence ('111'B),
-               boolean p_f,
-               LlcCtrlM m
-       } with {
-               variant (p_f) "FIELDLENGTH(1)"
-       };
-
-
-       /* TS 44.064 Chapter 6.4 */
-       type enumerated LlcCtrlS {
-               LLC_S_RR        ('00'B),
-               LLC_S_ACK       ('01'B),
-               LLC_S_RNR       ('10'B),
-               LLC_S_SACK      ('11'B)
-       } with { variant "FIELDLENGTH(2)" };
-
-       /* TS 44.064 Chapter 6.4 */
-       type enumerated LlcCtrlM {
-               LLC_M_DM        ('0001'B),
-               LLC_M_DISC      ('0100'B),
-               LLC_M_UA        ('0110'B),
-               LLC_M_SABM      ('0111'B),
-               LLC_M_FRMR      ('1000'B),
-               LLC_M_XID       ('1011'B),
-               LLC_M_NULL      ('0000'B)
-       } with { variant "FIELDLENGTH(4)" };
-
-       type union LlcCtrlUnion {
-               LlcCtrlFieldI   i,
-               LlcCtrlFieldS   s,
-               LlcCtrlFieldUI  ui,
-               LlcCtrlFieldU   u
-       } with { variant "TAG(i, presence = '0'B;
-                             s, presence = '10'B;
-                             ui, presence = '110'B;
-                             u, presence = '111'B)"
-                variant "FIELDORDER(msb)"
-       };
-
-       external function enc_LlcCtrlUnion(in LlcCtrlUnion pdu) return 
octetstring
-               with { extension "prototype(convert) encode(RAW)" };
-       external function dec_LlcCtrlUnion(in octetstring stream) return 
LlcCtrlUnion
-               with { extension "prototype(convert) decode(RAW)" };
-
-
-       type uint24_t LlcFcs;
-
-       type record LlcPdu {
-               LlcAddressField addr,
-               LlcCtrlUnion    ctrl,
-               octetstring     payload//,
-               //LlcFcs                fcs
-       } with { variant "" };
-
-       external function enc_LlcPdu(in LlcPdu pdu) return octetstring
-               with { extension "prototype(convert) encode(RAW)" };
-       external function dec_LlcPdu(in octetstring stream) return LlcPdu
-               with { extension "prototype(convert) decode(RAW)" };
-
-
-       template LlcPdu t_LLC_UI(template boolean c_r, template uint8_t n_u, 
template octetstring payload,
-                                template LlcSapi sapi := LLC_SAPI_GMM) := {
-               addr := t_LLC_Addr(c_r, sapi),
-               ctrl := {
-                       ui := t_LlcCtrlUI(n_u)
-               },
-               payload := payload
-       };
-} with { encode "RAW"; variant "FIELDORDER(msb)" }
diff --git a/gprs_gb/Test.ttcn b/gprs_gb/Test.ttcn
index 19cfd26..732b3f5 100644
--- a/gprs_gb/Test.ttcn
+++ b/gprs_gb/Test.ttcn
@@ -10,9 +10,27 @@
        import from NS_Types all;
        import from NS_Emulation all;
        import from LLC_Types all;
+       import from LLC_Templates all;
        import from RLCMAC_Types all;
        import from RLCMAC_CSN1_Types all;
        import from LAPDm_RAW_PT all;
+
+       modulepar {
+               BssgpConfig mp_gb_cfg := {
+                       nsei := 96,
+                       bvci := 196,
+                       cell_id := {
+                               ra_id := {
+                                       lai := {
+                                               mcc_mnc := '26242F'H, lac := 
13135
+                                       },
+                                       rac := 0
+                               },
+                               cell_id := 20960
+                       },
+                       sgsn_role := true
+               };
+       }
 
        type record MmContext {
                octetstring     imsi optional,
@@ -51,7 +69,7 @@
                /* connect lower-end of NS emulation to NS_CODEC_PORT (on top 
of IPl4) */
                map(ns_component:NSCP, system:NS_CODEC_PORT);
                ns_component.start(NSStart());
-               bssgp_component.start(BssgpStart());
+               bssgp_component.start(BssgpStart(mp_gb_cfg));
 
                lapdm_component := lapdm_CT.create;
                connect(self:L1, lapdm_component:LAPDM_SP);
@@ -138,20 +156,19 @@
 
        const octetstring gmm_auth_req := 
'081200102198c72477ea104895e8b959acc58b108182'O;
 
-       function tx_gmm(boolean c_r, in octetstring gmm_pdu, LlcSapi sapi := 
LLC_SAPI_GMM) runs on dummy_CT {
-               var LlcPdu llc;
+       function tx_gmm(BIT1 c_r, in octetstring gmm_pdu, BIT4 sapi := 
c_LLC_SAPI_LLGMM) runs on dummy_CT {
+               var PDU_LLC llc;
 
                //log("GMM Tx: ", dec_PDU_L3_SGSN_MS(gmm_pdu));
 
                log(c_r, g_mmctx.n_u, gmm_pdu, sapi);
-               log(t_LLC_UI(c_r, g_mmctx.n_u, gmm_pdu, sapi));
-               llc := valueof(t_LLC_UI(c_r, g_mmctx.n_u, gmm_pdu, sapi));
+               llc := valueof(ts_LLC_UI(gmm_pdu, sapi, c_r, g_mmctx.n_u));
                log(llc);
                g_mmctx.n_u := g_mmctx.n_u + 1;
 
-               log(ts_BSSGP_DL_UD(g_mmctx.tlli, enc_LlcPdu(llc)));
+               log(ts_BSSGP_DL_UD(g_mmctx.tlli, enc_PDU_LLC(llc)));
 
-               BSSGP.send(ts_BSSGP_DL_UD(g_mmctx.tlli, enc_LlcPdu(llc)));
+               BSSGP.send(ts_BSSGP_DL_UD(g_mmctx.tlli, enc_PDU_LLC(llc)));
        }
 
        function f_bssgp_establish() runs on dummy_CT {
@@ -179,10 +196,10 @@
                BSSGP.send(ts_BSSGP_PS_PAGING_PTMSI(bvci, imsi, tmsi));
 
                while (true) {
-                       var PDU_BSSGP pdu;
+                       var BssgpDecoded bd;
                        alt {
-                               [] BSSGP.receive(PDU_BSSGP:?) -> value pdu {
-                                       log("BSSGP Rx: ", pdu);
+                               [] BSSGP.receive(tr_BD_L3_MT(?)) -> value bd {
+                                       log("BSSGP Rx: ", bd);
                                }
                                [] BSSGP.receive(t_BssgpStsInd(?, ?, 
BVC_S_UNBLOCKED)) { repeat; }
                                [] BSSGP.receive { repeat; }
@@ -322,7 +339,7 @@
                var template RlcmacUlBlock blk := t_RLCMAC_UL_DATA_TLLI(0, 0, 
0, {t_RLCMAC_LLCBLOCK(payload)}, false, tlli);
                L1.send(RLCMAC_ph_data_req:{tbf_id := 0, cs := cs, block := 
blk});
                /* ensure that this LLC-PDU arrives from the right TLLI at the 
(simulated) SGSN */
-               BSSGP.receive(tr_BSSGP_UL_UD(tlli, ?, payload));
+               BSSGP.receive(tr_BD_BSSGP(tr_BSSGP_UL_UD(tlli, ?, payload)));
 
                /* ensure the MS eceives an UL_ACK_NACK */
                alt {
@@ -346,12 +363,12 @@
                f_single_ul_block(CS1);
 
                while (true) {
-                       var PDU_BSSGP pdu;
+                       var BssgpDecoded bd;
                        var RLCMAC_ph_data_ind dl_msg;
                        alt {
 
-                               [] BSSGP.receive(PDU_BSSGP:?) -> value pdu {
-                                       log("BSSGP Rx: ", pdu);
+                               [] BSSGP.receive(tr_BD_BSSGP(?)) -> value bd {
+                                       log("BSSGP Rx: ", bd);
                                }
                                [] BSSGP.receive(t_BssgpStsInd(?, ?, 
BVC_S_UNBLOCKED)) { repeat; }
                                [] BSSGP.receive { repeat; }
@@ -369,12 +386,12 @@
                f_bssgp_establish();
 
                while (true) {
-                       var PDU_BSSGP pdu;
+                       var BssgpDecoded bd;
                        alt {
-                               [] BSSGP.receive(PDU_BSSGP:?) -> value pdu {
-                                       log("BSSGP Rx: ", pdu);
+                               [] BSSGP.receive(tr_BD_BSSGP(?)) -> value bd {
+                                       log("BSSGP Rx: ", bd);
                                        //log("GMM Rx: ", 
dec_PDU_L3_MS_SGSN(pdu.payload));
-                                       g_mmctx.tlli := 
oct2int(pdu.pDU_BSSGP_UL_UNITDATA.tLLI);
+                                       g_mmctx.tlli := 
oct2int(bd.bssgp.pDU_BSSGP_UL_UNITDATA.tLLI);
                                        tx_gmm(LLC_CR_DL_CMD, gmm_auth_req);
                                }
                                [] BSSGP.receive(t_BssgpStsInd(?, ?, 
BVC_S_UNBLOCKED)) { repeat; }
@@ -386,7 +403,7 @@
 
        function f_llc_dec_and_log(in octetstring inp) {
                log("LLC Input: ", inp);
-               var LlcPdu dec := dec_LlcPdu(inp);
+               var PDU_LLC dec := dec_PDU_LLC(inp);
                log("LLC Decoded: ", dec);
        }
 
@@ -405,17 +422,13 @@
        testcase TC_selftest_llc() runs on dummy_CT {
                const octetstring c_gmm_att_pcu := 
'01c001080103e5e000210a0005f4fb146ddd32f44000c8001d1b53432b37159ef9090070000dd9c6321200e00019b32c642401c00020170580460b'O;
                const octetstring c_gmm_att_pcu_nofcs := 
'01c001080103e5e000210a0005f4fb146ddd32f44000c8001d1b53432b37159ef9090070000dd9c6321200e00019b32c642401c000201705'O;
-               const octetstring c_ctrl_ui := 'c001'O;
-
-               log(dec_LlcCtrlUnion(c_ctrl_ui));
-               f_llc_assert(enc_LlcCtrlUnion({ ui := { presence := '110'B, 
spare := '00'B, n_u := 0, e := false, pm := true } }), c_ctrl_ui);
 
                f_llc_dec_and_log(c_gmm_att_pcu);
 
                //f_llc_assert(f_LLC_append_fcs(c_gmm_att_pcu_nofcs), 
c_gmm_att_pcu);
 
-               log(valueof(t_LLC_UI(LLC_CR_DL_CMD, g_mmctx.n_u, gmm_auth_req, 
LLC_SAPI_GMM)));
-               log(t_LLC_UI(LLC_CR_DL_CMD, g_mmctx.n_u, gmm_auth_req, 
LLC_SAPI_GMM));
+               log(valueof(ts_LLC_UI(gmm_auth_req, c_LLC_SAPI_LLGMM, 
LLC_CR_DL_CMD, g_mmctx.n_u)));
+               log(ts_LLC_UI(gmm_auth_req, c_LLC_SAPI_LLGMM, LLC_CR_DL_CMD, 
g_mmctx.n_u));
        }
 
        testcase TC_selftest_rlcmac() runs on dummy_CT {
diff --git a/gprs_gb/gen_links.sh b/gprs_gb/gen_links.sh
index 53b50fa..85a35ab 100755
--- a/gprs_gb/gen_links.sh
+++ b/gprs_gb/gen_links.sh
@@ -39,9 +39,17 @@
 FILES="BSSGP_EncDec.cc  BSSGP_Types.ttcn"
 gen_links $DIR $FILES
 
+DIR=$BASEDIR/titan.ProtocolModules.MobileL3_v13.4.0/src
+FILES="MobileL3_CC_Types.ttcn MobileL3_CommonIE_Types.ttcn 
MobileL3_GMM_SM_Types.ttcn MobileL3_MM_Types.ttcn MobileL3_RRM_Types.ttcn 
MobileL3_SMS_Types.ttcn MobileL3_SS_Types.ttcn MobileL3_Types.ttcn"
+gen_links $DIR $FILES
+
+DIR=$BASEDIR/titan.ProtocolModules.LLC_v7.1.0/src
+FILES="LLC_EncDec.cc LLC_Types.ttcn"
+gen_links $DIR $FILES
 
 DIR=../library
 FILES="General_Types.ttcn GSM_Types.ttcn GSM_RR_Types.ttcn Osmocom_Types.ttcn 
RLCMAC_Types.ttcn RLCMAC_CSN1_Types.ttcn RLCMAC_EncDec.cc L1CTL_Types.ttcn 
L1CTL_PortType.ttcn LAPDm_RAW_PT.ttcn LAPDm_Types.ttcn "
 FILES+="NS_Emulation.ttcn NS_CodecPort.ttcn NS_CodecPort_CtrlFunct.ttcn 
NS_CodecPort_CtrlFunctDef.cc "
 FILES+="BSSGP_Emulation.ttcn Osmocom_Gb_Types.ttcn "
+FILES+="LLC_Templates.ttcn L3_Templates.ttcn L3_Common.ttcn "
 gen_links $DIR $FILES
diff --git a/gprs_gb/regen_makefile.sh b/gprs_gb/regen_makefile.sh
index 656726b..8b79d73 100755
--- a/gprs_gb/regen_makefile.sh
+++ b/gprs_gb/regen_makefile.sh
@@ -1,5 +1,5 @@
 #!/bin/sh
 
-FILES="*.ttcn BSSGP_EncDec.cc IPL4asp_PT.cc IPL4asp_discovery.cc 
TCCConversion.cc TCCInterface.cc NS_CodecPort_CtrlFunctDef.cc UD_PT.cc 
RLCMAC_EncDec.cc"
+FILES="*.ttcn BSSGP_EncDec.cc IPL4asp_PT.cc IPL4asp_discovery.cc 
TCCConversion.cc TCCInterface.cc NS_CodecPort_CtrlFunctDef.cc UD_PT.cc 
RLCMAC_EncDec.cc LLC_EncDec.cc"
 
 ../regen-makefile.sh Test.ttcn $FILES
diff --git a/library/BSSGP_Emulation.ttcn b/library/BSSGP_Emulation.ttcn
index b41cd25..f981adb 100644
--- a/library/BSSGP_Emulation.ttcn
+++ b/library/BSSGP_Emulation.ttcn
@@ -1,10 +1,22 @@
 module BSSGP_Emulation {
 
+import from General_Types all;
+import from Osmocom_Types all;
 import from NS_Types all;
 import from NS_Emulation all;
 import from BSSGP_Types all;
 import from Osmocom_Gb_Types all;
 import from IPL4asp_Types all;
+
+import from MobileL3_GMM_SM_Types all;
+import from MobileL3_Types all;
+
+import from LLC_Types all;
+import from LLC_Templates all;
+
+/***********************************************************************
+ * Communication between Client Components and Main Component
+ ***********************************************************************/
 
 type record BssgpStatusIndication {
        Nsei            nsei,
@@ -25,11 +37,15 @@
 
 /* port from our (internal) point of view */
 type port BSSGP_SP_PT message {
-       in      PDU_BSSGP;
-       out     PDU_BSSGP,
+       in      PDU_BSSGP,
+               PDU_L3_MS_SGSN,
+               PDU_L3_SGSN_MS;
+       out     BssgpDecoded,
                NsStatusIndication,
                BssgpStatusIndication,
-               ASP_Event;
+               ASP_Event,
+               PDU_L3_MS_SGSN,
+               PDU_L3_SGSN_MS;
 } with { extension "internal" };
 
 /* port from the user point of view */
@@ -37,12 +53,37 @@
        in      ASP_Event,
                NsStatusIndication,
                BssgpStatusIndication,
-               PDU_BSSGP;
-       out     PDU_BSSGP;
+               BssgpDecoded,
+               PDU_L3_MS_SGSN,
+               PDU_L3_SGSN_MS;
+       out     PDU_BSSGP,
+               PDU_L3_SGSN_MS,
+               PDU_L3_MS_SGSN;
 } with { extension "internal" };
 
-function BssgpStart(boolean sgsn_role := false) runs on BSSGP_CT {
-       g_sgsn_role := sgsn_role
+signature BSSGP_register_client(hexstring imsi, OCT4 tlli, BssgpCellId 
cell_id);
+signature BSSGP_unregister_client(hexstring imsi);
+
+type port BSSGP_PROC_PT procedure {
+       inout BSSGP_register_client, BSSGP_unregister_client;
+} with { extension "internal" };
+
+
+/***********************************************************************
+ * Client Component for a single MS/TLLI
+ ***********************************************************************/
+
+type component BSSGP_Client_CT {
+       port BSSGP_PT BSSGP;
+       port BSSGP_PROC_PT BSSGP_PROC;
+};
+
+/***********************************************************************
+ * Main Component
+ ***********************************************************************/
+
+function BssgpStart(BssgpConfig cfg) runs on BSSGP_CT {
+       g_cfg := cfg;
        f_init();
        f_ScanEvents();
 }
@@ -57,23 +98,53 @@
        port NS_PT BSCP;
        /* NS-User SAP towards the user */
        port BSSGP_SP_PT BSSGP_SP;
+       port BSSGP_PROC_PT BSSGP_PROC;
 
-       var boolean g_sgsn_role := true;
+       var BssgpConfig g_cfg;
+
        var BvcState g_ptp_bvc_state := BVC_S_BLOCKED;
        timer g_T1 := 15.0;
        timer g_T2 := 60.0;
+
+       var ClientEntity ClientTable[16];
 }
 
-modulepar {
-       Nsvci mp_nsei := 96;
-       Nsvci mp_bvci := 196;
-       BssgpCellId mp_cellid := { ra_id := { lai := { mcc_mnc := '26242F'H, 
lac := 13135}, rac := 0 }, cell_id := 20960 };
+type record ClientEntity {
+       OCT4 tlli,
+       OCT4 tlli_old optional,
+       hexstring imsi,
+       BssgpCellId cell_id,
+       BSSGP_Client_CT comp_ref,
+       /* LLC entities, one for each SAPI */
+       LLC_Entity llc[16]
 };
 
-function f_BnsUdReq(template PDU_BSSGP pdu, BssgpBvci bvci := mp_bvci) return 
NsUnitdataRequest {
+type record LLC_Entity {
+       boolean sgsn_role,
+       /* N(U) on transmit side for next PDU */
+       uint9_t n_u_tx_next,
+       /* N(U) on receive side, last PDU */
+       uint9_t n_u_rx_last optional
+};
+
+private template LLC_Entity t_LLC_init(boolean sgsn_role := false) := {
+       sgsn_role := sgsn_role,
+       n_u_tx_next := 0,
+       n_u_rx_last := -
+}
+
+type record BssgpConfig {
+       Nsvci nsei,
+       Nsvci bvci,
+       BssgpCellId cell_id,
+       boolean sgsn_role
+};
+
+function f_BnsUdReq(template PDU_BSSGP pdu, BssgpBvci bvci)
+runs on BSSGP_CT return NsUnitdataRequest {
        var NsUnitdataRequest udr := {
                bvci := bvci,
-               nsei := mp_nsei,
+               nsei := g_cfg.nsei,
                /* for some weird reason we get "Dynamic test case error: Text 
encoder: Encoding an
                 * unbound integer value." when trying to send the reocrd 
rather than the octetstring */
                //sdu := omit,
@@ -84,10 +155,11 @@
        return udr;
 }
 
-function f_BnsUdInd(template PDU_BSSGP pdu, template BssgpBvci bvci := 
mp_bvci) return template NsUnitdataIndication {
+function f_BnsUdInd(template PDU_BSSGP pdu, template BssgpBvci bvci)
+runs on BSSGP_CT return template NsUnitdataIndication {
        var template NsUnitdataIndication udi := {
                bvci := bvci,
-               nsei := mp_nsei,
+               nsei := g_cfg.nsei,
                sdu := *,
                bssgp := pdu
        }
@@ -97,11 +169,15 @@
 private function f_change_state(BvcState new_state) runs on BSSGP_CT {
        log("BSSGP State Transition: ", g_ptp_bvc_state, " -> ", new_state);
        g_ptp_bvc_state := new_state;
-       BSSGP_SP.send(t_BssgpStsInd(mp_nsei, mp_bvci, g_ptp_bvc_state));
+       for (var integer i := 0; i < sizeof(ClientTable); i := i+1) {
+               if (isbound(ClientTable[i].comp_ref)) {
+                       BSSGP_SP.send(t_BssgpStsInd(g_cfg.nsei, g_cfg.bvci, 
g_ptp_bvc_state)) to ClientTable[i].comp_ref;
+               }
+       }
 }
 
 private function f_sendReset() runs on BSSGP_CT {
-       var PDU_BSSGP pdu := valueof(ts_BVC_RESET(BSSGP_CAUSE_OM_INTERVENTION, 
mp_bvci, mp_cellid));
+       var PDU_BSSGP pdu := valueof(ts_BVC_RESET(BSSGP_CAUSE_OM_INTERVENTION, 
g_cfg.bvci, g_cfg.cell_id));
        log("PDU: ", pdu);
        log("ENC: ", enc_PDU_BSSGP(pdu));
 
@@ -112,24 +188,177 @@
 }
 
 private function f_sendUnblock() runs on BSSGP_CT {
-       BSCP.send(f_BnsUdReq(t_BVC_UNBLOCK(mp_bvci), 0));
+       BSCP.send(f_BnsUdReq(t_BVC_UNBLOCK(g_cfg.bvci), 0));
        g_T1.start;
 }
 
 private function f_sendBlock(BssgpCause cause) runs on BSSGP_CT {
-       BSCP.send(f_BnsUdReq(t_BVC_BLOCK(mp_bvci, cause), 0));
+       BSCP.send(f_BnsUdReq(t_BVC_BLOCK(g_cfg.bvci, cause), 0));
        g_T1.start;
 }
 
 private function f_sendStatus(BssgpCause cause, PDU_BSSGP pdu) runs on 
BSSGP_CT {
        /* FIXME: Make sure correct Signaling or PTP BVCI is used! */
-       BSCP.send(f_BnsUdReq(ts_BSSGP_STATUS(mp_bvci, cause, pdu)));
+       BSCP.send(f_BnsUdReq(ts_BSSGP_STATUS(g_cfg.bvci, cause, pdu), 
g_cfg.bvci));
+}
+
+/* attempt to extract the TLLI from a BSSGP PDU */
+function f_bssgp_get_tlli(PDU_BSSGP bssgp) return template OCT4 {
+       if (ischosen(bssgp.pDU_BSSGP_DL_UNITDATA)) {
+               return bssgp.pDU_BSSGP_DL_UNITDATA.tLLI_current;
+       } else if (ischosen(bssgp.pDU_BSSGP_UL_UNITDATA)) {
+               return bssgp.pDU_BSSGP_UL_UNITDATA.tLLI;
+       } else if (ischosen(bssgp.pDU_BSSGP_RA_CAPABILITY)) {
+               return bssgp.pDU_BSSGP_RA_CAPABILITY.tLLI.tLLI_Value;
+       } else if (ischosen(bssgp.pDU_BSSGP_RA_CAPABILITY_UPDATE)) {
+               return bssgp.pDU_BSSGP_RA_CAPABILITY_UPDATE.tLLI.tLLI_Value;
+       } else if (ischosen(bssgp.pDU_BSSGP_RA_CAPABILITY_UPDATE_ACK)) {
+               return bssgp.pDU_BSSGP_RA_CAPABILITY_UPDATE_ACK.tLLI.tLLI_Value;
+       } else if (ischosen(bssgp.pDU_BSSGP_RADIO_STATUS)) {
+               return bssgp.pDU_BSSGP_RADIO_STATUS.tLLI.tLLI_Value;
+       } else if (ischosen(bssgp.pDU_BSSGP_SUSPEND)) {
+               return bssgp.pDU_BSSGP_SUSPEND.tLLI.tLLI_Value;
+       } else if (ischosen(bssgp.pDU_BSSGP_SUSPEND_ACK)) {
+               return bssgp.pDU_BSSGP_SUSPEND_ACK.tLLI.tLLI_Value;
+       } else if (ischosen(bssgp.pDU_BSSGP_SUSPEND_NACK)) {
+               return bssgp.pDU_BSSGP_SUSPEND_NACK.tLLI.tLLI_Value;
+       } else if (ischosen(bssgp.pDU_BSSGP_RESUME)) {
+               return bssgp.pDU_BSSGP_RESUME.tLLI.tLLI_Value;
+       } else if (ischosen(bssgp.pDU_BSSGP_RESUME_ACK)) {
+               return bssgp.pDU_BSSGP_RESUME_ACK.tLLI.tLLI_Value;
+       } else if (ischosen(bssgp.pDU_BSSGP_RESUME_NACK)) {
+               return bssgp.pDU_BSSGP_RESUME_NACK.tLLI.tLLI_Value;
+       } else if (ischosen(bssgp.pDU_BSSGP_FLUSH_LL)) {
+               return bssgp.pDU_BSSGP_FLUSH_LL.tLLI.tLLI_Value;
+       } else if (ischosen(bssgp.pDU_BSSGP_FLUSH_LL_ACK)) {
+               return bssgp.pDU_BSSGP_FLUSH_LL_ACK.tLLI.tLLI_Value;
+       } else if (ischosen(bssgp.pDU_BSSGP_LLC_DISCARDED)) {
+               return bssgp.pDU_BSSGP_LLC_DISCARDED.tLLI.tLLI_Value;
+       } else if (ischosen(bssgp.pDU_BSSGP_LLC_DISCARDED)) {
+               return bssgp.pDU_BSSGP_LLC_DISCARDED.tLLI.tLLI_Value;
+       } else if (ischosen(bssgp.pDU_BSSGP_PAGING_CS) and
+                  isvalue(bssgp.pDU_BSSGP_PAGING_CS.tLLI)) {
+               return bssgp.pDU_BSSGP_PAGING_CS.tLLI.tLLI_Value;
+       } else if (ischosen(bssgp.pDU_BSSGP_FLOW_CONTROL_MS)) {
+               return bssgp.pDU_BSSGP_FLOW_CONTROL_MS.tLLI.tLLI_Value;
+       } else if (ischosen(bssgp.pDU_BSSGP_FLOW_CONTROL_MS_ACK)) {
+               return bssgp.pDU_BSSGP_FLOW_CONTROL_MS_ACK.tLLI.tLLI_Value;
+       }
+       /* TODO: Handover, PFC, LCS */
+       return omit;
+}
+
+/*
+private function f_tbl_init() runs on BSSGP_CT {
+       var integer i;
+       for (i := 0; i < sizeof(ImsiTable); i := i+1) {
+               ImsiTable[i] := -;
+       }
+
+       for (i := 0; i < sizeof(TlliTable); i := i+1) {
+               TlliTable[i] := -;
+       }
+}
+*/
+
+private function f_tbl_client_add(hexstring imsi, OCT4 tlli, BssgpCellId 
cell_id, BSSGP_Client_CT vc_conn)
+runs on BSSGP_CT {
+       var integer i;
+       for (i := 0; i < sizeof(ClientTable); i := i+1) {
+               if (not isbound(ClientTable[i].comp_ref)) {
+                       log("Adding Client IMSI=", imsi, ", TLLI=", tlli, ", 
index=", i);
+                       ClientTable[i] := {
+                               tlli := tlli,
+                               tlli_old := omit,
+                               imsi := imsi,
+                               cell_id := cell_id,
+                               comp_ref := vc_conn,
+                               llc := -
+                       };
+                       for (var integer j := 0; j < 
sizeof(ClientTable[i].llc); j := j+1) {
+                               ClientTable[i].llc[j] := 
valueof(t_LLC_init(g_cfg.sgsn_role));
+                       }
+                       return;
+               }
+       }
+       setverdict(fail, "Client Table full");
+       self.stop;
+}
+
+private function f_tbl_client_del(hexstring imsi, BSSGP_Client_CT vc_conn) 
runs on BSSGP_CT {
+       var integer i;
+       for (i := 0; i < sizeof(ClientTable); i := i+1) {
+               if (isbound(ClientTable[i].imsi) and ClientTable[i].imsi == 
imsi) {
+                       if (ClientTable[i].comp_ref != vc_conn) {
+                               setverdict(fail, "Cannot unregister IMSI ", 
imsi, " registred to ",
+                                          ClientTable[i].comp_ref, " from ", 
vc_conn);
+                               self.stop;
+                       }
+                       log("Removing Client IMSI=", imsi, ", index=", i);
+                       ClientTable[i] := { -, omit, -, -, - };
+                       return;
+               }
+       }
+       setverdict(fail, "Could not find client for IMSI ", imsi);
+       self.stop;
+}
+
+private function f_tbl_comp_by_imsi(hexstring imsi) runs on BSSGP_CT return 
BSSGP_Client_CT {
+       var integer i;
+       for (i := 0; i < sizeof(ClientTable); i := i+1) {
+               if (isbound(ClientTable[i].imsi) and 
isbound(ClientTable[i].comp_ref)
+                   and ClientTable[i].imsi == imsi) {
+                       return ClientTable[i].comp_ref;
+               }
+       }
+       setverdict(fail, "Couldn't find Component for IMSI ", imsi);
+       self.stop;
+}
+
+private function f_tbl_comp_by_tlli(OCT4 tlli) runs on BSSGP_CT return 
BSSGP_Client_CT {
+       var integer i;
+       for (i := 0; i < sizeof(ClientTable); i := i+1) {
+               if (isbound(ClientTable[i].comp_ref) and
+                   (isbound(ClientTable[i].tlli) and (ClientTable[i].tlli == 
tlli or
+                    isbound(ClientTable[i].tlli_old) and 
ClientTable[i].tlli_old == tlli) )) {
+                       return ClientTable[i].comp_ref;
+               }
+       }
+       setverdict(fail, "Couldn't find Component for TLLI ", tlli);
+       self.stop;
+}
+
+private function f_tbl_idx_by_comp(BSSGP_Client_CT comp_ref) runs on BSSGP_CT 
return integer {
+       var integer i;
+       for (i := 0; i < sizeof(ClientTable); i := i+1) {
+               if (isbound(ClientTable[i].comp_ref) and 
ClientTable[i].comp_ref == comp_ref) {
+                       return i;
+               }
+       }
+       setverdict(fail, "Couldn't find Client for Component ", comp_ref);
+       self.stop;
+}
+
+private function f_tbl_tlli_by_comp(BSSGP_Client_CT comp_ref) runs on BSSGP_CT 
return OCT4 {
+       var integer i;
+       for (i := 0; i < sizeof(ClientTable); i := i+1) {
+               if (isbound(ClientTable[i].tlli) and 
isbound(ClientTable[i].comp_ref)
+                   and ClientTable[i].comp_ref == comp_ref) {
+                       return ClientTable[i].tlli;
+               }
+       }
+       setverdict(fail, "Couldn't find TLLI for Component ", comp_ref);
+       self.stop;
 }
 
 altstep as_allstate() runs on BSSGP_CT {
+       var BSSGP_Client_CT vc_conn;
        var NsUnitdataIndication udi;
        var NsStatusIndication nsi;
        var ASP_Event evt;
+       var hexstring imsi;
+       var OCT4 tlli;
+       var BssgpCellId cell_id;
 
        /* Respond to BLOCK for wrong NSVCI */
        [] BSCP.receive(f_BnsUdInd(t_BVC_BLOCK(?, ?), 0)) -> value udi {
@@ -138,16 +367,16 @@
        }
 
        /* Respond to RESET with correct BVCI/CellID */
-       [] BSCP.receive(f_BnsUdInd(tr_BVC_RESET(?, mp_bvci, mp_cellid), 0)) -> 
value udi {
-               log("Rx BVC-RESET for Our BVCI=", mp_bvci);
-               BSCP.send(f_BnsUdReq(ts_BVC_RESET_ACK(mp_bvci, mp_cellid), 0));
+       [] BSCP.receive(f_BnsUdInd(tr_BVC_RESET(?, g_cfg.bvci, g_cfg.cell_id), 
0)) -> value udi {
+               log("Rx BVC-RESET for Our BVCI=", g_cfg.bvci);
+               BSCP.send(f_BnsUdReq(ts_BVC_RESET_ACK(g_cfg.bvci, 
g_cfg.cell_id), 0));
                f_change_state(BVC_S_UNBLOCKED);
        }
 
        /* Respond to RESET for signalling BVCI 0 */
-       [] BSCP.receive(f_BnsUdInd(tr_BVC_RESET(?, 0, mp_cellid), 0)) -> value 
udi {
+       [] BSCP.receive(f_BnsUdInd(tr_BVC_RESET(?, 0, g_cfg.cell_id), 0)) -> 
value udi {
                log("Rx BVC-RESET for Signaling BVCI=0");
-               BSCP.send(f_BnsUdReq(ts_BVC_RESET_ACK(0, mp_cellid), 0));
+               BSCP.send(f_BnsUdReq(ts_BVC_RESET_ACK(0, g_cfg.cell_id), 0));
        }
 
        /* Respond to RESET with wrong NSEI/NSVCI */
@@ -162,95 +391,258 @@
                
f_sendStatus(BSSGP_CAUSE_PDU_NOT_COMPATIBLE_WITH_PROTOCOL_STATE, udi.bssgp);
        }
        /* Forwarding of ASP_Event and NsStatusIndication to user */
-       [] BSCP.receive(ASP_Event:?) -> value evt { BSSGP_SP.send(evt); }
+       [] BSCP.receive(ASP_Event:?) -> value evt {
+               for (var integer i := 0; i < sizeof(ClientTable); i := i+1) {
+                       if (isbound(ClientTable[i].comp_ref)) {
+                               BSSGP_SP.send(evt) to ClientTable[i].comp_ref;
+                       }
+               }
+               }
        [] BSCP.receive(NsStatusIndication:?) -> value nsi { 
                /* if we just became NS-unblocked, send a BCC-RESET */
                if (nsi.old_state != NSE_S_ALIVE_UNBLOCKED and nsi.new_state == 
NSE_S_ALIVE_UNBLOCKED) {
-                       if (g_sgsn_role == false) {
+                       if (g_cfg.sgsn_role == false) {
                                f_sendReset();
                        }
-                       /* Idea: We coudl send BVC-UNBLOCK here like some SGSN 
do */
+                       /* Idea: We could send BVC-UNBLOCK here like some SGSN 
do */
                }
-               BSSGP_SP.send(nsi);
+               for (var integer i := 0; i < sizeof(ClientTable); i := i+1) {
+                       if (isbound(ClientTable[i].comp_ref)) {
+                               BSSGP_SP.send(nsi) to ClientTable[i].comp_ref;
+                       }
+               }
+       }
+
+       [] BSSGP_PROC.getcall(BSSGP_register_client:{?,?,?}) -> param(imsi, 
tlli, cell_id) sender vc_conn {
+               f_tbl_client_add(imsi, tlli, cell_id, vc_conn);
+               BSSGP_PROC.reply(BSSGP_register_client:{imsi, tlli, cell_id});
+               }
+       [] BSSGP_PROC.getcall(BSSGP_unregister_client:{?}) -> param(imsi) 
sender vc_conn {
+               f_tbl_client_del(imsi, vc_conn);
+               BSSGP_PROC.reply(BSSGP_unregister_client:{imsi});
+               }
+}
+
+altstep as_blocked() runs on BSSGP_CT {
+       [] g_T1.timeout {
+               f_sendUnblock();
+       }
+       [] BSCP.receive(f_BnsUdInd(t_BVC_UNBLOCK_ACK(g_cfg.bvci), 0)) {
+               g_T1.stop;
+               f_change_state(BVC_S_UNBLOCKED);
+       }
+       [not g_cfg.sgsn_role] 
BSCP.receive(f_BnsUdInd(tr_BVC_RESET_ACK(g_cfg.bvci, omit), 0)) {
+               f_sendUnblock();
        }
 }
 
-private function f_ScanEvents() runs on BSSGP_CT {
+altstep as_unblocked() runs on BSSGP_CT {
+       var BSSGP_Client_CT vc_conn;
        var NsUnitdataIndication udi;
        var PDU_BSSGP bs_pdu;
-       var default d;
+       var PDU_L3_MS_SGSN l3_mo;
+       var PDU_L3_SGSN_MS l3_mt;
 
+       /* bogus unblock, just respond with ACK */
+       [] BSCP.receive(f_BnsUdInd(t_BVC_UNBLOCK(g_cfg.bvci), 0)) -> value udi {
+               BSCP.send(f_BnsUdReq(t_BVC_UNBLOCK_ACK(g_cfg.bvci), 0));
+       }
+       /* Respond to BLOCK with BLOCK-ACK + change state */
+       [] BSCP.receive(f_BnsUdInd(t_BVC_BLOCK(g_cfg.bvci, ?), 0)) -> value udi 
{
+               BSCP.send(f_BnsUdReq(t_BVC_BLOCK_ACK(g_cfg.bvci), 0));
+               g_T1.stop;
+               f_change_state(BVC_S_BLOCKED);
+       }
+       [] g_T1.timeout {
+               f_sendBlock(BSSGP_CAUSE_OM_INTERVENTION);
+       }
+       [] BSCP.receive(f_BnsUdInd(t_BVC_BLOCK_ACK(g_cfg.bvci), 0)) -> value 
udi {
+               g_T1.stop;
+               f_change_state(BVC_S_BLOCKED);
+       }
+       [] BSCP.receive(f_BnsUdInd(tr_BVC_RESET_ACK(g_cfg.bvci, g_cfg.cell_id), 
0)) -> value udi {
+               g_T2.stop;
+               f_change_state(BVC_S_UNBLOCKED);
+       }
 
-       log("matching against ", tr_BVC_RESET(?, mp_bvci, mp_cellid));
-
-       d := activate(as_allstate());
-
-       while (true) {
-       if (g_ptp_bvc_state == BVC_S_BLOCKED) {
-               alt {
-                       [] g_T1.timeout {
-                               f_sendUnblock();
-                       }
-                       [] BSCP.receive(f_BnsUdInd(t_BVC_UNBLOCK_ACK(mp_bvci), 
0)) {
-                               g_T1.stop;
-                               f_change_state(BVC_S_UNBLOCKED);
-                       }
-                       [not g_sgsn_role] 
BSCP.receive(f_BnsUdInd(tr_BVC_RESET_ACK(mp_bvci, omit), 0)) {
-                               f_sendUnblock();
-                       }
-               }
-       } else if (g_ptp_bvc_state == BVC_S_UNBLOCKED) {
-               alt {
-                       /* bogus unblock, just respond with ACK */
-                       [] BSCP.receive(f_BnsUdInd(t_BVC_UNBLOCK(mp_bvci), 0)) 
-> value udi {
-                               
BSCP.send(f_BnsUdReq(t_BVC_UNBLOCK_ACK(mp_bvci), 0));
-                       }
-                       /* Respond to BLOCK with BLOCK-ACK + change state */
-                       [] BSCP.receive(f_BnsUdInd(t_BVC_BLOCK(mp_bvci, ?), 0)) 
-> value udi {
-                               BSCP.send(f_BnsUdReq(t_BVC_BLOCK_ACK(mp_bvci), 
0));
-                               g_T1.stop;
-                               f_change_state(BVC_S_BLOCKED);
-                       }
-                       [] g_T1.timeout {
-                               f_sendBlock(BSSGP_CAUSE_OM_INTERVENTION);
-                       }
-                       [] BSCP.receive(f_BnsUdInd(t_BVC_BLOCK_ACK(mp_bvci), 
0)) -> value udi {
-                               g_T1.stop;
-                               f_change_state(BVC_S_BLOCKED);
-                       }
-                       [] BSCP.receive(f_BnsUdInd(tr_BVC_RESET_ACK(mp_bvci, 
mp_cellid), 0)) -> value udi {
-                               g_T2.stop;
-                               f_change_state(BVC_S_UNBLOCKED);
-                       }
-
-                       /* simply acknowledge all Flow Control Messages */
+       /* simply acknowledge all Flow Control Messages */
 /*
-                       [g_sgsn_role] BSCP.receive(f_BnsUdInd(t_BVC_FC_BVC)) {
-                               BSCP.send(f_BnsUdReq(t_BVC_FC_BVC_ACK));
-                       }
-                       [g_sgsn_role] BSCP.receive(f_BnsUdInd(t_BVC_FC_MS)) {
-                               BSCP.send(f_BnsUdReq(t_BVC_FC_MS_ACK));
-                       }
+       [g_cfg.sgsn_role] BSCP.receive(f_BnsUdInd(t_BVC_FC_BVC), g_cfg.bvci) {
+               BSCP.send(f_BnsUdReq(t_BVC_FC_BVC_ACK), g_cfg.bvci);
+       }
+       [g_cfg.sgsn_role] BSCP.receive(f_BnsUdInd(t_BVC_FC_MS), g_cfg.bvci) {
+               BSCP.send(f_BnsUdReq(t_BVC_FC_MS_ACK), g_cfg.bvci);
+       }
 */
 
-                       /* BSSGP-UNITDATA PDUs from network to NS-UNITDATA.ind 
to user */
-                       [not g_sgsn_role] 
BSCP.receive(f_BnsUdInd(tr_BSSGP_DL_UD)) -> value udi {
-                               BSSGP_SP.send(udi.bssgp);
-                       }
-                       [g_sgsn_role] BSCP.receive(f_BnsUdInd(tr_BSSGP_UL_UD)) 
-> value udi {
-                               BSSGP_SP.send(udi.bssgp);
-                       }
-                       /* pass virtually any PDU from user to NS-UNITDATA PDU 
on network */
-                       [] BSSGP_SP.receive(PDU_BSSGP:?) -> value bs_pdu {
-                               BSCP.send(f_BnsUdReq(bs_pdu));
-                       }
+       /* FIXME: CS PAGING: dispatch by IMSI */
 
+       /* PS PAGING: dispatch by IMSI */
+       [] BSCP.receive(f_BnsUdInd(tr_BSSGP_PS_PAGING(g_cfg.bvci), g_cfg.bvci)) 
-> value udi {
+               var hexstring imsi := udi.bssgp.pDU_BSSGP_PAGING_PS.iMSI.digits
+               vc_conn := f_tbl_comp_by_imsi(imsi);
+               BSSGP_SP.send(f_dec_bssgp(udi.bssgp)) to vc_conn;
+       }
+
+       /* Any other BSSGP message: If it has TLLi, route to component; 
otherwise broadcast */
+       [] BSCP.receive(f_BnsUdInd(?, g_cfg.bvci)) -> value udi {
+               var BssgpDecoded dec := f_dec_bssgp(udi.bssgp);
+               var template OCT4 tlli := f_bssgp_get_tlli(udi.bssgp);
+               if (isvalue(tlli)) {
+                       vc_conn := f_tbl_comp_by_tlli(valueof(tlli));
+                       BSSGP_SP.send(dec) to vc_conn;
+               } else {
+                       log("No TLLI: Broadcasting ", dec);
+                       /* broadcast this message to all components */
+                       // TITAN DOESN'T DO THIS, *SIGH*: "BSSGP_SP.send(dec) 
to all component;"
+                       for (var integer i := 0; i < sizeof(ClientTable); i := 
i+1) {
+                               if (isbound(ClientTable[i].comp_ref)) {
+                                       BSSGP_SP.send(dec) to 
ClientTable[i].comp_ref;
+                               }
+                       }
                }
        }
 
-       } /* while */
-       //deactivate(d);
+       /* pass virtually any PDU from user to NS-UNITDATA PDU on network */
+       [] BSSGP_SP.receive(PDU_BSSGP:?) -> value bs_pdu sender vc_conn {
+               BSCP.send(f_BnsUdReq(bs_pdu, g_cfg.bvci));
+       }
+
+       [not g_cfg.sgsn_role] BSSGP_SP.receive(PDU_L3_MS_SGSN:?) -> value l3_mo 
sender vc_conn {
+               var integer idx := f_tbl_idx_by_comp(vc_conn);
+               var octetstring l3_enc := enc_PDU_L3_MS_SGSN(l3_mo);
+               var BIT4 sapi := f_llc_sapi_by_l3_mo(l3_mo);
+               var integer n_u := 
f_llc_get_n_u_tx(ClientTable[idx].llc[bit2int(sapi)]);
+               var octetstring llc_enc := 
enc_PDU_LLC(valueof(ts_LLC_UI(l3_enc, sapi, '0'B, n_u)));
+               BSCP.send(f_BnsUdReq(ts_BSSGP_UL_UD(ClientTable[idx].tlli, 
ClientTable[idx].cell_id, llc_enc), g_cfg.bvci));
+       }
+
+       [g_cfg.sgsn_role] BSSGP_SP.receive(PDU_L3_SGSN_MS:?) -> value l3_mt 
sender vc_conn {
+               var integer idx := f_tbl_idx_by_comp(vc_conn);
+               var octetstring l3_enc := enc_PDU_L3_SGSN_MS(l3_mt);
+               var BIT4 sapi := f_llc_sapi_by_l3_mt(l3_mt);
+               var integer n_u := 
f_llc_get_n_u_tx(ClientTable[idx].llc[bit2int(sapi)]);
+               var octetstring llc_enc := 
enc_PDU_LLC(valueof(ts_LLC_UI(l3_enc, sapi, '1'B, n_u)));
+               //BSCP.send(f_BnsUdReq(ts_BSSGP_DL_UD(ClientTable[idx].tlli, 
ClientTable[idx].cell_id, llc_enc)), g_cfg.bvci);
+       }
 }
 
+private function f_llc_get_n_u_tx(inout LLC_Entity llc) return uint9_t {
+       var uint9_t ret := llc.n_u_tx_next;
+       llc.n_u_tx_next := llc.n_u_tx_next + 1;
+       return ret;
+}
+
+private function f_llc_sapi_by_l3_mo(PDU_L3_MS_SGSN l3_mo) return BIT4 {
+       if (ischosen(l3_mo.msgs.gprs_mm)) {
+               return c_LLC_SAPI_LLGMM;
+       } else if (ischosen(l3_mo.msgs.gprs_sm)) {
+               return c_LLC_SAPI_LLSM;
+       } else if (ischosen(l3_mo.msgs.sms)) {
+               return c_LLC_SAPI_LLSMS;
+       }
+       setverdict(fail, "No LLC SAPI for ", l3_mo);
+       self.stop;
+}
+
+private function f_llc_sapi_by_l3_mt(PDU_L3_SGSN_MS l3_mt) return BIT4 {
+       if (ischosen(l3_mt.msgs.gprs_mm)) {
+               return c_LLC_SAPI_LLGMM;
+       } else if (ischosen(l3_mt.msgs.gprs_sm)) {
+               return c_LLC_SAPI_LLSM;
+       } else if (ischosen(l3_mt.msgs.sms)) {
+               return c_LLC_SAPI_LLSMS;
+       }
+       setverdict(fail, "No LLC SAPI for ", l3_mt);
+       self.stop;
+}
+
+
+
+private function f_ScanEvents() runs on BSSGP_CT {
+       log("matching against ", tr_BVC_RESET(?, g_cfg.bvci, g_cfg.cell_id));
+
+       while (true) {
+               alt {
+               [g_ptp_bvc_state == BVC_S_BLOCKED] as_blocked();
+               [g_ptp_bvc_state == BVC_S_UNBLOCKED] as_unblocked();
+               [] as_allstate();
+               }
+       } /* while */
+}
+
+/* PDU_BSSGP enhanced with LLC and possibly L3 decoded payloads */
+type record BssgpDecoded {
+       PDU_BSSGP bssgp,
+       PDU_LLC llc optional,
+       PDU_L3_MS_SGSN l3_mo optional,
+       PDU_L3_SGSN_MS l3_mt optional
+}
+
+/* Decode a PDU_BSSGP into a BssgpDecoded (i.e. with LLC/L3 decoded, as 
applicable) */
+private function f_dec_bssgp(PDU_BSSGP bssgp) runs on BSSGP_CT return 
BssgpDecoded {
+       var BssgpDecoded dec := {
+               bssgp := bssgp,
+               llc := omit,
+               l3_mo := omit,
+               l3_mt := omit
+       };
+
+       /* Decode LLC, if it is a PDU that contains LLC */
+       if (ischosen(bssgp.pDU_BSSGP_DL_UNITDATA)) {
+               dec.llc := 
dec_PDU_LLC(bssgp.pDU_BSSGP_DL_UNITDATA.lLC_PDU.lLC_PDU);
+       } else if (ischosen(bssgp.pDU_BSSGP_UL_UNITDATA)) {
+               dec.llc := 
dec_PDU_LLC(bssgp.pDU_BSSGP_UL_UNITDATA.lLC_PDU.lLC_PDU);
+       }
+
+       /* Decode L3, if it is a LLC PDU containing L3 */
+       if (isvalue(dec.llc) and match(dec.llc, tr_LLC_UI_L3)) {
+               if (g_cfg.sgsn_role) {
+                       dec.l3_mo := 
dec_PDU_L3_MS_SGSN(dec.llc.pDU_LLC_UI.information_field_UI);
+               } else {
+                       dec.l3_mt := 
dec_PDU_L3_SGSN_MS(dec.llc.pDU_LLC_UI.information_field_UI);
+               }
+       }
+       return dec;
+}
+
+function f_bssgp_client_register(hexstring imsi, OCT4 tlli, BssgpCellId 
cell_id, BSSGP_PROC_PT PT := BSSGP_PROC)
+runs on BSSGP_Client_CT {
+       PT.call(BSSGP_register_client:{imsi, tlli, cell_id}) {
+               [] PT.getreply(BSSGP_register_client:{imsi, tlli, cell_id}) {};
+       }
+}
+
+function f_bssgp_client_unregister(hexstring imsi, BSSGP_PROC_PT PT := 
BSSGP_PROC)
+runs on BSSGP_Client_CT {
+       PT.call(BSSGP_unregister_client:{imsi}) {
+               [] PT.getreply(BSSGP_unregister_client:{imsi}) {};
+       }
+}
+
+template BssgpDecoded tr_BD_BSSGP(template PDU_BSSGP bg) := {
+       bssgp := bg,
+       llc := *,
+       l3_mo := *,
+       l3_mt := *
+}
+
+
+template BssgpDecoded tr_BD_L3_MT(template PDU_L3_SGSN_MS mt) := {
+       bssgp := ?,
+       llc := ?,
+       l3_mo := omit,
+       l3_mt := mt
+}
+
+template BssgpDecoded tr_BD_L3_MO(template PDU_L3_MS_SGSN mo) := {
+       bssgp := ?,
+       llc := ?,
+       l3_mo := mo,
+       l3_mt := omit
+}
+
+
+
 
 }
diff --git a/library/LLC_Templates.ttcn b/library/LLC_Templates.ttcn
new file mode 100644
index 0000000..e387b36
--- /dev/null
+++ b/library/LLC_Templates.ttcn
@@ -0,0 +1,73 @@
+module LLC_Templates {
+
+import from LLC_Types all;
+import from Osmocom_Types all;
+import from General_Types all;
+
+template Address_field t_LLC_Addr(template BIT4 sapi, template BIT1 cr, 
template BIT1 pd := '0'B) := {
+       sAPI := sapi,
+       spare := '00'B,
+       cR := cr,
+       pD := '0'B
+}
+
+template (value) Control_field_UI ts_LLC_CtrlUI(uint9_t n_u, boolean encrypted 
:= false,
+                                       boolean protected := false) := {
+       format := '110'B,
+       spare := '00'B,
+       nU := n_u,
+       e := bool2bit(encrypted),
+       pM := bool2bit(protected)
+}
+
+template Control_field_UI tr_LLC_CtrlUI(template uint9_t n_u,
+                                       template boolean encrypted := ?,
+                                       template boolean protected := ?) := {
+       format := '110'B,
+       spare := '00'B,
+       nU := n_u,
+       e := bool2bit_tmpl(encrypted),
+       pM := bool2bit_tmpl(protected)
+}
+
+template PDU_LLC ts_LLC_UI(octetstring payload, BIT4 sapi, BIT1 cr, uint9_t 
n_u,
+                          boolean encrypted := false, boolean protected := 
false) := {
+       pDU_LLC_UI := {
+               address_field := t_LLC_Addr(sapi, cr),
+               control_field := ts_LLC_CtrlUI(n_u, encrypted, protected),
+               information_field_UI := payload,
+               fCS := omit /* causes encoder to generate FCS */
+       }
+}
+
+template PDU_LLC tr_LLC_UI(template octetstring payload := ?, template BIT4 
sapi := ?,
+                          template BIT1 cr := ?, template uint9_t n_u := ?,
+                          template boolean encrypted := ?, template boolean 
protected := ?) := {
+       pDU_LLC_UI := {
+               address_field := t_LLC_Addr(sapi, cr),
+               control_field := tr_LLC_CtrlUI(n_u, encrypted, protected),
+               information_field_UI := payload,
+               fCS := '000000'O /* provided by decoder if FCS OK */
+       }
+}
+
+const BIT4 c_LLC_SAPI_LLGMM := '0001'B;
+const BIT4 c_LLC_SAPI_TOM2 := '0010'B;
+const BIT4 c_LLC_SAPI_LL3 := '0011'B;
+const BIT4 c_LLC_SAPI_LL5 := '0101'B;
+const BIT4 c_LLC_SAPI_LLSMS := '0111'B;
+const BIT4 c_LLC_SAPI_TOM8 := '1000'B;
+const BIT4 c_LLC_SAPI_LL9 := '1001'B;
+const BIT4 c_LLC_SAPI_LLSM := '1010'B;
+const BIT4 c_LLC_SAPI_LL11 := '1011'B;
+
+const BIT1 LLC_CR_DL_CMD := '1'B;
+const BIT1 LLC_CR_DL_RSP := '0'B;
+const BIT1 LLC_CR_UL_CMD := '0'B;
+const BIT1 LLC_CR_UL_RSP := '1'B;
+
+/* LLC UI frame with SAPI for L3 payload */
+template PDU_LLC tr_LLC_UI_L3 := ( tr_LLC_UI(?, c_LLC_SAPI_LLGMM), 
tr_LLC_UI(?, c_LLC_SAPI_LLSM) );
+
+
+}
diff --git a/sgsn/SGSN_Tests.ttcn b/sgsn/SGSN_Tests.ttcn
index d535432..c47403e 100644
--- a/sgsn/SGSN_Tests.ttcn
+++ b/sgsn/SGSN_Tests.ttcn
@@ -6,33 +6,181 @@
 import from NS_Emulation all;
 import from BSSGP_Types all;
 import from BSSGP_Emulation all;
+import from Osmocom_Gb_Types all;
+
+import from MobileL3_CommonIE_Types all;
+import from MobileL3_GMM_SM_Types all;
+import from MobileL3_Types all;
+import from L3_Templates all;
+import from L3_Common all;
+
+import from GSUP_Emulation all;
+import from GSUP_Types all;
+import from IPA_Emulation all;
+
+modulepar {
+       /* IP/port on which we run our internal GSUP/HLR emulation */
+       charstring mp_hlr_ip := "127.0.0.1";
+       integer mp_hlr_port := 4222;
+};
+
+type record GbInstance {
+       NS_CT vc_NS,
+       BSSGP_CT vc_BSSGP,
+       BssgpConfig cfg
+};
 
 type component test_CT {
-       var NS_CT vc_NS;
+       var GbInstance g_gb[3];
 
-       var BSSGP_CT vc_BSSGP;
-       port BSSGP_PT BSSGP;
+       var GSUP_Emulation_CT vc_GSUP;
+       var IPA_Emulation_CT vc_GSUP_IPA;
+       /* only to get events from IPA underneath GSUP */
+       port IPA_CTRL_PT GSUP_IPA_EVENT;
 
        var boolean g_initialized := false;
 };
+
+type component BSSGP_ConnHdlr extends BSSGP_Client_CT, GSUP_ConnHdlr {
+       var BSSGP_ConnHdlrPars g_pars;
+}
+
+type record SGSN_ConnHdlrNetworkPars {
+       boolean expect_ptmsi,
+       boolean expect_auth,
+       boolean expect_ciph
+};
+
+type record BSSGP_ConnHdlrPars {
+       /* IMEI of the simulated ME */
+       hexstring imei,
+       /* IMEI of the simulated MS */
+       hexstring imsi,
+       /* MSISDN of the simulated MS (probably unused) */
+       hexstring msisdn,
+       /* P-TMSI allocated to the simulated MS */
+       OCT4 p_tmsi optional,
+       /* TLLI of the simulated MS */
+       OCT4 tlli,
+       RoutingAreaIdentificationV ra optional,
+       BssgpCellId bssgp_cell_id,
+       AuthVector vec optional,
+       SGSN_ConnHdlrNetworkPars net
+};
+
+
+private function f_init_gb(inout GbInstance gb) runs on test_CT {
+       gb.vc_NS := NS_CT.create;
+       gb.vc_BSSGP := BSSGP_CT.create;
+       /* connect lower end of BSSGP emulation with NS upper port */
+       connect(gb.vc_BSSGP:BSCP, gb.vc_NS:NS_SP);
+       /* connect lower end of NS emulation to NS codec port (on top of IPL4) 
*/
+       map(gb.vc_NS:NSCP, system:NS_CODEC_PORT);
+
+       gb.vc_NS.start(NSStart());
+       gb.vc_BSSGP.start(BssgpStart(gb.cfg));
+}
+
+private function f_init_gsup(charstring id) runs on test_CT {
+       id := id & "-GSUP";
+       var GsupOps ops := {
+               create_cb := refers(GSUP_Emulation.ExpectedCreateCallback)
+       };
+
+       vc_GSUP_IPA := IPA_Emulation_CT.create(id & "-IPA");
+       vc_GSUP := GSUP_Emulation_CT.create(id);
+
+       map(vc_GSUP_IPA:IPA_PORT, system:IPA_CODEC_PT);
+       connect(vc_GSUP:GSUP, vc_GSUP_IPA:IPA_GSUP_PORT);
+       /* we use this hack to get events like ASP_IPA_EVENT_UP */
+       connect(vc_GSUP_IPA:IPA_CTRL_PORT, self:GSUP_IPA_EVENT);
+
+       vc_GSUP.start(GSUP_Emulation.main(ops, id));
+       vc_GSUP_IPA.start(IPA_Emulation.main_server(mp_hlr_ip, mp_hlr_port));
+
+       /* wait for incoming connection to GSUP port before proceeding */
+       timer T := 10.0;
+       T.start;
+       alt {
+               [] GSUP_IPA_EVENT.receive(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_UP)) { 
}
+               [] T.timeout {
+                       setverdict(fail, "No connection to GSUP Port");
+                       self.stop;
+               }
+       }
+}
 
 function f_init() runs on test_CT {
        if (g_initialized == true) {
                return;
        }
        g_initialized := true;
+       g_gb[0].cfg := {
+               nsei := 96,
+               bvci := 196,
+               cell_id := {
+                       ra_id := {
+                               lai := {
+                                       mcc_mnc := '26242F'H, lac := 13135},
+                                       rac := 0
+                               },
+                       cell_id := 20960
+               },
+               sgsn_role := false
+       };
 
-       vc_NS := NS_CT.create;
-       vc_BSSGP := BSSGP_CT.create;
-       /* connect our BSSGP port to upper end of BSSGP emulation */
-       connect(self:BSSGP, vc_BSSGP:BSSGP_SP);
-       /* connect lower end of BSSGP emulation with NS upper port */
-       connect(vc_BSSGP:BSCP, vc_NS:NS_SP);
-       /* connect lower end of NS emulation to NS codec port (on top of IPL4) 
*/
-       map(vc_NS:NSCP, system:NS_CODEC_PORT);
+       f_init_gb(g_gb[0]);
+       f_init_gsup("SGSN_Test");
+}
 
-       vc_NS.start(NSStart());
-       vc_BSSGP.start(BssgpStart(false));
+type function void_fn(charstring id) runs on BSSGP_ConnHdlr;
+
+/* helper function to create, connect and start a BSSGP_ConnHdlr component */
+function f_start_handler(void_fn fn, charstring id, GbInstance gb, integer 
imsi_suffix)
+runs on test_CT return BSSGP_ConnHdlr {
+       var BSSGP_ConnHdlr vc_conn;
+       var SGSN_ConnHdlrNetworkPars net_pars := {
+               expect_ptmsi := true,
+               expect_auth := true,
+               expect_ciph := false
+       };
+       var BSSGP_ConnHdlrPars pars := {
+               imei := f_gen_imei(imsi_suffix),
+               imsi := f_gen_imsi(imsi_suffix),
+               msisdn := f_gen_msisdn(imsi_suffix),
+               p_tmsi := omit,
+               tlli := 'FFFFFFFF'O,
+               ra := omit,
+               bssgp_cell_id := gb.cfg.cell_id,
+               vec := omit,
+               net := net_pars
+       };
+
+       vc_conn := BSSGP_ConnHdlr.create(id);
+       connect(vc_conn:BSSGP, gb.vc_BSSGP:BSSGP_SP);
+       connect(vc_conn:BSSGP_PROC, gb.vc_BSSGP:BSSGP_PROC);
+
+       connect(vc_conn:GSUP, vc_GSUP:GSUP_CLIENT);
+       connect(vc_conn:GSUP_PROC, vc_GSUP:GSUP_PROC);
+
+       vc_conn.start(f_handler_init(fn, id, pars));
+       return vc_conn;
+}
+
+/* first function called in every ConnHdlr */
+private function f_handler_init(void_fn fn, charstring id, BSSGP_ConnHdlrPars 
pars)
+runs on BSSGP_ConnHdlr {
+       /* do some common stuff like setting up g_pars */
+       g_pars := pars;
+
+       /* register with BSSGP core */
+       f_bssgp_client_register(g_pars.imsi, g_pars.tlli, g_pars.bssgp_cell_id);
+       /* tell GSUP dispatcher to send this IMSI to us */
+       f_create_gsup_expect(hex2str(g_pars.imsi));
+
+       /* call the user-supplied test case function */
+       fn.apply(id);
+       f_bssgp_client_unregister(g_pars.imsi);
 }
 
 /* TODO:
@@ -59,8 +207,86 @@
        f_sleep(20.0);
 }
 
+altstep as_mm_identity() runs on BSSGP_ConnHdlr {
+       var MobileIdentityLV mi;
+       [] BSSGP.receive(tr_BD_L3_MT(tr_GMM_ID_REQ('001'B))) {
+               mi := valueof(ts_MI_IMSI_LV(g_pars.imsi));
+               BSSGP.send(ts_GMM_ID_RESP(mi));
+               repeat;
+       }
+       [] BSSGP.receive(tr_BD_L3_MT(tr_GMM_ID_REQ('010'B))) {
+               mi := valueof(ts_MI_IMEI_LV(g_pars.imei));
+               BSSGP.send(ts_GMM_ID_RESP(mi));
+               repeat;
+       }
+}
 
-//control { }
+function f_gmm_auth () runs on BSSGP_ConnHdlr {
+       var BssgpDecoded bd;
+       var PDU_L3_MS_SGSN l3_mo;
+       var PDU_L3_SGSN_MS l3_mt;
+       var default di := activate(as_mm_identity());
+       if (g_pars.net.expect_auth) {
+               g_pars.vec := f_gen_auth_vec_2g();
+               var GSUP_IE auth_tuple := 
valueof(ts_GSUP_IE_AuthTuple2G(g_pars.vec.rand,
+                                                                        
g_pars.vec.sres,
+                                                                        
g_pars.vec.kc));
+               GSUP.receive(tr_GSUP_SAI_REQ(g_pars.imsi));
+               GSUP.send(ts_GSUP_SAI_RES(g_pars.imsi, auth_tuple));
+               BSSGP.receive(tr_BD_L3_MT(tr_GMM_AUTH_REQ(g_pars.vec.rand))) -> 
value bd;
+               l3_mt := bd.l3_mt;
+               var BIT4 ac_ref := 
l3_mt.msgs.gprs_mm.authenticationAndCipheringRequest.acReferenceNumber.valueField;
+               l3_mo := valueof(ts_GMM_AUTH_RESP_2G(ac_ref, g_pars.vec.sres));
+               if 
(ispresent(l3_mt.msgs.gprs_mm.authenticationAndCipheringRequest.imeisvRequest) 
and
+                   
l3_mt.msgs.gprs_mm.authenticationAndCipheringRequest.imeisvRequest.valueField 
== '001'B) {
+                       
l3_mo.msgs.gprs_mm.authenticationAndCipheringResponse.imeisv :=
+                                               
valueof(ts_MI_IMEISV_TLV(g_pars.imei & '0'H));
+               }
+               BSSGP.send(l3_mo);
+       }
+       deactivate(di);
+}
+
+private function f_TC_attach(charstring id) runs on BSSGP_ConnHdlr {
+       var MobileIdentityLV mi;
+       var RoutingAreaIdentificationV old_ra := { '2'H, '6'H, '2'H, 'F'H, 
'4'H, '2'H, '2342'O, '00'O };
+
+       if (ispresent(g_pars.p_tmsi)) {
+               mi := valueof(ts_MI_TMSI_LV(g_pars.p_tmsi));
+       } else {
+               mi := valueof(ts_MI_IMSI_LV(g_pars.imsi));
+       }
+
+       BSSGP.send(ts_GMM_ATTACH_REQ(mi, old_ra, false, false, omit, omit));
+       f_gmm_auth();
+       /* Expect MSC to perform LU with HLR */
+       GSUP.receive(tr_GSUP_UL_REQ(g_pars.imsi));
+       GSUP.send(ts_GSUP_ISD_REQ(g_pars.imsi, g_pars.msisdn));
+       GSUP.receive(tr_GSUP_ISD_RES(g_pars.imsi));
+       GSUP.send(ts_GSUP_UL_RES(g_pars.imsi));
+
+       BSSGP.receive(tr_BD_L3_MT(tr_GMM_ATTACH_ACCEPT(?, ?, ?)));
+       BSSGP.send(ts_GMM_ATTACH_COMPL);
+/*
+       alt {
+       [] as_mm_identity();
+       }
+*/
+       f_sleep(5.0);
+}
+
+testcase TC_attach() runs on test_CT {
+       var BSSGP_ConnHdlr vc_conn;
+       f_init();
+       f_sleep(1.0);
+       vc_conn := f_start_handler(refers(f_TC_attach), testcasename(), 
g_gb[0], 1);
+       vc_conn.done;
+}
+
+
+control {
+       execute( TC_wait_ns_up() );
+}
 
 
 
diff --git a/sgsn/gen_links.sh b/sgsn/gen_links.sh
index 4b76196..bc2727d 100755
--- a/sgsn/gen_links.sh
+++ b/sgsn/gen_links.sh
@@ -55,13 +55,22 @@
 FILES="BSSGP_EncDec.cc  BSSGP_Types.ttcn"
 gen_links $DIR $FILES
 
+DIR=$BASEDIR/titan.ProtocolModules.LLC_v7.1.0/src
+FILES="LLC_EncDec.cc LLC_Types.ttcn"
+gen_links $DIR $FILES
+
+DIR=$BASEDIR/titan.ProtocolModules.MobileL3_v13.4.0/src
+FILES="MobileL3_CC_Types.ttcn MobileL3_CommonIE_Types.ttcn 
MobileL3_GMM_SM_Types.ttcn MobileL3_MM_Types.ttcn MobileL3_RRM_Types.ttcn 
MobileL3_SMS_Types.ttcn MobileL3_SS_Types.ttcn MobileL3_Types.ttcn"
+gen_links $DIR $FILES
+
 DIR=../library
 FILES="General_Types.ttcn GSM_Types.ttcn GSM_RR_Types.ttcn Osmocom_Types.ttcn 
RLCMAC_Types.ttcn RLCMAC_CSN1_Types.ttcn RLCMAC_EncDec.cc "
 FILES+="NS_Emulation.ttcn NS_CodecPort.ttcn NS_CodecPort_CtrlFunct.ttcn 
NS_CodecPort_CtrlFunctDef.cc "
 FILES+="BSSGP_Emulation.ttcn Osmocom_Gb_Types.ttcn "
 FILES+="Osmocom_CTRL_Types.ttcn Osmocom_CTRL_Functions.ttcn 
Osmocom_CTRL_Adapter.ttcn "
 FILES+="Osmocom_VTY_Functions.ttcn "
+FILES+="LLC_Templates.ttcn L3_Templates.ttcn L3_Common.ttcn "
 # IPA_Emulation + dependencies
 FILES+="IPA_Types.ttcn IPA_Emulation.ttcn IPA_CodecPort.ttcn 
IPA_CodecPort_CtrlFunct.ttcn
-IPA_CodecPort_CtrlFunctDef.cc Native_Functions.ttcn Native_FunctionDefs.cc 
GSUP_Types.ttcn MGCP_Types.ttcn RSL_Types.ttcn "
+IPA_CodecPort_CtrlFunctDef.cc Native_Functions.ttcn Native_FunctionDefs.cc 
GSUP_Types.ttcn GSUP_Emulation.ttcn MGCP_Types.ttcn RSL_Types.ttcn "
 gen_links $DIR $FILES
diff --git a/sgsn/regen_makefile.sh b/sgsn/regen_makefile.sh
index 6824d94..c055065 100755
--- a/sgsn/regen_makefile.sh
+++ b/sgsn/regen_makefile.sh
@@ -1,5 +1,5 @@
 #!/bin/sh
 
-FILES="*.ttcn BSSGP_EncDec.cc IPL4asp_PT.cc IPL4asp_discovery.cc 
TCCConversion.cc TCCInterface.cc NS_CodecPort_CtrlFunctDef.cc RLCMAC_EncDec.cc 
Native_FunctionDefs.cc SDP_EncDec.cc SDP_parse_.tab.c lex.SDP_parse_.c 
TELNETasp_PT.cc IPA_CodecPort_CtrlFunctDef.cc"
+FILES="*.ttcn BSSGP_EncDec.cc LLC_EncDec.cc IPL4asp_PT.cc IPL4asp_discovery.cc 
TCCConversion.cc TCCInterface.cc NS_CodecPort_CtrlFunctDef.cc RLCMAC_EncDec.cc 
Native_FunctionDefs.cc SDP_EncDec.cc SDP_parse_.tab.c lex.SDP_parse_.c 
TELNETasp_PT.cc IPA_CodecPort_CtrlFunctDef.cc"
 
 ../regen-makefile.sh SGSN_Tests.ttcn $FILES

-- 
To view, visit https://gerrit.osmocom.org/6536
To unsubscribe, visit https://gerrit.osmocom.org/settings

Gerrit-MessageType: newpatchset
Gerrit-Change-Id: Id66ddf8dbe1c5cfa96a087235588ba67763b7f05
Gerrit-PatchSet: 4
Gerrit-Project: osmo-ttcn3-hacks
Gerrit-Branch: master
Gerrit-Owner: Harald Welte <lafo...@gnumonks.org>
Gerrit-Reviewer: Harald Welte <lafo...@gnumonks.org>
Gerrit-Reviewer: Jenkins Builder

Reply via email to