| module BSC_ConnectionHandler { |
| |
| import from General_Types all; |
| import from Osmocom_Types all; |
| import from GSM_Types all; |
| import from SCCPasp_Types all; |
| import from BSSAP_Types all; |
| import from BSSMAP_Emulation all; |
| import from BSSMAP_Templates all; |
| |
| import from GSUP_Types all; |
| import from GSUP_Emulation all; |
| |
| import from MNCC_Types all; |
| import from MNCC_Emulation all; |
| |
| import from MobileL3_Types all; |
| import from MobileL3_CommonIE_Types all; |
| import from MobileL3_MM_Types all; |
| import from L3_Templates all; |
| |
| /* this component represents a single subscriber connection */ |
| type component BSC_ConnHdlr extends BSSAP_ConnHdlr, MNCC_ConnHdlr, GSUP_ConnHdlr { |
| var BSC_ConnHdlrPars g_pars; |
| } |
| |
| type record BSC_ConnHdlrPars { |
| SCCP_PAR_Address sccp_addr_own, |
| SCCP_PAR_Address sccp_addr_peer, |
| BSSMAP_IE_CellIdentifier cell_id, |
| hexstring imei, |
| hexstring imsi, |
| hexstring msisdn, |
| OCT4 tmsi optional, |
| BSSMAP_IE_ClassmarkInformationType2 cm2, |
| BSSMAP_IE_ClassmarkInformationType3 cm3 optional |
| }; |
| |
| |
| /* Callback function from general BSSMAP_Emulation whenever a connectionless |
| * BSSMAP message arrives. Canreturn a PDU_BSSAPthat should be sent in return */ |
| private function BscUnitdataCallback(PDU_BSSAP bssap) |
| runs on BSSMAP_Emulation_CT return template PDU_BSSAP { |
| var template PDU_BSSAP resp := omit; |
| |
| log("BSSMAP_BscUnitdataCallback"); |
| /* answer all RESET with RESET ACK */ |
| if (match(bssap, tr_BSSMAP_Reset)){ |
| log("BSSMAP_BscUnitdataCallback: Responding to RESET with RESET-ACK"); |
| resp := ts_BSSMAP_ResetAck; |
| } |
| |
| /* FIXME: Handle paging, etc. */ |
| return resp; |
| } |
| |
| const BssmapOps BSC_BssmapOps := { |
| /* Create call-back for inbound connections from MSC (hand-over) */ |
| create_cb := refers(BSSMAP_Emulation.ExpectedCreateCallback), |
| unitdata_cb := refers(BscUnitdataCallback), |
| decode_dtap := true, |
| role_ms := true |
| } |
| |
| |
| private function MnccUnitdataCallback(MNCC_PDU mncc) |
| runs on MNCC_Emulation_CT return template MNCC_PDU { |
| log("Ignoring MNCC", mncc); |
| return omit; |
| } |
| |
| const MnccOps BCC_MnccOps := { |
| create_cb := refers(MNCC_Emulation.ExpectedCreateCallback), |
| unitdata_cb := refers(MnccUnitdataCallback) |
| } |
| |
| |
| |
| template BSSAP_Conn_Req ts_BSSAP_Conn_Req(SCCP_PAR_Address peer, SCCP_PAR_Address own, PDU_BSSAP bssap) := { |
| addr_peer := peer, |
| addr_own := own, |
| bssap := bssap |
| }; |
| |
| /* Encode 'l3' and ask BSSMAP_Emulation to create new connection with COMPL L3 INFO */ |
| function f_bssap_compl_l3(PDU_ML3_MS_NW l3) |
| runs on BSC_ConnHdlr { |
| log("Sending COMPL L3: ", l3); |
| var octetstring l3_enc := enc_PDU_ML3_MS_NW(l3); |
| BSSAP.send(ts_BSSAP_Conn_Req(g_pars.sccp_addr_peer, g_pars.sccp_addr_own, |
| valueof(ts_BSSMAP_ComplL3(g_pars.cell_id, l3_enc)))); |
| alt { |
| [] BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_CONF_IND) {} |
| [] BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND) { |
| setverdict(fail, "DISC.ind from SCCP"); |
| self.stop; |
| } |
| } |
| } |
| |
| /* helper function to fully establish a dedicated channel */ |
| function f_establish_fully(MobileIdentityLV mi, boolean expect_auth) |
| runs on BSC_ConnHdlr { |
| var PDU_ML3_MS_NW l3_info := valueof(ts_CM_SERV_REQ('0001'B, mi)); |
| var PDU_DTAP_MT dtap_mt; |
| |
| /* Send BSSAP_Conn_Req with COMPL L3 INFO to MSC */ |
| f_bssap_compl_l3(l3_info); |
| |
| if (expect_auth) { |
| /* FIXME */ |
| } |
| BSSAP.receive(tr_PDU_DTAP_MT(tr_CM_SERV_ACC)); |
| } |
| |
| /* build a PDU_ML3_MS_NW containing a Location Update by IMSI */ |
| function f_build_lu_imsi(hexstring imsi) return PDU_ML3_MS_NW |
| { |
| var MobileIdentityLV mi := valueof(ts_MI_IMSI_LV(imsi)); |
| return f_build_lu(mi); |
| } |
| function f_build_lu_imei(hexstring imei) return PDU_ML3_MS_NW |
| { |
| var MobileIdentityLV mi := valueof(ts_MI_IMEI_LV(imei)); |
| return f_build_lu(mi); |
| } |
| function f_build_lu_tmsi(OCT4 tmsi) return PDU_ML3_MS_NW |
| { |
| var MobileIdentityLV mi := valueof(ts_MI_TMSI_LV(tmsi)); |
| return f_build_lu(mi); |
| } |
| private function f_build_lu(MobileIdentityLV mi) return PDU_ML3_MS_NW |
| { |
| var LocationAreaIdentification_V old_lai := { '62F220'O, '9999'O }; |
| var PDU_ML3_MS_NW l3_info := valueof(ts_ML3_MO_LU_Req(valueof(ts_ML3_IE_LuType_Attach), |
| old_lai, mi, valueof(ts_CM1))); |
| return l3_info; |
| } |
| |
| type record AuthVector { |
| OCT16 rand, |
| OCT4 sres, |
| OCT8 kc |
| /* FIXME: 3G elements */ |
| } |
| |
| private function f_rnd_oct(integer len) return octetstring { |
| var integer i; |
| var octetstring res; |
| for (i := 0; i < len; i := i + 1) { |
| res[i] := int2oct(float2int(rnd()*256.0), 1); |
| } |
| return res; |
| } |
| |
| function f_gen_auth_vec_2g() return AuthVector { |
| var AuthVector vec; |
| vec.rand := f_rnd_oct(16); |
| vec.sres := f_rnd_oct(4); |
| vec.kc := f_rnd_oct(8); |
| return vec; |
| } |
| |
| function f_perform_lu(boolean expect_auth, boolean expect_tmsi, boolean send_early_cm) |
| runs on BSC_ConnHdlr { |
| var PDU_ML3_MS_NW l3_lu := f_build_lu_imsi(g_pars.imsi) |
| var PDU_DTAP_MT dtap_mt; |
| |
| /* tell GSUP dispatcher to send this IMSI to us */ |
| f_create_gsup_expect(hex2str(g_pars.imsi)); |
| |
| /* Send BSSAP_Conn_Req with COMPL L3 INFO to MSC */ |
| f_bssap_compl_l3(l3_lu); |
| |
| if (send_early_cm) { |
| BSSAP.send(ts_BSSMAP_ClassmarkUpd(g_pars.cm2, g_pars.cm3)); |
| } |
| |
| if (expect_auth) { |
| var AuthVector vec := f_gen_auth_vec_2g(); |
| var GSUP_IE auth_tuple := valueof(ts_GSUP_IE_AuthTuple2G(vec.rand, vec.sres, vec.kc)); |
| GSUP.receive(tr_GSUP_SAI_REQ(g_pars.imsi)); |
| GSUP.send(ts_GSUP_SAI_RES(g_pars.imsi, auth_tuple)); |
| |
| BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_MM_AUTH_REQ(vec.rand))); |
| BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MT_MM_AUTH_RESP_2G(vec.sres))); |
| } |
| |
| /* 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)); |
| |
| alt { |
| [] BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_LU_Acc)) -> value dtap_mt { |
| var PDU_ML3_LocationUpdateAccept lu_acc := dtap_mt.dtap.msgs.mm.locationUpdateAccept; |
| if (expect_tmsi) { |
| if (not ispresent(lu_acc.mobileIdentityTLV) or |
| not ischosen(lu_acc.mobileIdentityTLV.mobileIdentityLV.mobileIdentityV.oddEvenInd_identity.tmsi_ptmsi)) { |
| setverdict(fail, "Expected TMSI but no TMSI was allocated"); |
| self.stop; |
| } else { |
| g_pars.tmsi := lu_acc.mobileIdentityTLV.mobileIdentityLV.mobileIdentityV.oddEvenInd_identity.tmsi_ptmsi.octets; |
| BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_TmsiRealloc_Cmpl)); |
| } |
| } else { |
| if (ispresent(lu_acc.mobileIdentityTLV) and |
| ischosen(lu_acc.mobileIdentityTLV.mobileIdentityLV.mobileIdentityV.oddEvenInd_identity.tmsi_ptmsi)) { |
| setverdict(fail, "Expected no TMSI but TMSI was allocated"); |
| self.stop; |
| } |
| } |
| } |
| [] BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_LU_Rej)) { |
| setverdict(fail, "Expected LU ACK, but received LU REJ"); |
| self.stop; |
| } |
| } |
| /* FIXME: there could be pending SMS or other common procedures by the MSC, let's ignore them */ |
| BSSAP.receive(tr_BSSMAP_ClearCommand); |
| BSSAP.send(ts_BSSMAP_ClearComplete); |
| BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND); |
| setverdict(pass); |
| } |
| |
| function f_foo() runs on BSC_ConnHdlr{ |
| /* SCCP CC handled by BSSMAP_Emulation_CT.main() */ |
| /* Expect auth, if enabled */ |
| |
| /* TODO: ISD */ |
| /* Expect encr, if enabled */ |
| /* Expect encr, if enabled */ |
| /* Expect ASS CMD, if chan_type != requested */ |
| /* Send ASS CMPL in successful case */ |
| |
| /* Expect AoIP port/ip information for RTP stream */ |
| /* Expect MSC-originated MGCP to our simulated MGW */ |
| /* Verify Counters via CTRL */ |
| /* re-configure MSC behaviour via VTY */ |
| } |
| |
| |
| |
| |
| |
| } |
| |
| |