blob: 8145c13380fe9b16a00e7ef6958a1a9a92b59f42 [file] [log] [blame]
Harald Welte013d65a2020-09-13 14:41:31 +02001/* NS Provider for NS/UDP/IP
Harald Welte4bef0dd2021-03-29 21:45:46 +02002 * (C) 2020-2021 Harald Welte <laforge@gnumonks.org>
Harald Welte013d65a2020-09-13 14:41:31 +02003 * contributions by sysmocom - s.f.m.c. GmbH
4 * All rights reserved.
5 *
6 * Released under the terms of GNU General Public License, Version 2 or
7 * (at your option) any later version.
8 *
9 * SPDX-License-Identifier: GPL-2.0-or-later
10 */
11
Harald Welte4bef0dd2021-03-29 21:45:46 +020012/* This provider can be operated in two modes:
13 *
14 * 1) the "classic" mode, where - similar to the NS_Provider_FR - there is
15 * only one NSVC per provider. In this mode, the "NSE" port is used to
16 * exchange data with the next higher level component, such as a NSVC_CT
17 * or a RAW_NS_CT.
18 *
19 * 2) the enew "endpoint" mode, where one provider can host a number of different
20 * NSVCs. This is needed in most non-trivial IP-SNS scenarios. The 'NSE'
21 * port of this component is no longer used. Instead, there is a NSVC port
22 * array, one of which will be used for each NSVC. The NSVCs are dynamically
23 * added and removed via the PROC procedure port, controlled by NS_CT.
24 */
25
Harald Welte013d65a2020-09-13 14:41:31 +020026module NS_Provider_IPL4 {
27
Harald Welte4bef0dd2021-03-29 21:45:46 +020028import from Misc_Helpers all;
Harald Welte013d65a2020-09-13 14:41:31 +020029import from NS_Emulation all;
30import from NS_Types all;
31
32import from IPL4asp_Types all;
33import from IPL4asp_PortType all;
34
Harald Welte4bef0dd2021-03-29 21:45:46 +020035/* maximum number of NS-VCs within one Provider (== IP endpoint) */
36private const integer NUM_MAX_NSVC := 16;
37
Harald Welte013d65a2020-09-13 14:41:31 +020038type component NS_Provider_IPL4_CT extends NS_Provider_CT {
39 /* down-facing port towards IPL4asp to IUT */
40 port IPL4asp_PT IPL4;
41 var integer g_conn_id := -1;
Harald Welte4bef0dd2021-03-29 21:45:46 +020042
43 /* per-NSVC ports and state */
44 port NS_PROVIDER_PT NSVC[NUM_MAX_NSVC];
45 var PerNsvcState g_nsvc[NUM_MAX_NSVC];
46
47 /* management port via which */
48 port NSPIP_PROC_PT PROC;
Harald Welte013d65a2020-09-13 14:41:31 +020049};
50
Harald Welte4bef0dd2021-03-29 21:45:46 +020051type record PerNsvcState {
52 charstring remote_ip,
53 PortNumber remote_port,
54 NSVC_CT vc_nsvc
55};
Harald Welte013d65a2020-09-13 14:41:31 +020056
Harald Welte4bef0dd2021-03-29 21:45:46 +020057signature NSPIP_add_nsvc(charstring remote_ip, PortNumber remote_port, NSVC_CT vc_nsvc);
58signature NSPIP_del_nsvc(charstring remote_ip, PortNumber remote_port);
59
60type port NSPIP_PROC_PT procedure {
61 inout NSPIP_add_nsvc, NSPIP_del_nsvc;
62} with { extension "internal" };
63
64/* add a new NSVC to the provider */
65private function f_nsvc_add(PerNsvcState nsvc) runs on NS_Provider_IPL4_CT
66{
67 for (var integer i := 0; i < sizeof(g_nsvc); i := i+1) {
68 if (g_nsvc[i].vc_nsvc == null) {
69 g_nsvc[i] := nsvc;
70 connect(self:NSVC[i], nsvc.vc_nsvc:NSCP);
71 NSVC[i].send(NS_Provider_Evt:{link_status := NS_PROV_LINK_STATUS_UP});
72 return;
73 }
74 }
75 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Overflow of g_nsvc array"));
76}
77
78private function f_nsvc_del(PerNsvcState nsvc) runs on NS_Provider_IPL4_CT
79{
80 for (var integer i := 0; i < sizeof(g_nsvc); i := i+1) {
81 if (g_nsvc[i].vc_nsvc != null and
82 g_nsvc[i].remote_ip == nsvc.remote_ip and
83 g_nsvc[i].remote_port == nsvc.remote_port) {
84 g_nsvc[i] := {
85 remote_ip := -,
86 remote_port := -,
87 vc_nsvc := null
88 }
89 NSVC[i].send(NS_Provider_Evt:{link_status := NS_PROV_LINK_STATUS_DOWN});
90 disconnect(self:NSVC[i], nsvc.vc_nsvc:NSCP);
91 return;
92 }
93 }
94 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("attempt to delete unknown NSVC"));
95}
96
97private function f_get_nsvc_idx(charstring remote_ip, PortNumber remote_port)
98runs on NS_Provider_IPL4_CT return integer
99{
100 for (var integer i := 0; i < sizeof(g_nsvc); i := i+1) {
101 if (g_nsvc[i].vc_nsvc != null and
102 g_nsvc[i].remote_ip == remote_ip and g_nsvc[i].remote_port == remote_port) {
103 return i;
104 }
105 }
106 return -1;
107}
108
109function main(NSVCConfiguration config, NSConfiguration nsconfig, charstring id) runs on NS_Provider_IPL4_CT {
110 for (var integer i := 0; i < sizeof(g_nsvc); i := i+1) {
111 g_nsvc[i].vc_nsvc := null;
112 }
113
114 /* in order to support any number of NSVC on this endpoiint, we only bind the socket
115 * to its local ip/port, but do not connect it to the remote peer provided in 'config'. */
Alexander Couzens3ee82682020-09-17 23:53:32 +0200116 map(self:IPL4, system:IPL4);
Harald Welte4bef0dd2021-03-29 21:45:46 +0200117 var Result res := f_IPL4_listen(IPL4, config.provider.ip.local_ip,
118 config.provider.ip.local_udp_port, { udp := {}});
Harald Welte013d65a2020-09-13 14:41:31 +0200119 if (not ispresent(res.connId)) {
Harald Welte5e8573e2020-09-13 15:32:56 +0200120 setverdict(fail, "Could not connect NS UDP socket ", config.provider.ip);
Harald Welte013d65a2020-09-13 14:41:31 +0200121 mtc.stop;
122 }
123 g_conn_id := res.connId;
Harald Welte4bef0dd2021-03-29 21:45:46 +0200124
125 if (NSE.checkstate("Connected")) {
126 NSE.send(NS_Provider_Evt:{link_status := NS_PROV_LINK_STATUS_UP});
127 }
Harald Welte013d65a2020-09-13 14:41:31 +0200128
Alexander Couzens6da7aaf2021-01-10 21:40:43 +0100129 /* transceive between user-facing port and UDP socket */
Harald Welte013d65a2020-09-13 14:41:31 +0200130 while (true) {
131 var ASP_RecvFrom rx_rf;
132 var PDU_NS rx_pdu;
Harald Welte4bef0dd2021-03-29 21:45:46 +0200133 var integer rx_idx;
134 var charstring remote_ip;
135 var PortNumber remote_port;
136 var NSVC_CT vc_nsvc;
137 var NS_CT vc_caller;
Harald Welte013d65a2020-09-13 14:41:31 +0200138 alt {
139
140 [] IPL4.receive(ASP_RecvFrom:?) -> value rx_rf {
Harald Welte4bef0dd2021-03-29 21:45:46 +0200141 /* we have to resolve the NS-VC based on the remote peer */
142 var integer nsvc_idx := f_get_nsvc_idx(rx_rf.remName, rx_rf.remPort);
143 if (nsvc_idx == -1) {
144 /* backwards compatibility; if there's no NSVC, send to NSE port */
145 NSE.send(dec_PDU_NS(rx_rf.msg));
146 } else {
147 /* endpoint mode; send to the per-NSVC component via NSVC port */
148 NSVC[nsvc_idx].send(dec_PDU_NS(rx_rf.msg));
149 }
Harald Welte013d65a2020-09-13 14:41:31 +0200150 }
151
152 [] IPL4.receive(ASP_ConnId_ReadyToRelease:?) {
153 }
154
155 [] IPL4.receive(ASP_Event:?) {
156 }
157
Harald Welte4bef0dd2021-03-29 21:45:46 +0200158 [] any from NSVC.receive(PDU_NS:?) -> value rx_pdu @index value rx_idx {
159 /* we can use the port array index directly into the g_nsvc array in order
160 * to resolve the IP + port of the remote peer to which to send */
161 var ASP_SendTo tx := {
162 connId := g_conn_id,
163 remName := g_nsvc[rx_idx].remote_ip,
164 remPort := g_nsvc[rx_idx].remote_port,
165 proto := { udp := {} },
166 msg := enc_PDU_NS(rx_pdu)
167 };
168 IPL4.send(tx);
169 }
Harald Welte013d65a2020-09-13 14:41:31 +0200170 [] NSE.receive(PDU_NS:?) -> value rx_pdu {
Harald Welte4bef0dd2021-03-29 21:45:46 +0200171 /* backwards compatibility: If user uses the NSE port, use the destination
172 * provided during main() initialization */
173 var ASP_SendTo tx := {
174 connId := g_conn_id,
175 remName := config.provider.ip.remote_ip,
176 remPort := config.provider.ip.remote_udp_port,
177 proto := { udp := {} },
178 msg := enc_PDU_NS(rx_pdu)
179 };
180 IPL4.send(tx);
181 }
182
183 /* procedure port to add/remove NSVCs from this provider */
184 [] PROC.getcall(NSPIP_add_nsvc:{?,?,?}) -> param (remote_ip, remote_port, vc_nsvc) sender vc_caller {
185 f_nsvc_add(PerNsvcState:{remote_ip, remote_port, vc_nsvc});
186 PROC.reply(NSPIP_add_nsvc:{remote_ip, remote_port, vc_nsvc}) to vc_caller;
187 }
188 [] PROC.getcall(NSPIP_del_nsvc:{?,?}) -> param (remote_ip, remote_port) sender vc_caller {
189 f_nsvc_del(PerNsvcState:{remote_ip, remote_port});
190 PROC.reply(NSPIP_del_nsvc:{remote_ip, remote_port}) to vc_caller;
Harald Welte013d65a2020-09-13 14:41:31 +0200191 }
192
193 } /* alt */
194 } /* while */
195
196} /* main */
197
Harald Weltead320712021-03-29 21:56:48 +0200198function f_nspip_add_nsvc(NS_Provider_IPL4_CT vc_ipep, charstring remote_ip, PortNumber remote_port, NSVC_CT vc_nsvc)
199runs on NS_CT {
200 NSPIP_PROC.call(NSPIP_add_nsvc:{remote_ip, remote_port, vc_nsvc}) to vc_ipep {
201 [] NSPIP_PROC.getreply(NSPIP_add_nsvc:{?,?,?});
202 }
203}
204
Harald Welte013d65a2020-09-13 14:41:31 +0200205} /* module */