| /* NS Provider for NS/FR/E1 |
| * (C) 2020 Harald Welte <laforge@gnumonks.org> |
| * 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; |
| |
| var boolean link_available := false; |
| var boolean pvc_active := false; |
| }; |
| |
| function main(NSVCConfiguration config, NSConfiguration nsconfig, charstring id) runs on NS_Provider_FR_CT system af_packet { |
| |
| /* start Frame Relay Emulation */ |
| vc_FREMU := FR_Emulation_CT.create(id & "-FRemu"); |
| var Q933em_Config q933_cfg := valueof(ts_Q933em_Config(ats_is_user := not nsconfig.role_sgsn, bidirectional := false)); |
| q933_cfg.T391 := 1.0; |
| 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 { |
| |
| [not link_available] FR.receive(FrameRelayFrame:?) -> value rx_fr { |
| log("Dropping Rx Msg because FR link not yet available", rx_fr); |
| /* this can happen if the remote side has not yet recognized the |
| * link is dead; don' fail here */ |
| } |
| [link_available and pvc_active] FR.receive(tr_FR(config.provider.fr.dlci)) -> value rx_fr { |
| var PDU_NS ns := dec_PDU_NS(rx_fr.payload); |
| NSE.send(ns); |
| } |
| [not pvc_active] FR.receive(tr_FR(config.provider.fr.dlci)) -> value rx_fr { |
| log("Dropping Rx Msg because FR DLC not yet available", rx_fr); |
| } |
| [] FR.receive(tr_FR(?)) -> value rx_fr { |
| log("Dropping Rx Msg because DLCI unknown", rx_fr); |
| setverdict(fail); |
| } |
| |
| [] FR.receive(FRemu_Event:{link_status:=FR_LINK_STS_AVAILABLE}) -> value rx_frevt { |
| if (link_available == false and pvc_active == true) { |
| NSE.send(NS_Provider_Evt:{link_status := NS_PROV_LINK_STATUS_UP}); |
| } |
| link_available := true; |
| } |
| [] FR.receive(FRemu_Event:{link_status:=FR_LINK_STS_UNAVAILABLE}) -> value rx_frevt { |
| link_available := false; |
| pvc_active := false; |
| NSE.send(NS_Provider_Evt:{link_status := NS_PROV_LINK_STATUS_DOWN}); |
| } |
| [] FR.receive(tr_FRemu_PvcStatusAct(config.provider.fr.dlci, true)) -> value rx_frevt { |
| if (pvc_active == false and link_available == true) { |
| NSE.send(NS_Provider_Evt:{link_status := NS_PROV_LINK_STATUS_UP}); |
| } |
| pvc_active := true; |
| } |
| [] FR.receive(tr_FRemu_PvcStatusAct(config.provider.fr.dlci, false)) -> value rx_frevt { |
| pvc_active := false; |
| NSE.send(NS_Provider_Evt:{link_status := NS_PROV_LINK_STATUS_DOWN}); |
| } |
| [] FR.receive(FRemu_Event:?) -> value rx_frevt { |
| log("Unhandled FRemu_event: ", rx_frevt); |
| } |
| [] NSE.receive(PDU_NS:?) -> value rx_pdu { |
| FR.send(ts_FR(config.provider.fr.dlci, enc_PDU_NS(rx_pdu), true)); |
| } |
| |
| } |
| } |
| |
| } /* main */ |
| |
| |
| |
| } /* module */ |