gprs_gb: Build stack of NS and BSSGP emulation from test component

We're already getting the NS link up and fail at the BSSGP RESET
procedure at this point.  The problem is erroneous encoding of the
message.
This commit is contained in:
Harald Welte 2017-07-23 16:19:35 +02:00
parent 1067fbd8c9
commit 6e594f217a
5 changed files with 325 additions and 81 deletions

View File

@ -28,6 +28,11 @@ module NS_CodecPort {
NsPdu msg
}
template NS_Send t_NS_Send(template ConnectionId connId, template NsPdu msg) := {
connId := connId,
msg := msg
}
private function IPL4_to_NS_RecvFrom(in ASP_RecvFrom pin, out NS_RecvFrom pout) {
pout.connId := pin.connId;
pout.remName := pin.remName;
@ -37,7 +42,7 @@ module NS_CodecPort {
pout.msg := dec_NsPdu(f_NS_expand_len(pin.msg));
} with { extension "prototype(fast)" };
private function NS_to_IPL4_Send(in NS_Send pin, out ASP_SendTo pout) {
private function NS_to_IPL4_Send(in NS_Send pin, out ASP_Send pout) {
pout.connId := pin.connId;
pout.proto := { udp := {} };
pout.msg := f_NS_compact_len(enc_NsPdu(pin.msg));
@ -48,7 +53,7 @@ module NS_CodecPort {
in NS_RecvFrom,
ASP_Event;
} with { extension "user IPL4asp_PT
out(NS_Send -> ASP_SendTo: function(NS_to_IPL4_Send))
out(NS_Send -> ASP_Send: function(NS_to_IPL4_Send))
in(ASP_RecvFrom -> NS_RecvFrom: function(IPL4_to_NS_RecvFrom);
ASP_Event -> ASP_Event: simple)"
}

View File

@ -1,39 +1,73 @@
module NS_Emulation {
import from NS_Types all;
import from BSSGP_Types all;
import from BSSGP_Helper_Functions all;
import from NS_CodecPort all;
import from NS_CodecPort_CtrlFunct all;
//import from IPL4asp_PortType all;
import from IPL4asp_Types all;
type record NsUnitdataRequest {
BssgpBvci bvci,
Nsei nsei,
octetstring sdu
octetstring sdu optional,
BssgpPdu bssgp optional
}
template NsUnitdataRequest t_NsUdReq(template Nsei nsei, template BssgpBvci bvci, template octetstring sdu,
template BssgpPdu bssgp) := {
bvci := bvci,
nsei := nsei,
sdu := sdu,
bssgp := bssgp
}
type record NsUnitdataIndication {
BssgpBvci bvci,
Nsei nsei,
octetstring sdu
octetstring sdu optional,
BssgpPdu bssgp optional
}
template NsUnitdataIndication t_NsUdInd(Nsei nsei, BssgpBvci bvci, octetstring sdu) := {
bvci := bvci,
nsei := nsei,
sdu := sdu,
bssgp := dec_BssgpPdu(f_BSSGP_expand_len(sdu))
}
type record NsStatusIndication {
Nsei nsei,
Nsvci nsvci,
NseState old_state,
NseState new_state
}
template NsStatusIndication t_NsStsInd(Nsei nsei, Nsvci nsvci, NseState old_state, NseState state) := {
nsei := nsei,
nsvci := nsvci,
old_state := old_state,
new_state := state
}
type enumerated NseState {
NSE_S_BLOCKED,
NSE_S_ALIVE,
NSE_S_RESET
};
NSE_S_DEAD_BLOCKED,
NSE_S_WAIT_RESET,
NSE_S_ALIVE_BLOCKED,
NSE_S_ALIVE_UNBLOCKED
}
/* port from our (internal) point of view */
type port NS_SP_PT message {
in NsUnitdataRequest;
out NsUnitdataIndication,
NsStatusIndication,
ASP_Event;
} with { extension "internal" };
/* port from the user point of view */
type port NS_PT message {
in ASP_Event,
NsStatusIndication,
NsUnitdataIndication;
out NsUnitdataRequest;
} with { extension "internal" };
@ -44,7 +78,13 @@ module NS_Emulation {
}
private function f_init() runs on NS_CT {
f_IPL4_connect(NSCP, remote_ip, remote_udp_port, local_ip, local_udp_port, 0, { udp := {}});
var Result res;
/* Connect the UDP socket */
res := f_IPL4_connect(NSCP, mp_remote_ip, mp_remote_udp_port, mp_local_ip, mp_local_udp_port, 0, { udp := {}});
g_conn_id := res.connId;
f_change_state(NSE_S_DEAD_BLOCKED);
/* Send the first NS-ALIVE to test the connection */
f_sendReset();
}
type component NS_CT {
@ -53,105 +93,179 @@ module NS_Emulation {
/* NS-User SAP towards the user */
port NS_SP_PT NS_SP;
var NseState state;
var ConnectionId conn_id;
var NseState g_state := NSE_S_DEAD_BLOCKED;
var ConnectionId g_conn_id := -1;
timer Tns_alive := 3.0;
timer Tns_test := 10.0;
timer Tns_block := 10.0;
}
modulepar {
PortNumber local_udp_port := 23001;
charstring local_ip := "127.0.0.1";
PortNumber remote_udp_port := 23000;
charstring remote_ip := "127.0.0.1";
PortNumber mp_local_udp_port := 23001;
charstring mp_local_ip := "127.0.0.1";
PortNumber mp_remote_udp_port := 23000;
charstring mp_remote_ip := "127.0.0.1";
Nsvci mp_nsvci := 0;
Nsvci mp_nsei := 2342;
};
template NsTLV t_NS_IE_CAUSE(template NsCause cause) := {
iei := NS_IEI_CAUSE,
len := 1,
u := { cause := cause }
};
template NsTLV t_NS_IE_NSVCI(template Nsvci nsvci) := {
iei := NS_IEI_NSVCI,
len := 2,
u := { nsvci := nsvci }
private function f_change_state(NseState new_state) runs on NS_CT {
var NseState old_state := g_state;
g_state := new_state;
log("NS State Transition: ", old_state, " -> ", new_state);
NS_SP.send(t_NsStsInd(mp_nsei, mp_nsvci, old_state, new_state));
}
template NsTLV t_NS_IE_NSEI(template Nsvci nsei) := {
iei := NS_IEI_NSEI,
len := 2,
u := { nsei := nsei }
private function f_sendReset() runs on NS_CT {
NSCP.send(t_NS_Send(g_conn_id, t_NS_RESET(NS_CAUSE_OM_INTERVENTION, mp_nsvci, mp_nsei)));
g_state := NSE_S_WAIT_RESET;
}
template NsPdu t_NS_RESET(template NsCause cause, template Nsvci nsvci, template Nsei nsei) := {
pdu_type := NS_PDUT_NS_RESET,
u := {
other := {
tlvs := { t_NS_IE_CAUSE(cause), t_NS_IE_NSVCI(nsvci), t_NS_IE_NSEI(nsei) }
}
private function f_sendAlive() runs on NS_CT {
NSCP.send(t_NS_Send(g_conn_id, t_NS_ALIVE));
Tns_alive.start;
}
private function f_sendUnblock() runs on NS_CT {
NSCP.send(t_NS_Send(g_conn_id, t_NS_UNBLOCK));
Tns_block.start;
}
private function f_sendBlock(NsCause cause) runs on NS_CT {
NSCP.send(t_NS_Send(g_conn_id, t_NS_BLOCK(cause, mp_nsvci)));
Tns_block.start;
}
altstep as_allstate() runs on NS_CT {
var NS_RecvFrom rf;
var ASP_Event evt;
/* transition to DEAD if t_alive times out */
[] Tns_alive.timeout {
log("Tns-alive expired: changing to DEAD_BLOCKED + starting Tns-test");
f_change_state(NSE_S_DEAD_BLOCKED);
Tns_test.start;
}
};
template NsPdu t_NS_RESET_ACK(template Nsvci nsvci, template Nsei nsei) := {
pdu_type := NS_PDUT_NS_RESET,
u := {
other := {
tlvs := { t_NS_IE_NSVCI(nsvci), t_NS_IE_NSEI(nsei) }
}
[] Tns_test.timeout {
log("Tns-test expired: sending NS-ALIVE");
f_sendAlive();
}
};
template NsPdu t_NS_SIMPLE(template NsPduType pdut) := { pdu_type := pdut, u := { other := { tlvs := {} } } };
template NsPdu t_NS_ALIVE := t_NS_SIMPLE(NS_PDUT_NS_ALIVE);
template NsPdu t_NS_ALIVE_ACK := t_NS_SIMPLE(NS_PDUT_NS_ALIVE_ACK);
template NsPdu t_NS_UNBLOCK := t_NS_SIMPLE(NS_PDUT_NS_UNBLOCK);
template NsPdu t_NS_UNBLOCK_ACK := t_NS_SIMPLE(NS_PDUT_NS_UNBLOCK_ACK);
template NsPdu t_NS_BLOCK := t_NS_SIMPLE(NS_PDUT_NS_BLOCK);
template NsPdu t_NS_BLOCK_ACK := t_NS_SIMPLE(NS_PDUT_NS_BLOCK_ACK);
/* Stop t_alive when receiving ALIVE-ACK */
[] NSCP.receive(t_NS_RecvFrom(t_NS_ALIVE_ACK)) {
log("NS-ALIVE-ACK received: stopping Tns-alive; starting Tns-test");
Tns_alive.stop;
Tns_test.start;
}
template NS_Send t_NS_Send(template ConnectionId connId, template NsPdu msg) := {
connId := connId,
msg := msg
/* respond to NS-ALIVE with NS-ALIVE-ACK */
[] NSCP.receive(t_NS_RecvFrom(t_NS_ALIVE)) {
NSCP.send(t_NS_Send(g_conn_id, t_NS_ALIVE_ACK));
}
/* Respond to BLOCK for wrong NSVCI */
[] NSCP.receive(t_NS_RecvFrom(t_NS_BLOCK(?, ?))) -> value rf {
log("Rx NS-BLOCK for unknown NSVCI");
/* FIXME */
}
/* Respond to RESET with correct NSEI/NSVCI */
[] NSCP.receive(t_NS_RecvFrom(t_NS_RESET(?, mp_nsvci, mp_nsei))) -> value rf {
f_change_state(NSE_S_ALIVE_BLOCKED);
NSCP.send(t_NS_Send(g_conn_id, t_NS_RESET_ACK(mp_nsvci, mp_nsei)));
}
/* Respond to RESET with wrong NSEI/NSVCI */
[] NSCP.receive(t_NS_RecvFrom(t_NS_RESET(?, ?, ?))) -> value rf {
log("Rx NS-RESET for unknown NSEI/NSVCI");
/* FIXME */
}
/* default case of handling unknown PDUs */
[] NSCP.receive(t_NS_RecvFrom(?)) -> value rf {
log("Rx Unexpected NS PDU ", rf.msg," in state ", g_state);
NSCP.send(t_NS_Send(g_conn_id, t_NS_STATUS(NS_CAUSE_PDU_NOT_COMPATIBLE_WITH_PROTOCOL_STATE, rf.msg)));
}
/* Forwarding of ASP_Evet to user */
[] NSCP.receive(ASP_Event:?) -> value evt { NS_SP.send(evt); }
}
private function f_ScanEvents() runs on NS_CT {
var NsUnitdataRequest ud_req;
var NS_RecvFrom rf;
var ASP_Event evt;
var default d;
d := activate(as_allstate());
while (true) {
if (state == NSE_S_BLOCKED) {
if (g_state == NSE_S_DEAD_BLOCKED) {
alt {
[] NSCP.receive(t_NS_RecvFrom(t_NS_BLOCK)) -> value rf {
NSCP.send(t_NS_Send(conn_id, t_NS_BLOCK_ACK));
}
[] NSCP.receive(t_NS_RecvFrom(t_NS_UNBLOCK)) -> value rf {
NSCP.send(t_NS_Send(conn_id, t_NS_UNBLOCK_ACK));
state := NSE_S_ALIVE;
}
[] NSCP.receive(ASP_Event:?) -> value evt { NS_SP.send(evt); }
[false] any timer.timeout {}
}
} else if (state == NSE_S_ALIVE) {
} else if (g_state == NSE_S_WAIT_RESET) {
alt {
[] NSCP.receive(t_NS_RecvFrom(t_NS_BLOCK)) -> value rf {
NSCP.send(t_NS_Send(conn_id, t_NS_BLOCK_ACK));
state := NSE_S_BLOCKED;
[] NSCP.receive(t_NS_RecvFrom(t_NS_RESET_ACK(mp_nsvci, mp_nsei))) -> value rf {
f_change_state(NSE_S_ALIVE_BLOCKED);
f_sendAlive();
f_sendUnblock();
}
[] NSCP.receive(t_NS_RecvFrom(t_NS_UNBLOCK)) -> value rf {
NSCP.send(t_NS_Send(conn_id, t_NS_UNBLOCK_ACK));
}
[] NS_SP.receive(NsUnitdataRequest:?) -> value ud_req {
//NSCP.send(t_NS_Send(
}
[] NSCP.receive(ASP_Event:?) -> value evt { NS_SP.send(evt); }
}
} else if (state == NSE_S_RESET) {
} else if (g_state == NSE_S_ALIVE_BLOCKED) {
alt {
[] NSCP.receive(ASP_Event:?) -> value evt { NS_SP.send(evt); }
/* bogus block, just respond with ACK */
[] NSCP.receive(t_NS_RecvFrom(t_NS_BLOCK(?, mp_nsvci))) -> value rf {
NSCP.send(t_NS_Send(g_conn_id, t_NS_BLOCK_ACK(mp_nsvci)));
}
/* Respond to UNBLOCK with UNBLOCK-ACK + change state */
[] NSCP.receive(t_NS_RecvFrom(t_NS_UNBLOCK)) -> value rf {
NSCP.send(t_NS_Send(g_conn_id, t_NS_UNBLOCK_ACK));
Tns_block.stop;
f_change_state(NSE_S_ALIVE_UNBLOCKED);
}
[] NSCP.receive(t_NS_RecvFrom(t_NS_UNBLOCK_ACK)) -> value rf {
Tns_block.stop;
f_change_state(NSE_S_ALIVE_UNBLOCKED);
}
[] Tns_block.timeout {
/* repeat unblock transmission */
f_sendUnblock();
}
}
} else if (g_state == NSE_S_ALIVE_UNBLOCKED) {
alt {
/* bogus unblock, just respond with ACK */
[] NSCP.receive(t_NS_RecvFrom(t_NS_UNBLOCK)) -> value rf {
NSCP.send(t_NS_Send(g_conn_id, t_NS_UNBLOCK_ACK));
}
/* Respond to BLOCK with BLOCK-ACK + change state */
[] NSCP.receive(t_NS_RecvFrom(t_NS_BLOCK(?, mp_nsvci))) -> value rf {
NSCP.send(t_NS_Send(g_conn_id, t_NS_BLOCK_ACK(mp_nsvci)));
Tns_block.stop;
f_change_state(NSE_S_ALIVE_BLOCKED);
}
[] NSCP.receive(t_NS_RecvFrom(t_NS_BLOCK_ACK(mp_nsvci))) -> value rf {
Tns_block.stop;
}
/* NS-UNITDATA PDU from network to NS-UNITDATA.ind to user */
[] NSCP.receive(t_NS_RecvFrom(t_NS_UNITDATA(?, ?, ?))) -> value rf {
NS_SP.send(t_NsUdInd(mp_nsei, rf.msg.u.unitdata.bvci, rf.msg.u.unitdata.sdu));
}
/* NS-UNITDATA.req from user to NS-UNITDATA PDU on network */
[] NS_SP.receive(t_NsUdReq(mp_nsei, ?, ?, omit)) -> value ud_req {
/* using raw octetstring PDU */
NSCP.send(t_NS_Send(g_conn_id, t_NS_UNITDATA(t_SduCtrlB, ud_req.bvci, ud_req.sdu)));
}
[] NS_SP.receive(t_NsUdReq(mp_nsei, ?, omit, ?)) -> value ud_req {
/* using decoded BSSGP PDU that we need to encode first */
var octetstring enc := f_BSSGP_compact_len(enc_BssgpPdu(ud_req.bssgp));
NSCP.send(t_NS_Send(g_conn_id, t_NS_UNITDATA(t_SduCtrlB, ud_req.bvci, enc)));
}
}
}
}
} /* while */
//deactivate(d);
}
}

View File

@ -3,6 +3,7 @@ module NS_Types {
import from Osmocom_Types all;
import from GSM_Types all;
import from BSSGP_Types all;
import from BSSGP_Helper_Functions all;
/* TS 48.016 10.3.7 */
type enumerated NsPduType {
@ -66,6 +67,12 @@ module NS_Types {
variant (r) "FIELDLENGTH(1)"
};
template NsSduControlBits t_SduCtrlB := {
spare := '000000'B,
c := false,
r := false
}
type uint16_t Nsvci;
type uint16_t Nsei;
@ -127,4 +134,97 @@ module NS_Types {
external function dec_NsPdu(in octetstring stream) return NsPdu
with { extension "prototype(convert) decode(RAW)" };
template NsTLV t_NS_IE_CAUSE(template NsCause cause) := {
iei := NS_IEI_CAUSE,
len := 1,
u := { cause := cause }
};
template NsTLV t_NS_IE_NSVCI(template Nsvci nsvci) := {
iei := NS_IEI_NSVCI,
len := 2,
u := { nsvci := nsvci }
}
template NsTLV t_NS_IE_NSEI(template Nsvci nsei) := {
iei := NS_IEI_NSEI,
len := 2,
u := { nsei := nsei }
}
template NsTLV t_NsIE(NsIEI iei, NsIeUnion u) := {
iei := iei,
u := u
}
template NsTLV t_NsIE_other(NsIEI iei, octetstring val) := {
iei := iei,
len := lengthof(val),
u := { other := val }
}
template NsPdu t_NS_RESET(template NsCause cause, template Nsvci nsvci, template Nsei nsei) := {
pdu_type := NS_PDUT_NS_RESET,
u := {
other := {
tlvs := { t_NS_IE_CAUSE(cause), t_NS_IE_NSVCI(nsvci), t_NS_IE_NSEI(nsei) }
}
}
};
template NsPdu t_NS_RESET_ACK(template Nsvci nsvci, template Nsei nsei) := {
pdu_type := NS_PDUT_NS_RESET_ACK,
u := {
other := {
tlvs := { t_NS_IE_NSVCI(nsvci), t_NS_IE_NSEI(nsei) }
}
}
};
template NsPdu t_NS_BLOCK(template NsCause cause, template Nsvci nsvci) := {
pdu_type := NS_PDUT_NS_BLOCK,
u := {
other := {
tlvs := { t_NS_IE_CAUSE(cause), t_NS_IE_NSVCI(nsvci) }
}
}
}
template NsPdu t_NS_BLOCK_ACK(template Nsvci nsvci) := {
pdu_type := NS_PDUT_NS_BLOCK_ACK,
u := {
other := {
tlvs := { t_NS_IE_NSVCI(nsvci) }
}
}
}
template NsPdu t_NsPduSimple(template NsPduType pdut) := { pdu_type := pdut, u := { other := { tlvs := omit } } };
template NsPdu t_NS_ALIVE := t_NsPduSimple(NS_PDUT_NS_ALIVE);
template NsPdu t_NS_ALIVE_ACK := t_NsPduSimple(NS_PDUT_NS_ALIVE_ACK);
template NsPdu t_NS_UNBLOCK := t_NsPduSimple(NS_PDUT_NS_UNBLOCK);
template NsPdu t_NS_UNBLOCK_ACK := t_NsPduSimple(NS_PDUT_NS_UNBLOCK_ACK);
template NsPdu t_NS_STATUS(NsCause cause, NsPdu pdu) := {
pdu_type := NS_PDUT_NS_STATUS,
u := {
other := {
tlvs := { t_NS_IE_CAUSE(cause), t_NsIE_other(NS_IEI_NS_PDU, f_NS_compact_len(enc_NsPdu(pdu))) }
}
}
}
template NsPdu t_NS_UNITDATA(template NsSduControlBits bits, template BssgpBvci bvci, template octetstring sdu) := {
pdu_type := NS_PDUT_NS_UNITDATA,
u := {
unitdata := {
control_bits := bits,
bvci := bvci,
sdu := sdu
}
}
}
} with { encode "RAW" };

View File

@ -2,9 +2,28 @@ module Test {
import from BSSGP_Helper_Functions all;
import from BSSGP_Types all;
import from BSSGP_Emulation all;
import from NS_Types all;
import from NS_Emulation all;
type component dummy_CT {
port BSSGP_PT BSSGP;
var NS_CT ns_component;
var BSSGP_CT bssgp_component;
}
function f_init() runs on dummy_CT {
/* create a new NS component */
ns_component := NS_CT.create;
bssgp_component := BSSGP_CT.create;
/* connect our BSSGP port to the BSSGP Emulation */
connect(self:BSSGP, bssgp_component:BSSGP_SP);
/* connect lower-end of BSSGP with BSSGP_CODEC_PORT (maps to NS_PT*/
connect(bssgp_component:BSCP, ns_component:NS_SP);
/* connect lower-end of NS emulation to NS_CODEC_PORT (on top of IPl4) */
map(ns_component:NSCP, system:NS_CODEC_PORT);
ns_component.start(NSStart());
bssgp_component.start(BssgpStart());
}
function f_bssgp_assert_prepr(in octetstring a, in octetstring b) {
@ -113,8 +132,14 @@ module Test {
f_ns_dec_and_log(c_ns_reset_pcu);
}
testcase TC_nsem() runs on dummy_CT {
f_init();
while (true) { }
}
control {
execute(TC_selftest_bssgp());
execute(TC_selftest_ns());
execute(TC_nsem());
}
};

View File

@ -5,5 +5,5 @@ FILES="*.ttcn BSSGP_Helper.cc IPL4asp_PT.cc IPL4asp_discovery.cc TCCConversion.c
ttcn3_makefilegen -f Test.ttcn $FILES
sed -i -e 's/# TTCN3_DIR = /TTCN3_DIR = \/usr/' Makefile
sed -i -e 's/LDFLAGS = /LDFLAGS = -L \/usr\/lib\/titan `pkg-config --libs libnetfilter_conntrack`/' Makefile
sed -i -e 's/TTCN3_LIB = ttcn3-parallel/TTCN3_LIB = ttcn3/' Makefile
#sed -i -e 's/TTCN3_LIB = ttcn3-parallel/TTCN3_LIB = ttcn3/' Makefile
sed -i -e 's/CPPFLAGS = -D$(PLATFORM) -I$(TTCN3_DIR)\/include/CPPFLAGS = -D$(PLATFORM) -I$(TTCN3_DIR)\/include -I\/usr\/include\/titan/' Makefile