diff --git a/gprs_gb/BSSGP_Emulation.ttcn b/gprs_gb/BSSGP_Emulation.ttcn index 25b96cda3..5937a278f 100644 --- a/gprs_gb/BSSGP_Emulation.ttcn +++ b/gprs_gb/BSSGP_Emulation.ttcn @@ -11,7 +11,7 @@ module BSSGP_Emulation { BvcState state } - template BssgpStatusIndication t_BssgpStsInd(Nsei nsei, BssgpBvci bvci, BvcState state) := { + template BssgpStatusIndication t_BssgpStsInd(template Nsei nsei, template BssgpBvci bvci, template BvcState state) := { nsei := nsei, bvci := bvci, state := state @@ -56,20 +56,21 @@ module BSSGP_Emulation { /* NS-User SAP towards the user */ port BSSGP_SP_PT BSSGP_SP; + var boolean g_sgsn_role := true; var BvcState g_ptp_bvc_state := BVC_S_BLOCKED; timer g_T1 := 15.0; timer g_T2 := 60.0; } modulepar { - Nsvci mp_nsei := 2342; - Nsvci mp_bvci := 2342; + Nsvci mp_nsei := 96; + Nsvci mp_bvci := 196; BssgpCellId mp_cellid := { ra_id := { lai := { mcc_mnc := '234F04'H, lac := 200}, rac := 0 }, cell_id := 20960 }; }; - function f_BnsUdReq(template BssgpPdu pdu) return NsUnitdataRequest { + function f_BnsUdReq(template BssgpPdu pdu, BssgpBvci bvci := mp_bvci) return NsUnitdataRequest { var NsUnitdataRequest udr := { - bvci := mp_bvci, + bvci := bvci, nsei := mp_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 */ @@ -81,9 +82,9 @@ module BSSGP_Emulation { return udr; } - function f_BnsUdInd(template BssgpPdu pdu) return template NsUnitdataIndication { + function f_BnsUdInd(template BssgpPdu pdu, template BssgpBvci bvci := mp_bvci) return template NsUnitdataIndication { var template NsUnitdataIndication udi := { - bvci := mp_bvci, + bvci := bvci, nsei := mp_nsei, sdu := *, bssgp := pdu @@ -102,57 +103,71 @@ module BSSGP_Emulation { log("PDU: ", pdu); log("ENC: ", enc_BssgpPdu(pdu)); - BSCP.send(f_BnsUdReq(pdu)); + /* BVC-RESET is always sent via the SIGNALLING BVCI, see Table 5.4.1 */ + BSCP.send(f_BnsUdReq(pdu, 0)); g_T2.start; //f_change_state(BVC_S_WAIT_RESET); } private function f_sendUnblock() runs on BSSGP_CT { - BSCP.send(f_BnsUdReq(t_BVC_UNBLOCK(mp_bvci))); + BSCP.send(f_BnsUdReq(t_BVC_UNBLOCK(mp_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))); + BSCP.send(f_BnsUdReq(t_BVC_BLOCK(mp_bvci, cause), 0)); g_T1.start; } + private function f_sendStatus(BssgpCause cause, BssgpPdu pdu) runs on BSSGP_CT { + /* FIXME: Make sure correct Signaling or PTP BVCI is used! */ + BSCP.send(f_BnsUdReq(t_BSSGP_STATUS({ t_BSSGP_IE_Cause(cause), t_BSSGP_IE_Bvci(mp_bvci), t_BSSGP_IE_PDU(pdu)}))); + } + altstep as_allstate() runs on BSSGP_CT { var NsUnitdataIndication udi; var NsStatusIndication nsi; var ASP_Event evt; /* Respond to BLOCK for wrong NSVCI */ - [] BSCP.receive(f_BnsUdInd(t_BVC_BLOCK(?, ?))) -> value udi { + [] BSCP.receive(f_BnsUdInd(t_BVC_BLOCK(?, ?), 0)) -> value udi { log("Rx BVC-BLOCK for unknown BVCI"); - /* FIXME */ + f_sendStatus(BSSGP_CAUSE_BVCI_UNKNOWN, udi.bssgp); } - /* Respond to RESET with correct NSEI/NSVCI */ - [] BSCP.receive(f_BnsUdInd(t_BVC_RESET(?, mp_bvci, mp_cellid))) -> value udi { + /* Respond to RESET with correct BVCI/CellID */ + [] BSCP.receive(f_BnsUdInd(t_BVC_RESET(?, mp_bvci, mp_cellid), 0)) -> value udi { + log("Rx BVC-RESET for Our BVCI=", mp_bvci); + BSCP.send(f_BnsUdReq(t_BVC_RESET_ACK(mp_bvci, mp_cellid), 0)); f_change_state(BVC_S_UNBLOCKED); - BSCP.send(f_BnsUdReq(t_BVC_RESET_ACK(mp_bvci, mp_cellid))); + } + + /* Respond to RESET for signalling BVCI 0 */ + [] BSCP.receive(f_BnsUdInd(t_BVC_RESET(?, 0, mp_cellid), 0)) -> value udi { + log("Rx BVC-RESET for Signaling BVCI=0"); + BSCP.send(f_BnsUdReq(t_BVC_RESET_ACK(0, mp_cellid), 0)); } /* Respond to RESET with wrong NSEI/NSVCI */ - [] BSCP.receive(f_BnsUdInd(t_BVC_RESET(?, ?, ?))) -> value udi { + [] BSCP.receive(f_BnsUdInd(t_BVC_RESET(?, ?, ?), 0)) -> value udi { log("Rx BVC-RESET for unknown BVCI"); - /* FIXME */ + f_sendStatus(BSSGP_CAUSE_BVCI_UNKNOWN, udi.bssgp); } /* default case of handling unknown PDUs */ - [] BSCP.receive(f_BnsUdInd(?)) -> value udi { + [] BSCP.receive(f_BnsUdInd(?, ?)) -> value udi { log("Rx Unexpected BSSGP PDU ", udi.bssgp," in state ", g_ptp_bvc_state); - BSCP.send(f_BnsUdReq(t_BSSGP_STATUS({ - t_BSSGP_IE_Cause(BSSGP_CAUSE_PDU_NOT_COMPATIBLE_WITH_PROTOCOL_STATE), - t_BSSGP_IE_Bvci(mp_bvci), t_BSSGP_IE_PDU(udi.bssgp)}))); + 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(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) { - f_sendReset(); + if (g_sgsn_role == false) { + f_sendReset(); + } + /* Idea: We coudl send BVC-UNBLOCK here like some SGSN do */ } BSSGP_SP.send(nsi); } @@ -163,6 +178,9 @@ module BSSGP_Emulation { var BssgpPdu bs_pdu; var default d; + + log("matching against ", t_BVC_RESET(?, mp_bvci, mp_cellid)); + d := activate(as_allstate()); while (true) { @@ -179,26 +197,35 @@ module BSSGP_Emulation { } 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))) -> value udi { - BSCP.send(f_BnsUdReq(t_BVC_UNBLOCK_ACK(mp_bvci))); + [] 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, ?))) -> value udi { - BSCP.send(f_BnsUdReq(t_BVC_BLOCK_ACK(mp_bvci))); + [] 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))) -> value udi { + [] 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(t_BVC_RESET_ACK(mp_bvci, mp_cellid))) -> value udi { + [] BSCP.receive(f_BnsUdInd(t_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 */ + [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)); + } + /* BSSGP-UNITDATA PDUs from network to NS-UNITDATA.ind to user */ [] BSCP.receive(f_BnsUdInd(tr_BSSGP_type(DL_UNITDATA))) -> value udi { BSSGP_SP.send(udi.bssgp); diff --git a/gprs_gb/BSSGP_Types.ttcn b/gprs_gb/BSSGP_Types.ttcn index 5e4a0bc9d..aef111a7e 100644 --- a/gprs_gb/BSSGP_Types.ttcn +++ b/gprs_gb/BSSGP_Types.ttcn @@ -278,6 +278,12 @@ module BSSGP_Types { variant (len) "LENGTHTO(u)" }; + external function enc_BssgpTLV(in BssgpTLV pdu) return octetstring + with { extension "prototype(convert) encode(RAW)" }; + external function dec_BssgpTLV(in octetstring stream) return BssgpTLV + with { extension "prototype(convert) decode(RAW)" }; + + type record of BssgpTLV BssgpTLVs; /* 10.2.1 */ @@ -344,6 +350,13 @@ module BSSGP_Types { u := { bvci := bvci } } + template BssgpTLV t_BSSGP_IE_CellId(template BssgpCellId cid) := { + iei := CELL_ID, + len := 8, + u := { cell_id := cid } + } + + template BssgpTLV t_BssgpIE(template BssgpIEI iei, template BssgpIeUnion u) := { iei := iei, u := u @@ -351,7 +364,6 @@ module BSSGP_Types { template BssgpTLV t_BSSGP_IE_PDU(BssgpPdu pdu) := t_BssgpIE(PDU_IN_ERROR, { other := f_BSSGP_compact_len(enc_BssgpPdu(pdu)) }); - template BssgpTLV t_BSSGP_IE_CellId(template BssgpCellId cid) := t_BssgpIE(CELL_ID, { cell_id := cid }); template BssgpPdu t_BVC_RESET(template BssgpCause cause, template BssgpBvci bvci, template BssgpCellId cell_id) := t_BSSGP_other(BVC_RESET, { t_BSSGP_IE_Bvci(bvci), t_BSSGP_IE_Cause(cause), t_BSSGP_IE_CellId(cell_id) }); @@ -365,11 +377,16 @@ module BSSGP_Types { t_BSSGP_other(BVC_BLOCK, { t_BSSGP_IE_Bvci(bvci), t_BSSGP_IE_Cause(cause) }); template BssgpPdu t_BVC_BLOCK_ACK(template BssgpBvci bvci) := t_BSSGP_other(BVC_BLOCK_ACK, { t_BSSGP_IE_Bvci(bvci) }); - template BssgpPdu tr_BSSGP_type(template BssgpPduType pdu_type) := { + + template BssgpPdu tr_BSSGP_type(template BssgpPduType pdu_type, template BssgpPduUnion u := ?) := { pdu_type := pdu_type, - u := ? + u := u } + template BssgpPdu t_BVC_FC_BVC := t_BSSGP_other(FLOW_CONTROL_BVC, ?); + template BssgpPdu t_BVC_FC_BVC_ACK := t_BSSGP_other(FLOW_CONTROL_BVC_ACK, {}); + template BssgpPdu t_BVC_FC_MS := t_BSSGP_other(FLOW_CONTROL_MS, ?); + template BssgpPdu t_BVC_FC_MS_ACK := t_BSSGP_other(FLOW_CONTROL_MS_ACK, {}); template BssgpPdu t_BSSGP_STATUS(template BssgpTLVs tlvs) := t_BSSGP_other(STATUS, tlvs); diff --git a/gprs_gb/Test.cfg b/gprs_gb/Test.cfg new file mode 100644 index 000000000..252704fb6 --- /dev/null +++ b/gprs_gb/Test.cfg @@ -0,0 +1,27 @@ +[LOGGING] + +[MODULE_PARAMETERS] +mp_local_ip := "192.168.100.239" +mp_local_udp_port := 23000 +mp_remote_ip := "192.168.100.196" +mp_remote_udp_port := 21000 +mp_nsei := 96 + +[TESTPORT_PARAMETERS] +#*.BSCVTY.CTRL_MODE := "client" +#*.BSCVTY.CTRL_HOSTNAME := "127.0.0.1" +#*.BSCVTY.CTRL_PORTNUM := "4242" +#*.BSCVTY.CTRL_LOGIN_SKIPPED := "yes" +#*.BSCVTY.CTRL_DETECT_SERVER_DISCONNECTED := "yes" +#*.BSCVTY.CTRL_READMODE := "buffered" +#*.BSCVTY.CTRL_CLIENT_CLEANUP_LINEFEED := "yes" +#*.BSCVTY.PROMPT1 := "OpenBSC> " +#*.BSCVTY.PROMPT2 := "OpenBSC# " +#*.BSCVTY.REGEX_PROMPT1 := "^OpenBSC.*$" + +*.*.udpReuseAddress := "yes"; + +[MAIN_CONTROLLER] + +[EXECUTE] +Test.TC_nsem diff --git a/gprs_gb/Test.ttcn b/gprs_gb/Test.ttcn index dec5cda80..6e772dc08 100644 --- a/gprs_gb/Test.ttcn +++ b/gprs_gb/Test.ttcn @@ -133,8 +133,28 @@ module Test { } testcase TC_nsem() runs on dummy_CT { + timer T:= 60.0; + f_init(); - while (true) { } + T.start + alt { + [] BSSGP.receive(t_BssgpStsInd(?, ?, BVC_S_UNBLOCKED)) { } + [] BSSGP.receive { repeat; } + [] T.timeout { setverdict(fail); } + } + T.stop + log("BSSGP successfully initialized"); + + while (true) { + var BssgpPdu pdu; + alt { + [] BSSGP.receive(BssgpPdu:?) -> value pdu { + log("BSSGP Rx: ", pdu); + } + [] BSSGP.receive(t_BssgpStsInd(?, ?, BVC_S_UNBLOCKED)) { repeat; } + [] BSSGP.receive { repeat; } + } + } } control {