| 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 imsi, |
| hexstring msisdn, |
| 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 |
| }; |
| |
| template (value) MobileStationClassmark1_V ts_CM1(BIT1 a5_1_unavail := '0'B, BIT2 rev := '10'B) := { |
| rf_PowerCapability := '010'B, |
| a5_1 := a5_1_unavail, |
| esind := '1'B, |
| revisionLevel := rev, |
| spare1_1 := '0'B |
| } |
| |
| /* 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); |
| } |
| 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; |
| } |
| |
| function f_perform_lu(boolean expect_auth, boolean expect_tmsi) |
| 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); |
| |
| BSSAP.send(ts_BSSMAP_ClassmarkUpd(g_pars.cm2, g_pars.cm3)); |
| |
| if (expect_auth) { |
| /* FIXME */ |
| } |
| |
| /* 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 { |
| 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 */ |
| } |
| |
| |
| |
| |
| |
| } |
| |
| |