248 lines
7.2 KiB
Plaintext
248 lines
7.2 KiB
Plaintext
module BSSGP_Emulation {
|
|
import from NS_Types all;
|
|
import from NS_Emulation all;
|
|
import from BSSGP_Types all;
|
|
import from BSSGP_Helper_Functions all;
|
|
import from IPL4asp_Types all;
|
|
|
|
type record BssgpStatusIndication {
|
|
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
|
|
}
|
|
|
|
type enumerated BvcState {
|
|
BVC_S_BLOCKED,
|
|
BVC_S_UNBLOCKED
|
|
};
|
|
|
|
/* port from our (internal) point of view */
|
|
type port BSSGP_SP_PT message {
|
|
in BssgpPdu;
|
|
out BssgpPdu,
|
|
NsStatusIndication,
|
|
BssgpStatusIndication,
|
|
ASP_Event;
|
|
} with { extension "internal" };
|
|
|
|
/* port from the user point of view */
|
|
type port BSSGP_PT message {
|
|
in ASP_Event,
|
|
NsStatusIndication,
|
|
BssgpStatusIndication,
|
|
BssgpPdu;
|
|
out BssgpPdu;
|
|
} with { extension "internal" };
|
|
|
|
function BssgpStart() runs on BSSGP_CT {
|
|
f_init();
|
|
f_ScanEvents();
|
|
}
|
|
|
|
private function f_init() runs on BSSGP_CT {
|
|
/* Connect the UDP socket */
|
|
f_change_state(BVC_S_BLOCKED);
|
|
}
|
|
|
|
type component BSSGP_CT {
|
|
/* UDP port towards the bottom (IUT) */
|
|
port NS_PT BSCP;
|
|
/* 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 := 96;
|
|
Nsvci mp_bvci := 196;
|
|
BssgpCellId mp_cellid := { ra_id := { lai := { mcc_mnc := '262F42'H, lac := 13135}, rac := 0 }, cell_id := 20960 };
|
|
};
|
|
|
|
function f_BnsUdReq(template BssgpPdu pdu, BssgpBvci bvci := mp_bvci) return NsUnitdataRequest {
|
|
var NsUnitdataRequest udr := {
|
|
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 */
|
|
//sdu := omit,
|
|
//bssgp := valueof(pdu)
|
|
sdu := f_BSSGP_compact_len(enc_BssgpPdu(valueof(pdu))),
|
|
bssgp := omit
|
|
}
|
|
return udr;
|
|
}
|
|
|
|
function f_BnsUdInd(template BssgpPdu pdu, template BssgpBvci bvci := mp_bvci) return template NsUnitdataIndication {
|
|
var template NsUnitdataIndication udi := {
|
|
bvci := bvci,
|
|
nsei := mp_nsei,
|
|
sdu := *,
|
|
bssgp := pdu
|
|
}
|
|
return udi;
|
|
}
|
|
|
|
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));
|
|
}
|
|
|
|
private function f_sendReset() runs on BSSGP_CT {
|
|
var BssgpPdu pdu := valueof(t_BVC_RESET(BSSGP_CAUSE_OM_INTERVENTION, mp_bvci, mp_cellid));
|
|
log("PDU: ", pdu);
|
|
log("ENC: ", enc_BssgpPdu(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), 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));
|
|
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(?, ?), 0)) -> value udi {
|
|
log("Rx BVC-BLOCK for unknown BVCI");
|
|
f_sendStatus(BSSGP_CAUSE_BVCI_UNKNOWN, udi.bssgp);
|
|
}
|
|
|
|
/* 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);
|
|
}
|
|
|
|
/* 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(?, ?, ?), 0)) -> value udi {
|
|
log("Rx BVC-RESET for unknown BVCI");
|
|
f_sendStatus(BSSGP_CAUSE_BVCI_UNKNOWN, udi.bssgp);
|
|
}
|
|
|
|
/* default case of handling unknown PDUs */
|
|
[] BSCP.receive(f_BnsUdInd(?, ?)) -> value udi {
|
|
log("Rx Unexpected BSSGP PDU ", udi.bssgp," in state ", g_ptp_bvc_state);
|
|
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) {
|
|
if (g_sgsn_role == false) {
|
|
f_sendReset();
|
|
}
|
|
/* Idea: We coudl send BVC-UNBLOCK here like some SGSN do */
|
|
}
|
|
BSSGP_SP.send(nsi);
|
|
}
|
|
}
|
|
|
|
private function f_ScanEvents() runs on BSSGP_CT {
|
|
var NsUnitdataIndication udi;
|
|
var BssgpPdu bs_pdu;
|
|
var default d;
|
|
|
|
|
|
log("matching against ", t_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))) {
|
|
g_T1.stop;
|
|
f_change_state(BVC_S_UNBLOCKED);
|
|
}
|
|
}
|
|
} 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(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);
|
|
}
|
|
[] BSCP.receive(f_BnsUdInd(tr_BSSGP_type(UL_UNITDATA))) -> value udi {
|
|
BSSGP_SP.send(udi.bssgp);
|
|
}
|
|
/* pass virtually any PDU from user to NS-UNITDATA PDU on network */
|
|
[] BSSGP_SP.receive(BssgpPdu:?) -> value bs_pdu {
|
|
BSCP.send(f_BnsUdReq(bs_pdu));
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
} /* while */
|
|
//deactivate(d);
|
|
}
|
|
}
|