blob: 09e7dc0e25a437bf8b95eb6b416576c107119540 [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 *
Alexander Couzens99b837a2021-05-25 01:14:45 +020019 * 2) the new "endpoint" mode, where one provider can host a number of different
Harald Welte4bef0dd2021-03-29 21:45:46 +020020 * 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
Alexander Couzens99b837a2021-05-25 01:14:45 +020022 * array, one of which will be used for each NSVC. The NSVCs are dynamically
Harald Welte4bef0dd2021-03-29 21:45:46 +020023 * 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;
Alexander Couzensbd6e9a12021-06-07 00:45:15 +020030import from RAW_NS all;
Harald Welte013d65a2020-09-13 14:41:31 +020031import from NS_Types all;
32
33import from IPL4asp_Types all;
34import from IPL4asp_PortType all;
35
Harald Welte4bef0dd2021-03-29 21:45:46 +020036/* maximum number of NS-VCs within one Provider (== IP endpoint) */
37private const integer NUM_MAX_NSVC := 16;
38
Harald Welte013d65a2020-09-13 14:41:31 +020039type component NS_Provider_IPL4_CT extends NS_Provider_CT {
40 /* down-facing port towards IPL4asp to IUT */
41 port IPL4asp_PT IPL4;
42 var integer g_conn_id := -1;
Harald Welte4bef0dd2021-03-29 21:45:46 +020043
44 /* per-NSVC ports and state */
45 port NS_PROVIDER_PT NSVC[NUM_MAX_NSVC];
Alexander Couzensbd6e9a12021-06-07 00:45:15 +020046 var boolean g_nsvc_bound[NUM_MAX_NSVC];
Harald Welte4bef0dd2021-03-29 21:45:46 +020047 var PerNsvcState g_nsvc[NUM_MAX_NSVC];
48
49 /* management port via which */
50 port NSPIP_PROC_PT PROC;
Harald Welte013d65a2020-09-13 14:41:31 +020051};
52
Harald Welte4bef0dd2021-03-29 21:45:46 +020053type record PerNsvcState {
54 charstring remote_ip,
55 PortNumber remote_port,
56 NSVC_CT vc_nsvc
57};
Harald Welte013d65a2020-09-13 14:41:31 +020058
Alexander Couzensbd6e9a12021-06-07 00:45:15 +020059signature NSPIP_add_nsvc(charstring remote_ip, PortNumber remote_port, NSVC_CT vc_nsvc) return integer;
60signature NSPIP_del_nsvc(charstring remote_ip, PortNumber remote_port) return integer;
Harald Welte4bef0dd2021-03-29 21:45:46 +020061
62type port NSPIP_PROC_PT procedure {
63 inout NSPIP_add_nsvc, NSPIP_del_nsvc;
64} with { extension "internal" };
65
66/* add a new NSVC to the provider */
Alexander Couzensbd6e9a12021-06-07 00:45:15 +020067private function f_nsvc_add(PerNsvcState nsvc) runs on NS_Provider_IPL4_CT return integer
Harald Welte4bef0dd2021-03-29 21:45:46 +020068{
69 for (var integer i := 0; i < sizeof(g_nsvc); i := i+1) {
Alexander Couzensbd6e9a12021-06-07 00:45:15 +020070 if (g_nsvc_bound[i] == false) {
Harald Welte4bef0dd2021-03-29 21:45:46 +020071 g_nsvc[i] := nsvc;
Alexander Couzensbd6e9a12021-06-07 00:45:15 +020072 g_nsvc_bound[i] := true;
73 if (isbound(nsvc.vc_nsvc) and nsvc.vc_nsvc != null) {
74 connect(self:NSVC[i], nsvc.vc_nsvc:NSCP);
75 NSVC[i].send(NS_Provider_Evt:{link_status := NS_PROV_LINK_STATUS_UP});
76 }
77 return i;
Harald Welte4bef0dd2021-03-29 21:45:46 +020078 }
79 }
80 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Overflow of g_nsvc array"));
Alexander Couzensbd6e9a12021-06-07 00:45:15 +020081 return -1;
Harald Welte4bef0dd2021-03-29 21:45:46 +020082}
83
Alexander Couzensbd6e9a12021-06-07 00:45:15 +020084private function f_nsvc_del(PerNsvcState nsvc) runs on NS_Provider_IPL4_CT return integer
Harald Welte4bef0dd2021-03-29 21:45:46 +020085{
86 for (var integer i := 0; i < sizeof(g_nsvc); i := i+1) {
Alexander Couzensbd6e9a12021-06-07 00:45:15 +020087 if (g_nsvc_bound[i] and
Harald Welte4bef0dd2021-03-29 21:45:46 +020088 g_nsvc[i].remote_ip == nsvc.remote_ip and
89 g_nsvc[i].remote_port == nsvc.remote_port) {
90 g_nsvc[i] := {
91 remote_ip := -,
92 remote_port := -,
93 vc_nsvc := null
94 }
Alexander Couzensbd6e9a12021-06-07 00:45:15 +020095 g_nsvc_bound[i] := false;
Harald Welte4bef0dd2021-03-29 21:45:46 +020096 NSVC[i].send(NS_Provider_Evt:{link_status := NS_PROV_LINK_STATUS_DOWN});
Alexander Couzensbd6e9a12021-06-07 00:45:15 +020097 if (isbound(g_nsvc[i].vc_nsvc) and g_nsvc[i].vc_nsvc != null) {
98 disconnect(self:NSVC[i], nsvc.vc_nsvc:NSCP);
99 }
100 return i;
Harald Welte4bef0dd2021-03-29 21:45:46 +0200101 }
102 }
103 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("attempt to delete unknown NSVC"));
Alexander Couzensbd6e9a12021-06-07 00:45:15 +0200104 return -1;
Harald Welte4bef0dd2021-03-29 21:45:46 +0200105}
106
107private function f_get_nsvc_idx(charstring remote_ip, PortNumber remote_port)
108runs on NS_Provider_IPL4_CT return integer
109{
110 for (var integer i := 0; i < sizeof(g_nsvc); i := i+1) {
Alexander Couzensbd6e9a12021-06-07 00:45:15 +0200111 if (g_nsvc_bound[i] and
Harald Welte4bef0dd2021-03-29 21:45:46 +0200112 g_nsvc[i].remote_ip == remote_ip and g_nsvc[i].remote_port == remote_port) {
113 return i;
114 }
115 }
116 return -1;
117}
118
119function main(NSVCConfiguration config, NSConfiguration nsconfig, charstring id) runs on NS_Provider_IPL4_CT {
120 for (var integer i := 0; i < sizeof(g_nsvc); i := i+1) {
121 g_nsvc[i].vc_nsvc := null;
Alexander Couzensbd6e9a12021-06-07 00:45:15 +0200122 g_nsvc_bound[i] := false;
Harald Welte4bef0dd2021-03-29 21:45:46 +0200123 }
124
125 /* in order to support any number of NSVC on this endpoiint, we only bind the socket
126 * to its local ip/port, but do not connect it to the remote peer provided in 'config'. */
Alexander Couzens3ee82682020-09-17 23:53:32 +0200127 map(self:IPL4, system:IPL4);
Harald Welte4bef0dd2021-03-29 21:45:46 +0200128 var Result res := f_IPL4_listen(IPL4, config.provider.ip.local_ip,
129 config.provider.ip.local_udp_port, { udp := {}});
Harald Welte013d65a2020-09-13 14:41:31 +0200130 if (not ispresent(res.connId)) {
Harald Welte5e8573e2020-09-13 15:32:56 +0200131 setverdict(fail, "Could not connect NS UDP socket ", config.provider.ip);
Harald Welte013d65a2020-09-13 14:41:31 +0200132 mtc.stop;
133 }
134 g_conn_id := res.connId;
Harald Welte4bef0dd2021-03-29 21:45:46 +0200135
136 if (NSE.checkstate("Connected")) {
137 NSE.send(NS_Provider_Evt:{link_status := NS_PROV_LINK_STATUS_UP});
138 }
Harald Welte013d65a2020-09-13 14:41:31 +0200139
Alexander Couzens6da7aaf2021-01-10 21:40:43 +0100140 /* transceive between user-facing port and UDP socket */
Harald Welte013d65a2020-09-13 14:41:31 +0200141 while (true) {
142 var ASP_RecvFrom rx_rf;
143 var PDU_NS rx_pdu;
Harald Welte4bef0dd2021-03-29 21:45:46 +0200144 var integer rx_idx;
145 var charstring remote_ip;
146 var PortNumber remote_port;
147 var NSVC_CT vc_nsvc;
148 var NS_CT vc_caller;
Harald Welte013d65a2020-09-13 14:41:31 +0200149 alt {
150
151 [] IPL4.receive(ASP_RecvFrom:?) -> value rx_rf {
Harald Welte4bef0dd2021-03-29 21:45:46 +0200152 /* we have to resolve the NS-VC based on the remote peer */
153 var integer nsvc_idx := f_get_nsvc_idx(rx_rf.remName, rx_rf.remPort);
154 if (nsvc_idx == -1) {
155 /* backwards compatibility; if there's no NSVC, send to NSE port */
156 NSE.send(dec_PDU_NS(rx_rf.msg));
157 } else {
158 /* endpoint mode; send to the per-NSVC component via NSVC port */
159 NSVC[nsvc_idx].send(dec_PDU_NS(rx_rf.msg));
160 }
Harald Welte013d65a2020-09-13 14:41:31 +0200161 }
162
163 [] IPL4.receive(ASP_ConnId_ReadyToRelease:?) {
164 }
165
166 [] IPL4.receive(ASP_Event:?) {
167 }
168
Harald Welte4bef0dd2021-03-29 21:45:46 +0200169 [] any from NSVC.receive(PDU_NS:?) -> value rx_pdu @index value rx_idx {
170 /* we can use the port array index directly into the g_nsvc array in order
171 * to resolve the IP + port of the remote peer to which to send */
172 var ASP_SendTo tx := {
173 connId := g_conn_id,
174 remName := g_nsvc[rx_idx].remote_ip,
175 remPort := g_nsvc[rx_idx].remote_port,
176 proto := { udp := {} },
177 msg := enc_PDU_NS(rx_pdu)
178 };
179 IPL4.send(tx);
180 }
Harald Welte013d65a2020-09-13 14:41:31 +0200181 [] NSE.receive(PDU_NS:?) -> value rx_pdu {
Harald Welte4bef0dd2021-03-29 21:45:46 +0200182 /* backwards compatibility: If user uses the NSE port, use the destination
183 * provided during main() initialization */
184 var ASP_SendTo tx := {
185 connId := g_conn_id,
186 remName := config.provider.ip.remote_ip,
187 remPort := config.provider.ip.remote_udp_port,
188 proto := { udp := {} },
189 msg := enc_PDU_NS(rx_pdu)
190 };
191 IPL4.send(tx);
192 }
193
194 /* procedure port to add/remove NSVCs from this provider */
195 [] PROC.getcall(NSPIP_add_nsvc:{?,?,?}) -> param (remote_ip, remote_port, vc_nsvc) sender vc_caller {
Alexander Couzensbd6e9a12021-06-07 00:45:15 +0200196 var integer idx;
197 idx := f_nsvc_add(PerNsvcState:{remote_ip, remote_port, vc_nsvc});
198 PROC.reply(NSPIP_add_nsvc:{remote_ip, remote_port, vc_nsvc} value idx) to vc_caller;
Harald Welte4bef0dd2021-03-29 21:45:46 +0200199 }
200 [] PROC.getcall(NSPIP_del_nsvc:{?,?}) -> param (remote_ip, remote_port) sender vc_caller {
Alexander Couzensbd6e9a12021-06-07 00:45:15 +0200201 var integer idx;
202 idx := f_nsvc_del(PerNsvcState:{remote_ip, remote_port});
203 PROC.reply(NSPIP_del_nsvc:{remote_ip, remote_port} value idx) to vc_caller;
Harald Welte013d65a2020-09-13 14:41:31 +0200204 }
205
206 } /* alt */
207 } /* while */
208
209} /* main */
210
Harald Weltead320712021-03-29 21:56:48 +0200211function f_nspip_add_nsvc(NS_Provider_IPL4_CT vc_ipep, charstring remote_ip, PortNumber remote_port, NSVC_CT vc_nsvc)
212runs on NS_CT {
Alexander Couzensbd6e9a12021-06-07 00:45:15 +0200213 var integer idx := -1;
Harald Weltead320712021-03-29 21:56:48 +0200214 NSPIP_PROC.call(NSPIP_add_nsvc:{remote_ip, remote_port, vc_nsvc}) to vc_ipep {
Alexander Couzensbd6e9a12021-06-07 00:45:15 +0200215 [] NSPIP_PROC.getreply(NSPIP_add_nsvc:{?,?,?}) -> value idx;
Harald Weltead320712021-03-29 21:56:48 +0200216 }
217}
218
Alexander Couzensbd6e9a12021-06-07 00:45:15 +0200219function f_nspip_add_nsvc2(NS_Provider_IPL4_CT vc_ipep, charstring remote_ip, PortNumber remote_port)
220runs on RAW_NS_CT return integer {
221 var integer idx := -1;
222 NSPIP_PROC.call(NSPIP_add_nsvc:{remote_ip, remote_port, null}) to vc_ipep {
223 [] NSPIP_PROC.getreply(NSPIP_add_nsvc:{?,?,?}) -> value idx;
224 }
225
226 return idx;
227}
228
Harald Welte013d65a2020-09-13 14:41:31 +0200229} /* module */