From 867243a3ec2389fa67ab2b132dca1240abdf1913 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 13 Sep 2020 18:32:32 +0200 Subject: NS_Emulation: Add [optional] support for FrameRelay transport This adds a NS_Provider_FR which interfaces between FrameRelay_Emulation and NS_Emulation. Include support for it only if enabled at compile time to avoid pulling in a dependency on the FrameRelay stack for every user of NS_Emulation. Change-Id: I42ca811d23e383e362d2527c8ff2c916a62a5b42 --- library/NS_Emulation.ttcn | 353 ----------------------------------------- library/NS_Emulation.ttcnpp | 372 ++++++++++++++++++++++++++++++++++++++++++++ library/NS_Provider_FR.ttcn | 67 ++++++++ pcu/gen_links.sh | 2 +- sgsn/gen_links.sh | 2 +- 5 files changed, 441 insertions(+), 355 deletions(-) delete mode 100644 library/NS_Emulation.ttcn create mode 100644 library/NS_Emulation.ttcnpp create mode 100644 library/NS_Provider_FR.ttcn diff --git a/library/NS_Emulation.ttcn b/library/NS_Emulation.ttcn deleted file mode 100644 index a0b24c9c..00000000 --- a/library/NS_Emulation.ttcn +++ /dev/null @@ -1,353 +0,0 @@ -/* GPRS-NS Emulation in TTCN-3 - * (C) 2018-2020 Harald Welte - * contributions by sysmocom - s.f.m.c. GmbH - * All rights reserved. - * - * Released under the terms of GNU General Public License, Version 2 or - * (at your option) any later version. - * - * SPDX-License-Identifier: GPL-2.0-or-later - */ - -module NS_Emulation { - import from NS_Types all; - import from BSSGP_Types all; - import from Osmocom_Gb_Types all; - import from NS_Provider_IPL4 all; - import from Osmocom_Types all; - import from IPL4asp_Types all; - - type record NsUnitdataRequest { - BssgpBvci bvci, - Nsei nsei, - octetstring sdu optional, - PDU_BSSGP bssgp optional - } - - template NsUnitdataRequest t_NsUdReq(template Nsei nsei, template BssgpBvci bvci, template octetstring sdu, - template PDU_BSSGP bssgp) := { - bvci := bvci, - nsei := nsei, - sdu := sdu, - bssgp := bssgp - } - - type record NsUnitdataIndication { - BssgpBvci bvci, - Nsei nsei, - octetstring sdu optional, - PDU_BSSGP bssgp optional - } - - template NsUnitdataIndication t_NsUdInd(Nsei nsei, BssgpBvci bvci, octetstring sdu) := { - bvci := bvci, - nsei := nsei, - sdu := sdu, - bssgp := dec_PDU_BSSGP(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_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; - } 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" }; - - function NSStart(NSConfiguration init_config) runs on NS_CT { - config := init_config; - f_init(); - f_ScanEvents(); - } - - private function f_init() runs on NS_CT { - var Result res; - - /* Connect the UDP socket */ - vc_NSP_IP := NS_Provider_IPL4_CT.create; - connect(self:NSCP, vc_NSP_IP:NSE); - vc_NSP_IP.start(NS_Provider_IPL4.main(config)); - - f_change_state(NSE_S_DEAD_BLOCKED); - /* Send the first NS-ALIVE to test the connection */ - if (not config.role_sgsn) { - f_sendReset(); - } - } - - type component NS_Provider_CT { - /* upper port, facing to NS_Emulation:NSCP */ - port NS_PROVIDER_PT NSE; - /* lower layer ports (UDP/IP, Frame Relay) are added in derived components */ - }; - - /* port between NS_Provider and NS_CT */ - type port NS_PROVIDER_PT message { - inout PDU_NS; - } with { extension "internal" }; - - type component NS_CT { - /* UDP port towards the bottom (IUT) */ - port NS_PROVIDER_PT NSCP; - var NS_Provider_IPL4_CT vc_NSP_IP; - - /* NS-User SAP towards the user */ - port NS_SP_PT NS_SP; - - var NSConfiguration config; - - var NseState g_state := NSE_S_DEAD_BLOCKED; - - timer Tns_alive := 3.0; - timer Tns_test := 10.0; - timer Tns_block := 10.0; - } - - type record NSConfigurationIP { - AddressFamily address_family, - PortNumber local_udp_port, - charstring local_ip, - PortNumber remote_udp_port, - charstring remote_ip - }; - type union NSConfigurationP { - NSConfigurationIP ip - }; - type record NSConfiguration { - NSConfigurationP provider, - Nsvci nsvci, - Nsvci nsei, - boolean role_sgsn, - boolean handle_sns - } - - 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(config.nsei, config.nsvci, old_state, new_state)); - } - - private function f_sendReset() runs on NS_CT { - NSCP.send(ts_NS_RESET(NS_CAUSE_OM_INTERVENTION, config.nsvci, config.nsei)); - g_state := NSE_S_WAIT_RESET; - } - - private function f_sendAlive() runs on NS_CT { - NSCP.send(t_NS_ALIVE); - Tns_alive.start; - } - - private function f_sendUnblock() runs on NS_CT { - NSCP.send(t_NS_UNBLOCK); - Tns_block.start; - } - - private function f_sendBlock(NsCause cause) runs on NS_CT { - NSCP.send(ts_NS_BLOCK(cause, config.nsvci)); - Tns_block.start; - } - - altstep as_allstate() runs on NS_CT { - var PDU_NS 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; - } - - [] Tns_test.timeout { - log("Tns-test expired: sending NS-ALIVE"); - f_sendAlive(); - } - - /* Stop t_alive when receiving ALIVE-ACK */ - [Tns_alive.running] NSCP.receive(t_NS_ALIVE_ACK) { - log("NS-ALIVE-ACK received: stopping Tns-alive; starting Tns-test"); - Tns_alive.stop; - Tns_test.start; - } - - /* respond to NS-ALIVE with NS-ALIVE-ACK */ - [] NSCP.receive(t_NS_ALIVE) { - NSCP.send(t_NS_ALIVE_ACK); - } - - /* Respond to BLOCK for wrong NSVCI */ - [] NSCP.receive(tr_NS_BLOCK(?, ?)) -> value rf { - log("Rx NS-BLOCK for unknown NSVCI"); - /* FIXME */ - } - - /* Respond to RESET with correct NSEI/NSVCI */ - [] NSCP.receive(tr_NS_RESET(?, config.nsvci, config.nsei)) -> value rf { - f_change_state(NSE_S_ALIVE_BLOCKED); - NSCP.send(ts_NS_RESET_ACK(config.nsvci, config.nsei)); - } - - /* Respond to RESET with wrong NSEI/NSVCI */ - [] NSCP.receive(tr_NS_RESET(?, ?, ?)) -> value rf { - log("Rx NS-RESET for unknown NSEI/NSVCI"); - /* FIXME */ - } - - [config.role_sgsn and config.handle_sns and ischosen(config.provider.ip)] as_sns_sgsn(); - - /* default case of handling unknown PDUs */ - [] NSCP.receive(PDU_NS: ?) -> value rf { - log("Rx Unexpected NS PDU ", rf," in state ", g_state); - NSCP.send(ts_NS_STATUS(NS_CAUSE_PDU_NOT_COMPATIBLE_WITH_PROTOCOL_STATE, rf)); - } - } - - /* simple IP Sub-Network Service responder for the SGSN side. This is not a full implementation - * of the protocol, merely sufficient to make the PCU/BSS side happy to proceed */ - altstep as_sns_sgsn() runs on NS_CT { - var PDU_NS rf; - [] NSCP.receive(tr_SNS_SIZE(config.nsei)) -> value rf { - /* blindly acknowledge whatever the PCU sends */ - NSCP.send(ts_SNS_SIZE_ACK(config.nsei, omit)); - } - [] NSCP.receive(tr_SNS_SIZE(?)) { - setverdict(fail, "SNS-SIZE from unexpected NSEI"); - self.stop; - } - [] NSCP.receive(tr_SNS_CONFIG(config.nsei, true, - {tr_SNS_IPv4(config.provider.ip.remote_ip, - config.provider.ip.remote_udp_port)})) -> value rf { - /* blindly acknowledge whatever the PCU sends */ - NSCP.send(ts_SNS_CONFIG_ACK(config.nsei, omit)); - /* send a SNS-CONFIG in response and expect a SNS-CONFIG-ACK */ - var IP4_Elements v4 := { valueof(ts_SNS_IPv4(config.provider.ip.local_ip, config.provider.ip.local_udp_port)) }; - NSCP.send(ts_SNS_CONFIG(config.nsei, true, v4)); - alt { - [] NSCP.receive(tr_SNS_CONFIG_ACK(config.nsei, omit)) { - /* success */ - } - [] NSCP.receive(tr_SNS_CONFIG_ACK(config.nsei, ?)) { - setverdict(fail, "Unexpected SNS-CONFIG-NACK"); - self.stop; - } - } - } - [] NSCP.receive(tr_SNS_CONFIG(config.nsei, false, ?)) { /* ignore */} - [] NSCP.receive(tr_SNS_CONFIG(config.nsei, true, ?)) { - setverdict(fail, "Unexpected SNS-CONFIG content"); - self.stop; - } - [] NSCP.receive(tr_SNS_CONFIG(?, ?, ?)) { - setverdict(fail, "SNS-CONFIG from unexpected NSEI"); - self.stop; - } - } - - private function f_ScanEvents() runs on NS_CT { - var NsUnitdataRequest ud_req; - var PDU_NS rf; - var default d; - - d := activate(as_allstate()); - - while (true) { - if (g_state == NSE_S_DEAD_BLOCKED) { - alt { - [false] any timer.timeout {} - } - } else if (g_state == NSE_S_WAIT_RESET) { - alt { - [] NSCP.receive(tr_NS_RESET_ACK(config.nsvci, config.nsei)) -> value rf { - f_change_state(NSE_S_ALIVE_BLOCKED); - f_sendAlive(); - f_sendUnblock(); - } - } - } else if (g_state == NSE_S_ALIVE_BLOCKED) { - alt { - /* bogus block, just respond with ACK */ - [] NSCP.receive(tr_NS_BLOCK(?, config.nsvci)) -> value rf { - NSCP.send(ts_NS_BLOCK_ACK(config.nsvci)); - } - /* Respond to UNBLOCK with UNBLOCK-ACK + change state */ - [] NSCP.receive(t_NS_UNBLOCK) -> value rf { - NSCP.send(t_NS_UNBLOCK_ACK); - Tns_block.stop; - f_change_state(NSE_S_ALIVE_UNBLOCKED); - } - [] NSCP.receive(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_UNBLOCK) -> value rf { - NSCP.send(t_NS_UNBLOCK_ACK); - } - /* Respond to BLOCK with BLOCK-ACK + change state */ - [] NSCP.receive(tr_NS_BLOCK(?, config.nsvci)) -> value rf { - NSCP.send(ts_NS_BLOCK_ACK(config.nsvci)); - Tns_block.stop; - f_change_state(NSE_S_ALIVE_BLOCKED); - } - [] NSCP.receive(tr_NS_BLOCK_ACK(config.nsvci)) -> value rf { - Tns_block.stop; - } - /* NS-UNITDATA PDU from network to NS-UNITDATA.ind to user */ - [] NSCP.receive(tr_NS_UNITDATA(?, ?, ?)) -> value rf { - NS_SP.send(t_NsUdInd(config.nsei, - oct2int(rf.pDU_NS_Unitdata.bVCI), - rf.pDU_NS_Unitdata.nS_SDU)); - } - /* NS-UNITDATA.req from user to NS-UNITDATA PDU on network */ - [] NS_SP.receive(t_NsUdReq(config.nsei, ?, ?, omit)) -> value ud_req { - /* using raw octetstring PDU */ - NSCP.send(ts_NS_UNITDATA(t_SduCtrlB, ud_req.bvci, ud_req.sdu)); - } - [] NS_SP.receive(t_NsUdReq(config.nsei, ?, omit, ?)) -> value ud_req { - /* using decoded BSSGP PDU that we need to encode first */ - var octetstring enc := enc_PDU_BSSGP(ud_req.bssgp); - NSCP.send(ts_NS_UNITDATA(t_SduCtrlB, ud_req.bvci, enc)); - } - } - } - - } /* while */ - //deactivate(d); - } -} diff --git a/library/NS_Emulation.ttcnpp b/library/NS_Emulation.ttcnpp new file mode 100644 index 00000000..32746b41 --- /dev/null +++ b/library/NS_Emulation.ttcnpp @@ -0,0 +1,372 @@ +/* GPRS-NS Emulation in TTCN-3 + * (C) 2018-2020 Harald Welte + * contributions by sysmocom - s.f.m.c. GmbH + * All rights reserved. + * + * Released under the terms of GNU General Public License, Version 2 or + * (at your option) any later version. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +module NS_Emulation { + import from NS_Types all; + import from BSSGP_Types all; + import from Osmocom_Types all; + import from Osmocom_Gb_Types all; + import from NS_Provider_IPL4 all; +#ifdef NS_EMULATION_FR + import from NS_Provider_FR all; +#endif + import from IPL4asp_Types all; + + type record NsUnitdataRequest { + BssgpBvci bvci, + Nsei nsei, + octetstring sdu optional, + PDU_BSSGP bssgp optional + } + + template NsUnitdataRequest t_NsUdReq(template Nsei nsei, template BssgpBvci bvci, template octetstring sdu, + template PDU_BSSGP bssgp) := { + bvci := bvci, + nsei := nsei, + sdu := sdu, + bssgp := bssgp + } + + type record NsUnitdataIndication { + BssgpBvci bvci, + Nsei nsei, + octetstring sdu optional, + PDU_BSSGP bssgp optional + } + + template NsUnitdataIndication t_NsUdInd(Nsei nsei, BssgpBvci bvci, octetstring sdu) := { + bvci := bvci, + nsei := nsei, + sdu := sdu, + bssgp := dec_PDU_BSSGP(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_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; + } 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" }; + + function NSStart(NSConfiguration init_config) runs on NS_CT { + config := init_config; + f_init(); + f_ScanEvents(); + } + + private function f_init() runs on NS_CT { + var Result res; + + if (ischosen(config.provider.ip)) { + /* Connect the UDP socket */ + vc_NSP_IP := NS_Provider_IPL4_CT.create; + connect(self:NSCP, vc_NSP_IP:NSE); + vc_NSP_IP.start(NS_Provider_IPL4.main(config)); +#ifdef NS_EMULATION_FR + } else if (ischosen(config.provider.fr)) { + vc_NSP_FR := NS_Provider_FR_CT.create; + connect(self:NSCP, vc_NSP_FR:NSE); + vc_NSP_FR.start(NS_Provider_FR.main(config)); +#endif + } + + f_change_state(NSE_S_DEAD_BLOCKED); + /* Send the first NS-ALIVE to test the connection */ + if (not config.role_sgsn) { + f_sendReset(); + } + } + + type component NS_Provider_CT { + /* upper port, facing to NS_Emulation:NSCP */ + port NS_PROVIDER_PT NSE; + /* lower layer ports (UDP/IP, Frame Relay) are added in derived components */ + }; + + /* port between NS_Provider and NS_CT */ + type port NS_PROVIDER_PT message { + inout PDU_NS; + } with { extension "internal" }; + + type component NS_CT { + /* UDP port towards the bottom (IUT) */ + port NS_PROVIDER_PT NSCP; + var NS_Provider_IPL4_CT vc_NSP_IP; +#ifdef NS_EMULATION_FR + var NS_Provider_FR_CT vc_NSP_FR; +#endif + + /* NS-User SAP towards the user */ + port NS_SP_PT NS_SP; + + var NSConfiguration config; + + var NseState g_state := NSE_S_DEAD_BLOCKED; + + timer Tns_alive := 3.0; + timer Tns_test := 10.0; + timer Tns_block := 10.0; + } + + type record NSConfigurationIP { + AddressFamily address_family, + PortNumber local_udp_port, + charstring local_ip, + PortNumber remote_udp_port, + charstring remote_ip + }; + type record NSConfigurationFR { + charstring netdev, /* HDLC net-device for AF_PACKET socket */ + integer dlci + }; + type union NSConfigurationP { + NSConfigurationIP ip, + NSConfigurationFR fr + }; + type record NSConfiguration { + NSConfigurationP provider, + Nsvci nsvci, + Nsvci nsei, + boolean role_sgsn, + boolean handle_sns + } + + 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(config.nsei, config.nsvci, old_state, new_state)); + } + + private function f_sendReset() runs on NS_CT { + NSCP.send(ts_NS_RESET(NS_CAUSE_OM_INTERVENTION, config.nsvci, config.nsei)); + g_state := NSE_S_WAIT_RESET; + } + + private function f_sendAlive() runs on NS_CT { + NSCP.send(t_NS_ALIVE); + Tns_alive.start; + } + + private function f_sendUnblock() runs on NS_CT { + NSCP.send(t_NS_UNBLOCK); + Tns_block.start; + } + + private function f_sendBlock(NsCause cause) runs on NS_CT { + NSCP.send(ts_NS_BLOCK(cause, config.nsvci)); + Tns_block.start; + } + + altstep as_allstate() runs on NS_CT { + var PDU_NS 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; + } + + [] Tns_test.timeout { + log("Tns-test expired: sending NS-ALIVE"); + f_sendAlive(); + } + + /* Stop t_alive when receiving ALIVE-ACK */ + [Tns_alive.running] NSCP.receive(t_NS_ALIVE_ACK) { + log("NS-ALIVE-ACK received: stopping Tns-alive; starting Tns-test"); + Tns_alive.stop; + Tns_test.start; + } + + /* respond to NS-ALIVE with NS-ALIVE-ACK */ + [] NSCP.receive(t_NS_ALIVE) { + NSCP.send(t_NS_ALIVE_ACK); + } + + /* Respond to BLOCK for wrong NSVCI */ + [] NSCP.receive(tr_NS_BLOCK(?, ?)) -> value rf { + log("Rx NS-BLOCK for unknown NSVCI"); + /* FIXME */ + } + + /* Respond to RESET with correct NSEI/NSVCI */ + [] NSCP.receive(tr_NS_RESET(?, config.nsvci, config.nsei)) -> value rf { + f_change_state(NSE_S_ALIVE_BLOCKED); + NSCP.send(ts_NS_RESET_ACK(config.nsvci, config.nsei)); + } + + /* Respond to RESET with wrong NSEI/NSVCI */ + [] NSCP.receive(tr_NS_RESET(?, ?, ?)) -> value rf { + log("Rx NS-RESET for unknown NSEI/NSVCI"); + /* FIXME */ + } + + [config.role_sgsn and config.handle_sns and ischosen(config.provider.ip)] as_sns_sgsn(); + + /* default case of handling unknown PDUs */ + [] NSCP.receive(PDU_NS: ?) -> value rf { + log("Rx Unexpected NS PDU ", rf," in state ", g_state); + NSCP.send(ts_NS_STATUS(NS_CAUSE_PDU_NOT_COMPATIBLE_WITH_PROTOCOL_STATE, rf)); + } + } + + /* simple IP Sub-Network Service responder for the SGSN side. This is not a full implementation + * of the protocol, merely sufficient to make the PCU/BSS side happy to proceed */ + altstep as_sns_sgsn() runs on NS_CT { + var PDU_NS rf; + [] NSCP.receive(tr_SNS_SIZE(config.nsei)) -> value rf { + /* blindly acknowledge whatever the PCU sends */ + NSCP.send(ts_SNS_SIZE_ACK(config.nsei, omit)); + } + [] NSCP.receive(tr_SNS_SIZE(?)) { + setverdict(fail, "SNS-SIZE from unexpected NSEI"); + self.stop; + } + [] NSCP.receive(tr_SNS_CONFIG(config.nsei, true, + {tr_SNS_IPv4(config.provider.ip.remote_ip, + config.provider.ip.remote_udp_port)})) -> value rf { + /* blindly acknowledge whatever the PCU sends */ + NSCP.send(ts_SNS_CONFIG_ACK(config.nsei, omit)); + /* send a SNS-CONFIG in response and expect a SNS-CONFIG-ACK */ + var IP4_Elements v4 := { valueof(ts_SNS_IPv4(config.provider.ip.local_ip, config.provider.ip.local_udp_port)) }; + NSCP.send(ts_SNS_CONFIG(config.nsei, true, v4)); + alt { + [] NSCP.receive(tr_SNS_CONFIG_ACK(config.nsei, omit)) { + /* success */ + } + [] NSCP.receive(tr_SNS_CONFIG_ACK(config.nsei, ?)) { + setverdict(fail, "Unexpected SNS-CONFIG-NACK"); + self.stop; + } + } + } + [] NSCP.receive(tr_SNS_CONFIG(config.nsei, false, ?)) { /* ignore */} + [] NSCP.receive(tr_SNS_CONFIG(config.nsei, true, ?)) { + setverdict(fail, "Unexpected SNS-CONFIG content"); + self.stop; + } + [] NSCP.receive(tr_SNS_CONFIG(?, ?, ?)) { + setverdict(fail, "SNS-CONFIG from unexpected NSEI"); + self.stop; + } + } + + private function f_ScanEvents() runs on NS_CT { + var NsUnitdataRequest ud_req; + var PDU_NS rf; + var default d; + + d := activate(as_allstate()); + + while (true) { + if (g_state == NSE_S_DEAD_BLOCKED) { + alt { + [false] any timer.timeout {} + } + } else if (g_state == NSE_S_WAIT_RESET) { + alt { + [] NSCP.receive(tr_NS_RESET_ACK(config.nsvci, config.nsei)) -> value rf { + f_change_state(NSE_S_ALIVE_BLOCKED); + f_sendAlive(); + f_sendUnblock(); + } + } + } else if (g_state == NSE_S_ALIVE_BLOCKED) { + alt { + /* bogus block, just respond with ACK */ + [] NSCP.receive(tr_NS_BLOCK(?, config.nsvci)) -> value rf { + NSCP.send(ts_NS_BLOCK_ACK(config.nsvci)); + } + /* Respond to UNBLOCK with UNBLOCK-ACK + change state */ + [] NSCP.receive(t_NS_UNBLOCK) -> value rf { + NSCP.send(t_NS_UNBLOCK_ACK); + Tns_block.stop; + f_change_state(NSE_S_ALIVE_UNBLOCKED); + } + [] NSCP.receive(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_UNBLOCK) -> value rf { + NSCP.send(t_NS_UNBLOCK_ACK); + } + /* Respond to BLOCK with BLOCK-ACK + change state */ + [] NSCP.receive(tr_NS_BLOCK(?, config.nsvci)) -> value rf { + NSCP.send(ts_NS_BLOCK_ACK(config.nsvci)); + Tns_block.stop; + f_change_state(NSE_S_ALIVE_BLOCKED); + } + [] NSCP.receive(tr_NS_BLOCK_ACK(config.nsvci)) -> value rf { + Tns_block.stop; + } + /* NS-UNITDATA PDU from network to NS-UNITDATA.ind to user */ + [] NSCP.receive(tr_NS_UNITDATA(?, ?, ?)) -> value rf { + NS_SP.send(t_NsUdInd(config.nsei, + oct2int(rf.pDU_NS_Unitdata.bVCI), + rf.pDU_NS_Unitdata.nS_SDU)); + } + /* NS-UNITDATA.req from user to NS-UNITDATA PDU on network */ + [] NS_SP.receive(t_NsUdReq(config.nsei, ?, ?, omit)) -> value ud_req { + /* using raw octetstring PDU */ + NSCP.send(ts_NS_UNITDATA(t_SduCtrlB, ud_req.bvci, ud_req.sdu)); + } + [] NS_SP.receive(t_NsUdReq(config.nsei, ?, omit, ?)) -> value ud_req { + /* using decoded BSSGP PDU that we need to encode first */ + var octetstring enc := enc_PDU_BSSGP(ud_req.bssgp); + NSCP.send(ts_NS_UNITDATA(t_SduCtrlB, ud_req.bvci, enc)); + } + } + } + + } /* while */ + //deactivate(d); + } +} diff --git a/library/NS_Provider_FR.ttcn b/library/NS_Provider_FR.ttcn new file mode 100644 index 00000000..851e6c4f --- /dev/null +++ b/library/NS_Provider_FR.ttcn @@ -0,0 +1,67 @@ +/* NS Provider for NS/FR/E1 + * (C) 2020 Harald Welte + * contributions by sysmocom - s.f.m.c. GmbH + * All rights reserved. + * + * Released under the terms of GNU General Public License, Version 2 or + * (at your option) any later version. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +module NS_Provider_FR { + +import from NS_Emulation all; +import from NS_Types all; + +import from AF_PACKET_PortType all; +import from FrameRelay_Types all; +import from FrameRelay_Emulation all; + + +type component NS_Provider_FR_CT extends NS_Provider_CT, FR_Client_CT { + /* component reference to Frame Relay emulation */ + var FR_Emulation_CT vc_FREMU; +}; + +function main(NSConfiguration config) runs on NS_Provider_FR_CT system af_packet { + + /* start Frame Relay Emulation */ + vc_FREMU := FR_Emulation_CT.create(); + var Q933em_Config q933_cfg := valueof(ts_Q933em_Config(ats_is_user := not config.role_sgsn, bidirectional := false)); + map(vc_FREMU:FR, system:AF_PACKET) param (config.provider.fr.netdev); + vc_FREMU.start(FrameRelay_Emulation.main(q933_cfg)); + + /* connect ourselves to frame relay emulation */ + connect(self:FR, vc_FREMU:CLIENT); + connect(self:FR_PROC, vc_FREMU:PROC); + + /* register ourselves for the specified DLCI */ + f_fremu_register(config.provider.fr.dlci); + + /* transceive between user-facing port and FR socket */ + while (true) { + var FrameRelayFrame rx_fr; + var FRemu_Event rx_frevt; + var PDU_NS rx_pdu; + alt { + + [] FR.receive(FrameRelayFrame:?) -> value rx_fr { + NSE.send(dec_PDU_NS(rx_fr.payload)); + } + + [] FR.receive(FRemu_Event:?) -> value rx_frevt { + /* TODO: dispatch to user */ + } + [] NSE.receive(PDU_NS:?) -> value rx_pdu { + FR.send(ts_FR(config.provider.fr.dlci, enc_PDU_NS(rx_pdu), true)); + } + + } + } + +} /* main */ + + + +} /* module */ diff --git a/pcu/gen_links.sh b/pcu/gen_links.sh index fbb79a00..a33cb276 100755 --- a/pcu/gen_links.sh +++ b/pcu/gen_links.sh @@ -51,7 +51,7 @@ gen_links $DIR $FILES DIR=../library FILES="Misc_Helpers.ttcn General_Types.ttcn Osmocom_VTY_Functions.ttcn Native_Functions.ttcn Native_FunctionDefs.cc GSM_Types.ttcn GSM_RR_Types.ttcn Osmocom_Types.ttcn RLCMAC_Templates.ttcn RLCMAC_Types.ttcn RLCMAC_CSN1_Templates.ttcn RLCMAC_CSN1_Types.ttcn RLCMAC_EncDec.cc " FILES+="StatsD_Types.ttcn StatsD_CodecPort.ttcn StatsD_CodecPort_CtrlFunct.ttcn StatsD_CodecPort_CtrlFunctdef.cc StatsD_Checker.ttcn " -FILES+="NS_Provider_IPL4.ttcn NS_Emulation.ttcn NS_CodecPort.ttcn NS_CodecPort_CtrlFunct.ttcn NS_CodecPort_CtrlFunctDef.cc " +FILES+="NS_Provider_IPL4.ttcn NS_Emulation.ttcnpp NS_CodecPort.ttcn NS_CodecPort_CtrlFunct.ttcn NS_CodecPort_CtrlFunctDef.cc " FILES+="BSSGP_Emulation.ttcnpp Osmocom_Gb_Types.ttcn " FILES+="LLC_Templates.ttcn L3_Templates.ttcn L3_Common.ttcn " FILES+="PCUIF_Types.ttcn PCUIF_CodecPort.ttcn RAW_NS.ttcn " diff --git a/sgsn/gen_links.sh b/sgsn/gen_links.sh index 334df590..47baa543 100755 --- a/sgsn/gen_links.sh +++ b/sgsn/gen_links.sh @@ -84,7 +84,7 @@ gen_links $DIR $FILES DIR=../library FILES="Misc_Helpers.ttcn General_Types.ttcn GSM_Types.ttcn GSM_RR_Types.ttcn Osmocom_Types.ttcn RLCMAC_Templates.ttcn RLCMAC_Types.ttcn RLCMAC_CSN1_Templates.ttcn RLCMAC_CSN1_Types.ttcn RLCMAC_EncDec.cc " -FILES+="NS_Provider_IPL4.ttcn NS_Emulation.ttcn PCUIF_Types.ttcn NS_CodecPort.ttcn NS_CodecPort_CtrlFunct.ttcn NS_CodecPort_CtrlFunctDef.cc " +FILES+="NS_Provider_IPL4.ttcn NS_Emulation.ttcnpp PCUIF_Types.ttcn NS_CodecPort.ttcn NS_CodecPort_CtrlFunct.ttcn NS_CodecPort_CtrlFunctDef.cc " FILES+="BSSGP_Emulation.ttcnpp Osmocom_Gb_Types.ttcn " FILES+="Osmocom_CTRL_Types.ttcn Osmocom_CTRL_Functions.ttcn Osmocom_CTRL_Adapter.ttcn " FILES+="Osmocom_VTY_Functions.ttcn " -- cgit v1.2.3