Harald Welte | 96a33b0 | 2018-02-04 10:36:22 +0100 | [diff] [blame] | 1 | module SGSN_Tests { |
| 2 | |
| 3 | import from General_Types all; |
| 4 | import from Osmocom_Types all; |
| 5 | import from NS_Types all; |
| 6 | import from NS_Emulation all; |
| 7 | import from BSSGP_Types all; |
| 8 | import from BSSGP_Emulation all; |
Harald Welte | 5ac3149 | 2018-02-15 20:39:13 +0100 | [diff] [blame] | 9 | import from Osmocom_Gb_Types all; |
| 10 | |
| 11 | import from MobileL3_CommonIE_Types all; |
| 12 | import from MobileL3_GMM_SM_Types all; |
| 13 | import from MobileL3_Types all; |
| 14 | import from L3_Templates all; |
| 15 | import from L3_Common all; |
| 16 | |
| 17 | import from GSUP_Emulation all; |
| 18 | import from GSUP_Types all; |
| 19 | import from IPA_Emulation all; |
| 20 | |
| 21 | modulepar { |
| 22 | /* IP/port on which we run our internal GSUP/HLR emulation */ |
| 23 | charstring mp_hlr_ip := "127.0.0.1"; |
| 24 | integer mp_hlr_port := 4222; |
| 25 | }; |
| 26 | |
| 27 | type record GbInstance { |
| 28 | NS_CT vc_NS, |
| 29 | BSSGP_CT vc_BSSGP, |
| 30 | BssgpConfig cfg |
| 31 | }; |
Harald Welte | 96a33b0 | 2018-02-04 10:36:22 +0100 | [diff] [blame] | 32 | |
| 33 | type component test_CT { |
Harald Welte | 5ac3149 | 2018-02-15 20:39:13 +0100 | [diff] [blame] | 34 | var GbInstance g_gb[3]; |
Harald Welte | 96a33b0 | 2018-02-04 10:36:22 +0100 | [diff] [blame] | 35 | |
Harald Welte | 5ac3149 | 2018-02-15 20:39:13 +0100 | [diff] [blame] | 36 | var GSUP_Emulation_CT vc_GSUP; |
| 37 | var IPA_Emulation_CT vc_GSUP_IPA; |
| 38 | /* only to get events from IPA underneath GSUP */ |
| 39 | port IPA_CTRL_PT GSUP_IPA_EVENT; |
Harald Welte | 96a33b0 | 2018-02-04 10:36:22 +0100 | [diff] [blame] | 40 | |
| 41 | var boolean g_initialized := false; |
| 42 | }; |
| 43 | |
Harald Welte | 5ac3149 | 2018-02-15 20:39:13 +0100 | [diff] [blame] | 44 | type component BSSGP_ConnHdlr extends BSSGP_Client_CT, GSUP_ConnHdlr { |
| 45 | var BSSGP_ConnHdlrPars g_pars; |
| 46 | } |
| 47 | |
| 48 | type record SGSN_ConnHdlrNetworkPars { |
| 49 | boolean expect_ptmsi, |
| 50 | boolean expect_auth, |
| 51 | boolean expect_ciph |
| 52 | }; |
| 53 | |
| 54 | type record BSSGP_ConnHdlrPars { |
| 55 | /* IMEI of the simulated ME */ |
| 56 | hexstring imei, |
| 57 | /* IMEI of the simulated MS */ |
| 58 | hexstring imsi, |
| 59 | /* MSISDN of the simulated MS (probably unused) */ |
| 60 | hexstring msisdn, |
| 61 | /* P-TMSI allocated to the simulated MS */ |
| 62 | OCT4 p_tmsi optional, |
| 63 | /* TLLI of the simulated MS */ |
| 64 | OCT4 tlli, |
| 65 | RoutingAreaIdentificationV ra optional, |
| 66 | BssgpCellId bssgp_cell_id, |
| 67 | AuthVector vec optional, |
| 68 | SGSN_ConnHdlrNetworkPars net |
| 69 | }; |
| 70 | |
| 71 | |
| 72 | private function f_init_gb(inout GbInstance gb) runs on test_CT { |
| 73 | gb.vc_NS := NS_CT.create; |
| 74 | gb.vc_BSSGP := BSSGP_CT.create; |
| 75 | /* connect lower end of BSSGP emulation with NS upper port */ |
| 76 | connect(gb.vc_BSSGP:BSCP, gb.vc_NS:NS_SP); |
| 77 | /* connect lower end of NS emulation to NS codec port (on top of IPL4) */ |
| 78 | map(gb.vc_NS:NSCP, system:NS_CODEC_PORT); |
| 79 | |
| 80 | gb.vc_NS.start(NSStart()); |
| 81 | gb.vc_BSSGP.start(BssgpStart(gb.cfg)); |
| 82 | } |
| 83 | |
| 84 | private function f_init_gsup(charstring id) runs on test_CT { |
| 85 | id := id & "-GSUP"; |
| 86 | var GsupOps ops := { |
| 87 | create_cb := refers(GSUP_Emulation.ExpectedCreateCallback) |
| 88 | }; |
| 89 | |
| 90 | vc_GSUP_IPA := IPA_Emulation_CT.create(id & "-IPA"); |
| 91 | vc_GSUP := GSUP_Emulation_CT.create(id); |
| 92 | |
| 93 | map(vc_GSUP_IPA:IPA_PORT, system:IPA_CODEC_PT); |
| 94 | connect(vc_GSUP:GSUP, vc_GSUP_IPA:IPA_GSUP_PORT); |
| 95 | /* we use this hack to get events like ASP_IPA_EVENT_UP */ |
| 96 | connect(vc_GSUP_IPA:IPA_CTRL_PORT, self:GSUP_IPA_EVENT); |
| 97 | |
| 98 | vc_GSUP.start(GSUP_Emulation.main(ops, id)); |
| 99 | vc_GSUP_IPA.start(IPA_Emulation.main_server(mp_hlr_ip, mp_hlr_port)); |
| 100 | |
| 101 | /* wait for incoming connection to GSUP port before proceeding */ |
| 102 | timer T := 10.0; |
| 103 | T.start; |
| 104 | alt { |
| 105 | [] GSUP_IPA_EVENT.receive(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_UP)) { } |
| 106 | [] T.timeout { |
| 107 | setverdict(fail, "No connection to GSUP Port"); |
| 108 | self.stop; |
| 109 | } |
| 110 | } |
| 111 | } |
| 112 | |
Harald Welte | 96a33b0 | 2018-02-04 10:36:22 +0100 | [diff] [blame] | 113 | function f_init() runs on test_CT { |
| 114 | if (g_initialized == true) { |
| 115 | return; |
| 116 | } |
| 117 | g_initialized := true; |
Harald Welte | 5ac3149 | 2018-02-15 20:39:13 +0100 | [diff] [blame] | 118 | g_gb[0].cfg := { |
| 119 | nsei := 96, |
| 120 | bvci := 196, |
| 121 | cell_id := { |
| 122 | ra_id := { |
| 123 | lai := { |
| 124 | mcc_mnc := '26242F'H, lac := 13135}, |
| 125 | rac := 0 |
| 126 | }, |
| 127 | cell_id := 20960 |
| 128 | }, |
| 129 | sgsn_role := false |
| 130 | }; |
Harald Welte | 96a33b0 | 2018-02-04 10:36:22 +0100 | [diff] [blame] | 131 | |
Harald Welte | 5ac3149 | 2018-02-15 20:39:13 +0100 | [diff] [blame] | 132 | f_init_gb(g_gb[0]); |
| 133 | f_init_gsup("SGSN_Test"); |
| 134 | } |
Harald Welte | 96a33b0 | 2018-02-04 10:36:22 +0100 | [diff] [blame] | 135 | |
Harald Welte | 5ac3149 | 2018-02-15 20:39:13 +0100 | [diff] [blame] | 136 | type function void_fn(charstring id) runs on BSSGP_ConnHdlr; |
| 137 | |
| 138 | /* helper function to create, connect and start a BSSGP_ConnHdlr component */ |
| 139 | function f_start_handler(void_fn fn, charstring id, GbInstance gb, integer imsi_suffix) |
| 140 | runs on test_CT return BSSGP_ConnHdlr { |
| 141 | var BSSGP_ConnHdlr vc_conn; |
| 142 | var SGSN_ConnHdlrNetworkPars net_pars := { |
| 143 | expect_ptmsi := true, |
| 144 | expect_auth := true, |
| 145 | expect_ciph := false |
| 146 | }; |
| 147 | var BSSGP_ConnHdlrPars pars := { |
| 148 | imei := f_gen_imei(imsi_suffix), |
| 149 | imsi := f_gen_imsi(imsi_suffix), |
| 150 | msisdn := f_gen_msisdn(imsi_suffix), |
| 151 | p_tmsi := omit, |
Harald Welte | 14a0f94 | 2018-02-16 20:42:23 +0100 | [diff] [blame] | 152 | tlli := f_gprs_tlli_random(), |
Harald Welte | 5ac3149 | 2018-02-15 20:39:13 +0100 | [diff] [blame] | 153 | ra := omit, |
| 154 | bssgp_cell_id := gb.cfg.cell_id, |
| 155 | vec := omit, |
| 156 | net := net_pars |
| 157 | }; |
| 158 | |
| 159 | vc_conn := BSSGP_ConnHdlr.create(id); |
| 160 | connect(vc_conn:BSSGP, gb.vc_BSSGP:BSSGP_SP); |
| 161 | connect(vc_conn:BSSGP_PROC, gb.vc_BSSGP:BSSGP_PROC); |
| 162 | |
| 163 | connect(vc_conn:GSUP, vc_GSUP:GSUP_CLIENT); |
| 164 | connect(vc_conn:GSUP_PROC, vc_GSUP:GSUP_PROC); |
| 165 | |
| 166 | vc_conn.start(f_handler_init(fn, id, pars)); |
| 167 | return vc_conn; |
| 168 | } |
| 169 | |
| 170 | /* first function called in every ConnHdlr */ |
| 171 | private function f_handler_init(void_fn fn, charstring id, BSSGP_ConnHdlrPars pars) |
| 172 | runs on BSSGP_ConnHdlr { |
| 173 | /* do some common stuff like setting up g_pars */ |
| 174 | g_pars := pars; |
| 175 | |
| 176 | /* register with BSSGP core */ |
| 177 | f_bssgp_client_register(g_pars.imsi, g_pars.tlli, g_pars.bssgp_cell_id); |
| 178 | /* tell GSUP dispatcher to send this IMSI to us */ |
| 179 | f_create_gsup_expect(hex2str(g_pars.imsi)); |
| 180 | |
| 181 | /* call the user-supplied test case function */ |
| 182 | fn.apply(id); |
| 183 | f_bssgp_client_unregister(g_pars.imsi); |
Harald Welte | 96a33b0 | 2018-02-04 10:36:22 +0100 | [diff] [blame] | 184 | } |
| 185 | |
| 186 | /* TODO: |
| 187 | * RAU without Attach |
| 188 | * Detach without Attach |
| 189 | * SM procedures without attach / RAU |
| 190 | * ATTACH / RAU |
| 191 | ** with / without authentication |
| 192 | ** with / without P-TMSI allocation |
| 193 | ** timeout from HLR on SAI |
| 194 | ** timeout from HLR on UL |
| 195 | ** reject from HLR on SAI |
| 196 | ** reject from HLR on UL |
| 197 | * re-transmissions of LLC frames |
| 198 | * PDP Context activation |
| 199 | ** with different GGSN config in SGSN VTY |
| 200 | ** with different PDP context type (v4/v6/v46) |
| 201 | ** timeout from GGSN |
| 202 | ** reject from GGSN |
| 203 | */ |
| 204 | |
| 205 | testcase TC_wait_ns_up() runs on test_CT { |
| 206 | f_init(); |
| 207 | f_sleep(20.0); |
| 208 | } |
| 209 | |
Harald Welte | 5ac3149 | 2018-02-15 20:39:13 +0100 | [diff] [blame] | 210 | altstep as_mm_identity() runs on BSSGP_ConnHdlr { |
| 211 | var MobileIdentityLV mi; |
| 212 | [] BSSGP.receive(tr_BD_L3_MT(tr_GMM_ID_REQ('001'B))) { |
| 213 | mi := valueof(ts_MI_IMSI_LV(g_pars.imsi)); |
| 214 | BSSGP.send(ts_GMM_ID_RESP(mi)); |
| 215 | repeat; |
| 216 | } |
| 217 | [] BSSGP.receive(tr_BD_L3_MT(tr_GMM_ID_REQ('010'B))) { |
| 218 | mi := valueof(ts_MI_IMEI_LV(g_pars.imei)); |
| 219 | BSSGP.send(ts_GMM_ID_RESP(mi)); |
| 220 | repeat; |
| 221 | } |
| 222 | } |
Harald Welte | 96a33b0 | 2018-02-04 10:36:22 +0100 | [diff] [blame] | 223 | |
Harald Welte | 5ac3149 | 2018-02-15 20:39:13 +0100 | [diff] [blame] | 224 | function f_gmm_auth () runs on BSSGP_ConnHdlr { |
| 225 | var BssgpDecoded bd; |
| 226 | var PDU_L3_MS_SGSN l3_mo; |
| 227 | var PDU_L3_SGSN_MS l3_mt; |
| 228 | var default di := activate(as_mm_identity()); |
| 229 | if (g_pars.net.expect_auth) { |
| 230 | g_pars.vec := f_gen_auth_vec_2g(); |
| 231 | var GSUP_IE auth_tuple := valueof(ts_GSUP_IE_AuthTuple2G(g_pars.vec.rand, |
| 232 | g_pars.vec.sres, |
| 233 | g_pars.vec.kc)); |
| 234 | GSUP.receive(tr_GSUP_SAI_REQ(g_pars.imsi)); |
| 235 | GSUP.send(ts_GSUP_SAI_RES(g_pars.imsi, auth_tuple)); |
| 236 | BSSGP.receive(tr_BD_L3_MT(tr_GMM_AUTH_REQ(g_pars.vec.rand))) -> value bd; |
| 237 | l3_mt := bd.l3_mt; |
| 238 | var BIT4 ac_ref := l3_mt.msgs.gprs_mm.authenticationAndCipheringRequest.acReferenceNumber.valueField; |
| 239 | l3_mo := valueof(ts_GMM_AUTH_RESP_2G(ac_ref, g_pars.vec.sres)); |
| 240 | if (ispresent(l3_mt.msgs.gprs_mm.authenticationAndCipheringRequest.imeisvRequest) and |
| 241 | l3_mt.msgs.gprs_mm.authenticationAndCipheringRequest.imeisvRequest.valueField == '001'B) { |
| 242 | l3_mo.msgs.gprs_mm.authenticationAndCipheringResponse.imeisv := |
| 243 | valueof(ts_MI_IMEISV_TLV(g_pars.imei & '0'H)); |
| 244 | } |
| 245 | BSSGP.send(l3_mo); |
| 246 | } |
| 247 | deactivate(di); |
| 248 | } |
| 249 | |
Harald Welte | 5a4fa04 | 2018-02-16 20:59:21 +0100 | [diff] [blame^] | 250 | function f_random_RAI(HEX0_3n mcc := '262'H, HEX0_3n mnc := '42'H) return RoutingAreaIdentificationV { |
| 251 | return f_RAI(mcc, mnc, f_rnd_octstring(2), f_rnd_octstring(1)); |
| 252 | } |
| 253 | |
Harald Welte | 5ac3149 | 2018-02-15 20:39:13 +0100 | [diff] [blame] | 254 | private function f_TC_attach(charstring id) runs on BSSGP_ConnHdlr { |
| 255 | var MobileIdentityLV mi; |
Harald Welte | 5a4fa04 | 2018-02-16 20:59:21 +0100 | [diff] [blame^] | 256 | var RoutingAreaIdentificationV old_ra := f_random_RAI(); |
Harald Welte | 5ac3149 | 2018-02-15 20:39:13 +0100 | [diff] [blame] | 257 | |
| 258 | if (ispresent(g_pars.p_tmsi)) { |
| 259 | mi := valueof(ts_MI_TMSI_LV(g_pars.p_tmsi)); |
| 260 | } else { |
| 261 | mi := valueof(ts_MI_IMSI_LV(g_pars.imsi)); |
| 262 | } |
| 263 | |
| 264 | BSSGP.send(ts_GMM_ATTACH_REQ(mi, old_ra, false, false, omit, omit)); |
| 265 | f_gmm_auth(); |
| 266 | /* Expect MSC to perform LU with HLR */ |
| 267 | GSUP.receive(tr_GSUP_UL_REQ(g_pars.imsi)); |
| 268 | GSUP.send(ts_GSUP_ISD_REQ(g_pars.imsi, g_pars.msisdn)); |
| 269 | GSUP.receive(tr_GSUP_ISD_RES(g_pars.imsi)); |
| 270 | GSUP.send(ts_GSUP_UL_RES(g_pars.imsi)); |
| 271 | |
| 272 | BSSGP.receive(tr_BD_L3_MT(tr_GMM_ATTACH_ACCEPT(?, ?, ?))); |
| 273 | BSSGP.send(ts_GMM_ATTACH_COMPL); |
Harald Welte | 5a4fa04 | 2018-02-16 20:59:21 +0100 | [diff] [blame^] | 274 | setverdict(pass); |
Harald Welte | 5ac3149 | 2018-02-15 20:39:13 +0100 | [diff] [blame] | 275 | } |
| 276 | |
| 277 | testcase TC_attach() runs on test_CT { |
| 278 | var BSSGP_ConnHdlr vc_conn; |
| 279 | f_init(); |
| 280 | f_sleep(1.0); |
| 281 | vc_conn := f_start_handler(refers(f_TC_attach), testcasename(), g_gb[0], 1); |
| 282 | vc_conn.done; |
| 283 | } |
| 284 | |
| 285 | |
| 286 | control { |
| 287 | execute( TC_wait_ns_up() ); |
| 288 | } |
Harald Welte | 96a33b0 | 2018-02-04 10:36:22 +0100 | [diff] [blame] | 289 | |
| 290 | |
| 291 | |
| 292 | } |