blob: 22ca7b2a4886d9b69ba5a9e715be032bb42a7bd9 [file] [log] [blame]
Alexander Couzens6a161492020-07-12 13:45:50 +02001/*! \file gprs_ns2_sns.c
2 * NS Sub-Network Service Protocol implementation
3 * 3GPP TS 08.16 version 8.0.1 Release 1999 / ETSI TS 101 299 V8.0.1 (2002-05)
4 * as well as its successor 3GPP TS 48.016 */
5
Harald Weltec1c7e4a2021-03-02 20:47:29 +01006/* (C) 2018-2021 by Harald Welte <laforge@gnumonks.org>
Alexander Couzens6a161492020-07-12 13:45:50 +02007 * (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
8 * Author: Alexander Couzens <lynxis@fe80.eu>
9 *
10 * All Rights Reserved
11 *
12 * SPDX-License-Identifier: GPL-2.0+
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program. If not, see <http://www.gnu.org/licenses/>.
26 *
27 */
28
29/* The BSS NSE only has one SGSN IP address configured, and it will use the SNS procedures
30 * to communicated its local IPs/ports as well as all the SGSN side IPs/ports and
31 * associated weights. The BSS then uses this to establish a full mesh
32 * of NSVCs between all BSS-side IPs/ports and SGSN-side IPs/ports.
33 *
34 * Known limitation/expectation/bugs:
35 * - No concurrent dual stack. It supports either IPv4 or IPv6, but not both at the same time.
36 * - SNS Add/Change/Delete: Doesn't answer on the same NSVC as received SNS ADD/CHANGE/DELETE PDUs.
37 * - SNS Add/Change/Delete: Doesn't communicated the failed IPv4/IPv6 entries on the SNS_ACK.
38 */
39
40#include <errno.h>
41
42#include <netinet/in.h>
43#include <arpa/inet.h>
44#include <stdint.h>
45
46#include <osmocom/core/fsm.h>
47#include <osmocom/core/msgb.h>
48#include <osmocom/core/socket.h>
Alexander Couzens412bc342020-11-19 05:24:37 +010049#include <osmocom/core/sockaddr_str.h>
Alexander Couzens6a161492020-07-12 13:45:50 +020050#include <osmocom/gsm/tlv.h>
51#include <osmocom/gprs/gprs_msgb.h>
52#include <osmocom/gprs/gprs_ns2.h>
53#include <osmocom/gprs/protocol/gsm_08_16.h>
54
55#include "gprs_ns2_internal.h"
56
57#define S(x) (1 << (x))
58
Harald Welte4f127462021-03-02 20:49:10 +010059enum ns2_sns_role {
60 GPRS_SNS_ROLE_BSS,
61 GPRS_SNS_ROLE_SGSN,
62};
63
Harald Welte694dad52021-03-23 15:22:16 +010064/* BSS-side-only states _ST_BSS_; SGSN-side only states _ST_SGSN_; others shared */
Alexander Couzens6a161492020-07-12 13:45:50 +020065enum gprs_sns_bss_state {
66 GPRS_SNS_ST_UNCONFIGURED,
Harald Welte694dad52021-03-23 15:22:16 +010067 GPRS_SNS_ST_BSS_SIZE, /*!< SNS-SIZE procedure ongoing */
68 GPRS_SNS_ST_BSS_CONFIG_BSS, /*!< SNS-CONFIG procedure (BSS->SGSN) ongoing */
69 GPRS_SNS_ST_BSS_CONFIG_SGSN, /*!< SNS-CONFIG procedure (SGSN->BSS) ongoing */
Alexander Couzens6a161492020-07-12 13:45:50 +020070 GPRS_SNS_ST_CONFIGURED,
Harald Welte4f127462021-03-02 20:49:10 +010071 GPRS_SNS_ST_SGSN_WAIT_CONFIG, /* !< SGSN role: Wait for CONFIG from BSS */
72 GPRS_SNS_ST_SGSN_WAIT_CONFIG_ACK, /* !< SGSN role: Wait for CONFIG-ACK from BSS */
Alexander Couzens1f3193d2021-06-05 22:08:11 +020073 GPRS_SNS_ST_LOCAL_PROCEDURE, /*!< in process of a ADD/DEL/CHANGE procedure towards SGSN (BSS->SGSN) */
Alexander Couzens6a161492020-07-12 13:45:50 +020074};
75
Alexander Couzens6a161492020-07-12 13:45:50 +020076static const struct value_string gprs_sns_event_names[] = {
Alexander Couzens175eb7b2021-07-20 18:41:14 +020077 { NS2_SNS_EV_REQ_SELECT_ENDPOINT, "REQ_SELECT_ENDPOINT" },
78 { NS2_SNS_EV_RX_SIZE, "RX_SIZE" },
79 { NS2_SNS_EV_RX_SIZE_ACK, "RX_SIZE_ACK" },
80 { NS2_SNS_EV_RX_CONFIG, "RX_CONFIG" },
81 { NS2_SNS_EV_RX_CONFIG_END, "RX_CONFIG_END" },
82 { NS2_SNS_EV_RX_CONFIG_ACK, "RX_CONFIG_ACK" },
83 { NS2_SNS_EV_RX_ADD, "RX_ADD" },
84 { NS2_SNS_EV_RX_DELETE, "RX_DELETE" },
85 { NS2_SNS_EV_RX_ACK, "RX_ACK" },
86 { NS2_SNS_EV_RX_CHANGE_WEIGHT, "RX_CHANGE_WEIGHT" },
87 { NS2_SNS_EV_REQ_NO_NSVC, "REQ_NO_NSVC" },
Alexander Couzens83f06ce2021-08-06 19:50:09 +020088 { NS2_SNS_EV_REQ_FREE_NSVCS, "REQ_FREE_NSVCS" },
Alexander Couzens175eb7b2021-07-20 18:41:14 +020089 { NS2_SNS_EV_REQ_NSVC_ALIVE, "REQ_NSVC_ALIVE"},
90 { NS2_SNS_EV_REQ_ADD_BIND, "REQ_ADD_BIND"},
91 { NS2_SNS_EV_REQ_DELETE_BIND, "REQ_DELETE_BIND"},
Alexander Couzens1f3193d2021-06-05 22:08:11 +020092 { NS2_SNS_EV_REQ_CHANGE_WEIGHT, "REQ_CHANGE_WEIGHT"},
Alexander Couzens6a161492020-07-12 13:45:50 +020093 { 0, NULL }
94};
95
Alexander Couzens9cd39ac2021-06-06 18:57:56 +020096#define GPRS_SNS_FLAG_KEEP_SELECT_ENDPOINT_ORDER (void *) 1
97
Alexander Couzens1f3193d2021-06-05 22:08:11 +020098enum sns_procedure {
99 SNS_PROC_NONE, /*!< used as invalid/idle value */
100 SNS_PROC_ADD,
101 SNS_PROC_DEL,
102 SNS_PROC_CHANGE_WEIGHT,
103};
104
Alexander Couzense769f522020-12-07 07:37:07 +0100105struct sns_endpoint {
106 struct llist_head list;
107 struct osmo_sockaddr saddr;
108};
109
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100110struct ns2_sns_bind {
111 struct llist_head list;
112 struct gprs_ns2_vc_bind *bind;
Alexander Couzens1f3193d2021-06-05 22:08:11 +0200113 uint8_t change_weight_state;
114};
115
116struct ns2_sns_procedure {
117 struct llist_head list;
118 struct ns2_sns_bind *sbind;
119 uint16_t sig_weight;
120 uint16_t data_weight;
121 /* copy entry to protect against changes of gss->local */
122 struct gprs_ns_ie_ip4_elem ip4;
123 struct gprs_ns_ie_ip6_elem ip6;
124 enum sns_procedure procedure;
125 uint8_t trans_id;
126 /* is the procedure in process */
127 bool running;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100128};
129
Alexander Couzens71128672021-06-05 18:44:01 +0200130struct ns2_sns_elems {
131 struct gprs_ns_ie_ip4_elem *ip4;
132 unsigned int num_ip4;
133 struct gprs_ns_ie_ip6_elem *ip6;
134 unsigned int num_ip6;
135};
136
Alexander Couzens6a161492020-07-12 13:45:50 +0200137struct ns2_sns_state {
138 struct gprs_ns2_nse *nse;
139
Alexander Couzens077ce5a2021-06-06 01:32:45 +0200140 /* containing the address family AF_* */
141 int family;
Harald Welte4f127462021-03-02 20:49:10 +0100142 enum ns2_sns_role role; /* local role: BSS or SGSN */
Alexander Couzens6a161492020-07-12 13:45:50 +0200143
Alexander Couzense769f522020-12-07 07:37:07 +0100144 /* holds the list of initial SNS endpoints */
145 struct llist_head sns_endpoints;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100146 /* list of used struct ns2_sns_bind */
147 struct llist_head binds;
148 /* pointer to the bind which was used to initiate the SNS connection */
149 struct ns2_sns_bind *initial_bind;
Alexander Couzense769f522020-12-07 07:37:07 +0100150 /* prevent recursive reselection */
151 bool reselection_running;
152
Alexander Couzensdb07a442021-06-06 18:58:01 +0200153 /* protection against recursive free() */
154 bool block_no_nsvc_events;
155
Alexander Couzense769f522020-12-07 07:37:07 +0100156 /* The current initial SNS endpoints.
157 * The initial connection will be moved into the NSE
158 * if configured via SNS. Otherwise it will be removed
159 * in configured state. */
160 struct sns_endpoint *initial;
Alexander Couzens6a161492020-07-12 13:45:50 +0200161 /* all SNS PDU will be sent over this nsvc */
162 struct gprs_ns2_vc *sns_nsvc;
Alexander Couzens90ee9632020-12-07 06:18:32 +0100163 /* timer N */
164 int N;
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100165 /* true if at least one nsvc is alive */
166 bool alive;
Alexander Couzens6a161492020-07-12 13:45:50 +0200167
168 /* local configuration to send to the remote end */
Alexander Couzens71128672021-06-05 18:44:01 +0200169 struct ns2_sns_elems local;
Alexander Couzens6a161492020-07-12 13:45:50 +0200170
Alexander Couzens1f3193d2021-06-05 22:08:11 +0200171 /* local configuration after all local procedures applied */
172 struct ns2_sns_elems local_procedure;
173
Alexander Couzens71128672021-06-05 18:44:01 +0200174 /* remote configuration as received */
175 struct ns2_sns_elems remote;
Alexander Couzens6a161492020-07-12 13:45:50 +0200176
177 /* local configuration about our capabilities in terms of connections to
178 * remote (SGSN) side */
179 size_t num_max_nsvcs;
180 size_t num_max_ip4_remote;
181 size_t num_max_ip6_remote;
Alexander Couzens1f3193d2021-06-05 22:08:11 +0200182
183 struct llist_head procedures;
184 struct ns2_sns_procedure *current_procedure;
185 uint8_t trans_id;
Alexander Couzens6a161492020-07-12 13:45:50 +0200186};
187
188static inline struct gprs_ns2_nse *nse_inst_from_fi(struct osmo_fsm_inst *fi)
189{
190 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
191 return gss->nse;
192}
193
Alexander Couzens652ab4d2021-06-12 23:09:46 +0200194/* The SNS has failed. Etither restart the SNS (BSS) or remove the SNS (SGSN) */
195#define sns_failed(fi, reason) \
196 _sns_failed(fi, reason, __FILE__, __LINE__)
197static void _sns_failed(struct osmo_fsm_inst *fi, const char *reason, const char *file, int line)
198{
199 struct ns2_sns_state *gss = fi->priv;
200
201 if (reason)
Alexander Couzensb0874cd2021-07-20 22:15:00 +0200202 LOGPFSMLSRC(fi, LOGL_ERROR, file, line, "NSE %d: SNS failed: %s\n", gss->nse->nsei, reason);
Alexander Couzens652ab4d2021-06-12 23:09:46 +0200203
204 if (gss->role == GPRS_SNS_ROLE_SGSN) {
205 if (!gss->nse->persistent)
206 gprs_ns2_free_nse(gss->nse);
207 else
208 _osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0, file, line);
209 } else {
Alexander Couzens175eb7b2021-07-20 18:41:14 +0200210 _osmo_fsm_inst_dispatch(fi, NS2_SNS_EV_REQ_SELECT_ENDPOINT, NULL, file, line);
Alexander Couzens652ab4d2021-06-12 23:09:46 +0200211 }
212}
213
Alexander Couzens6a161492020-07-12 13:45:50 +0200214/* helper function to compute the sum of all (data or signaling) weights */
Alexander Couzens62310552021-06-06 02:43:14 +0200215static int ip4_weight_sum(const struct ns2_sns_elems *elems, bool data_weight)
Alexander Couzens6a161492020-07-12 13:45:50 +0200216{
217 unsigned int i;
218 int weight_sum = 0;
219
Alexander Couzens62310552021-06-06 02:43:14 +0200220 for (i = 0; i < elems->num_ip4; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200221 if (data_weight)
Alexander Couzens62310552021-06-06 02:43:14 +0200222 weight_sum += elems->ip4[i].data_weight;
Alexander Couzens6a161492020-07-12 13:45:50 +0200223 else
Alexander Couzens62310552021-06-06 02:43:14 +0200224 weight_sum += elems->ip4[i].sig_weight;
Alexander Couzens6a161492020-07-12 13:45:50 +0200225 }
226 return weight_sum;
227}
Alexander Couzens62310552021-06-06 02:43:14 +0200228#define ip4_weight_sum_data(elems) ip4_weight_sum(elems, true)
229#define ip4_weight_sum_sig(elems) ip4_weight_sum(elems, false)
Alexander Couzens6a161492020-07-12 13:45:50 +0200230
231/* helper function to compute the sum of all (data or signaling) weights */
Alexander Couzens62310552021-06-06 02:43:14 +0200232static int ip6_weight_sum(const struct ns2_sns_elems *elems, bool data_weight)
Alexander Couzens6a161492020-07-12 13:45:50 +0200233{
234 unsigned int i;
235 int weight_sum = 0;
236
Alexander Couzens62310552021-06-06 02:43:14 +0200237 for (i = 0; i < elems->num_ip6; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200238 if (data_weight)
Alexander Couzens62310552021-06-06 02:43:14 +0200239 weight_sum += elems->ip6[i].data_weight;
Alexander Couzens6a161492020-07-12 13:45:50 +0200240 else
Alexander Couzens62310552021-06-06 02:43:14 +0200241 weight_sum += elems->ip6[i].sig_weight;
Alexander Couzens6a161492020-07-12 13:45:50 +0200242 }
243 return weight_sum;
244}
Alexander Couzens62310552021-06-06 02:43:14 +0200245#define ip6_weight_sum_data(elems) ip6_weight_sum(elems, true)
246#define ip6_weight_sum_sig(elems) ip6_weight_sum(elems, false)
Alexander Couzens6a161492020-07-12 13:45:50 +0200247
Alexander Couzens019da4b2021-06-06 02:48:18 +0200248static int ip46_weight_sum(const struct ns2_sns_elems *elems, bool data_weight)
Harald Weltec1c7e4a2021-03-02 20:47:29 +0100249{
Alexander Couzens019da4b2021-06-06 02:48:18 +0200250 return ip4_weight_sum(elems, data_weight) +
251 ip6_weight_sum(elems, data_weight);
Harald Weltec1c7e4a2021-03-02 20:47:29 +0100252}
Alexander Couzens019da4b2021-06-06 02:48:18 +0200253#define ip46_weight_sum_data(elems) ip46_weight_sum(elems, true)
254#define ip46_weight_sum_sig(elems) ip46_weight_sum(elems, false)
Harald Weltec1c7e4a2021-03-02 20:47:29 +0100255
Alexander Couzens6a161492020-07-12 13:45:50 +0200256static struct gprs_ns2_vc *nsvc_by_ip4_elem(struct gprs_ns2_nse *nse,
257 const struct gprs_ns_ie_ip4_elem *ip4)
258{
259 struct osmo_sockaddr sa;
260 /* copy over. Both data structures use network byte order */
261 sa.u.sin.sin_addr.s_addr = ip4->ip_addr;
262 sa.u.sin.sin_port = ip4->udp_port;
263 sa.u.sin.sin_family = AF_INET;
264
Alexander Couzens38b19e82020-09-23 23:56:37 +0200265 return gprs_ns2_nsvc_by_sockaddr_nse(nse, &sa);
Alexander Couzens6a161492020-07-12 13:45:50 +0200266}
267
268static struct gprs_ns2_vc *nsvc_by_ip6_elem(struct gprs_ns2_nse *nse,
269 const struct gprs_ns_ie_ip6_elem *ip6)
270{
271 struct osmo_sockaddr sa;
272 /* copy over. Both data structures use network byte order */
273 sa.u.sin6.sin6_addr = ip6->ip_addr;
274 sa.u.sin6.sin6_port = ip6->udp_port;
275 sa.u.sin6.sin6_family = AF_INET;
276
Alexander Couzens38b19e82020-09-23 23:56:37 +0200277 return gprs_ns2_nsvc_by_sockaddr_nse(nse, &sa);
Alexander Couzens6a161492020-07-12 13:45:50 +0200278}
279
Alexander Couzens125298f2020-10-11 21:22:42 +0200280/*! Return the initial SNS remote socket address
281 * \param nse NS Entity
282 * \return address of the initial SNS connection; NULL in case of error
283 */
284const struct osmo_sockaddr *gprs_ns2_nse_sns_remote(struct gprs_ns2_nse *nse)
285{
286 struct ns2_sns_state *gss;
287
288 if (!nse->bss_sns_fi)
289 return NULL;
290
291 gss = (struct ns2_sns_state *) nse->bss_sns_fi->priv;
Alexander Couzense769f522020-12-07 07:37:07 +0100292 return &gss->initial->saddr;
Alexander Couzens125298f2020-10-11 21:22:42 +0200293}
294
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100295/*! called when a nsvc is beeing freed or the nsvc became dead */
296void ns2_sns_replace_nsvc(struct gprs_ns2_vc *nsvc)
Alexander Couzens6a161492020-07-12 13:45:50 +0200297{
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100298 struct gprs_ns2_nse *nse = nsvc->nse;
Alexander Couzens6a161492020-07-12 13:45:50 +0200299 struct gprs_ns2_vc *tmp;
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100300 struct osmo_fsm_inst *fi = nse->bss_sns_fi;
Alexander Couzens6a161492020-07-12 13:45:50 +0200301 struct ns2_sns_state *gss;
Alexander Couzens6a161492020-07-12 13:45:50 +0200302
303 if (!fi)
304 return;
305
306 gss = (struct ns2_sns_state *) fi->priv;
307 if (nsvc != gss->sns_nsvc)
308 return;
309
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100310 gss->sns_nsvc = NULL;
311 if (gss->alive) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200312 llist_for_each_entry(tmp, &nse->nsvc, list) {
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100313 if (ns2_vc_is_unblocked(tmp)) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200314 gss->sns_nsvc = tmp;
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100315 return;
316 }
Alexander Couzens6a161492020-07-12 13:45:50 +0200317 }
318 } else {
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100319 /* the SNS is waiting for its first NS-VC to come up
320 * choose any other nsvc */
321 llist_for_each_entry(tmp, &nse->nsvc, list) {
322 if (nsvc != tmp) {
323 gss->sns_nsvc = tmp;
324 return;
325 }
326 }
Alexander Couzens6a161492020-07-12 13:45:50 +0200327 }
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100328
Alexander Couzensdb07a442021-06-06 18:58:01 +0200329 if (gss->block_no_nsvc_events)
330 osmo_fsm_inst_dispatch(fi, NS2_SNS_EV_REQ_NO_NSVC, NULL);
Alexander Couzens6a161492020-07-12 13:45:50 +0200331}
332
Alexander Couzensd2c6c492021-06-06 01:57:52 +0200333static void ns2_clear_elems(struct ns2_sns_elems *elems)
Alexander Couzens7a7b20b2021-01-18 10:47:33 +0100334{
Alexander Couzensd2c6c492021-06-06 01:57:52 +0200335 TALLOC_FREE(elems->ip4);
336 TALLOC_FREE(elems->ip6);
Alexander Couzens7a7b20b2021-01-18 10:47:33 +0100337
Alexander Couzensd2c6c492021-06-06 01:57:52 +0200338 elems->num_ip4 = 0;
339 elems->num_ip6 = 0;
Alexander Couzens7a7b20b2021-01-18 10:47:33 +0100340}
341
Alexander Couzens1f3193d2021-06-05 22:08:11 +0200342static void ns2_clear_procedures(struct ns2_sns_state *gss)
343{
344 struct ns2_sns_procedure *procedure, *tmp;
345 gss->current_procedure = NULL;
346 llist_for_each_entry_safe(procedure, tmp, &gss->procedures, list) {
347 llist_del(&procedure->list);
348 talloc_free(procedure);
349 }
350}
351
Daniel Willmanncf8371a2021-01-16 15:13:51 +0100352static void ns2_vc_create_ip(struct osmo_fsm_inst *fi, struct gprs_ns2_nse *nse, const struct osmo_sockaddr *remote,
353 uint8_t sig_weight, uint8_t data_weight)
Alexander Couzens6a161492020-07-12 13:45:50 +0200354{
355 struct gprs_ns2_inst *nsi = nse->nsi;
356 struct gprs_ns2_vc *nsvc;
357 struct gprs_ns2_vc_bind *bind;
Daniel Willmanncf8371a2021-01-16 15:13:51 +0100358
359 /* for every bind, create a connection if bind type == IP */
360 llist_for_each_entry(bind, &nsi->binding, list) {
361 if (bind->ll != GPRS_NS2_LL_UDP)
362 continue;
363 /* ignore failed connection */
364 nsvc = gprs_ns2_ip_connect_inactive(bind,
365 remote,
366 nse, 0);
367 if (!nsvc) {
368 LOGPFSML(fi, LOGL_ERROR, "SNS-CONFIG: Failed to create NSVC\n");
369 continue;
370 }
371
372 nsvc->sig_weight = sig_weight;
373 nsvc->data_weight = data_weight;
374 }
375}
376
377static void ns2_nsvc_create_ip4(struct osmo_fsm_inst *fi,
378 struct gprs_ns2_nse *nse,
379 const struct gprs_ns_ie_ip4_elem *ip4)
380{
Alexander Couzensc068d862020-10-12 04:11:51 +0200381 struct osmo_sockaddr remote = { };
Alexander Couzens6a161492020-07-12 13:45:50 +0200382 /* copy over. Both data structures use network byte order */
383 remote.u.sin.sin_family = AF_INET;
384 remote.u.sin.sin_addr.s_addr = ip4->ip_addr;
385 remote.u.sin.sin_port = ip4->udp_port;
386
Daniel Willmanncf8371a2021-01-16 15:13:51 +0100387 ns2_vc_create_ip(fi, nse, &remote, ip4->sig_weight, ip4->data_weight);
Alexander Couzens6a161492020-07-12 13:45:50 +0200388}
389
390static void ns2_nsvc_create_ip6(struct osmo_fsm_inst *fi,
391 struct gprs_ns2_nse *nse,
392 const struct gprs_ns_ie_ip6_elem *ip6)
393{
Alexander Couzens6a161492020-07-12 13:45:50 +0200394 struct osmo_sockaddr remote = {};
395 /* copy over. Both data structures use network byte order */
396 remote.u.sin6.sin6_family = AF_INET6;
397 remote.u.sin6.sin6_addr = ip6->ip_addr;
398 remote.u.sin6.sin6_port = ip6->udp_port;
399
Daniel Willmanncf8371a2021-01-16 15:13:51 +0100400 ns2_vc_create_ip(fi, nse, &remote, ip6->sig_weight, ip6->data_weight);
Alexander Couzens6a161492020-07-12 13:45:50 +0200401}
402
Harald Weltee8c61062021-03-24 13:16:27 +0100403static struct gprs_ns2_vc *nsvc_for_bind_and_remote(struct gprs_ns2_nse *nse,
404 struct gprs_ns2_vc_bind *bind,
405 const struct osmo_sockaddr *remote)
406{
407 struct gprs_ns2_vc *nsvc;
408
409 llist_for_each_entry(nsvc, &nse->nsvc, list) {
410 if (nsvc->bind != bind)
411 continue;
412
413 if (!osmo_sockaddr_cmp(remote, gprs_ns2_ip_vc_remote(nsvc)))
414 return nsvc;
415 }
416 return NULL;
417}
Alexander Couzens6a161492020-07-12 13:45:50 +0200418
419static int create_missing_nsvcs(struct osmo_fsm_inst *fi)
420{
421 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
422 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
423 struct gprs_ns2_vc *nsvc;
Harald Welte3053bbb2021-03-24 13:22:18 +0100424 struct ns2_sns_bind *sbind;
Alexander Couzens6a161492020-07-12 13:45:50 +0200425 struct osmo_sockaddr remote = { };
426 unsigned int i;
427
Harald Weltee8c61062021-03-24 13:16:27 +0100428 /* iterate over all remote IPv4 endpoints */
Alexander Couzens71128672021-06-05 18:44:01 +0200429 for (i = 0; i < gss->remote.num_ip4; i++) {
430 const struct gprs_ns_ie_ip4_elem *ip4 = &gss->remote.ip4[i];
Alexander Couzens6a161492020-07-12 13:45:50 +0200431
432 remote.u.sin.sin_family = AF_INET;
433 remote.u.sin.sin_addr.s_addr = ip4->ip_addr;
434 remote.u.sin.sin_port = ip4->udp_port;
435
Harald Welte3053bbb2021-03-24 13:22:18 +0100436 /* iterate over all local binds within this SNS */
437 llist_for_each_entry(sbind, &gss->binds, list) {
438 struct gprs_ns2_vc_bind *bind = sbind->bind;
439
Harald Weltee8c61062021-03-24 13:16:27 +0100440 /* we only care about UDP binds */
Daniel Willmann967e2c12021-01-14 16:58:17 +0100441 if (bind->ll != GPRS_NS2_LL_UDP)
442 continue;
Alexander Couzens6a161492020-07-12 13:45:50 +0200443
Harald Weltee8c61062021-03-24 13:16:27 +0100444 nsvc = nsvc_for_bind_and_remote(nse, bind, &remote);
445 if (!nsvc) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200446 nsvc = gprs_ns2_ip_connect_inactive(bind, &remote, nse, 0);
447 if (!nsvc) {
448 /* TODO: add to a list to send back a NS-STATUS */
449 continue;
450 }
451 }
452
453 /* update data / signalling weight */
454 nsvc->data_weight = ip4->data_weight;
455 nsvc->sig_weight = ip4->sig_weight;
456 nsvc->sns_only = false;
457 }
458 }
459
Harald Weltee8c61062021-03-24 13:16:27 +0100460 /* iterate over all remote IPv4 endpoints */
Alexander Couzens71128672021-06-05 18:44:01 +0200461 for (i = 0; i < gss->remote.num_ip6; i++) {
462 const struct gprs_ns_ie_ip6_elem *ip6 = &gss->remote.ip6[i];
Alexander Couzens6a161492020-07-12 13:45:50 +0200463
464 remote.u.sin6.sin6_family = AF_INET6;
465 remote.u.sin6.sin6_addr = ip6->ip_addr;
466 remote.u.sin6.sin6_port = ip6->udp_port;
467
Harald Welte3053bbb2021-03-24 13:22:18 +0100468 /* iterate over all local binds within this SNS */
469 llist_for_each_entry(sbind, &gss->binds, list) {
470 struct gprs_ns2_vc_bind *bind = sbind->bind;
471
Daniel Willmann967e2c12021-01-14 16:58:17 +0100472 if (bind->ll != GPRS_NS2_LL_UDP)
473 continue;
Alexander Couzens6a161492020-07-12 13:45:50 +0200474
Harald Weltee8c61062021-03-24 13:16:27 +0100475 /* we only care about UDP binds */
476 nsvc = nsvc_for_bind_and_remote(nse, bind, &remote);
477 if (!nsvc) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200478 nsvc = gprs_ns2_ip_connect_inactive(bind, &remote, nse, 0);
479 if (!nsvc) {
480 /* TODO: add to a list to send back a NS-STATUS */
481 continue;
482 }
483 }
484
485 /* update data / signalling weight */
486 nsvc->data_weight = ip6->data_weight;
487 nsvc->sig_weight = ip6->sig_weight;
488 nsvc->sns_only = false;
489 }
490 }
491
492
493 return 0;
494}
495
496/* Add a given remote IPv4 element to gprs_sns_state */
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200497static int add_ip4_elem(struct ns2_sns_state *gss, struct ns2_sns_elems *elems,
498 const struct gprs_ns_ie_ip4_elem *ip4)
Alexander Couzens6a161492020-07-12 13:45:50 +0200499{
Alexander Couzens6a161492020-07-12 13:45:50 +0200500 /* check for duplicates */
Alexander Couzenscc56ddc2021-06-06 03:33:35 +0200501 for (unsigned int i = 0; i < elems->num_ip4; i++) {
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200502 if (memcmp(&elems->ip4[i], ip4, sizeof(*ip4)))
Alexander Couzens6a161492020-07-12 13:45:50 +0200503 continue;
Alexander Couzensd3507e82021-06-06 03:32:32 +0200504 return -1;
Alexander Couzens6a161492020-07-12 13:45:50 +0200505 }
506
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200507 elems->ip4 = talloc_realloc(gss, elems->ip4, struct gprs_ns_ie_ip4_elem,
508 elems->num_ip4+1);
509 elems->ip4[elems->num_ip4] = *ip4;
510 elems->num_ip4 += 1;
Alexander Couzens6a161492020-07-12 13:45:50 +0200511 return 0;
512}
513
514/* Remove a given remote IPv4 element from gprs_sns_state */
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200515static int remove_ip4_elem(struct ns2_sns_state *gss, struct ns2_sns_elems *elems,
516 const struct gprs_ns_ie_ip4_elem *ip4)
Alexander Couzens6a161492020-07-12 13:45:50 +0200517{
518 unsigned int i;
519
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200520 for (i = 0; i < elems->num_ip4; i++) {
521 if (memcmp(&elems->ip4[i], ip4, sizeof(*ip4)))
Alexander Couzens6a161492020-07-12 13:45:50 +0200522 continue;
523 /* all array elements < i remain as they are; all > i are shifted left by one */
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200524 memmove(&elems->ip4[i], &elems->ip4[i+1], elems->num_ip4-i-1);
525 elems->num_ip4 -= 1;
Alexander Couzens6a161492020-07-12 13:45:50 +0200526 return 0;
527 }
528 return -1;
529}
530
531/* update the weights for specified remote IPv4 */
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200532static int update_ip4_elem(struct ns2_sns_state *gss, struct ns2_sns_elems *elems,
533 const struct gprs_ns_ie_ip4_elem *ip4)
Alexander Couzens6a161492020-07-12 13:45:50 +0200534{
535 unsigned int i;
536
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200537 for (i = 0; i < elems->num_ip4; i++) {
538 if (elems->ip4[i].ip_addr != ip4->ip_addr ||
539 elems->ip4[i].udp_port != ip4->udp_port)
Alexander Couzens6a161492020-07-12 13:45:50 +0200540 continue;
541
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200542 elems->ip4[i].sig_weight = ip4->sig_weight;
543 elems->ip4[i].data_weight = ip4->data_weight;
Alexander Couzens6a161492020-07-12 13:45:50 +0200544 return 0;
545 }
546 return -1;
547}
548
549/* Add a given remote IPv6 element to gprs_sns_state */
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200550static int add_ip6_elem(struct ns2_sns_state *gss, struct ns2_sns_elems *elems,
551 const struct gprs_ns_ie_ip6_elem *ip6)
Alexander Couzens6a161492020-07-12 13:45:50 +0200552{
Alexander Couzenscc56ddc2021-06-06 03:33:35 +0200553 /* check for duplicates */
554 for (unsigned int i = 0; i < elems->num_ip6; i++) {
555 if (memcmp(&elems->ip6[i].ip_addr, &ip6->ip_addr, sizeof(ip6->ip_addr)) ||
556 elems->ip6[i].udp_port != ip6->udp_port)
557 continue;
558 return -1;
559 }
Alexander Couzens6a161492020-07-12 13:45:50 +0200560
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200561 elems->ip6 = talloc_realloc(gss, elems->ip6, struct gprs_ns_ie_ip6_elem,
562 elems->num_ip6+1);
563 elems->ip6[elems->num_ip6] = *ip6;
564 elems->num_ip6 += 1;
Alexander Couzens6a161492020-07-12 13:45:50 +0200565 return 0;
566}
567
568/* Remove a given remote IPv6 element from gprs_sns_state */
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200569static int remove_ip6_elem(struct ns2_sns_state *gss, struct ns2_sns_elems *elems,
570 const struct gprs_ns_ie_ip6_elem *ip6)
Alexander Couzens6a161492020-07-12 13:45:50 +0200571{
572 unsigned int i;
573
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200574 for (i = 0; i < elems->num_ip6; i++) {
575 if (memcmp(&elems->ip6[i], ip6, sizeof(*ip6)))
Alexander Couzens6a161492020-07-12 13:45:50 +0200576 continue;
577 /* all array elements < i remain as they are; all > i are shifted left by one */
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200578 memmove(&elems->ip6[i], &elems->ip6[i+1], elems->num_ip6-i-1);
579 elems->num_ip6 -= 1;
Alexander Couzens6a161492020-07-12 13:45:50 +0200580 return 0;
581 }
582 return -1;
583}
584
585/* update the weights for specified remote IPv6 */
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200586static int update_ip6_elem(struct ns2_sns_state *gss, struct ns2_sns_elems *elems,
587 const struct gprs_ns_ie_ip6_elem *ip6)
Alexander Couzens6a161492020-07-12 13:45:50 +0200588{
589 unsigned int i;
590
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200591 for (i = 0; i < elems->num_ip6; i++) {
592 if (memcmp(&elems->ip6[i].ip_addr, &ip6->ip_addr, sizeof(ip6->ip_addr)) ||
593 elems->ip6[i].udp_port != ip6->udp_port)
Alexander Couzens6a161492020-07-12 13:45:50 +0200594 continue;
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200595 elems->ip6[i].sig_weight = ip6->sig_weight;
596 elems->ip6[i].data_weight = ip6->data_weight;
Alexander Couzens6a161492020-07-12 13:45:50 +0200597 return 0;
598 }
599 return -1;
600}
601
Alexander Couzensdb07a442021-06-06 18:58:01 +0200602static int remove_bind_elem(struct ns2_sns_state *gss, struct ns2_sns_elems *elems, struct ns2_sns_bind *sbind)
603{
604 struct gprs_ns_ie_ip4_elem ip4;
605 struct gprs_ns_ie_ip6_elem ip6;
606 const struct osmo_sockaddr *saddr = gprs_ns2_ip_bind_sockaddr(sbind->bind);
607
608 switch (saddr->u.sa.sa_family) {
609 case AF_INET:
610 ip4.ip_addr = saddr->u.sin.sin_addr.s_addr;
611 ip4.udp_port = saddr->u.sin.sin_port;
612 ip4.sig_weight = sbind->bind->sns_sig_weight;
613 ip4.data_weight = sbind->bind->sns_data_weight;
614 return remove_ip4_elem(gss, elems, &ip4);
615 case AF_INET6:
616 memcpy(&ip6.ip_addr, &saddr->u.sin6.sin6_addr, sizeof(struct in6_addr));
617 ip6.udp_port = saddr->u.sin.sin_port;
618 ip6.sig_weight = sbind->bind->sns_sig_weight;
619 ip6.data_weight = sbind->bind->sns_data_weight;
620 return remove_ip6_elem(gss, elems, &ip6);
621 default:
622 return -1;
623 }
624
625 return -1;
626}
627
Alexander Couzens6a161492020-07-12 13:45:50 +0200628static int do_sns_change_weight(struct osmo_fsm_inst *fi, const struct gprs_ns_ie_ip4_elem *ip4, const struct gprs_ns_ie_ip6_elem *ip6)
629{
630 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
631 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
632 struct gprs_ns2_vc *nsvc;
633 struct osmo_sockaddr sa = {};
Alexander Couzens9a4cf272020-10-11 20:48:04 +0200634 const struct osmo_sockaddr *remote;
Alexander Couzens6a161492020-07-12 13:45:50 +0200635 uint8_t new_signal;
636 uint8_t new_data;
637
638 /* TODO: Upon receiving an SNS-CHANGEWEIGHT PDU, if the resulting sum of the
639 * signalling weights of all the peer IP endpoints configured for this NSE is
640 * equal to zero or if the resulting sum of the data weights of all the peer IP
641 * endpoints configured for this NSE is equal to zero, the BSS/SGSN shall send an
642 * SNS-ACK PDU with a cause code of "Invalid weights". */
643
644 if (ip4) {
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200645 if (update_ip4_elem(gss, &gss->remote, ip4))
Alexander Couzens6a161492020-07-12 13:45:50 +0200646 return -NS_CAUSE_UNKN_IP_EP;
647
648 /* copy over. Both data structures use network byte order */
649 sa.u.sin.sin_addr.s_addr = ip4->ip_addr;
650 sa.u.sin.sin_port = ip4->udp_port;
651 sa.u.sin.sin_family = AF_INET;
652 new_signal = ip4->sig_weight;
653 new_data = ip4->data_weight;
654 } else if (ip6) {
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200655 if (update_ip6_elem(gss, &gss->remote, ip6))
Alexander Couzens6a161492020-07-12 13:45:50 +0200656 return -NS_CAUSE_UNKN_IP_EP;
657
658 /* copy over. Both data structures use network byte order */
659 sa.u.sin6.sin6_addr = ip6->ip_addr;
660 sa.u.sin6.sin6_port = ip6->udp_port;
661 sa.u.sin6.sin6_family = AF_INET6;
662 new_signal = ip6->sig_weight;
663 new_data = ip6->data_weight;
664 } else {
665 OSMO_ASSERT(false);
666 }
667
668 llist_for_each_entry(nsvc, &nse->nsvc, list) {
Alexander Couzensc4229a42020-10-11 20:58:04 +0200669 remote = gprs_ns2_ip_vc_remote(nsvc);
Alexander Couzens6a161492020-07-12 13:45:50 +0200670 /* all nsvc in NSE should be IP/UDP nsvc */
671 OSMO_ASSERT(remote);
672
673 if (osmo_sockaddr_cmp(&sa, remote))
674 continue;
675
676 LOGPFSML(fi, LOGL_INFO, "CHANGE-WEIGHT NS-VC %s data_weight %u->%u, sig_weight %u->%u\n",
677 gprs_ns2_ll_str(nsvc), nsvc->data_weight, new_data,
678 nsvc->sig_weight, new_signal);
679
680 nsvc->data_weight = new_data;
681 nsvc->sig_weight = new_signal;
682 }
683
684 return 0;
685}
686
687static int do_sns_delete(struct osmo_fsm_inst *fi,
688 const struct gprs_ns_ie_ip4_elem *ip4,
689 const struct gprs_ns_ie_ip6_elem *ip6)
690{
691 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
692 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
693 struct gprs_ns2_vc *nsvc, *tmp;
Alexander Couzens9a4cf272020-10-11 20:48:04 +0200694 const struct osmo_sockaddr *remote;
Alexander Couzens6a161492020-07-12 13:45:50 +0200695 struct osmo_sockaddr sa = {};
696
697 if (ip4) {
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200698 if (remove_ip4_elem(gss, &gss->remote, ip4) < 0)
Alexander Couzens6a161492020-07-12 13:45:50 +0200699 return -NS_CAUSE_UNKN_IP_EP;
700 /* copy over. Both data structures use network byte order */
701 sa.u.sin.sin_addr.s_addr = ip4->ip_addr;
702 sa.u.sin.sin_port = ip4->udp_port;
703 sa.u.sin.sin_family = AF_INET;
704 } else if (ip6) {
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200705 if (remove_ip6_elem(gss, &gss->remote, ip6))
Alexander Couzens6a161492020-07-12 13:45:50 +0200706 return -NS_CAUSE_UNKN_IP_EP;
707
708 /* copy over. Both data structures use network byte order */
709 sa.u.sin6.sin6_addr = ip6->ip_addr;
710 sa.u.sin6.sin6_port = ip6->udp_port;
711 sa.u.sin6.sin6_family = AF_INET6;
712 } else {
713 OSMO_ASSERT(false);
714 }
715
716 llist_for_each_entry_safe(nsvc, tmp, &nse->nsvc, list) {
Alexander Couzensc4229a42020-10-11 20:58:04 +0200717 remote = gprs_ns2_ip_vc_remote(nsvc);
Alexander Couzens6a161492020-07-12 13:45:50 +0200718 /* all nsvc in NSE should be IP/UDP nsvc */
719 OSMO_ASSERT(remote);
720 if (osmo_sockaddr_cmp(&sa, remote))
721 continue;
722
723 LOGPFSML(fi, LOGL_INFO, "DELETE NS-VC %s\n", gprs_ns2_ll_str(nsvc));
724 gprs_ns2_free_nsvc(nsvc);
725 }
726
727 return 0;
728}
729
730static int do_sns_add(struct osmo_fsm_inst *fi,
731 const struct gprs_ns_ie_ip4_elem *ip4,
732 const struct gprs_ns_ie_ip6_elem *ip6)
733{
734 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
735 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
736 struct gprs_ns2_vc *nsvc;
737 int rc = 0;
738
739 /* Upon receiving an SNS-ADD PDU, if the consequent number of IPv4 endpoints
740 * exceeds the number of IPv4 endpoints supported by the NSE, the NSE shall send
741 * an SNS-ACK PDU with a cause code set to "Invalid number of IP4 Endpoints". */
Alexander Couzens077ce5a2021-06-06 01:32:45 +0200742 switch (gss->family) {
743 case AF_INET:
Alexander Couzensd3507e82021-06-06 03:32:32 +0200744 if (gss->remote.num_ip4 >= gss->num_max_ip4_remote)
745 return -NS_CAUSE_INVAL_NR_NS_VC;
746 /* TODO: log message duplicate */
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200747 rc = add_ip4_elem(gss, &gss->remote, ip4);
Alexander Couzens6a161492020-07-12 13:45:50 +0200748 break;
Alexander Couzens077ce5a2021-06-06 01:32:45 +0200749 case AF_INET6:
Alexander Couzensd3507e82021-06-06 03:32:32 +0200750 if (gss->remote.num_ip6 >= gss->num_max_ip6_remote)
751 return -NS_CAUSE_INVAL_NR_NS_VC;
752 /* TODO: log message duplicate */
Alexander Couzensc2ba25e2021-06-06 02:26:40 +0200753 rc = add_ip6_elem(gss, &gss->remote, ip6);
Alexander Couzens6a161492020-07-12 13:45:50 +0200754 break;
755 default:
756 /* the gss->ip is initialized with the bss */
757 OSMO_ASSERT(false);
758 }
759
760 if (rc)
Alexander Couzensd3507e82021-06-06 03:32:32 +0200761 return -NS_CAUSE_PROTO_ERR_UNSPEC;
Alexander Couzens6a161492020-07-12 13:45:50 +0200762
763 /* Upon receiving an SNS-ADD PDU containing an already configured IP endpoint the
764 * NSE shall send an SNS-ACK PDU with the cause code "Protocol error -
765 * unspecified" */
Alexander Couzens077ce5a2021-06-06 01:32:45 +0200766 switch (gss->family) {
767 case AF_INET:
Alexander Couzens6a161492020-07-12 13:45:50 +0200768 nsvc = nsvc_by_ip4_elem(nse, ip4);
769 if (nsvc) {
770 /* the nsvc should be already in sync with the ip4 / ip6 elements */
771 return -NS_CAUSE_PROTO_ERR_UNSPEC;
772 }
773
774 /* TODO: failure case */
775 ns2_nsvc_create_ip4(fi, nse, ip4);
776 break;
Alexander Couzens077ce5a2021-06-06 01:32:45 +0200777 case AF_INET6:
Alexander Couzens6a161492020-07-12 13:45:50 +0200778 nsvc = nsvc_by_ip6_elem(nse, ip6);
779 if (nsvc) {
780 /* the nsvc should be already in sync with the ip4 / ip6 elements */
781 return -NS_CAUSE_PROTO_ERR_UNSPEC;
782 }
783
784 /* TODO: failure case */
785 ns2_nsvc_create_ip6(fi, nse, ip6);
786 break;
787 }
788
789 gprs_ns2_start_alive_all_nsvcs(nse);
790
791 return 0;
792}
793
794
Harald Welte694dad52021-03-23 15:22:16 +0100795static void ns2_sns_st_bss_unconfigured(struct osmo_fsm_inst *fi, uint32_t event, void *data)
Alexander Couzens6a161492020-07-12 13:45:50 +0200796{
Harald Weltef61a9152021-03-02 22:20:17 +0100797 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
798 OSMO_ASSERT(gss->role == GPRS_SNS_ROLE_BSS);
Alexander Couzense769f522020-12-07 07:37:07 +0100799 /* empty state - SNS Select will start by ns2_sns_st_all_action() */
Alexander Couzens6a161492020-07-12 13:45:50 +0200800}
801
Harald Welte694dad52021-03-23 15:22:16 +0100802static void ns2_sns_st_bss_size(struct osmo_fsm_inst *fi, uint32_t event, void *data)
Alexander Couzens6a161492020-07-12 13:45:50 +0200803{
Harald Weltef61a9152021-03-02 22:20:17 +0100804 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
Alexander Couzens6a161492020-07-12 13:45:50 +0200805 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
806 struct gprs_ns2_inst *nsi = nse->nsi;
807 struct tlv_parsed *tp = NULL;
808
Harald Weltef61a9152021-03-02 22:20:17 +0100809 OSMO_ASSERT(gss->role == GPRS_SNS_ROLE_BSS);
810
Alexander Couzens6a161492020-07-12 13:45:50 +0200811 switch (event) {
Alexander Couzens175eb7b2021-07-20 18:41:14 +0200812 case NS2_SNS_EV_RX_SIZE_ACK:
Alexander Couzens6a161492020-07-12 13:45:50 +0200813 tp = data;
814 if (TLVP_VAL_MINLEN(tp, NS_IE_CAUSE, 1)) {
815 LOGPFSML(fi, LOGL_ERROR, "SNS-SIZE-ACK with cause %s\n",
816 gprs_ns2_cause_str(*TLVP_VAL(tp, NS_IE_CAUSE)));
817 /* TODO: What to do? */
818 } else {
Harald Welte694dad52021-03-23 15:22:16 +0100819 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_BSS_CONFIG_BSS,
Alexander Couzens6a161492020-07-12 13:45:50 +0200820 nsi->timeout[NS_TOUT_TSNS_PROV], 2);
821 }
822 break;
823 default:
824 OSMO_ASSERT(0);
825 }
826}
827
Alexander Couzens077ce5a2021-06-06 01:32:45 +0200828static int ns2_sns_count_num_local_ep(struct osmo_fsm_inst *fi, int ip_proto)
Harald Welte01fa6a32021-03-04 19:49:38 +0100829{
830 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
831 struct ns2_sns_bind *sbind;
832 int count = 0;
833
834 llist_for_each_entry(sbind, &gss->binds, list) {
835 const struct osmo_sockaddr *sa = gprs_ns2_ip_bind_sockaddr(sbind->bind);
836 if (!sa)
837 continue;
838
Alexander Couzens077ce5a2021-06-06 01:32:45 +0200839 switch (ip_proto) {
840 case AF_INET:
Harald Welte01fa6a32021-03-04 19:49:38 +0100841 if (sa->u.sas.ss_family == AF_INET)
842 count++;
843 break;
Alexander Couzens077ce5a2021-06-06 01:32:45 +0200844 case AF_INET6:
Harald Welte01fa6a32021-03-04 19:49:38 +0100845 if (sa->u.sas.ss_family == AF_INET6)
846 count++;
847 break;
848 }
849 }
850 return count;
851}
852
Alexander Couzens1f3193d2021-06-05 22:08:11 +0200853static int ns2_sns_copy_local_endpoints(struct ns2_sns_state *gss)
854{
855 switch (gss->family) {
856 case AF_INET:
857 gss->local_procedure.ip4 = talloc_realloc(gss, gss->local_procedure.ip4, struct gprs_ns_ie_ip4_elem,
858 gss->local.num_ip4);
859 if (!gss->local_procedure.ip4)
860 return -ENOMEM;
861
862 gss->local_procedure.num_ip4 = gss->local.num_ip4;
863 memcpy(gss->local_procedure.ip4, gss->local.ip4,
864 sizeof(struct gprs_ns_ie_ip4_elem) * gss->local.num_ip4);
865 break;
866 case AF_INET6:
867 gss->local_procedure.ip6 = talloc_realloc(gss, gss->local_procedure.ip6, struct gprs_ns_ie_ip6_elem,
868 gss->local.num_ip6);
869 if (!gss->local_procedure.ip6)
870 return -ENOMEM;
871
872 gss->local_procedure.num_ip6 = gss->local.num_ip6;
873 memcpy(gss->local_procedure.ip6, gss->local.ip6,
874 sizeof(struct gprs_ns_ie_ip6_elem) * gss->local.num_ip6);
875 break;
876 default:
877 OSMO_ASSERT(0);
878 }
879
880 return 0;
881}
882
Harald Welte24920e22021-03-04 13:03:27 +0100883static void ns2_sns_compute_local_ep_from_binds(struct osmo_fsm_inst *fi)
Alexander Couzens6a161492020-07-12 13:45:50 +0200884{
885 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
Alexander Couzense769f522020-12-07 07:37:07 +0100886 struct gprs_ns_ie_ip4_elem *ip4_elems;
887 struct gprs_ns_ie_ip6_elem *ip6_elems;
888 struct gprs_ns2_vc_bind *bind;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100889 struct ns2_sns_bind *sbind;
Harald Welte4f127462021-03-02 20:49:10 +0100890 const struct osmo_sockaddr *remote;
Alexander Couzense769f522020-12-07 07:37:07 +0100891 const struct osmo_sockaddr *sa;
892 struct osmo_sockaddr local;
893 int count;
Alexander Couzens6a161492020-07-12 13:45:50 +0200894
Alexander Couzensd2c6c492021-06-06 01:57:52 +0200895 ns2_clear_elems(&gss->local);
Alexander Couzens7a7b20b2021-01-18 10:47:33 +0100896
Alexander Couzense769f522020-12-07 07:37:07 +0100897 /* no initial available */
Harald Welte4f127462021-03-02 20:49:10 +0100898 if (gss->role == GPRS_SNS_ROLE_BSS) {
899 if (!gss->initial)
900 return;
901 remote = &gss->initial->saddr;
902 } else
903 remote = gprs_ns2_ip_vc_remote(gss->sns_nsvc);
Alexander Couzense769f522020-12-07 07:37:07 +0100904
905 /* count how many bindings are available (only UDP binds) */
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100906 count = llist_count(&gss->binds);
Alexander Couzense769f522020-12-07 07:37:07 +0100907 if (count == 0) {
Harald Welte05992872021-03-04 15:49:21 +0100908 LOGPFSML(fi, LOGL_ERROR, "No local binds for this NSE -> cannot determine IP endpoints\n");
Alexander Couzense769f522020-12-07 07:37:07 +0100909 return;
910 }
911
Alexander Couzens077ce5a2021-06-06 01:32:45 +0200912 switch (gss->family) {
913 case AF_INET:
Alexander Couzens71128672021-06-05 18:44:01 +0200914 ip4_elems = talloc_realloc(fi, gss->local.ip4, struct gprs_ns_ie_ip4_elem, count);
Alexander Couzense769f522020-12-07 07:37:07 +0100915 if (!ip4_elems)
916 return;
917
Alexander Couzens71128672021-06-05 18:44:01 +0200918 gss->local.ip4 = ip4_elems;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100919 llist_for_each_entry(sbind, &gss->binds, list) {
920 bind = sbind->bind;
Alexander Couzense769f522020-12-07 07:37:07 +0100921 sa = gprs_ns2_ip_bind_sockaddr(bind);
922 if (!sa)
923 continue;
924
925 if (sa->u.sas.ss_family != AF_INET)
926 continue;
927
928 /* check if this is an specific bind */
929 if (sa->u.sin.sin_addr.s_addr == 0) {
930 if (osmo_sockaddr_local_ip(&local, remote))
931 continue;
932
933 ip4_elems->ip_addr = local.u.sin.sin_addr.s_addr;
934 } else {
935 ip4_elems->ip_addr = sa->u.sin.sin_addr.s_addr;
936 }
937
938 ip4_elems->udp_port = sa->u.sin.sin_port;
Alexander Couzensc4704762021-02-08 23:13:12 +0100939 ip4_elems->sig_weight = bind->sns_sig_weight;
940 ip4_elems->data_weight = bind->sns_data_weight;
Alexander Couzense769f522020-12-07 07:37:07 +0100941 ip4_elems++;
942 }
943
Alexander Couzens71128672021-06-05 18:44:01 +0200944 gss->local.num_ip4 = count;
945 gss->num_max_nsvcs = OSMO_MAX(gss->num_max_ip4_remote * gss->local.num_ip4, 8);
Alexander Couzense769f522020-12-07 07:37:07 +0100946 break;
Alexander Couzens077ce5a2021-06-06 01:32:45 +0200947 case AF_INET6:
Alexander Couzense769f522020-12-07 07:37:07 +0100948 /* IPv6 */
Alexander Couzens71128672021-06-05 18:44:01 +0200949 ip6_elems = talloc_realloc(fi, gss->local.ip6, struct gprs_ns_ie_ip6_elem, count);
Alexander Couzense769f522020-12-07 07:37:07 +0100950 if (!ip6_elems)
951 return;
952
Alexander Couzens71128672021-06-05 18:44:01 +0200953 gss->local.ip6 = ip6_elems;
Alexander Couzense769f522020-12-07 07:37:07 +0100954
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100955 llist_for_each_entry(sbind, &gss->binds, list) {
956 bind = sbind->bind;
Alexander Couzense769f522020-12-07 07:37:07 +0100957 sa = gprs_ns2_ip_bind_sockaddr(bind);
958 if (!sa)
959 continue;
960
961 if (sa->u.sas.ss_family != AF_INET6)
962 continue;
963
964 /* check if this is an specific bind */
965 if (IN6_IS_ADDR_UNSPECIFIED(&sa->u.sin6.sin6_addr)) {
966 if (osmo_sockaddr_local_ip(&local, remote))
967 continue;
968
969 ip6_elems->ip_addr = local.u.sin6.sin6_addr;
970 } else {
971 ip6_elems->ip_addr = sa->u.sin6.sin6_addr;
972 }
973
974 ip6_elems->udp_port = sa->u.sin.sin_port;
Alexander Couzensc4704762021-02-08 23:13:12 +0100975 ip6_elems->sig_weight = bind->sns_sig_weight;
976 ip6_elems->data_weight = bind->sns_data_weight;
Alexander Couzense769f522020-12-07 07:37:07 +0100977
978 ip6_elems++;
979 }
Alexander Couzens71128672021-06-05 18:44:01 +0200980 gss->local.num_ip6 = count;
981 gss->num_max_nsvcs = OSMO_MAX(gss->num_max_ip6_remote * gss->local.num_ip6, 8);
Alexander Couzense769f522020-12-07 07:37:07 +0100982 break;
983 }
Alexander Couzens1f3193d2021-06-05 22:08:11 +0200984
985 ns2_sns_copy_local_endpoints(gss);
Harald Welte24920e22021-03-04 13:03:27 +0100986}
987
Alexander Couzens6608ce92021-04-26 20:39:46 +0200988static void ns2_sns_choose_next_bind(struct ns2_sns_state *gss)
989{
990 /* take the first bind or take the next bind */
991 if (!gss->initial_bind || gss->initial_bind->list.next == &gss->binds)
992 gss->initial_bind = llist_first_entry_or_null(&gss->binds, struct ns2_sns_bind, list);
993 else
994 gss->initial_bind = llist_entry(gss->initial_bind->list.next, struct ns2_sns_bind, list);
995}
996
Harald Welte24920e22021-03-04 13:03:27 +0100997/* setup all dynamic SNS settings, create a new nsvc and send the SIZE */
Harald Welte694dad52021-03-23 15:22:16 +0100998static void ns2_sns_st_bss_size_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
Harald Welte24920e22021-03-04 13:03:27 +0100999{
1000 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
1001
Harald Weltef61a9152021-03-02 22:20:17 +01001002 OSMO_ASSERT(gss->role == GPRS_SNS_ROLE_BSS);
1003
Harald Welte24920e22021-03-04 13:03:27 +01001004 /* on a generic failure, the timer callback will recover */
1005 if (old_state != GPRS_SNS_ST_UNCONFIGURED)
1006 ns2_prim_status_ind(gss->nse, NULL, 0, GPRS_NS2_AFF_CAUSE_SNS_FAILURE);
Harald Welte694dad52021-03-23 15:22:16 +01001007 if (old_state != GPRS_SNS_ST_BSS_SIZE)
Harald Welte24920e22021-03-04 13:03:27 +01001008 gss->N = 0;
1009
Alexander Couzens1f3193d2021-06-05 22:08:11 +02001010 ns2_clear_procedures(gss);
Harald Welte24920e22021-03-04 13:03:27 +01001011 gss->alive = false;
1012
1013 ns2_sns_compute_local_ep_from_binds(fi);
Alexander Couzens6608ce92021-04-26 20:39:46 +02001014 ns2_sns_choose_next_bind(gss);
Harald Welte24920e22021-03-04 13:03:27 +01001015
1016 /* setup the NSVC */
1017 if (!gss->sns_nsvc) {
1018 struct gprs_ns2_vc_bind *bind = gss->initial_bind->bind;
1019 struct osmo_sockaddr *remote = &gss->initial->saddr;
1020 gss->sns_nsvc = ns2_ip_bind_connect(bind, gss->nse, remote);
1021 if (!gss->sns_nsvc)
1022 return;
Harald Weltec962a2e2021-03-05 08:09:08 +01001023 /* A pre-configured endpoint shall not be used for NSE data or signalling traffic
1024 * (with the exception of Size and Configuration procedures) unless it is configured
1025 * by the SGSN using the auto-configuration procedures */
Harald Welte24920e22021-03-04 13:03:27 +01001026 gss->sns_nsvc->sns_only = true;
1027 }
1028
Alexander Couzens6a161492020-07-12 13:45:50 +02001029 if (gss->num_max_ip4_remote > 0)
Alexander Couzens71128672021-06-05 18:44:01 +02001030 ns2_tx_sns_size(gss->sns_nsvc, true, gss->num_max_nsvcs, gss->local.num_ip4, -1);
Alexander Couzens6a161492020-07-12 13:45:50 +02001031 else
Alexander Couzens71128672021-06-05 18:44:01 +02001032 ns2_tx_sns_size(gss->sns_nsvc, true, gss->num_max_nsvcs, -1, gss->local.num_ip6);
Alexander Couzens6a161492020-07-12 13:45:50 +02001033}
1034
Harald Welte694dad52021-03-23 15:22:16 +01001035static void ns2_sns_st_bss_config_bss(struct osmo_fsm_inst *fi, uint32_t event, void *data)
Alexander Couzens6a161492020-07-12 13:45:50 +02001036{
Harald Weltef61a9152021-03-02 22:20:17 +01001037 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
Alexander Couzens3df58862021-02-05 17:18:08 +01001038 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
Harald Weltef61a9152021-03-02 22:20:17 +01001039 struct tlv_parsed *tp = NULL;
1040
1041 OSMO_ASSERT(gss->role == GPRS_SNS_ROLE_BSS);
Alexander Couzens6a161492020-07-12 13:45:50 +02001042
1043 switch (event) {
Alexander Couzens175eb7b2021-07-20 18:41:14 +02001044 case NS2_SNS_EV_RX_CONFIG_ACK:
Alexander Couzens6a161492020-07-12 13:45:50 +02001045 tp = (struct tlv_parsed *) data;
1046 if (TLVP_VAL_MINLEN(tp, NS_IE_CAUSE, 1)) {
1047 LOGPFSML(fi, LOGL_ERROR, "SNS-CONFIG-ACK with cause %s\n",
1048 gprs_ns2_cause_str(*TLVP_VAL(tp, NS_IE_CAUSE)));
1049 /* TODO: What to do? */
1050 } else {
Harald Welte694dad52021-03-23 15:22:16 +01001051 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_BSS_CONFIG_SGSN, nse->nsi->timeout[NS_TOUT_TSNS_PROV], 3);
Alexander Couzens6a161492020-07-12 13:45:50 +02001052 }
1053 break;
1054 default:
1055 OSMO_ASSERT(0);
1056 }
1057}
1058
Harald Welte694dad52021-03-23 15:22:16 +01001059static void ns2_sns_st_bss_config_bss_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
Alexander Couzens6a161492020-07-12 13:45:50 +02001060{
1061 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
Alexander Couzens790a9632021-02-05 17:18:39 +01001062
Harald Weltef61a9152021-03-02 22:20:17 +01001063 OSMO_ASSERT(gss->role == GPRS_SNS_ROLE_BSS);
1064
Harald Welte694dad52021-03-23 15:22:16 +01001065 if (old_state != GPRS_SNS_ST_BSS_CONFIG_BSS)
Alexander Couzens790a9632021-02-05 17:18:39 +01001066 gss->N = 0;
1067
Alexander Couzens6a161492020-07-12 13:45:50 +02001068 /* Transmit SNS-CONFIG */
Alexander Couzens077ce5a2021-06-06 01:32:45 +02001069 switch (gss->family) {
1070 case AF_INET:
Alexander Couzens6a161492020-07-12 13:45:50 +02001071 ns2_tx_sns_config(gss->sns_nsvc, true,
Alexander Couzens71128672021-06-05 18:44:01 +02001072 gss->local.ip4, gss->local.num_ip4,
Alexander Couzense78207f2020-12-07 06:19:29 +01001073 NULL, 0);
Alexander Couzens6a161492020-07-12 13:45:50 +02001074 break;
Alexander Couzens077ce5a2021-06-06 01:32:45 +02001075 case AF_INET6:
Alexander Couzens6a161492020-07-12 13:45:50 +02001076 ns2_tx_sns_config(gss->sns_nsvc, true,
Alexander Couzense78207f2020-12-07 06:19:29 +01001077 NULL, 0,
Alexander Couzens71128672021-06-05 18:44:01 +02001078 gss->local.ip6, gss->local.num_ip6);
Alexander Couzens6a161492020-07-12 13:45:50 +02001079 break;
1080 }
1081}
1082
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01001083/* calculate the timeout of the configured state. the configured
1084 * state will fail if not at least one NS-VC is alive within X second.
1085 */
1086static inline int ns_sns_configured_timeout(struct osmo_fsm_inst *fi)
1087{
1088 int secs;
1089 struct gprs_ns2_inst *nsi = nse_inst_from_fi(fi)->nsi;
1090 secs = nsi->timeout[NS_TOUT_TNS_ALIVE] * nsi->timeout[NS_TOUT_TNS_ALIVE_RETRIES];
1091 secs += nsi->timeout[NS_TOUT_TNS_TEST];
1092
1093 return secs;
1094}
Alexander Couzens6a161492020-07-12 13:45:50 +02001095
Harald Weltec1c7e4a2021-03-02 20:47:29 +01001096/* append the remote endpoints from the parsed TLV array to the ns2_sns_state */
1097static int ns_sns_append_remote_eps(struct osmo_fsm_inst *fi, const struct tlv_parsed *tp)
Alexander Couzens6a161492020-07-12 13:45:50 +02001098{
1099 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
Alexander Couzens6a161492020-07-12 13:45:50 +02001100
Harald Weltec1c7e4a2021-03-02 20:47:29 +01001101 if (TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
1102 const struct gprs_ns_ie_ip4_elem *v4_list;
1103 unsigned int num_v4;
1104 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
1105 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
Alexander Couzens6a161492020-07-12 13:45:50 +02001106
Alexander Couzens71128672021-06-05 18:44:01 +02001107 if (num_v4 && gss->remote.ip6)
Harald Weltec1c7e4a2021-03-02 20:47:29 +01001108 return -NS_CAUSE_INVAL_NR_IPv4_EP;
Alexander Couzens6a161492020-07-12 13:45:50 +02001109
Harald Weltec1c7e4a2021-03-02 20:47:29 +01001110 /* realloc to the new size */
Alexander Couzens71128672021-06-05 18:44:01 +02001111 gss->remote.ip4 = talloc_realloc(gss, gss->remote.ip4,
Harald Weltec1c7e4a2021-03-02 20:47:29 +01001112 struct gprs_ns_ie_ip4_elem,
Alexander Couzens71128672021-06-05 18:44:01 +02001113 gss->remote.num_ip4 + num_v4);
Harald Weltec1c7e4a2021-03-02 20:47:29 +01001114 /* append the new entries to the end of the list */
Alexander Couzens71128672021-06-05 18:44:01 +02001115 memcpy(&gss->remote.ip4[gss->remote.num_ip4], v4_list, num_v4*sizeof(*v4_list));
1116 gss->remote.num_ip4 += num_v4;
Harald Weltec1c7e4a2021-03-02 20:47:29 +01001117
1118 LOGPFSML(fi, LOGL_INFO, "Rx SNS-CONFIG: Remote IPv4 list now %u entries\n",
Alexander Couzens71128672021-06-05 18:44:01 +02001119 gss->remote.num_ip4);
Alexander Couzens6a161492020-07-12 13:45:50 +02001120 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001121
Harald Weltec1c7e4a2021-03-02 20:47:29 +01001122 if (TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
1123 const struct gprs_ns_ie_ip6_elem *v6_list;
1124 unsigned int num_v6;
1125 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
1126 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
1127
Alexander Couzens71128672021-06-05 18:44:01 +02001128 if (num_v6 && gss->remote.ip4)
Harald Weltec1c7e4a2021-03-02 20:47:29 +01001129 return -NS_CAUSE_INVAL_NR_IPv6_EP;
1130
1131 /* realloc to the new size */
Alexander Couzens71128672021-06-05 18:44:01 +02001132 gss->remote.ip6 = talloc_realloc(gss, gss->remote.ip6,
Harald Weltec1c7e4a2021-03-02 20:47:29 +01001133 struct gprs_ns_ie_ip6_elem,
Alexander Couzens71128672021-06-05 18:44:01 +02001134 gss->remote.num_ip6 + num_v6);
Harald Weltec1c7e4a2021-03-02 20:47:29 +01001135 /* append the new entries to the end of the list */
Alexander Couzens71128672021-06-05 18:44:01 +02001136 memcpy(&gss->remote.ip6[gss->remote.num_ip6], v6_list, num_v6*sizeof(*v6_list));
1137 gss->remote.num_ip6 += num_v6;
Harald Weltec1c7e4a2021-03-02 20:47:29 +01001138
Alexander Couzens71128672021-06-05 18:44:01 +02001139 LOGPFSML(fi, LOGL_INFO, "Rx SNS-CONFIG: Remote IPv6 list now %d entries\n",
1140 gss->remote.num_ip6);
Alexander Couzens6a161492020-07-12 13:45:50 +02001141 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001142
Harald Weltec1c7e4a2021-03-02 20:47:29 +01001143 return 0;
Alexander Couzens6a161492020-07-12 13:45:50 +02001144}
1145
Harald Welte694dad52021-03-23 15:22:16 +01001146static void ns2_sns_st_bss_config_sgsn_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
Alexander Couzens790a9632021-02-05 17:18:39 +01001147{
1148 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
1149
Harald Weltef61a9152021-03-02 22:20:17 +01001150 OSMO_ASSERT(gss->role == GPRS_SNS_ROLE_BSS);
1151
Harald Welte694dad52021-03-23 15:22:16 +01001152 if (old_state != GPRS_SNS_ST_BSS_CONFIG_SGSN)
Alexander Couzens790a9632021-02-05 17:18:39 +01001153 gss->N = 0;
1154}
1155
Harald Welte694dad52021-03-23 15:22:16 +01001156static void ns2_sns_st_bss_config_sgsn(struct osmo_fsm_inst *fi, uint32_t event, void *data)
Alexander Couzens6a161492020-07-12 13:45:50 +02001157{
1158 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
Harald Weltec1c7e4a2021-03-02 20:47:29 +01001159 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
1160 uint8_t cause;
1161 int rc;
Alexander Couzens6a161492020-07-12 13:45:50 +02001162
Harald Weltef61a9152021-03-02 22:20:17 +01001163 OSMO_ASSERT(gss->role == GPRS_SNS_ROLE_BSS);
1164
Alexander Couzens6a161492020-07-12 13:45:50 +02001165 switch (event) {
Alexander Couzens175eb7b2021-07-20 18:41:14 +02001166 case NS2_SNS_EV_RX_CONFIG_END:
1167 case NS2_SNS_EV_RX_CONFIG:
Harald Weltec1c7e4a2021-03-02 20:47:29 +01001168 rc = ns_sns_append_remote_eps(fi, data);
1169 if (rc < 0) {
1170 cause = -rc;
1171 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
1172 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
1173 return;
Alexander Couzens6a161492020-07-12 13:45:50 +02001174 }
Alexander Couzens175eb7b2021-07-20 18:41:14 +02001175 if (event == NS2_SNS_EV_RX_CONFIG_END) {
Harald Weltec1c7e4a2021-03-02 20:47:29 +01001176 /* check if sum of data / sig weights == 0 */
Alexander Couzens019da4b2021-06-06 02:48:18 +02001177 if (ip46_weight_sum_data(&gss->remote) == 0 || ip46_weight_sum_sig(&gss->remote) == 0) {
Harald Weltec1c7e4a2021-03-02 20:47:29 +01001178 cause = NS_CAUSE_INVAL_WEIGH;
1179 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
1180 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
1181 return;
1182 }
1183 create_missing_nsvcs(fi);
1184 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
1185 /* start the test procedure on ALL NSVCs! */
1186 gprs_ns2_start_alive_all_nsvcs(nse);
1187 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIGURED, 0, 0);
1188 } else {
1189 /* just send CONFIG-ACK */
1190 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
1191 osmo_timer_schedule(&fi->timer, nse->nsi->timeout[NS_TOUT_TSNS_PROV], 0);
Alexander Couzens6a161492020-07-12 13:45:50 +02001192 }
1193 break;
1194 default:
1195 OSMO_ASSERT(0);
1196 }
1197}
1198
Alexander Couzens175eb7b2021-07-20 18:41:14 +02001199/* called when receiving NS2_SNS_EV_RX_ADD in state configure */
Alexander Couzens6a161492020-07-12 13:45:50 +02001200static void ns2_sns_st_configured_add(struct osmo_fsm_inst *fi,
1201 struct ns2_sns_state *gss,
1202 struct tlv_parsed *tp)
1203{
1204 const struct gprs_ns_ie_ip4_elem *v4_list = NULL;
1205 const struct gprs_ns_ie_ip6_elem *v6_list = NULL;
1206 int num_v4 = 0, num_v6 = 0;
1207 uint8_t trans_id, cause = 0xff;
Harald Welte7da6ace2020-09-18 09:48:05 +02001208 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +02001209 int rc = 0;
1210
1211 /* TODO: refactor EV_ADD/CHANGE/REMOVE by
1212 * check uniqueness within the lists (no doublicate entries)
1213 * check not-known-by-us and sent back a list of unknown/known values
1214 * (abnormal behaviour according to 48.016)
1215 */
1216
1217 trans_id = *TLVP_VAL(tp, NS_IE_TRANS_ID);
Alexander Couzens077ce5a2021-06-06 01:32:45 +02001218 if (gss->family == AF_INET) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001219 if (!TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
1220 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
1221 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1222 return;
1223 }
1224
1225 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
1226 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001227 for (i = 0; i < num_v4; i++) {
1228 unsigned int j;
Alexander Couzens6a161492020-07-12 13:45:50 +02001229 rc = do_sns_add(fi, &v4_list[i], NULL);
1230 if (rc < 0) {
1231 /* rollback/undo to restore previous state */
Harald Welte7da6ace2020-09-18 09:48:05 +02001232 for (j = 0; j < i; j++)
Alexander Couzens6a161492020-07-12 13:45:50 +02001233 do_sns_delete(fi, &v4_list[j], NULL);
1234 cause = -rc;
1235 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1236 break;
1237 }
1238 }
1239 } else { /* IPv6 */
1240 if (!TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
1241 cause = NS_CAUSE_INVAL_NR_IPv6_EP;
1242 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1243 return;
1244 }
1245
1246 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
1247 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001248 for (i = 0; i < num_v6; i++) {
1249 unsigned int j;
Alexander Couzens6a161492020-07-12 13:45:50 +02001250 rc = do_sns_add(fi, NULL, &v6_list[i]);
1251 if (rc < 0) {
1252 /* rollback/undo to restore previous state */
Harald Welte7da6ace2020-09-18 09:48:05 +02001253 for (j = 0; j < i; j++)
Alexander Couzens6a161492020-07-12 13:45:50 +02001254 do_sns_delete(fi, NULL, &v6_list[j]);
1255 cause = -rc;
1256 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1257 break;
1258 }
1259 }
1260 }
1261
1262 /* TODO: correct behaviour is to answer to the *same* NSVC from which the SNS_ADD was received */
1263 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, NULL, v4_list, num_v4, v6_list, num_v6);
1264}
1265
1266static void ns2_sns_st_configured_delete(struct osmo_fsm_inst *fi,
1267 struct ns2_sns_state *gss,
1268 struct tlv_parsed *tp)
1269{
1270 const struct gprs_ns_ie_ip4_elem *v4_list = NULL;
1271 const struct gprs_ns_ie_ip6_elem *v6_list = NULL;
1272 int num_v4 = 0, num_v6 = 0;
1273 uint8_t trans_id, cause = 0xff;
Harald Welte7da6ace2020-09-18 09:48:05 +02001274 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +02001275 int rc = 0;
1276
1277 /* TODO: split up delete into v4 + v6
1278 * TODO: check if IPv4_LIST or IP_ADDR(v4) is present on IPv6 and vice versa
1279 * TODO: check if IPv4_LIST/IPv6_LIST and IP_ADDR is present at the same time
1280 */
1281 trans_id = *TLVP_VAL(tp, NS_IE_TRANS_ID);
Alexander Couzens077ce5a2021-06-06 01:32:45 +02001282 if (gss->family == AF_INET) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001283 if (TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
1284 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
1285 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001286 for ( i = 0; i < num_v4; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001287 rc = do_sns_delete(fi, &v4_list[i], NULL);
1288 if (rc < 0) {
1289 cause = -rc;
1290 /* continue to delete others */
1291 }
1292 }
1293 if (cause != 0xff) {
1294 /* TODO: create list of not-deleted and return it */
1295 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1296 return;
1297 }
1298
1299 } else if (TLVP_PRESENT(tp, NS_IE_IP_ADDR) && TLVP_LEN(tp, NS_IE_IP_ADDR) == 5) {
1300 /* delete all NS-VCs for given IPv4 address */
1301 const uint8_t *ie = TLVP_VAL(tp, NS_IE_IP_ADDR);
1302 struct gprs_ns_ie_ip4_elem *ip4_remote;
1303 uint32_t ip_addr = *(uint32_t *)(ie+1);
1304 if (ie[0] != 0x01) { /* Address Type != IPv4 */
1305 cause = NS_CAUSE_UNKN_IP_ADDR;
1306 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1307 return;
1308 }
1309 /* make a copy as do_sns_delete() will change the array underneath us */
Alexander Couzens71128672021-06-05 18:44:01 +02001310 ip4_remote = talloc_memdup(fi, gss->remote.ip4,
1311 gss->remote.num_ip4 * sizeof(*v4_list));
1312 for (i = 0; i < gss->remote.num_ip4; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001313 if (ip4_remote[i].ip_addr == ip_addr) {
1314 rc = do_sns_delete(fi, &ip4_remote[i], NULL);
1315 if (rc < 0) {
1316 cause = -rc;
1317 /* continue to delete others */
1318 }
1319 }
1320 }
1321 talloc_free(ip4_remote);
1322 if (cause != 0xff) {
1323 /* TODO: create list of not-deleted and return it */
1324 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1325 return;
1326 }
1327 } else {
1328 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
1329 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1330 return;
1331 }
1332 } else { /* IPv6 */
1333 if (TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
1334 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
1335 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001336 for (i = 0; i < num_v6; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001337 rc = do_sns_delete(fi, NULL, &v6_list[i]);
1338 if (rc < 0) {
1339 cause = -rc;
1340 /* continue to delete others */
1341 }
1342 }
1343 if (cause != 0xff) {
1344 /* TODO: create list of not-deleted and return it */
1345 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1346 return;
1347 }
1348 } else if (TLVP_PRES_LEN(tp, NS_IE_IP_ADDR, 17)) {
1349 /* delete all NS-VCs for given IPv4 address */
1350 const uint8_t *ie = TLVP_VAL(tp, NS_IE_IP_ADDR);
1351 struct gprs_ns_ie_ip6_elem *ip6_remote;
1352 struct in6_addr ip6_addr;
Harald Welte7da6ace2020-09-18 09:48:05 +02001353 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +02001354 if (ie[0] != 0x02) { /* Address Type != IPv6 */
1355 cause = NS_CAUSE_UNKN_IP_ADDR;
1356 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1357 return;
1358 }
1359 memcpy(&ip6_addr, (ie+1), sizeof(struct in6_addr));
1360 /* make a copy as do_sns_delete() will change the array underneath us */
Alexander Couzens71128672021-06-05 18:44:01 +02001361 ip6_remote = talloc_memdup(fi, gss->remote.ip6,
1362 gss->remote.num_ip6 * sizeof(*v4_list));
1363 for (i = 0; i < gss->remote.num_ip6; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001364 if (!memcmp(&ip6_remote[i].ip_addr, &ip6_addr, sizeof(struct in6_addr))) {
1365 rc = do_sns_delete(fi, NULL, &ip6_remote[i]);
1366 if (rc < 0) {
1367 cause = -rc;
1368 /* continue to delete others */
1369 }
1370 }
1371 }
1372
1373 talloc_free(ip6_remote);
1374 if (cause != 0xff) {
1375 /* TODO: create list of not-deleted and return it */
1376 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1377 return;
1378 }
1379 } else {
1380 cause = NS_CAUSE_INVAL_NR_IPv6_EP;
1381 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1382 return;
1383 }
1384 }
1385 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, NULL, v4_list, num_v4, v6_list, num_v6);
1386}
1387
1388static void ns2_sns_st_configured_change(struct osmo_fsm_inst *fi,
1389 struct ns2_sns_state *gss,
1390 struct tlv_parsed *tp)
1391{
1392 const struct gprs_ns_ie_ip4_elem *v4_list = NULL;
1393 const struct gprs_ns_ie_ip6_elem *v6_list = NULL;
1394 int num_v4 = 0, num_v6 = 0;
1395 uint8_t trans_id, cause = 0xff;
1396 int rc = 0;
Harald Welte7da6ace2020-09-18 09:48:05 +02001397 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +02001398
1399 trans_id = *TLVP_VAL(tp, NS_IE_TRANS_ID);
1400 if (TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
1401 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
1402 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001403 for (i = 0; i < num_v4; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001404 rc = do_sns_change_weight(fi, &v4_list[i], NULL);
1405 if (rc < 0) {
1406 cause = -rc;
1407 /* continue to others */
1408 }
1409 }
1410 if (cause != 0xff) {
1411 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1412 return;
1413 }
1414 } else if (TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
1415 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
1416 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001417 for (i = 0; i < num_v6; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001418 rc = do_sns_change_weight(fi, NULL, &v6_list[i]);
1419 if (rc < 0) {
1420 cause = -rc;
1421 /* continue to others */
1422 }
1423 }
1424 if (cause != 0xff) {
1425 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1426 return;
1427 }
1428 } else {
1429 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
1430 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1431 return;
1432 }
1433 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, NULL, v4_list, num_v4, v6_list, num_v6);
1434}
1435
1436static void ns2_sns_st_configured(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1437{
1438 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
1439 struct tlv_parsed *tp = data;
1440
1441 switch (event) {
Alexander Couzens175eb7b2021-07-20 18:41:14 +02001442 case NS2_SNS_EV_RX_ADD:
Alexander Couzens6a161492020-07-12 13:45:50 +02001443 ns2_sns_st_configured_add(fi, gss, tp);
1444 break;
Alexander Couzens175eb7b2021-07-20 18:41:14 +02001445 case NS2_SNS_EV_RX_DELETE:
Alexander Couzens6a161492020-07-12 13:45:50 +02001446 ns2_sns_st_configured_delete(fi, gss, tp);
1447 break;
Alexander Couzens175eb7b2021-07-20 18:41:14 +02001448 case NS2_SNS_EV_RX_CHANGE_WEIGHT:
Alexander Couzens6a161492020-07-12 13:45:50 +02001449 ns2_sns_st_configured_change(fi, gss, tp);
1450 break;
Alexander Couzens175eb7b2021-07-20 18:41:14 +02001451 case NS2_SNS_EV_REQ_NSVC_ALIVE:
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01001452 osmo_timer_del(&fi->timer);
1453 break;
Alexander Couzens6a161492020-07-12 13:45:50 +02001454 }
1455}
1456
1457static void ns2_sns_st_configured_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
1458{
Alexander Couzenscdb2baa2021-04-01 15:29:16 +02001459 struct gprs_ns2_vc *nsvc;
1460 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
Alexander Couzens6a161492020-07-12 13:45:50 +02001461 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
Alexander Couzenscdb2baa2021-04-01 15:29:16 +02001462 /* NS-VC status updates are only parsed in ST_CONFIGURED.
1463 * Do an initial check if there are any nsvc alive atm */
1464 llist_for_each_entry(nsvc, &nse->nsvc, list) {
1465 if (ns2_vc_is_unblocked(nsvc)) {
1466 gss->alive = true;
1467 osmo_timer_del(&fi->timer);
1468 break;
1469 }
1470 }
1471
Alexander Couzens53e70092021-04-06 15:45:47 +02001472 /* remove the initial NSVC if the NSVC isn't part of the configuration */
1473 if (gss->sns_nsvc->sns_only)
1474 gprs_ns2_free_nsvc(gss->sns_nsvc);
1475
Alexander Couzens1f3193d2021-06-05 22:08:11 +02001476 if (old_state != GPRS_SNS_ST_LOCAL_PROCEDURE)
1477 ns2_prim_status_ind(nse, NULL, 0, GPRS_NS2_AFF_CAUSE_SNS_CONFIGURED);
1478
1479 if (!llist_empty(&gss->procedures)) {
1480 osmo_fsm_inst_state_chg(gss->nse->bss_sns_fi, GPRS_SNS_ST_LOCAL_PROCEDURE,
1481 gss->nse->nsi->timeout[NS_TOUT_TSNS_PROV], 5);
1482 }
1483}
1484
1485static void ns2_sns_st_local_procedure_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
1486{
1487 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
1488
1489 /* check if resend or not */
1490 if (!gss->current_procedure) {
1491 /* take next procedure */
1492 gss->current_procedure = llist_first_entry_or_null(&gss->procedures,
1493 struct ns2_sns_procedure, list);
1494 if (!gss->current_procedure) {
1495 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIGURED, 0, 0);
1496 return;
1497 }
1498 gss->N = 0;
1499 gss->current_procedure->running = true;
1500 gss->current_procedure->trans_id = ++gss->trans_id;
1501 if (gss->trans_id == 0)
1502 gss->trans_id = gss->current_procedure->trans_id = 1;
1503
1504 }
1505
1506 /* also takes care of retransmitting */
1507 switch (gss->current_procedure->procedure) {
Alexander Couzens9cd39ac2021-06-06 18:57:56 +02001508 case SNS_PROC_ADD:
1509 if (gss->family == AF_INET)
1510 ns2_tx_sns_add(gss->sns_nsvc, gss->current_procedure->trans_id, &gss->current_procedure->ip4, 1, NULL, 0);
1511 else
1512 ns2_tx_sns_add(gss->sns_nsvc, gss->current_procedure->trans_id, NULL, 0, &gss->current_procedure->ip6, 1);
1513 break;
Alexander Couzens1f3193d2021-06-05 22:08:11 +02001514 case SNS_PROC_CHANGE_WEIGHT:
1515 if (gss->family == AF_INET)
1516 ns2_tx_sns_change_weight(gss->sns_nsvc, gss->current_procedure->trans_id, &gss->current_procedure->ip4, 1, NULL, 0);
1517 else
1518 ns2_tx_sns_change_weight(gss->sns_nsvc, gss->current_procedure->trans_id, NULL, 0, &gss->current_procedure->ip6, 1);
1519 break;
Alexander Couzensdb07a442021-06-06 18:58:01 +02001520 case SNS_PROC_DEL:
1521 if (gss->family == AF_INET)
1522 ns2_tx_sns_del(gss->sns_nsvc, gss->current_procedure->trans_id, &gss->current_procedure->ip4, 1, NULL, 0);
1523 else
1524 ns2_tx_sns_del(gss->sns_nsvc, gss->current_procedure->trans_id, NULL, 0, &gss->current_procedure->ip6, 1);
1525 break;
Alexander Couzens1f3193d2021-06-05 22:08:11 +02001526 default:
1527 break;
1528 }
1529}
1530
Alexander Couzens9cd39ac2021-06-06 18:57:56 +02001531static void create_nsvc_for_new_sbind(struct ns2_sns_state *gss, struct ns2_sns_bind *sbind)
1532{
1533 struct gprs_ns2_nse *nse = gss->nse;
1534 struct gprs_ns2_vc_bind *bind = sbind->bind;
1535 struct gprs_ns2_vc *nsvc;
1536 struct osmo_sockaddr remote = { };
1537 unsigned int i;
1538
1539 /* iterate over all remote IPv4 endpoints */
1540 for (i = 0; i < gss->remote.num_ip4; i++) {
1541 const struct gprs_ns_ie_ip4_elem *ip4 = &gss->remote.ip4[i];
1542
1543 remote.u.sin.sin_family = AF_INET;
1544 remote.u.sin.sin_addr.s_addr = ip4->ip_addr;
1545 remote.u.sin.sin_port = ip4->udp_port;
1546 /* we only care about UDP binds */
1547 if (bind->ll != GPRS_NS2_LL_UDP)
1548 continue;
1549
1550 nsvc = nsvc_for_bind_and_remote(nse, bind, &remote);
1551 if (!nsvc) {
1552 nsvc = gprs_ns2_ip_connect_inactive(bind, &remote, nse, 0);
1553 if (!nsvc) {
1554 /* TODO: add to a list to send back a NS-STATUS */
1555 continue;
1556 }
1557 }
1558
1559 /* update data / signalling weight */
1560 nsvc->data_weight = ip4->data_weight;
1561 nsvc->sig_weight = ip4->sig_weight;
1562 nsvc->sns_only = false;
1563 }
1564
1565 /* iterate over all remote IPv4 endpoints */
1566 for (i = 0; i < gss->remote.num_ip6; i++) {
1567 const struct gprs_ns_ie_ip6_elem *ip6 = &gss->remote.ip6[i];
1568
1569 remote.u.sin6.sin6_family = AF_INET6;
1570 remote.u.sin6.sin6_addr = ip6->ip_addr;
1571 remote.u.sin6.sin6_port = ip6->udp_port;
1572
1573 /* we only care about UDP binds */
1574 nsvc = nsvc_for_bind_and_remote(nse, bind, &remote);
1575 if (!nsvc) {
1576 nsvc = gprs_ns2_ip_connect_inactive(bind, &remote, nse, 0);
1577 if (!nsvc) {
1578 /* TODO: add to a list to send back a NS-STATUS */
1579 continue;
1580 }
1581 }
1582
1583 /* update data / signalling weight */
1584 nsvc->data_weight = ip6->data_weight;
1585 nsvc->sig_weight = ip6->sig_weight;
1586 nsvc->sns_only = false;
1587 }
1588}
1589
Alexander Couzens1f3193d2021-06-05 22:08:11 +02001590static void ns2_sns_st_local_procedure(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1591{
1592 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
1593 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
1594 struct gprs_ns_ie_ip4_elem *ip4, *proc4;
1595 struct gprs_ns_ie_ip6_elem *ip6, *proc6;
1596 struct tlv_parsed *tp = data;
1597 uint8_t trans_id;
1598 uint8_t cause;
1599
1600 switch (event) {
1601 case NS2_SNS_EV_RX_ADD:
1602 ns2_sns_st_configured_add(fi, gss, tp);
1603 break;
1604 case NS2_SNS_EV_RX_DELETE:
1605 ns2_sns_st_configured_delete(fi, gss, tp);
1606 break;
1607 case NS2_SNS_EV_RX_CHANGE_WEIGHT:
1608 ns2_sns_st_configured_change(fi, gss, tp);
1609 break;
1610 case NS2_SNS_EV_RX_ACK:
1611 /* presence of trans_id is already checked here */
1612 trans_id = tlvp_val8(tp, NS_IE_TRANS_ID, 0);
1613 if (trans_id != gss->current_procedure->trans_id) {
1614 LOGPFSML(fi, LOGL_INFO, "NSEI=%u Rx SNS ACK with invalid transaction id %d. Valid %d\n",
1615 nse->nsei, trans_id, gss->current_procedure->trans_id);
1616 break;
1617 }
1618
1619 if (TLVP_PRESENT(tp, NS_IE_CAUSE)) {
1620 /* what happend on error cause? return to size? */
1621 cause = tlvp_val8(tp, NS_IE_CAUSE, 0);
1622 LOGPFSML(fi, LOGL_ERROR, "NSEI=%u Rx SNS ACK trans %d with cause code %d.\n",
1623 nse->nsei, trans_id, cause);
1624 sns_failed(fi, NULL);
1625 break;
1626 }
1627
1628 switch (gss->current_procedure->procedure) {
Alexander Couzens9cd39ac2021-06-06 18:57:56 +02001629 case SNS_PROC_ADD:
1630 switch (gss->family) {
1631 case AF_INET:
1632 add_ip4_elem(gss, &gss->local, &gss->current_procedure->ip4);
1633 break;
1634 case AF_INET6:
1635 add_ip6_elem(gss, &gss->local, &gss->current_procedure->ip6);
1636 break;
1637 }
Alexander Couzensdb07a442021-06-06 18:58:01 +02001638 /* the sbind can be NULL if the bind has been released by del_bind */
1639 if (gss->current_procedure->sbind) {
1640 create_nsvc_for_new_sbind(gss, gss->current_procedure->sbind);
1641 gprs_ns2_start_alive_all_nsvcs(nse);
1642 }
Alexander Couzens9cd39ac2021-06-06 18:57:56 +02001643 break;
Alexander Couzens1f3193d2021-06-05 22:08:11 +02001644 case SNS_PROC_CHANGE_WEIGHT:
1645 switch (gss->family) {
1646 case AF_INET:
1647 proc4 = &gss->current_procedure->ip4;
1648 for (unsigned int i=0; i<gss->local.num_ip4; i++) {
1649 ip4 = &gss->local.ip4[i];
1650 if (ip4->ip_addr != proc4->ip_addr ||
1651 ip4->udp_port != proc4->udp_port)
1652 continue;
1653 ip4->sig_weight = proc4->sig_weight;
1654 ip4->data_weight = proc4->data_weight;
1655 break;
1656 }
1657 break;
1658 case AF_INET6:
1659 proc6 = &gss->current_procedure->ip6;
1660 for (unsigned int i=0; i<gss->local.num_ip6; i++) {
1661 ip6 = &gss->local.ip6[i];
1662 if (memcmp(&ip6->ip_addr, &proc6->ip_addr, sizeof(proc6->ip_addr)) ||
1663 ip6->udp_port != proc6->udp_port) {
1664 continue;
1665 }
1666 ip6->sig_weight = proc6->sig_weight;
1667 ip6->data_weight = proc6->data_weight;
1668 break;
1669 }
1670 break;
1671 default:
1672 OSMO_ASSERT(0);
1673 }
1674 break;
Alexander Couzensdb07a442021-06-06 18:58:01 +02001675 case SNS_PROC_DEL:
1676 switch (gss->family) {
1677 case AF_INET:
1678 remove_ip4_elem(gss, &gss->local, &gss->current_procedure->ip4);
1679 break;
1680 case AF_INET6:
1681 remove_ip6_elem(gss, &gss->local, &gss->current_procedure->ip6);
1682 break;
1683 }
1684 break;
Alexander Couzens1f3193d2021-06-05 22:08:11 +02001685 default:
1686 break;
1687 }
1688
1689 llist_del(&gss->current_procedure->list);
1690 talloc_free(gss->current_procedure);
1691 gss->current_procedure = NULL;
1692
1693 if (llist_empty(&gss->procedures))
1694 osmo_fsm_inst_state_chg(gss->nse->bss_sns_fi, GPRS_SNS_ST_CONFIGURED,
1695 0, 0);
1696 else
1697 osmo_fsm_inst_state_chg(gss->nse->bss_sns_fi, GPRS_SNS_ST_LOCAL_PROCEDURE,
1698 gss->nse->nsi->timeout[NS_TOUT_TSNS_PROV], 5);
1699 break;
1700 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001701}
1702
1703static const struct osmo_fsm_state ns2_sns_bss_states[] = {
1704 [GPRS_SNS_ST_UNCONFIGURED] = {
Alexander Couzense769f522020-12-07 07:37:07 +01001705 .in_event_mask = 0, /* handled by all_state_action */
Alexander Couzens0a7c5ee2021-04-10 18:20:21 +02001706 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
1707 S(GPRS_SNS_ST_BSS_SIZE),
Alexander Couzens6a161492020-07-12 13:45:50 +02001708 .name = "UNCONFIGURED",
Harald Welte694dad52021-03-23 15:22:16 +01001709 .action = ns2_sns_st_bss_unconfigured,
Alexander Couzens6a161492020-07-12 13:45:50 +02001710 },
Harald Welte694dad52021-03-23 15:22:16 +01001711 [GPRS_SNS_ST_BSS_SIZE] = {
Alexander Couzens175eb7b2021-07-20 18:41:14 +02001712 .in_event_mask = S(NS2_SNS_EV_RX_SIZE_ACK),
Alexander Couzens6a161492020-07-12 13:45:50 +02001713 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
Harald Welte694dad52021-03-23 15:22:16 +01001714 S(GPRS_SNS_ST_BSS_SIZE) |
1715 S(GPRS_SNS_ST_BSS_CONFIG_BSS),
1716 .name = "BSS_SIZE",
1717 .action = ns2_sns_st_bss_size,
1718 .onenter = ns2_sns_st_bss_size_onenter,
Alexander Couzens6a161492020-07-12 13:45:50 +02001719 },
Harald Welte694dad52021-03-23 15:22:16 +01001720 [GPRS_SNS_ST_BSS_CONFIG_BSS] = {
Alexander Couzens175eb7b2021-07-20 18:41:14 +02001721 .in_event_mask = S(NS2_SNS_EV_RX_CONFIG_ACK),
Alexander Couzens6a161492020-07-12 13:45:50 +02001722 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
Harald Welte694dad52021-03-23 15:22:16 +01001723 S(GPRS_SNS_ST_BSS_CONFIG_BSS) |
1724 S(GPRS_SNS_ST_BSS_CONFIG_SGSN) |
1725 S(GPRS_SNS_ST_BSS_SIZE),
1726 .name = "BSS_CONFIG_BSS",
1727 .action = ns2_sns_st_bss_config_bss,
1728 .onenter = ns2_sns_st_bss_config_bss_onenter,
Alexander Couzens6a161492020-07-12 13:45:50 +02001729 },
Harald Welte694dad52021-03-23 15:22:16 +01001730 [GPRS_SNS_ST_BSS_CONFIG_SGSN] = {
Alexander Couzens175eb7b2021-07-20 18:41:14 +02001731 .in_event_mask = S(NS2_SNS_EV_RX_CONFIG) |
1732 S(NS2_SNS_EV_RX_CONFIG_END),
Alexander Couzens6a161492020-07-12 13:45:50 +02001733 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
Harald Welte694dad52021-03-23 15:22:16 +01001734 S(GPRS_SNS_ST_BSS_CONFIG_SGSN) |
Alexander Couzens6a161492020-07-12 13:45:50 +02001735 S(GPRS_SNS_ST_CONFIGURED) |
Harald Welte694dad52021-03-23 15:22:16 +01001736 S(GPRS_SNS_ST_BSS_SIZE),
1737 .name = "BSS_CONFIG_SGSN",
1738 .action = ns2_sns_st_bss_config_sgsn,
1739 .onenter = ns2_sns_st_bss_config_sgsn_onenter,
Alexander Couzens6a161492020-07-12 13:45:50 +02001740 },
1741 [GPRS_SNS_ST_CONFIGURED] = {
Alexander Couzens175eb7b2021-07-20 18:41:14 +02001742 .in_event_mask = S(NS2_SNS_EV_RX_ADD) |
1743 S(NS2_SNS_EV_RX_DELETE) |
1744 S(NS2_SNS_EV_RX_CHANGE_WEIGHT) |
1745 S(NS2_SNS_EV_REQ_NSVC_ALIVE),
Alexander Couzense03d8632020-12-06 03:31:44 +01001746 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
Alexander Couzens1f3193d2021-06-05 22:08:11 +02001747 S(GPRS_SNS_ST_BSS_SIZE) |
1748 S(GPRS_SNS_ST_LOCAL_PROCEDURE),
Alexander Couzens6a161492020-07-12 13:45:50 +02001749 .name = "CONFIGURED",
1750 .action = ns2_sns_st_configured,
1751 .onenter = ns2_sns_st_configured_onenter,
1752 },
Alexander Couzens1f3193d2021-06-05 22:08:11 +02001753 [GPRS_SNS_ST_LOCAL_PROCEDURE] = {
1754 .in_event_mask = S(NS2_SNS_EV_RX_ADD) |
1755 S(NS2_SNS_EV_RX_DELETE) |
1756 S(NS2_SNS_EV_RX_CHANGE_WEIGHT) |
1757 S(NS2_SNS_EV_RX_ACK) |
1758 S(NS2_SNS_EV_REQ_NSVC_ALIVE),
1759 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
1760 S(GPRS_SNS_ST_BSS_SIZE) |
1761 S(GPRS_SNS_ST_CONFIGURED) |
1762 S(GPRS_SNS_ST_LOCAL_PROCEDURE),
1763 .name = "LOCAL_PROCEDURE",
1764 .action = ns2_sns_st_local_procedure,
1765 .onenter = ns2_sns_st_local_procedure_onenter,
1766 },
1767
Alexander Couzens6a161492020-07-12 13:45:50 +02001768};
1769
1770static int ns2_sns_fsm_bss_timer_cb(struct osmo_fsm_inst *fi)
1771{
Alexander Couzens90ee9632020-12-07 06:18:32 +01001772 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
Alexander Couzens6a161492020-07-12 13:45:50 +02001773 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
1774 struct gprs_ns2_inst *nsi = nse->nsi;
1775
Alexander Couzens90ee9632020-12-07 06:18:32 +01001776 gss->N++;
Alexander Couzens6a161492020-07-12 13:45:50 +02001777 switch (fi->T) {
1778 case 1:
Alexander Couzensa367d082020-12-21 14:06:24 +01001779 if (gss->N >= nsi->timeout[NS_TOUT_TSNS_SIZE_RETRIES]) {
Alexander Couzens652ab4d2021-06-12 23:09:46 +02001780 sns_failed(fi, "Size retries failed. Selecting next IP-SNS endpoint.");
Alexander Couzensa367d082020-12-21 14:06:24 +01001781 } else {
Harald Welte694dad52021-03-23 15:22:16 +01001782 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_BSS_SIZE, nsi->timeout[NS_TOUT_TSNS_PROV], 1);
Alexander Couzensa367d082020-12-21 14:06:24 +01001783 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001784 break;
1785 case 2:
Alexander Couzensa367d082020-12-21 14:06:24 +01001786 if (gss->N >= nsi->timeout[NS_TOUT_TSNS_CONFIG_RETRIES]) {
Alexander Couzens652ab4d2021-06-12 23:09:46 +02001787 sns_failed(fi, "BSS Config retries failed. Selecting next IP-SNS endpoint");
Alexander Couzensa367d082020-12-21 14:06:24 +01001788 } else {
Harald Welte694dad52021-03-23 15:22:16 +01001789 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_BSS_CONFIG_BSS, nsi->timeout[NS_TOUT_TSNS_PROV], 2);
Alexander Couzensa367d082020-12-21 14:06:24 +01001790 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001791 break;
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01001792 case 3:
Alexander Couzens3df58862021-02-05 17:18:08 +01001793 if (gss->N >= nsi->timeout[NS_TOUT_TSNS_CONFIG_RETRIES]) {
Alexander Couzens652ab4d2021-06-12 23:09:46 +02001794 sns_failed(fi, "SGSN Config retries failed. Selecting next IP-SNS endpoint.");
Alexander Couzens3df58862021-02-05 17:18:08 +01001795 } else {
Harald Welte694dad52021-03-23 15:22:16 +01001796 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_BSS_CONFIG_SGSN, nsi->timeout[NS_TOUT_TSNS_PROV], 3);
Alexander Couzens3df58862021-02-05 17:18:08 +01001797 }
1798 break;
1799 case 4:
Alexander Couzens652ab4d2021-06-12 23:09:46 +02001800 sns_failed(fi, "Config succeeded but no NS-VC came online. Selecting next IP-SNS endpoint.");
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01001801 break;
Alexander Couzens1f3193d2021-06-05 22:08:11 +02001802 case 5:
1803 if (gss->N >= nsi->timeout[NS_TOUT_TSNS_CONFIG_RETRIES]) {
1804 sns_failed(fi, "SNS Procedure retries failed.");
1805 } else {
1806 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_LOCAL_PROCEDURE, nsi->timeout[NS_TOUT_TSNS_PROV], 5);
1807 }
1808 break;
Alexander Couzens6a161492020-07-12 13:45:50 +02001809 }
1810 return 0;
1811}
1812
Alexander Couzens1f3193d2021-06-05 22:08:11 +02001813static struct gprs_ns_ie_ip4_elem *ns2_get_sbind_ip4_entry(struct ns2_sns_state *gss,
1814 struct ns2_sns_bind *sbind,
1815 struct ns2_sns_elems *endpoints)
1816{
1817 const struct osmo_sockaddr *addr;
1818 struct gprs_ns_ie_ip4_elem *ip4;
1819
1820 if (gss->family != AF_INET)
1821 return NULL;
1822
1823 addr = gprs_ns2_ip_bind_sockaddr(sbind->bind);
1824 if (addr->u.sa.sa_family != AF_INET)
1825 return NULL;
1826
1827 for (unsigned int i=0; i<endpoints->num_ip4; i++) {
1828 ip4 = &endpoints->ip4[i];
1829 if (ip4->ip_addr == addr->u.sin.sin_addr.s_addr &&
1830 ip4->udp_port == addr->u.sin.sin_port)
1831 return ip4;
1832 }
1833
1834 return NULL;
1835}
1836
1837static struct gprs_ns_ie_ip6_elem *ns2_get_sbind_ip6_entry(struct ns2_sns_state *gss,
1838 struct ns2_sns_bind *sbind,
1839 struct ns2_sns_elems *endpoints)
1840{
1841 const struct osmo_sockaddr *addr;
1842 struct gprs_ns_ie_ip6_elem *ip6;
1843
1844 if (gss->family != AF_INET6)
1845 return NULL;
1846
1847 addr = gprs_ns2_ip_bind_sockaddr(sbind->bind);
1848 if (addr->u.sa.sa_family != AF_INET6)
1849 return NULL;
1850
1851 for (unsigned int i=0; i<endpoints->num_ip6; i++) {
1852 ip6 = &endpoints->ip6[i];
1853 if (memcmp(&ip6->ip_addr, &addr->u.sin6.sin6_addr, sizeof(ip6->ip_addr)) ||
1854 ip6->udp_port != addr->u.sin6.sin6_port)
1855 return ip6;
1856 }
1857
1858 return NULL;
1859}
1860
1861/* return != 0 if the resulting weight is invalid. return 1 if sbind doesn't have an entry */
1862static int ns2_update_weight_entry(struct ns2_sns_state *gss, struct ns2_sns_bind *sbind,
1863 struct ns2_sns_elems *endpoints)
1864{
1865 struct gprs_ns_ie_ip4_elem *ip4;
1866 struct gprs_ns_ie_ip6_elem *ip6;
1867
1868 switch (gss->family) {
1869 case AF_INET:
1870 ip4 = ns2_get_sbind_ip4_entry(gss, sbind, endpoints);
1871 if (!ip4)
1872 return 1;
1873 ip4->sig_weight = sbind->bind->sns_sig_weight;
1874 ip4->data_weight = sbind->bind->sns_data_weight;
1875 return (ip4_weight_sum_sig(endpoints) != 0 && ip4_weight_sum_data(endpoints) != 0);
1876 break;
1877 case AF_INET6:
1878 ip6 = ns2_get_sbind_ip6_entry(gss, sbind, endpoints);
1879 if (!ip6)
1880 return 1;
1881 ip6->sig_weight = sbind->bind->sns_sig_weight;
1882 ip6->data_weight = sbind->bind->sns_data_weight;
1883 return (ip6_weight_sum_sig(endpoints) != 0 && ip6_weight_sum_data(endpoints) != 0);
1884 break;
1885 default:
1886 OSMO_ASSERT(0);
1887 }
1888}
Alexander Couzens1f3193d2021-06-05 22:08:11 +02001889static void ns2_add_procedure(struct ns2_sns_state *gss, struct ns2_sns_bind *sbind,
1890 enum sns_procedure procedure_type)
1891{
1892 struct ns2_sns_procedure *procedure = NULL;
1893 const struct osmo_sockaddr *saddr;
1894 saddr = gprs_ns2_ip_bind_sockaddr(sbind->bind);
1895
Alexander Couzens9cd39ac2021-06-06 18:57:56 +02001896 OSMO_ASSERT(saddr->u.sa.sa_family == gss->family);
Alexander Couzens1f3193d2021-06-05 22:08:11 +02001897
1898 switch (procedure_type) {
Alexander Couzens9cd39ac2021-06-06 18:57:56 +02001899 case SNS_PROC_ADD:
1900 break;
Alexander Couzensdb07a442021-06-06 18:58:01 +02001901 case SNS_PROC_DEL:
1902 break;
Alexander Couzens1f3193d2021-06-05 22:08:11 +02001903 case SNS_PROC_CHANGE_WEIGHT:
1904 llist_for_each_entry(procedure, &gss->procedures, list) {
1905 if (procedure->sbind == sbind && procedure->procedure == procedure_type &&
1906 !procedure->running) {
1907 switch(gss->family) {
1908 case AF_INET:
1909 /* merge it with a previous procedure */
1910 procedure->ip4.ip_addr = sbind->bind->sns_sig_weight;
1911 procedure->ip4.data_weight = sbind->bind->sns_data_weight;
1912 break;
1913 case AF_INET6:
1914 /* merge it with a previous procedure */
1915 procedure->ip6.sig_weight = sbind->bind->sns_sig_weight;
1916 procedure->ip6.data_weight = sbind->bind->sns_data_weight;
1917 break;
1918 default:
1919 OSMO_ASSERT(0);
1920 }
1921 return;
1922 }
1923 }
Alexander Couzens1f3193d2021-06-05 22:08:11 +02001924 break;
1925 default:
1926 return;
1927 }
1928
Alexander Couzens9cd39ac2021-06-06 18:57:56 +02001929 procedure = talloc_zero(gss, struct ns2_sns_procedure);
1930 if (!procedure)
1931 return;
1932
Alexander Couzensdb07a442021-06-06 18:58:01 +02001933 switch (procedure_type) {
1934 case SNS_PROC_ADD:
1935 case SNS_PROC_CHANGE_WEIGHT:
1936 procedure->sbind = sbind;
1937 break;
1938 default:
1939 break;
1940 }
1941
Alexander Couzens9cd39ac2021-06-06 18:57:56 +02001942 llist_add_tail(&procedure->list, &gss->procedures);
Alexander Couzens9cd39ac2021-06-06 18:57:56 +02001943 procedure->procedure = procedure_type;
1944 procedure->sig_weight = sbind->bind->sns_sig_weight;
1945 procedure->data_weight = sbind->bind->sns_data_weight;
1946
1947 switch(gss->family) {
1948 case AF_INET:
1949 procedure->ip4.ip_addr = saddr->u.sin.sin_addr.s_addr;
1950 procedure->ip4.udp_port = saddr->u.sin.sin_port;
1951 procedure->ip4.sig_weight = sbind->bind->sns_sig_weight;
1952 procedure->ip4.data_weight = sbind->bind->sns_data_weight;
1953 break;
1954 case AF_INET6:
Alexander Couzens9cd39ac2021-06-06 18:57:56 +02001955 memcpy(&procedure->ip6.ip_addr, &saddr->u.sin6.sin6_addr, sizeof(struct in6_addr));
1956 procedure->ip6.udp_port = saddr->u.sin.sin_port;
1957 procedure->ip6.sig_weight = sbind->bind->sns_sig_weight;
1958 procedure->ip6.data_weight = sbind->bind->sns_data_weight;
1959 break;
1960 default:
1961 OSMO_ASSERT(0);
1962 }
1963
Alexander Couzens1f3193d2021-06-05 22:08:11 +02001964 if (gss->nse->bss_sns_fi->state == GPRS_SNS_ST_CONFIGURED) {
1965 osmo_fsm_inst_state_chg(gss->nse->bss_sns_fi, GPRS_SNS_ST_LOCAL_PROCEDURE,
1966 gss->nse->nsi->timeout[NS_TOUT_TSNS_PROV], 5);
1967 }
1968}
1969
Alexander Couzens9cd39ac2021-06-06 18:57:56 +02001970/* add an entrypoint to sns_endpoints */
1971static int ns2_sns_add_elements(struct ns2_sns_state *gss, struct ns2_sns_bind *sbind,
1972 struct ns2_sns_elems *elems)
1973{
1974 const struct osmo_sockaddr *saddr;
1975 struct gprs_ns_ie_ip4_elem ip4;
1976 struct gprs_ns_ie_ip6_elem ip6;
1977 int rc = -1;
1978
1979 saddr = gprs_ns2_ip_bind_sockaddr(sbind->bind);
1980 OSMO_ASSERT(saddr->u.sa.sa_family == gss->family);
1981
1982 switch (gss->family) {
1983 case AF_INET:
1984 ip4.ip_addr = saddr->u.sin.sin_addr.s_addr;
1985 ip4.udp_port= saddr->u.sin.sin_port;
1986 ip4.sig_weight = sbind->bind->sns_sig_weight;
1987 ip4.data_weight = sbind->bind->sns_data_weight;
1988 rc = add_ip4_elem(gss, elems, &ip4);
1989 break;
1990 case AF_INET6:
1991 memcpy(&ip6.ip_addr, &saddr->u.sin6.sin6_addr, sizeof(struct in6_addr));
1992 ip6.udp_port= saddr->u.sin.sin_port;
1993 ip6.sig_weight = sbind->bind->sns_sig_weight;
1994 ip6.data_weight = sbind->bind->sns_data_weight;
1995 rc = add_ip6_elem(gss, elems, &ip6);
1996 break;
1997 }
1998
1999 return rc;
2000}
Alexander Couzens1f3193d2021-06-05 22:08:11 +02002001
Harald Welte9e37bf42021-03-02 20:48:31 +01002002/* common allstate-action for both roles */
Alexander Couzens6a161492020-07-12 13:45:50 +02002003static void ns2_sns_st_all_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
2004{
2005 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
Alexander Couzens1f3193d2021-06-05 22:08:11 +02002006 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002007 struct ns2_sns_bind *sbind;
2008 struct gprs_ns2_vc *nsvc, *nsvc2;
Alexander Couzensdb07a442021-06-06 18:58:01 +02002009 struct ns2_sns_procedure *procedure;
Alexander Couzens6a161492020-07-12 13:45:50 +02002010
Alexander Couzense769f522020-12-07 07:37:07 +01002011 switch (event) {
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002012 case NS2_SNS_EV_REQ_ADD_BIND:
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002013 sbind = data;
2014 switch (fi->state) {
2015 case GPRS_SNS_ST_UNCONFIGURED:
Alexander Couzens9cd39ac2021-06-06 18:57:56 +02002016 if (gss->role == GPRS_SNS_ROLE_BSS)
2017 osmo_fsm_inst_dispatch(nse->bss_sns_fi, NS2_SNS_EV_REQ_SELECT_ENDPOINT, NULL);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002018 break;
Harald Welte694dad52021-03-23 15:22:16 +01002019 case GPRS_SNS_ST_BSS_SIZE:
Alexander Couzens9cd39ac2021-06-06 18:57:56 +02002020 switch (gss->family) {
2021 case AF_INET:
2022 if (gss->num_max_ip4_remote <= gss->local.num_ip4 ||
2023 gss->num_max_ip4_remote * (gss->local.num_ip4 + 1) > gss->num_max_nsvcs) {
2024 osmo_fsm_inst_dispatch(nse->bss_sns_fi, NS2_SNS_EV_REQ_SELECT_ENDPOINT, GPRS_SNS_FLAG_KEEP_SELECT_ENDPOINT_ORDER);
2025 return;
2026 }
2027 break;
2028 case AF_INET6:
2029 if (gss->num_max_ip6_remote <= gss->local.num_ip6 ||
2030 gss->num_max_ip6_remote * (gss->local.num_ip6 + 1) > gss->num_max_nsvcs) {
2031 osmo_fsm_inst_dispatch(nse->bss_sns_fi, NS2_SNS_EV_REQ_SELECT_ENDPOINT, GPRS_SNS_FLAG_KEEP_SELECT_ENDPOINT_ORDER);
2032 return;
2033 }
2034 break;
2035 }
2036 ns2_sns_add_elements(gss, sbind, &gss->local);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002037 break;
Harald Welte694dad52021-03-23 15:22:16 +01002038 case GPRS_SNS_ST_BSS_CONFIG_BSS:
2039 case GPRS_SNS_ST_BSS_CONFIG_SGSN:
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002040 case GPRS_SNS_ST_CONFIGURED:
Alexander Couzens9cd39ac2021-06-06 18:57:56 +02002041 switch (gss->family) {
2042 case AF_INET:
2043 if (gss->num_max_ip4_remote <= gss->local.num_ip4) {
2044 LOGPFSML(fi, LOGL_ERROR,
2045 "NSE %d: ignoring bind %s because there are too many endpoints for the SNS.\n",
2046 nse->nsei, sbind->bind->name);
2047 return;
2048 }
2049 if (gss->remote.num_ip4 * (gss->local.num_ip4 + 1) > gss->num_max_nsvcs) {
2050 LOGPFSML(fi, LOGL_ERROR,
2051 "NSE %d: ignoring bind %s because there are too many endpoints for the SNS.\n",
2052 nse->nsei, sbind->bind->name);
2053 return;
2054 }
2055 break;
2056 case AF_INET6:
2057 if (gss->num_max_ip6_remote <= gss->local.num_ip6) {
2058 LOGPFSML(fi, LOGL_ERROR,
2059 "NSE %d: ignoring bind %s because there are too many endpoints for the SNS.\n",
2060 nse->nsei, sbind->bind->name);
2061 return;
2062 }
2063 if (gss->remote.num_ip6 * (gss->local.num_ip6 + 1) > gss->num_max_nsvcs) {
2064 LOGPFSML(fi, LOGL_ERROR,
2065 "NSE %d: ignoring bind %s because there are too many endpoints for the SNS.\n",
2066 nse->nsei, sbind->bind->name);
2067 return;
2068 }
2069 break;
2070 }
2071 ns2_sns_add_elements(gss, sbind, &gss->local_procedure);
2072 ns2_add_procedure(gss, sbind, SNS_PROC_ADD);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002073 break;
2074 }
2075 break;
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002076 case NS2_SNS_EV_REQ_DELETE_BIND:
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002077 sbind = data;
2078 switch (fi->state) {
2079 case GPRS_SNS_ST_UNCONFIGURED:
2080 break;
Harald Welte694dad52021-03-23 15:22:16 +01002081 case GPRS_SNS_ST_BSS_SIZE:
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002082 llist_for_each_entry_safe(nsvc, nsvc2, &nse->nsvc, list) {
2083 if (nsvc->bind == sbind->bind) {
2084 gprs_ns2_free_nsvc(nsvc);
2085 }
2086 }
Alexander Couzensdb07a442021-06-06 18:58:01 +02002087 osmo_fsm_inst_dispatch(fi, NS2_SNS_EV_REQ_SELECT_ENDPOINT, NULL);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002088 break;
Harald Welte694dad52021-03-23 15:22:16 +01002089 case GPRS_SNS_ST_BSS_CONFIG_BSS:
2090 case GPRS_SNS_ST_BSS_CONFIG_SGSN:
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002091 case GPRS_SNS_ST_CONFIGURED:
Alexander Couzensdb07a442021-06-06 18:58:01 +02002092 case GPRS_SNS_ST_LOCAL_PROCEDURE:
2093 remove_bind_elem(gss, &gss->local_procedure, sbind);
2094 if (ip46_weight_sum(&gss->local_procedure, true) == 0 ||
2095 ip46_weight_sum(&gss->local_procedure, false) == 0) {
2096 LOGPFSML(fi, LOGL_ERROR, "NSE %d: weight has become invalid because of removing bind %s. Resetting the configuration\n",
2097 nse->nsei, sbind->bind->name);
2098 sns_failed(fi, NULL);
2099 break;
2100 }
2101 gss->block_no_nsvc_events = true;
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002102 llist_for_each_entry_safe(nsvc, nsvc2, &nse->nsvc, list) {
2103 if (nsvc->bind == sbind->bind) {
2104 gprs_ns2_free_nsvc(nsvc);
2105 }
2106 }
Alexander Couzensdb07a442021-06-06 18:58:01 +02002107 gss->block_no_nsvc_events = false;
2108 if (nse->sum_sig_weight == 0 || !nse->alive || !gss->alive) {
2109 sns_failed(fi, "While deleting a bind the current state became invalid (no signalling weight)");
2110 break;
2111 }
2112
2113 /* ensure other procedures doesn't use the sbind */
2114 llist_for_each_entry(procedure, &gss->procedures, list) {
2115 if (procedure->sbind == sbind)
2116 procedure->sbind = NULL;
2117 }
2118 ns2_add_procedure(gss, sbind, SNS_PROC_DEL);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002119 break;
2120 }
Alexander Couzensdb07a442021-06-06 18:58:01 +02002121
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002122 /* if this is the last bind, the free_nsvc() will trigger a reselection */
2123 talloc_free(sbind);
2124 break;
Alexander Couzens1f3193d2021-06-05 22:08:11 +02002125 case NS2_SNS_EV_REQ_CHANGE_WEIGHT:
2126 sbind = data;
2127 switch (fi->state) {
2128 case GPRS_SNS_ST_UNCONFIGURED:
2129 /* select_endpoint will check if this is a valid configuration */
2130 if (gss->role == GPRS_SNS_ROLE_BSS)
2131 osmo_fsm_inst_dispatch(fi, NS2_SNS_EV_REQ_SELECT_ENDPOINT, NULL);
2132 break;
2133 case GPRS_SNS_ST_BSS_SIZE:
2134 /* invalid weight? */
2135 if (!ns2_update_weight_entry(gss, sbind, &gss->local))
2136 sns_failed(fi, "updating weights results in an invalid configuration.");
2137 break;
2138 default:
2139 if (!ns2_update_weight_entry(gss, sbind, &gss->local_procedure)) {
2140 sns_failed(fi, "updating weights results in an invalid configuration.");
2141 break;
2142 }
2143 ns2_add_procedure(gss, sbind, SNS_PROC_CHANGE_WEIGHT);
2144 break;
2145 }
Alexander Couzense769f522020-12-07 07:37:07 +01002146 }
Alexander Couzens6a161492020-07-12 13:45:50 +02002147}
2148
Alexander Couzens31d52e12021-06-05 20:04:04 +02002149/* validate the bss configuration (sns endpoint and binds)
2150 * - no endpoints -> invalid
2151 * - no binds -> invalid
2152 * - only v4 sns endpoints, only v6 binds -> invalid
2153 * - only v4 sns endpoints, but v4 sig weights == 0 -> invalid ...
2154 */
2155static int ns2_sns_bss_valid_configuration(struct ns2_sns_state *gss)
2156{
2157 struct ns2_sns_bind *sbind;
2158 struct sns_endpoint *endpoint;
2159 const struct osmo_sockaddr *addr;
2160 int v4_sig = 0, v4_data = 0, v6_sig = 0, v6_data = 0;
2161 bool v4_endpoints = false;
2162 bool v6_endpoints = false;
2163
2164 if (llist_empty(&gss->sns_endpoints) || llist_empty(&gss->binds))
2165 return 0;
2166
2167 llist_for_each_entry(sbind, &gss->binds, list) {
2168 addr = gprs_ns2_ip_bind_sockaddr(sbind->bind);
2169 if (!addr)
2170 continue;
2171 switch (addr->u.sa.sa_family) {
2172 case AF_INET:
2173 v4_sig += sbind->bind->sns_sig_weight;
2174 v4_data += sbind->bind->sns_data_weight;
2175 break;
2176 case AF_INET6:
2177 v6_sig += sbind->bind->sns_sig_weight;
2178 v6_data += sbind->bind->sns_data_weight;
2179 break;
2180 }
2181 }
2182
2183 llist_for_each_entry(endpoint, &gss->sns_endpoints, list) {
2184 switch (endpoint->saddr.u.sa.sa_family) {
2185 case AF_INET:
2186 v4_endpoints = true;
2187 break;
2188 case AF_INET6:
2189 v6_endpoints = true;
2190 break;
2191 }
2192 }
2193
2194 return (v4_endpoints && v4_sig && v4_data) || (v6_endpoints && v6_sig && v6_data);
2195}
2196
Harald Welte9e37bf42021-03-02 20:48:31 +01002197/* allstate-action for BSS role */
2198static void ns2_sns_st_all_action_bss(struct osmo_fsm_inst *fi, uint32_t event, void *data)
2199{
2200 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
2201 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
2202
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002203 /* reset when receiving NS2_SNS_EV_REQ_NO_NSVC */
Harald Welte9e37bf42021-03-02 20:48:31 +01002204 switch (event) {
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002205 case NS2_SNS_EV_REQ_NO_NSVC:
Harald Welte9e37bf42021-03-02 20:48:31 +01002206 /* ignore reselection running */
Alexander Couzensdb07a442021-06-06 18:58:01 +02002207 if (gss->reselection_running || gss->block_no_nsvc_events)
Harald Welte9e37bf42021-03-02 20:48:31 +01002208 break;
2209
Alexander Couzens652ab4d2021-06-12 23:09:46 +02002210 sns_failed(fi, "no remaining NSVC, resetting SNS FSM");
Harald Welte9e37bf42021-03-02 20:48:31 +01002211 break;
Alexander Couzens83f06ce2021-08-06 19:50:09 +02002212 case NS2_SNS_EV_REQ_FREE_NSVCS:
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002213 case NS2_SNS_EV_REQ_SELECT_ENDPOINT:
Alexander Couzens9cd39ac2021-06-06 18:57:56 +02002214 /* TODO: keep the order of binds when data == GPRS_SNS_FLAG_KEEP_SELECT_ENDPOINT_ORDER */
Harald Welte9e37bf42021-03-02 20:48:31 +01002215 /* tear down previous state
2216 * gprs_ns2_free_nsvcs() will trigger NO_NSVC, prevent this from triggering a reselection */
Alexander Couzensdb07a442021-06-06 18:58:01 +02002217 if (gss->reselection_running || gss->block_no_nsvc_events)
2218 break;
2219
Harald Welte9e37bf42021-03-02 20:48:31 +01002220 gss->reselection_running = true;
Alexander Couzensf0746592021-07-20 19:05:45 +02002221 ns2_free_nsvcs(nse);
Alexander Couzensd2c6c492021-06-06 01:57:52 +02002222 ns2_clear_elems(&gss->local);
2223 ns2_clear_elems(&gss->remote);
Harald Welte9e37bf42021-03-02 20:48:31 +01002224
2225 /* Choose the next sns endpoint. */
Alexander Couzens31d52e12021-06-05 20:04:04 +02002226 if (!ns2_sns_bss_valid_configuration(gss)) {
Harald Welte9e37bf42021-03-02 20:48:31 +01002227 gss->initial = NULL;
2228 ns2_prim_status_ind(gss->nse, NULL, 0, GPRS_NS2_AFF_CAUSE_SNS_NO_ENDPOINTS);
2229 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 3);
Alexander Couzens8a612de2021-07-20 22:15:40 +02002230 gss->reselection_running = false;
Harald Welte9e37bf42021-03-02 20:48:31 +01002231 return;
2232 } else if (!gss->initial) {
2233 gss->initial = llist_first_entry(&gss->sns_endpoints, struct sns_endpoint, list);
2234 } else if (gss->initial->list.next == &gss->sns_endpoints) {
2235 /* last entry, continue with first */
2236 gss->initial = llist_first_entry(&gss->sns_endpoints, struct sns_endpoint, list);
2237 } else {
2238 /* next element is an entry */
2239 gss->initial = llist_entry(gss->initial->list.next, struct sns_endpoint, list);
2240 }
2241
Alexander Couzens68ab9c42021-06-06 03:03:40 +02002242 gss->family = gss->initial->saddr.u.sa.sa_family;
Harald Welte9e37bf42021-03-02 20:48:31 +01002243 gss->reselection_running = false;
Harald Welte694dad52021-03-23 15:22:16 +01002244 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_BSS_SIZE, nse->nsi->timeout[NS_TOUT_TSNS_PROV], 1);
Harald Welte9e37bf42021-03-02 20:48:31 +01002245 break;
2246 default:
2247 ns2_sns_st_all_action(fi, event, data);
2248 break;
2249 }
2250}
2251
Alexander Couzens6a161492020-07-12 13:45:50 +02002252static struct osmo_fsm gprs_ns2_sns_bss_fsm = {
2253 .name = "GPRS-NS2-SNS-BSS",
2254 .states = ns2_sns_bss_states,
2255 .num_states = ARRAY_SIZE(ns2_sns_bss_states),
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002256 .allstate_event_mask = S(NS2_SNS_EV_REQ_NO_NSVC) |
Alexander Couzens83f06ce2021-08-06 19:50:09 +02002257 S(NS2_SNS_EV_REQ_FREE_NSVCS) |
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002258 S(NS2_SNS_EV_REQ_SELECT_ENDPOINT) |
2259 S(NS2_SNS_EV_REQ_ADD_BIND) |
Alexander Couzens1f3193d2021-06-05 22:08:11 +02002260 S(NS2_SNS_EV_REQ_CHANGE_WEIGHT) |
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002261 S(NS2_SNS_EV_REQ_DELETE_BIND),
Harald Welte9e37bf42021-03-02 20:48:31 +01002262 .allstate_action = ns2_sns_st_all_action_bss,
Alexander Couzens6a161492020-07-12 13:45:50 +02002263 .cleanup = NULL,
2264 .timer_cb = ns2_sns_fsm_bss_timer_cb,
Alexander Couzens6a161492020-07-12 13:45:50 +02002265 .event_names = gprs_sns_event_names,
2266 .pre_term = NULL,
2267 .log_subsys = DLNS,
2268};
2269
Harald Welte5bef2cc2020-09-18 22:33:24 +02002270/*! Allocate an IP-SNS FSM for the BSS side.
2271 * \param[in] nse NS Entity in which the FSM runs
2272 * \param[in] id string identifier
Alexander Couzens23aec352021-02-15 05:05:15 +01002273 * \returns FSM instance on success; NULL on error */
Alexander Couzens6a161492020-07-12 13:45:50 +02002274struct osmo_fsm_inst *ns2_sns_bss_fsm_alloc(struct gprs_ns2_nse *nse,
2275 const char *id)
2276{
2277 struct osmo_fsm_inst *fi;
2278 struct ns2_sns_state *gss;
2279
2280 fi = osmo_fsm_inst_alloc(&gprs_ns2_sns_bss_fsm, nse, NULL, LOGL_DEBUG, id);
2281 if (!fi)
2282 return fi;
2283
2284 gss = talloc_zero(fi, struct ns2_sns_state);
2285 if (!gss)
2286 goto err;
2287
2288 fi->priv = gss;
2289 gss->nse = nse;
Harald Welte4f127462021-03-02 20:49:10 +01002290 gss->role = GPRS_SNS_ROLE_BSS;
Harald Welte24f4df52021-03-04 18:02:54 +01002291 /* The SGSN doesn't tell the BSS, so we assume there's always sufficient */
2292 gss->num_max_ip4_remote = 8192;
2293 gss->num_max_ip6_remote = 8192;
Alexander Couzense769f522020-12-07 07:37:07 +01002294 INIT_LLIST_HEAD(&gss->sns_endpoints);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002295 INIT_LLIST_HEAD(&gss->binds);
Alexander Couzens1f3193d2021-06-05 22:08:11 +02002296 INIT_LLIST_HEAD(&gss->procedures);
Alexander Couzens6a161492020-07-12 13:45:50 +02002297
2298 return fi;
2299err:
2300 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
2301 return NULL;
2302}
2303
Harald Welte5bef2cc2020-09-18 22:33:24 +02002304/*! main entry point for receiving SNS messages from the network.
2305 * \param[in] nsvc NS-VC on which the message was received
2306 * \param[in] msg message buffer of the IP-SNS message
2307 * \param[in] tp parsed TLV structure of message
Alexander Couzens23aec352021-02-15 05:05:15 +01002308 * \returns 0 on success; negative on error */
Alexander Couzens8dfc24c2021-01-25 16:09:23 +01002309int ns2_sns_rx(struct gprs_ns2_vc *nsvc, struct msgb *msg, struct tlv_parsed *tp)
Alexander Couzens6a161492020-07-12 13:45:50 +02002310{
2311 struct gprs_ns2_nse *nse = nsvc->nse;
2312 struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h;
2313 uint16_t nsei = nsvc->nse->nsei;
Harald Welte4f127462021-03-02 20:49:10 +01002314 struct ns2_sns_state *gss;
Alexander Couzens6a161492020-07-12 13:45:50 +02002315 struct osmo_fsm_inst *fi;
Alexander Couzens7619ed42021-03-24 17:44:03 +01002316 int rc = 0;
Alexander Couzens6a161492020-07-12 13:45:50 +02002317
2318 if (!nse->bss_sns_fi) {
Harald Weltef2949742021-01-20 14:54:14 +01002319 LOGNSVC(nsvc, LOGL_NOTICE, "Rx %s for NS Instance that has no SNS!\n",
2320 get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
Alexander Couzens7619ed42021-03-24 17:44:03 +01002321 rc = -EINVAL;
2322 goto out;
Alexander Couzens6a161492020-07-12 13:45:50 +02002323 }
2324
Alexander Couzens6a161492020-07-12 13:45:50 +02002325 /* FIXME: how to resolve SNS FSM Instance by NSEI (SGSN)? */
2326 fi = nse->bss_sns_fi;
Harald Welte4f127462021-03-02 20:49:10 +01002327 gss = (struct ns2_sns_state *) fi->priv;
2328 if (!gss->sns_nsvc)
2329 gss->sns_nsvc = nsvc;
Alexander Couzens6a161492020-07-12 13:45:50 +02002330
Harald Weltef2949742021-01-20 14:54:14 +01002331 LOGPFSML(fi, LOGL_DEBUG, "NSEI=%u Rx SNS PDU type %s\n", nsei,
2332 get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
2333
Alexander Couzens6a161492020-07-12 13:45:50 +02002334 switch (nsh->pdu_type) {
2335 case SNS_PDUT_SIZE:
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002336 osmo_fsm_inst_dispatch(fi, NS2_SNS_EV_RX_SIZE, tp);
Alexander Couzens6a161492020-07-12 13:45:50 +02002337 break;
2338 case SNS_PDUT_SIZE_ACK:
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002339 osmo_fsm_inst_dispatch(fi, NS2_SNS_EV_RX_SIZE_ACK, tp);
Alexander Couzens6a161492020-07-12 13:45:50 +02002340 break;
2341 case SNS_PDUT_CONFIG:
2342 if (nsh->data[0] & 0x01)
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002343 osmo_fsm_inst_dispatch(fi, NS2_SNS_EV_RX_CONFIG_END, tp);
Alexander Couzens6a161492020-07-12 13:45:50 +02002344 else
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002345 osmo_fsm_inst_dispatch(fi, NS2_SNS_EV_RX_CONFIG, tp);
Alexander Couzens6a161492020-07-12 13:45:50 +02002346 break;
2347 case SNS_PDUT_CONFIG_ACK:
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002348 osmo_fsm_inst_dispatch(fi, NS2_SNS_EV_RX_CONFIG_ACK, tp);
Alexander Couzens6a161492020-07-12 13:45:50 +02002349 break;
2350 case SNS_PDUT_ADD:
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002351 osmo_fsm_inst_dispatch(fi, NS2_SNS_EV_RX_ADD, tp);
Alexander Couzens6a161492020-07-12 13:45:50 +02002352 break;
2353 case SNS_PDUT_DELETE:
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002354 osmo_fsm_inst_dispatch(fi, NS2_SNS_EV_RX_DELETE, tp);
Alexander Couzens6a161492020-07-12 13:45:50 +02002355 break;
2356 case SNS_PDUT_CHANGE_WEIGHT:
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002357 osmo_fsm_inst_dispatch(fi, NS2_SNS_EV_RX_CHANGE_WEIGHT, tp);
Alexander Couzens6a161492020-07-12 13:45:50 +02002358 break;
2359 case SNS_PDUT_ACK:
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002360 osmo_fsm_inst_dispatch(fi, NS2_SNS_EV_RX_ACK, tp);
Alexander Couzens6a161492020-07-12 13:45:50 +02002361 break;
2362 default:
Harald Weltef2949742021-01-20 14:54:14 +01002363 LOGPFSML(fi, LOGL_ERROR, "NSEI=%u Rx unknown SNS PDU type %s\n", nsei,
2364 get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
Alexander Couzens7619ed42021-03-24 17:44:03 +01002365 rc = -EINVAL;
Alexander Couzens6a161492020-07-12 13:45:50 +02002366 }
2367
Alexander Couzens7619ed42021-03-24 17:44:03 +01002368out:
2369 msgb_free(msg);
2370
2371 return rc;
Alexander Couzens6a161492020-07-12 13:45:50 +02002372}
2373
2374#include <osmocom/vty/vty.h>
2375#include <osmocom/vty/misc.h>
2376
Harald Welte1262c4f2021-01-19 20:58:33 +01002377static void vty_dump_sns_ip4(struct vty *vty, const char *prefix, const struct gprs_ns_ie_ip4_elem *ip4)
Alexander Couzens6a161492020-07-12 13:45:50 +02002378{
2379 struct in_addr in = { .s_addr = ip4->ip_addr };
Harald Welte1262c4f2021-01-19 20:58:33 +01002380 vty_out(vty, "%s %s:%u, Signalling Weight: %u, Data Weight: %u%s", prefix,
Alexander Couzens6a161492020-07-12 13:45:50 +02002381 inet_ntoa(in), ntohs(ip4->udp_port), ip4->sig_weight, ip4->data_weight, VTY_NEWLINE);
2382}
2383
Harald Welte1262c4f2021-01-19 20:58:33 +01002384static void vty_dump_sns_ip6(struct vty *vty, const char *prefix, const struct gprs_ns_ie_ip6_elem *ip6)
Alexander Couzens6a161492020-07-12 13:45:50 +02002385{
2386 char ip_addr[INET6_ADDRSTRLEN] = {};
2387 if (!inet_ntop(AF_INET6, &ip6->ip_addr, ip_addr, (INET6_ADDRSTRLEN)))
2388 strcpy(ip_addr, "Invalid IPv6");
2389
Harald Welte1262c4f2021-01-19 20:58:33 +01002390 vty_out(vty, "%s %s:%u, Signalling Weight: %u, Data Weight: %u%s", prefix,
Alexander Couzens6a161492020-07-12 13:45:50 +02002391 ip_addr, ntohs(ip6->udp_port), ip6->sig_weight, ip6->data_weight, VTY_NEWLINE);
2392}
2393
Harald Welte5bef2cc2020-09-18 22:33:24 +02002394/*! Dump the IP-SNS state to a vty.
2395 * \param[in] vty VTY to which the state shall be printed
Harald Welte1262c4f2021-01-19 20:58:33 +01002396 * \param[in] prefix prefix to print at start of each line (typically indenting)
Harald Welte5bef2cc2020-09-18 22:33:24 +02002397 * \param[in] nse NS Entity whose IP-SNS state shall be printed
2398 * \param[in] stats Whether or not statistics shall also be printed */
Alexander Couzens8dfc24c2021-01-25 16:09:23 +01002399void ns2_sns_dump_vty(struct vty *vty, const char *prefix, const struct gprs_ns2_nse *nse, bool stats)
Alexander Couzens6a161492020-07-12 13:45:50 +02002400{
2401 struct ns2_sns_state *gss;
2402 unsigned int i;
2403
2404 if (!nse->bss_sns_fi)
2405 return;
2406
Harald Welte1262c4f2021-01-19 20:58:33 +01002407 vty_out_fsm_inst2(vty, prefix, nse->bss_sns_fi);
Alexander Couzens6a161492020-07-12 13:45:50 +02002408 gss = (struct ns2_sns_state *) nse->bss_sns_fi->priv;
2409
Harald Welte1262c4f2021-01-19 20:58:33 +01002410 vty_out(vty, "%sMaximum number of remote NS-VCs: %zu, IPv4 Endpoints: %zu, IPv6 Endpoints: %zu%s",
2411 prefix, gss->num_max_nsvcs, gss->num_max_ip4_remote, gss->num_max_ip6_remote, VTY_NEWLINE);
Alexander Couzens6a161492020-07-12 13:45:50 +02002412
Alexander Couzens71128672021-06-05 18:44:01 +02002413 if (gss->local.num_ip4 && gss->remote.num_ip4) {
Harald Welte1262c4f2021-01-19 20:58:33 +01002414 vty_out(vty, "%sLocal IPv4 Endpoints:%s", prefix, VTY_NEWLINE);
Alexander Couzens71128672021-06-05 18:44:01 +02002415 for (i = 0; i < gss->local.num_ip4; i++)
2416 vty_dump_sns_ip4(vty, prefix, &gss->local.ip4[i]);
Alexander Couzens6a161492020-07-12 13:45:50 +02002417
Harald Welte1262c4f2021-01-19 20:58:33 +01002418 vty_out(vty, "%sRemote IPv4 Endpoints:%s", prefix, VTY_NEWLINE);
Alexander Couzens71128672021-06-05 18:44:01 +02002419 for (i = 0; i < gss->remote.num_ip4; i++)
2420 vty_dump_sns_ip4(vty, prefix, &gss->remote.ip4[i]);
Alexander Couzens6a161492020-07-12 13:45:50 +02002421 }
2422
Alexander Couzens71128672021-06-05 18:44:01 +02002423 if (gss->local.num_ip6 && gss->remote.num_ip6) {
Harald Welte1262c4f2021-01-19 20:58:33 +01002424 vty_out(vty, "%sLocal IPv6 Endpoints:%s", prefix, VTY_NEWLINE);
Alexander Couzens71128672021-06-05 18:44:01 +02002425 for (i = 0; i < gss->local.num_ip6; i++)
2426 vty_dump_sns_ip6(vty, prefix, &gss->local.ip6[i]);
Alexander Couzens6a161492020-07-12 13:45:50 +02002427
Harald Welte1262c4f2021-01-19 20:58:33 +01002428 vty_out(vty, "%sRemote IPv6 Endpoints:%s", prefix, VTY_NEWLINE);
Alexander Couzens71128672021-06-05 18:44:01 +02002429 for (i = 0; i < gss->remote.num_ip6; i++)
2430 vty_dump_sns_ip6(vty, prefix, &gss->remote.ip6[i]);
Alexander Couzens6a161492020-07-12 13:45:50 +02002431 }
2432}
2433
Alexander Couzens412bc342020-11-19 05:24:37 +01002434/*! write IP-SNS to a vty
2435 * \param[in] vty VTY to which the state shall be printed
2436 * \param[in] nse NS Entity whose IP-SNS state shall be printed */
Alexander Couzens8dfc24c2021-01-25 16:09:23 +01002437void ns2_sns_write_vty(struct vty *vty, const struct gprs_ns2_nse *nse)
Alexander Couzens412bc342020-11-19 05:24:37 +01002438{
2439 struct ns2_sns_state *gss;
2440 struct osmo_sockaddr_str addr_str;
2441 struct sns_endpoint *endpoint;
2442
2443 if (!nse->bss_sns_fi)
2444 return;
2445
2446 gss = (struct ns2_sns_state *) nse->bss_sns_fi->priv;
2447 llist_for_each_entry(endpoint, &gss->sns_endpoints, list) {
Vadim Yanitskiyd8b70032021-01-05 14:24:09 +01002448 /* It's unlikely that an error happens, but let's better be safe. */
2449 if (osmo_sockaddr_str_from_sockaddr(&addr_str, &endpoint->saddr.u.sas) != 0)
2450 addr_str = (struct osmo_sockaddr_str) { .ip = "<INVALID>" };
Alexander Couzens5fa431c2021-02-08 23:21:54 +01002451 vty_out(vty, " ip-sns-remote %s %u%s", addr_str.ip, addr_str.port, VTY_NEWLINE);
Alexander Couzens412bc342020-11-19 05:24:37 +01002452 }
2453}
2454
Alexander Couzense769f522020-12-07 07:37:07 +01002455static struct sns_endpoint *ns2_get_sns_endpoint(struct ns2_sns_state *state,
2456 const struct osmo_sockaddr *saddr)
2457{
2458 struct sns_endpoint *endpoint;
2459
2460 llist_for_each_entry(endpoint, &state->sns_endpoints, list) {
2461 if (!osmo_sockaddr_cmp(saddr, &endpoint->saddr))
2462 return endpoint;
2463 }
2464
2465 return NULL;
2466}
2467
2468/*! gprs_ns2_sns_add_endpoint
2469 * \param[in] nse
2470 * \param[in] sockaddr
2471 * \return
2472 */
2473int gprs_ns2_sns_add_endpoint(struct gprs_ns2_nse *nse,
2474 const struct osmo_sockaddr *saddr)
2475{
2476 struct ns2_sns_state *gss;
2477 struct sns_endpoint *endpoint;
2478 bool do_selection = false;
2479
2480 if (nse->ll != GPRS_NS2_LL_UDP) {
2481 return -EINVAL;
2482 }
2483
Alexander Couzens138b96f2021-01-25 16:23:29 +01002484 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
Alexander Couzense769f522020-12-07 07:37:07 +01002485 return -EINVAL;
2486 }
2487
2488 gss = nse->bss_sns_fi->priv;
2489
2490 if (ns2_get_sns_endpoint(gss, saddr))
2491 return -EADDRINUSE;
2492
2493 endpoint = talloc_zero(nse->bss_sns_fi->priv, struct sns_endpoint);
2494 if (!endpoint)
2495 return -ENOMEM;
2496
2497 endpoint->saddr = *saddr;
2498 if (llist_empty(&gss->sns_endpoints))
2499 do_selection = true;
2500
2501 llist_add_tail(&endpoint->list, &gss->sns_endpoints);
2502 if (do_selection)
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002503 osmo_fsm_inst_dispatch(nse->bss_sns_fi, NS2_SNS_EV_REQ_SELECT_ENDPOINT, NULL);
Alexander Couzense769f522020-12-07 07:37:07 +01002504
2505 return 0;
2506}
2507
2508/*! gprs_ns2_sns_del_endpoint
2509 * \param[in] nse
2510 * \param[in] sockaddr
2511 * \return 0 on success, otherwise < 0
2512 */
2513int gprs_ns2_sns_del_endpoint(struct gprs_ns2_nse *nse,
2514 const struct osmo_sockaddr *saddr)
2515{
2516 struct ns2_sns_state *gss;
2517 struct sns_endpoint *endpoint;
2518
2519 if (nse->ll != GPRS_NS2_LL_UDP) {
2520 return -EINVAL;
2521 }
2522
Alexander Couzens138b96f2021-01-25 16:23:29 +01002523 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
Alexander Couzense769f522020-12-07 07:37:07 +01002524 return -EINVAL;
2525 }
2526
2527 gss = nse->bss_sns_fi->priv;
2528 endpoint = ns2_get_sns_endpoint(gss, saddr);
2529 if (!endpoint)
2530 return -ENOENT;
2531
2532 /* if this is an unused SNS endpoint it's done */
2533 if (gss->initial != endpoint) {
2534 llist_del(&endpoint->list);
2535 talloc_free(endpoint);
2536 return 0;
2537 }
2538
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002539 /* gprs_ns2_free_nsvcs() will trigger NS2_SNS_EV_REQ_NO_NSVC on the last NS-VC
Alexander Couzense769f522020-12-07 07:37:07 +01002540 * and restart SNS SIZE procedure which selects a new initial */
Harald Weltef2949742021-01-20 14:54:14 +01002541 LOGNSE(nse, LOGL_INFO, "Current in-use SNS endpoint is being removed."
Alexander Couzense769f522020-12-07 07:37:07 +01002542 "Closing all NS-VC and restart SNS-SIZE procedure"
2543 "with a remaining SNS endpoint.\n");
2544
2545 /* Continue with the next endpoint in the list.
2546 * Special case if the endpoint is at the start or end of the list */
2547 if (endpoint->list.prev == &gss->sns_endpoints ||
2548 endpoint->list.next == &gss->sns_endpoints)
2549 gss->initial = NULL;
2550 else
2551 gss->initial = llist_entry(endpoint->list.next->prev,
2552 struct sns_endpoint,
2553 list);
2554
2555 llist_del(&endpoint->list);
2556 gprs_ns2_free_nsvcs(nse);
2557 talloc_free(endpoint);
2558
2559 return 0;
2560}
2561
2562/*! gprs_ns2_sns_count
2563 * \param[in] nse NS Entity whose IP-SNS endpoints shall be printed
2564 * \return the count of endpoints or < 0 if NSE doesn't contain sns.
2565 */
2566int gprs_ns2_sns_count(struct gprs_ns2_nse *nse)
2567{
2568 struct ns2_sns_state *gss;
2569 struct sns_endpoint *endpoint;
2570 int count = 0;
2571
2572 if (nse->ll != GPRS_NS2_LL_UDP) {
2573 return -EINVAL;
2574 }
2575
Alexander Couzens138b96f2021-01-25 16:23:29 +01002576 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
Alexander Couzense769f522020-12-07 07:37:07 +01002577 return -EINVAL;
2578 }
2579
2580 gss = nse->bss_sns_fi->priv;
2581 llist_for_each_entry(endpoint, &gss->sns_endpoints, list)
2582 count++;
2583
2584 return count;
2585}
2586
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01002587void ns2_sns_notify_alive(struct gprs_ns2_nse *nse, struct gprs_ns2_vc *nsvc, bool alive)
2588{
2589 struct ns2_sns_state *gss;
2590 struct gprs_ns2_vc *tmp;
2591
2592 if (!nse->bss_sns_fi)
2593 return;
2594
2595 gss = nse->bss_sns_fi->priv;
Alexander Couzens1f3193d2021-06-05 22:08:11 +02002596 if (nse->bss_sns_fi->state != GPRS_SNS_ST_CONFIGURED && nse->bss_sns_fi->state != GPRS_SNS_ST_LOCAL_PROCEDURE)
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01002597 return;
2598
Alexander Couzensdb07a442021-06-06 18:58:01 +02002599 if (gss->block_no_nsvc_events)
2600 return;
2601
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01002602 if (alive == gss->alive)
2603 return;
2604
2605 /* check if this is the current SNS NS-VC */
2606 if (nsvc == gss->sns_nsvc) {
2607 /* only replace the SNS NS-VC if there are other alive NS-VC.
2608 * There aren't any other alive NS-VC when the SNS fsm just reached CONFIGURED
2609 * and couldn't confirm yet if the NS-VC comes up */
2610 if (gss->alive && !alive)
2611 ns2_sns_replace_nsvc(nsvc);
2612 }
2613
2614 if (alive) {
2615 gss->alive = true;
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002616 osmo_fsm_inst_dispatch(nse->bss_sns_fi, NS2_SNS_EV_REQ_NSVC_ALIVE, NULL);
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01002617 } else {
2618 /* is there at least another alive nsvc? */
2619 llist_for_each_entry(tmp, &nse->nsvc, list) {
2620 if (ns2_vc_is_unblocked(tmp))
2621 return;
2622 }
2623
2624 /* all NS-VC have failed */
2625 gss->alive = false;
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002626 osmo_fsm_inst_dispatch(nse->bss_sns_fi, NS2_SNS_EV_REQ_NO_NSVC, NULL);
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01002627 }
2628}
2629
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002630int gprs_ns2_sns_add_bind(struct gprs_ns2_nse *nse,
2631 struct gprs_ns2_vc_bind *bind)
2632{
2633 struct ns2_sns_state *gss;
2634 struct ns2_sns_bind *tmp;
2635
2636 OSMO_ASSERT(nse->bss_sns_fi);
2637 gss = nse->bss_sns_fi->priv;
2638
2639 if (!gprs_ns2_is_ip_bind(bind)) {
2640 return -EINVAL;
2641 }
2642
2643 if (!llist_empty(&gss->binds)) {
2644 llist_for_each_entry(tmp, &gss->binds, list) {
2645 if (tmp->bind == bind)
2646 return -EALREADY;
2647 }
2648 }
2649
2650 tmp = talloc_zero(gss, struct ns2_sns_bind);
2651 if (!tmp)
2652 return -ENOMEM;
2653 tmp->bind = bind;
2654 llist_add_tail(&tmp->list, &gss->binds);
2655
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002656 osmo_fsm_inst_dispatch(nse->bss_sns_fi, NS2_SNS_EV_REQ_ADD_BIND, tmp);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002657 return 0;
2658}
2659
2660/* Remove a bind from the SNS. All assosiated NSVC must be removed. */
2661int gprs_ns2_sns_del_bind(struct gprs_ns2_nse *nse,
2662 struct gprs_ns2_vc_bind *bind)
2663{
2664 struct ns2_sns_state *gss;
2665 struct ns2_sns_bind *tmp, *tmp2;
2666 bool found = false;
2667
2668 if (!nse->bss_sns_fi)
2669 return -EINVAL;
2670
2671 gss = nse->bss_sns_fi->priv;
2672 if (gss->initial_bind && gss->initial_bind->bind == bind) {
2673 if (gss->initial_bind->list.prev == &gss->binds)
2674 gss->initial_bind = NULL;
2675 else
2676 gss->initial_bind = llist_entry(gss->initial_bind->list.prev, struct ns2_sns_bind, list);
2677 }
2678
2679 llist_for_each_entry_safe(tmp, tmp2, &gss->binds, list) {
2680 if (tmp->bind == bind) {
2681 llist_del(&tmp->list);
2682 found = true;
Alexander Couzensa35c2962021-04-19 03:30:15 +02002683 break;
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002684 }
2685 }
2686
2687 if (!found)
2688 return -ENOENT;
2689
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002690 osmo_fsm_inst_dispatch(nse->bss_sns_fi, NS2_SNS_EV_REQ_DELETE_BIND, tmp);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002691 return 0;
2692}
2693
Alexander Couzens71128672021-06-05 18:44:01 +02002694/* Update SNS weights for a bind (local endpoint).
2695 * \param[in] bind the bind which has been updated
Alexander Couzensc4704762021-02-08 23:13:12 +01002696 */
2697void ns2_sns_update_weights(struct gprs_ns2_vc_bind *bind)
2698{
Alexander Couzens1f3193d2021-06-05 22:08:11 +02002699 struct ns2_sns_bind *sbind;
2700 struct gprs_ns2_nse *nse;
2701 struct ns2_sns_state *gss;
2702 const struct osmo_sockaddr *addr = gprs_ns2_ip_bind_sockaddr(bind);
2703
2704 llist_for_each_entry(nse, &bind->nsi->nse, list) {
2705 if (!nse->bss_sns_fi)
2706 continue;
2707
2708 gss = nse->bss_sns_fi->priv;
2709 if (addr->u.sa.sa_family != gss->family)
2710 return;
2711
2712 llist_for_each_entry(sbind, &gss->binds, list) {
2713 if (sbind->bind == bind) {
2714 osmo_fsm_inst_dispatch(gss->nse->bss_sns_fi, NS2_SNS_EV_REQ_CHANGE_WEIGHT, sbind);
2715 break;
2716 }
2717 }
2718 }
Alexander Couzensc4704762021-02-08 23:13:12 +01002719}
2720
Harald Welte4f127462021-03-02 20:49:10 +01002721
2722
2723
2724/***********************************************************************
2725 * SGSN role
2726 ***********************************************************************/
2727
Alexander Couzensa2707822021-07-20 18:59:40 +02002728/* cleanup all state. If nsvc is given, don't remove this nsvc. (nsvc is given when a SIZE PDU received) */
2729static void ns2_clear_sgsn(struct ns2_sns_state *gss, struct gprs_ns2_vc *size_nsvc)
2730{
2731 struct gprs_ns2_vc *nsvc, *nsvc2;
2732
Alexander Couzens1f3193d2021-06-05 22:08:11 +02002733 ns2_clear_procedures(gss);
Alexander Couzensa2707822021-07-20 18:59:40 +02002734 ns2_clear_elems(&gss->local);
2735 ns2_clear_elems(&gss->remote);
Alexander Couzensc2fec692021-09-04 01:10:46 +02002736 gss->block_no_nsvc_events = true;
Alexander Couzensa2707822021-07-20 18:59:40 +02002737 llist_for_each_entry_safe(nsvc, nsvc2, &gss->nse->nsvc, list) {
2738 /* Ignore the NSVC over which the SIZE PDU got received */
2739 if (size_nsvc && size_nsvc == nsvc)
2740 continue;
2741
2742 gprs_ns2_free_nsvc(nsvc);
2743 }
Alexander Couzensc2fec692021-09-04 01:10:46 +02002744 gss->block_no_nsvc_events = false;
Alexander Couzensa2707822021-07-20 18:59:40 +02002745}
2746
2747static void ns2_sns_st_sgsn_unconfigured_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
2748{
2749 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
2750
2751 ns2_clear_sgsn(gss, NULL);
2752}
2753
Harald Welte4f127462021-03-02 20:49:10 +01002754static void ns2_sns_st_sgsn_unconfigured(struct osmo_fsm_inst *fi, uint32_t event, void *data)
2755{
2756 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
2757 OSMO_ASSERT(gss->role == GPRS_SNS_ROLE_SGSN);
2758 /* do nothing; Rx SNS-SIZE handled in ns2_sns_st_all_action_sgsn() */
2759}
2760
2761/* We're waiting for inbound SNS-CONFIG from the BSS */
2762static void ns2_sns_st_sgsn_wait_config(struct osmo_fsm_inst *fi, uint32_t event, void *data)
2763{
2764 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
2765 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
2766 struct gprs_ns2_inst *nsi = nse->nsi;
2767 uint8_t cause;
2768 int rc;
2769
2770 OSMO_ASSERT(gss->role == GPRS_SNS_ROLE_SGSN);
2771
2772 switch (event) {
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002773 case NS2_SNS_EV_RX_CONFIG:
2774 case NS2_SNS_EV_RX_CONFIG_END:
Harald Welte4f127462021-03-02 20:49:10 +01002775 rc = ns_sns_append_remote_eps(fi, data);
2776 if (rc < 0) {
2777 cause = -rc;
2778 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
2779 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
2780 return;
2781 }
2782 /* only change state if last CONFIG was received */
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002783 if (event == NS2_SNS_EV_RX_CONFIG_END) {
Harald Welte4f127462021-03-02 20:49:10 +01002784 /* ensure sum of data weight / sig weights is > 0 */
Alexander Couzens019da4b2021-06-06 02:48:18 +02002785 if (ip46_weight_sum_data(&gss->remote) == 0 || ip46_weight_sum_sig(&gss->remote) == 0) {
Harald Welte4f127462021-03-02 20:49:10 +01002786 cause = NS_CAUSE_INVAL_WEIGH;
2787 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
2788 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
2789 break;
2790 }
2791 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
2792 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_SGSN_WAIT_CONFIG_ACK, nsi->timeout[NS_TOUT_TSNS_PROV], 3);
2793 } else {
2794 /* just send CONFIG-ACK */
2795 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
2796 osmo_timer_schedule(&fi->timer, nse->nsi->timeout[NS_TOUT_TSNS_PROV], 0);
2797 }
2798 break;
2799 }
2800}
2801
2802static void ns2_sns_st_sgsn_wait_config_ack_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
2803{
2804 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
2805 OSMO_ASSERT(gss->role == GPRS_SNS_ROLE_SGSN);
2806
Harald Welte4f127462021-03-02 20:49:10 +01002807 /* transmit SGSN-oriented SNS-CONFIG */
Alexander Couzens71128672021-06-05 18:44:01 +02002808 ns2_tx_sns_config(gss->sns_nsvc, true, gss->local.ip4, gss->local.num_ip4,
2809 gss->local.ip6, gss->local.num_ip6);
Harald Welte4f127462021-03-02 20:49:10 +01002810}
2811
2812/* We're waiting for SNS-CONFIG-ACK from the BSS (in response to our outbound SNS-CONFIG) */
2813static void ns2_sns_st_sgsn_wait_config_ack(struct osmo_fsm_inst *fi, uint32_t event, void *data)
2814{
2815 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
2816 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
2817 struct tlv_parsed *tp = NULL;
2818
2819 OSMO_ASSERT(gss->role == GPRS_SNS_ROLE_SGSN);
2820
2821 switch (event) {
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002822 case NS2_SNS_EV_RX_CONFIG_ACK:
Harald Welte4f127462021-03-02 20:49:10 +01002823 tp = data;
2824 if (TLVP_VAL_MINLEN(tp, NS_IE_CAUSE, 1)) {
2825 LOGPFSML(fi, LOGL_ERROR, "Rx SNS-CONFIG-ACK with cause %s\n",
2826 gprs_ns2_cause_str(*TLVP_VAL(tp, NS_IE_CAUSE)));
2827 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
2828 break;
2829 }
2830 /* we currently only send one SNS-CONFIG with END FLAG */
2831 if (true) {
2832 create_missing_nsvcs(fi);
2833 /* start the test procedure on ALL NSVCs! */
2834 gprs_ns2_start_alive_all_nsvcs(nse);
2835 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIGURED, ns_sns_configured_timeout(fi), 4);
2836 }
2837 break;
2838 }
2839}
2840
2841/* SGSN-side SNS state machine */
2842static const struct osmo_fsm_state ns2_sns_sgsn_states[] = {
2843 [GPRS_SNS_ST_UNCONFIGURED] = {
2844 .in_event_mask = 0, /* handled by all_state_action */
2845 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
2846 S(GPRS_SNS_ST_SGSN_WAIT_CONFIG),
2847 .name = "UNCONFIGURED",
2848 .action = ns2_sns_st_sgsn_unconfigured,
Alexander Couzensa2707822021-07-20 18:59:40 +02002849 .onenter = ns2_sns_st_sgsn_unconfigured_onenter,
Harald Welte4f127462021-03-02 20:49:10 +01002850 },
2851 [GPRS_SNS_ST_SGSN_WAIT_CONFIG] = {
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002852 .in_event_mask = S(NS2_SNS_EV_RX_CONFIG) |
2853 S(NS2_SNS_EV_RX_CONFIG_END),
Harald Welte4f127462021-03-02 20:49:10 +01002854 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
2855 S(GPRS_SNS_ST_SGSN_WAIT_CONFIG) |
2856 S(GPRS_SNS_ST_SGSN_WAIT_CONFIG_ACK),
2857 .name = "SGSN_WAIT_CONFIG",
2858 .action = ns2_sns_st_sgsn_wait_config,
2859 },
2860 [GPRS_SNS_ST_SGSN_WAIT_CONFIG_ACK] = {
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002861 .in_event_mask = S(NS2_SNS_EV_RX_CONFIG_ACK),
Harald Welte4f127462021-03-02 20:49:10 +01002862 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
Alexander Couzensa2707822021-07-20 18:59:40 +02002863 S(GPRS_SNS_ST_SGSN_WAIT_CONFIG) |
Harald Welte4f127462021-03-02 20:49:10 +01002864 S(GPRS_SNS_ST_SGSN_WAIT_CONFIG_ACK) |
2865 S(GPRS_SNS_ST_CONFIGURED),
2866 .name = "SGSN_WAIT_CONFIG_ACK",
2867 .action = ns2_sns_st_sgsn_wait_config_ack,
2868 .onenter = ns2_sns_st_sgsn_wait_config_ack_onenter,
2869 },
2870 [GPRS_SNS_ST_CONFIGURED] = {
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002871 .in_event_mask = S(NS2_SNS_EV_RX_ADD) |
2872 S(NS2_SNS_EV_RX_DELETE) |
2873 S(NS2_SNS_EV_RX_CHANGE_WEIGHT) |
2874 S(NS2_SNS_EV_REQ_NSVC_ALIVE),
Alexander Couzensa2707822021-07-20 18:59:40 +02002875 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
Alexander Couzens1f3193d2021-06-05 22:08:11 +02002876 S(GPRS_SNS_ST_SGSN_WAIT_CONFIG) |
2877 S(GPRS_SNS_ST_LOCAL_PROCEDURE),
Harald Welte4f127462021-03-02 20:49:10 +01002878 .name = "CONFIGURED",
2879 /* shared with BSS side; once configured there's no difference */
2880 .action = ns2_sns_st_configured,
2881 .onenter = ns2_sns_st_configured_onenter,
2882 },
Alexander Couzens1f3193d2021-06-05 22:08:11 +02002883 [GPRS_SNS_ST_LOCAL_PROCEDURE] = {
2884 .in_event_mask = S(NS2_SNS_EV_RX_ADD) |
2885 S(NS2_SNS_EV_RX_DELETE) |
2886 S(NS2_SNS_EV_RX_CHANGE_WEIGHT) |
2887 S(NS2_SNS_EV_RX_ACK) |
2888 S(NS2_SNS_EV_REQ_CHANGE_WEIGHT) |
2889 S(NS2_SNS_EV_REQ_NSVC_ALIVE),
2890 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
2891 S(GPRS_SNS_ST_CONFIGURED) |
2892 S(GPRS_SNS_ST_LOCAL_PROCEDURE),
2893 .name = "LOCAL_PROCEDURE",
2894 /* shared with BSS side; once configured there's no difference */
2895 .action = ns2_sns_st_local_procedure,
2896 .onenter = ns2_sns_st_local_procedure_onenter,
2897 },
Harald Welte4f127462021-03-02 20:49:10 +01002898};
2899
2900static int ns2_sns_fsm_sgsn_timer_cb(struct osmo_fsm_inst *fi)
2901{
2902 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
2903 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
2904 struct gprs_ns2_inst *nsi = nse->nsi;
2905
2906 gss->N++;
2907 switch (fi->T) {
2908 case 3:
2909 if (gss->N >= nsi->timeout[NS_TOUT_TSNS_CONFIG_RETRIES]) {
2910 LOGPFSML(fi, LOGL_ERROR, "NSE %d: SGSN Config retries failed. Giving up.\n", nse->nsei);
2911 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, nsi->timeout[NS_TOUT_TSNS_PROV], 3);
2912 } else {
2913 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_SGSN_WAIT_CONFIG_ACK, nsi->timeout[NS_TOUT_TSNS_PROV], 3);
2914 }
2915 break;
2916 case 4:
2917 LOGPFSML(fi, LOGL_ERROR, "NSE %d: Config succeeded but no NS-VC came online.\n", nse->nsei);
2918 break;
Alexander Couzens1f3193d2021-06-05 22:08:11 +02002919 case 5:
2920 if (gss->N >= nsi->timeout[NS_TOUT_TSNS_PROCEDURES_RETRIES]) {
2921 sns_failed(fi, "SNS Procedure retries failed.");
2922 } else {
2923 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_LOCAL_PROCEDURE, nsi->timeout[NS_TOUT_TSNS_PROV],
2924 fi->T);
2925 }
2926 break;
Harald Welte4f127462021-03-02 20:49:10 +01002927 }
Alexander Couzens1f3193d2021-06-05 22:08:11 +02002928
Harald Welte4f127462021-03-02 20:49:10 +01002929 return 0;
2930}
2931
Harald Welte4f127462021-03-02 20:49:10 +01002932/* allstate-action for SGSN role */
2933static void ns2_sns_st_all_action_sgsn(struct osmo_fsm_inst *fi, uint32_t event, void *data)
2934{
2935 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
2936 struct tlv_parsed *tp = NULL;
Harald Welte01fa6a32021-03-04 19:49:38 +01002937 size_t num_local_eps, num_remote_eps;
Harald Welte4f127462021-03-02 20:49:10 +01002938 uint8_t flag;
Harald Weltea2c5af52021-03-04 17:59:35 +01002939 uint8_t cause;
Harald Welte4f127462021-03-02 20:49:10 +01002940
2941 OSMO_ASSERT(gss->role == GPRS_SNS_ROLE_SGSN);
2942
2943 switch (event) {
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002944 case NS2_SNS_EV_RX_SIZE:
Harald Welte4f127462021-03-02 20:49:10 +01002945 tp = (struct tlv_parsed *) data;
Harald Weltea2c5af52021-03-04 17:59:35 +01002946 /* check for mandatory / conditional IEs */
2947 if (!TLVP_PRES_LEN(tp, NS_IE_RESET_FLAG, 1) ||
2948 !TLVP_PRES_LEN(tp, NS_IE_MAX_NR_NSVC, 2)) {
2949 cause = NS_CAUSE_MISSING_ESSENT_IE;
2950 ns2_tx_sns_size_ack(gss->sns_nsvc, &cause);
Alexander Couzens1c405252021-06-13 00:14:48 +02002951 if (fi->state == GPRS_SNS_ST_UNCONFIGURED)
2952 sns_failed(fi, "Rx Size: Missing essential IE");
Harald Weltea2c5af52021-03-04 17:59:35 +01002953 break;
2954 }
2955 if (!TLVP_PRES_LEN(tp, NS_IE_IPv4_EP_NR, 2) &&
2956 !TLVP_PRES_LEN(tp, NS_IE_IPv6_EP_NR, 2)) {
2957 cause = NS_CAUSE_MISSING_ESSENT_IE;
Harald Welte4f127462021-03-02 20:49:10 +01002958 ns2_tx_sns_size_ack(gss->sns_nsvc, &cause);
Alexander Couzens1c405252021-06-13 00:14:48 +02002959 if (fi->state == GPRS_SNS_ST_UNCONFIGURED)
2960 sns_failed(fi, "Rx Size: Missing essential IE");
Harald Welte4f127462021-03-02 20:49:10 +01002961 break;
2962 }
Harald Welte01fa6a32021-03-04 19:49:38 +01002963 if (TLVP_PRES_LEN(tp, NS_IE_IPv4_EP_NR, 2))
2964 gss->num_max_ip4_remote = tlvp_val16be(tp, NS_IE_IPv4_EP_NR);
2965 if (TLVP_PRES_LEN(tp, NS_IE_IPv6_EP_NR, 2))
2966 gss->num_max_ip6_remote = tlvp_val16be(tp, NS_IE_IPv6_EP_NR);
2967 /* decide if we go for IPv4 or IPv6 */
Alexander Couzens077ce5a2021-06-06 01:32:45 +02002968 if (gss->num_max_ip6_remote && ns2_sns_count_num_local_ep(fi, AF_INET6)) {
2969 gss->family = AF_INET6;
Harald Welte2d807b62021-03-24 01:57:30 +01002970 ns2_sns_compute_local_ep_from_binds(fi);
Alexander Couzens71128672021-06-05 18:44:01 +02002971 num_local_eps = gss->local.num_ip6;
Harald Welte01fa6a32021-03-04 19:49:38 +01002972 num_remote_eps = gss->num_max_ip6_remote;
Alexander Couzens077ce5a2021-06-06 01:32:45 +02002973 } else if (gss->num_max_ip4_remote && ns2_sns_count_num_local_ep(fi, AF_INET)) {
2974 gss->family = AF_INET;
Harald Welte2d807b62021-03-24 01:57:30 +01002975 ns2_sns_compute_local_ep_from_binds(fi);
Alexander Couzens71128672021-06-05 18:44:01 +02002976 num_local_eps = gss->local.num_ip4;
Harald Welte01fa6a32021-03-04 19:49:38 +01002977 num_remote_eps = gss->num_max_ip4_remote;
2978 } else {
Alexander Couzens71128672021-06-05 18:44:01 +02002979 if (gss->local.num_ip4 && !gss->num_max_ip4_remote)
Harald Welte01fa6a32021-03-04 19:49:38 +01002980 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
2981 else
2982 cause = NS_CAUSE_INVAL_NR_IPv6_EP;
2983 ns2_tx_sns_size_ack(gss->sns_nsvc, &cause);
Alexander Couzens1c405252021-06-13 00:14:48 +02002984 if (fi->state == GPRS_SNS_ST_UNCONFIGURED)
2985 sns_failed(fi, "Rx Size: Invalid Nr of IPv4/IPv6 EPs");
Harald Welte01fa6a32021-03-04 19:49:38 +01002986 break;
2987 }
Harald Welte01fa6a32021-03-04 19:49:38 +01002988 /* ensure number of NS-VCs is sufficient for full mesh */
2989 gss->num_max_nsvcs = tlvp_val16be(tp, NS_IE_MAX_NR_NSVC);
2990 if (gss->num_max_nsvcs < num_remote_eps * num_local_eps) {
2991 LOGPFSML(fi, LOGL_ERROR, "%zu local and %zu remote EPs, requires %zu NS-VC, "
2992 "but BSS supports only %zu maximum NS-VCs\n", num_local_eps,
2993 num_remote_eps, num_local_eps * num_remote_eps, gss->num_max_nsvcs);
2994 cause = NS_CAUSE_INVAL_NR_NS_VC;
2995 ns2_tx_sns_size_ack(gss->sns_nsvc, &cause);
Alexander Couzens1c405252021-06-13 00:14:48 +02002996 if (fi->state == GPRS_SNS_ST_UNCONFIGURED)
2997 sns_failed(fi, NULL);
Harald Welte01fa6a32021-03-04 19:49:38 +01002998 break;
2999 }
3000 /* perform state reset, if requested */
Harald Welte4f127462021-03-02 20:49:10 +01003001 flag = *TLVP_VAL(tp, NS_IE_RESET_FLAG);
3002 if (flag & 1) {
Harald Welte4f127462021-03-02 20:49:10 +01003003 /* clear all state */
Alexander Couzensa2707822021-07-20 18:59:40 +02003004 /* TODO: ensure gss->sns_nsvc is always the NSVC on which we received the SIZE PDU */
Harald Welte4f127462021-03-02 20:49:10 +01003005 gss->N = 0;
Alexander Couzensa2707822021-07-20 18:59:40 +02003006 ns2_clear_sgsn(gss, gss->sns_nsvc);
3007 /* keep the NSVC we need for SNS, but unconfigure it */
3008 gss->sns_nsvc->sig_weight = 0;
3009 gss->sns_nsvc->data_weight = 0;
3010 ns2_vc_force_unconfigured(gss->sns_nsvc);
Harald Welte2d807b62021-03-24 01:57:30 +01003011 ns2_sns_compute_local_ep_from_binds(fi);
Harald Welte4f127462021-03-02 20:49:10 +01003012 }
Alexander Couzens1c405252021-06-13 00:14:48 +02003013
3014 if (fi->state == GPRS_SNS_ST_UNCONFIGURED && !(flag & 1)) {
3015 sns_failed(fi, "Rx Size without Reset flag, but NSE is unknown");
3016 break;
3017 }
3018
Harald Welte4f127462021-03-02 20:49:10 +01003019 /* send SIZE_ACK */
3020 ns2_tx_sns_size_ack(gss->sns_nsvc, NULL);
3021 /* only wait for SNS-CONFIG in case of Reset flag */
3022 if (flag & 1)
3023 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_SGSN_WAIT_CONFIG, 0, 0);
3024 break;
Alexander Couzens83f06ce2021-08-06 19:50:09 +02003025 case NS2_SNS_EV_REQ_FREE_NSVCS:
3026 sns_failed(fi, "On user request to free all NSVCs");
3027 break;
Harald Welte4f127462021-03-02 20:49:10 +01003028 default:
3029 ns2_sns_st_all_action(fi, event, data);
3030 break;
3031 }
3032}
3033
3034static struct osmo_fsm gprs_ns2_sns_sgsn_fsm = {
3035 .name = "GPRS-NS2-SNS-SGSN",
3036 .states = ns2_sns_sgsn_states,
3037 .num_states = ARRAY_SIZE(ns2_sns_sgsn_states),
Alexander Couzens175eb7b2021-07-20 18:41:14 +02003038 .allstate_event_mask = S(NS2_SNS_EV_RX_SIZE) |
3039 S(NS2_SNS_EV_REQ_NO_NSVC) |
Alexander Couzens83f06ce2021-08-06 19:50:09 +02003040 S(NS2_SNS_EV_REQ_FREE_NSVCS) |
Alexander Couzens175eb7b2021-07-20 18:41:14 +02003041 S(NS2_SNS_EV_REQ_ADD_BIND) |
Alexander Couzens1f3193d2021-06-05 22:08:11 +02003042 S(NS2_SNS_EV_REQ_CHANGE_WEIGHT) |
Alexander Couzens175eb7b2021-07-20 18:41:14 +02003043 S(NS2_SNS_EV_REQ_DELETE_BIND),
Harald Welte4f127462021-03-02 20:49:10 +01003044 .allstate_action = ns2_sns_st_all_action_sgsn,
3045 .cleanup = NULL,
3046 .timer_cb = ns2_sns_fsm_sgsn_timer_cb,
3047 .event_names = gprs_sns_event_names,
3048 .pre_term = NULL,
3049 .log_subsys = DLNS,
3050};
3051
3052/*! Allocate an IP-SNS FSM for the SGSN side.
3053 * \param[in] nse NS Entity in which the FSM runs
3054 * \param[in] id string identifier
3055 * \returns FSM instance on success; NULL on error */
3056struct osmo_fsm_inst *ns2_sns_sgsn_fsm_alloc(struct gprs_ns2_nse *nse, const char *id)
3057{
3058 struct osmo_fsm_inst *fi;
3059 struct ns2_sns_state *gss;
3060
3061 fi = osmo_fsm_inst_alloc(&gprs_ns2_sns_sgsn_fsm, nse, NULL, LOGL_DEBUG, id);
3062 if (!fi)
3063 return fi;
3064
3065 gss = talloc_zero(fi, struct ns2_sns_state);
3066 if (!gss)
3067 goto err;
3068
3069 fi->priv = gss;
3070 gss->nse = nse;
3071 gss->role = GPRS_SNS_ROLE_SGSN;
3072 INIT_LLIST_HEAD(&gss->sns_endpoints);
3073 INIT_LLIST_HEAD(&gss->binds);
Alexander Couzens1f3193d2021-06-05 22:08:11 +02003074 INIT_LLIST_HEAD(&gss->procedures);
Harald Welte4f127462021-03-02 20:49:10 +01003075
3076 return fi;
3077err:
3078 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
3079 return NULL;
3080}
3081
3082
3083
3084
Alexander Couzens6a161492020-07-12 13:45:50 +02003085/* initialize osmo_ctx on main tread */
3086static __attribute__((constructor)) void on_dso_load_ctx(void)
3087{
3088 OSMO_ASSERT(osmo_fsm_register(&gprs_ns2_sns_bss_fsm) == 0);
Harald Welte4f127462021-03-02 20:49:10 +01003089 OSMO_ASSERT(osmo_fsm_register(&gprs_ns2_sns_sgsn_fsm) == 0);
Alexander Couzens6a161492020-07-12 13:45:50 +02003090}