blob: 7a3729bd152893a3ffeecc9176eed8c92e67d909 [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);
2230 return;
2231 } else if (!gss->initial) {
2232 gss->initial = llist_first_entry(&gss->sns_endpoints, struct sns_endpoint, list);
2233 } else if (gss->initial->list.next == &gss->sns_endpoints) {
2234 /* last entry, continue with first */
2235 gss->initial = llist_first_entry(&gss->sns_endpoints, struct sns_endpoint, list);
2236 } else {
2237 /* next element is an entry */
2238 gss->initial = llist_entry(gss->initial->list.next, struct sns_endpoint, list);
2239 }
2240
Alexander Couzens68ab9c42021-06-06 03:03:40 +02002241 gss->family = gss->initial->saddr.u.sa.sa_family;
Harald Welte9e37bf42021-03-02 20:48:31 +01002242 gss->reselection_running = false;
Harald Welte694dad52021-03-23 15:22:16 +01002243 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 +01002244 break;
2245 default:
2246 ns2_sns_st_all_action(fi, event, data);
2247 break;
2248 }
2249}
2250
Alexander Couzens6a161492020-07-12 13:45:50 +02002251static struct osmo_fsm gprs_ns2_sns_bss_fsm = {
2252 .name = "GPRS-NS2-SNS-BSS",
2253 .states = ns2_sns_bss_states,
2254 .num_states = ARRAY_SIZE(ns2_sns_bss_states),
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002255 .allstate_event_mask = S(NS2_SNS_EV_REQ_NO_NSVC) |
Alexander Couzens83f06ce2021-08-06 19:50:09 +02002256 S(NS2_SNS_EV_REQ_FREE_NSVCS) |
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002257 S(NS2_SNS_EV_REQ_SELECT_ENDPOINT) |
2258 S(NS2_SNS_EV_REQ_ADD_BIND) |
Alexander Couzens1f3193d2021-06-05 22:08:11 +02002259 S(NS2_SNS_EV_REQ_CHANGE_WEIGHT) |
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002260 S(NS2_SNS_EV_REQ_DELETE_BIND),
Harald Welte9e37bf42021-03-02 20:48:31 +01002261 .allstate_action = ns2_sns_st_all_action_bss,
Alexander Couzens6a161492020-07-12 13:45:50 +02002262 .cleanup = NULL,
2263 .timer_cb = ns2_sns_fsm_bss_timer_cb,
Alexander Couzens6a161492020-07-12 13:45:50 +02002264 .event_names = gprs_sns_event_names,
2265 .pre_term = NULL,
2266 .log_subsys = DLNS,
2267};
2268
Harald Welte5bef2cc2020-09-18 22:33:24 +02002269/*! Allocate an IP-SNS FSM for the BSS side.
2270 * \param[in] nse NS Entity in which the FSM runs
2271 * \param[in] id string identifier
Alexander Couzens23aec352021-02-15 05:05:15 +01002272 * \returns FSM instance on success; NULL on error */
Alexander Couzens6a161492020-07-12 13:45:50 +02002273struct osmo_fsm_inst *ns2_sns_bss_fsm_alloc(struct gprs_ns2_nse *nse,
2274 const char *id)
2275{
2276 struct osmo_fsm_inst *fi;
2277 struct ns2_sns_state *gss;
2278
2279 fi = osmo_fsm_inst_alloc(&gprs_ns2_sns_bss_fsm, nse, NULL, LOGL_DEBUG, id);
2280 if (!fi)
2281 return fi;
2282
2283 gss = talloc_zero(fi, struct ns2_sns_state);
2284 if (!gss)
2285 goto err;
2286
2287 fi->priv = gss;
2288 gss->nse = nse;
Harald Welte4f127462021-03-02 20:49:10 +01002289 gss->role = GPRS_SNS_ROLE_BSS;
Harald Welte24f4df52021-03-04 18:02:54 +01002290 /* The SGSN doesn't tell the BSS, so we assume there's always sufficient */
2291 gss->num_max_ip4_remote = 8192;
2292 gss->num_max_ip6_remote = 8192;
Alexander Couzense769f522020-12-07 07:37:07 +01002293 INIT_LLIST_HEAD(&gss->sns_endpoints);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002294 INIT_LLIST_HEAD(&gss->binds);
Alexander Couzens1f3193d2021-06-05 22:08:11 +02002295 INIT_LLIST_HEAD(&gss->procedures);
Alexander Couzens6a161492020-07-12 13:45:50 +02002296
2297 return fi;
2298err:
2299 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
2300 return NULL;
2301}
2302
Harald Welte5bef2cc2020-09-18 22:33:24 +02002303/*! main entry point for receiving SNS messages from the network.
2304 * \param[in] nsvc NS-VC on which the message was received
2305 * \param[in] msg message buffer of the IP-SNS message
2306 * \param[in] tp parsed TLV structure of message
Alexander Couzens23aec352021-02-15 05:05:15 +01002307 * \returns 0 on success; negative on error */
Alexander Couzens8dfc24c2021-01-25 16:09:23 +01002308int ns2_sns_rx(struct gprs_ns2_vc *nsvc, struct msgb *msg, struct tlv_parsed *tp)
Alexander Couzens6a161492020-07-12 13:45:50 +02002309{
2310 struct gprs_ns2_nse *nse = nsvc->nse;
2311 struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h;
2312 uint16_t nsei = nsvc->nse->nsei;
Harald Welte4f127462021-03-02 20:49:10 +01002313 struct ns2_sns_state *gss;
Alexander Couzens6a161492020-07-12 13:45:50 +02002314 struct osmo_fsm_inst *fi;
Alexander Couzens7619ed42021-03-24 17:44:03 +01002315 int rc = 0;
Alexander Couzens6a161492020-07-12 13:45:50 +02002316
2317 if (!nse->bss_sns_fi) {
Harald Weltef2949742021-01-20 14:54:14 +01002318 LOGNSVC(nsvc, LOGL_NOTICE, "Rx %s for NS Instance that has no SNS!\n",
2319 get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
Alexander Couzens7619ed42021-03-24 17:44:03 +01002320 rc = -EINVAL;
2321 goto out;
Alexander Couzens6a161492020-07-12 13:45:50 +02002322 }
2323
Alexander Couzens6a161492020-07-12 13:45:50 +02002324 /* FIXME: how to resolve SNS FSM Instance by NSEI (SGSN)? */
2325 fi = nse->bss_sns_fi;
Harald Welte4f127462021-03-02 20:49:10 +01002326 gss = (struct ns2_sns_state *) fi->priv;
2327 if (!gss->sns_nsvc)
2328 gss->sns_nsvc = nsvc;
Alexander Couzens6a161492020-07-12 13:45:50 +02002329
Harald Weltef2949742021-01-20 14:54:14 +01002330 LOGPFSML(fi, LOGL_DEBUG, "NSEI=%u Rx SNS PDU type %s\n", nsei,
2331 get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
2332
Alexander Couzens6a161492020-07-12 13:45:50 +02002333 switch (nsh->pdu_type) {
2334 case SNS_PDUT_SIZE:
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002335 osmo_fsm_inst_dispatch(fi, NS2_SNS_EV_RX_SIZE, tp);
Alexander Couzens6a161492020-07-12 13:45:50 +02002336 break;
2337 case SNS_PDUT_SIZE_ACK:
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002338 osmo_fsm_inst_dispatch(fi, NS2_SNS_EV_RX_SIZE_ACK, tp);
Alexander Couzens6a161492020-07-12 13:45:50 +02002339 break;
2340 case SNS_PDUT_CONFIG:
2341 if (nsh->data[0] & 0x01)
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002342 osmo_fsm_inst_dispatch(fi, NS2_SNS_EV_RX_CONFIG_END, tp);
Alexander Couzens6a161492020-07-12 13:45:50 +02002343 else
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002344 osmo_fsm_inst_dispatch(fi, NS2_SNS_EV_RX_CONFIG, tp);
Alexander Couzens6a161492020-07-12 13:45:50 +02002345 break;
2346 case SNS_PDUT_CONFIG_ACK:
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002347 osmo_fsm_inst_dispatch(fi, NS2_SNS_EV_RX_CONFIG_ACK, tp);
Alexander Couzens6a161492020-07-12 13:45:50 +02002348 break;
2349 case SNS_PDUT_ADD:
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002350 osmo_fsm_inst_dispatch(fi, NS2_SNS_EV_RX_ADD, tp);
Alexander Couzens6a161492020-07-12 13:45:50 +02002351 break;
2352 case SNS_PDUT_DELETE:
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002353 osmo_fsm_inst_dispatch(fi, NS2_SNS_EV_RX_DELETE, tp);
Alexander Couzens6a161492020-07-12 13:45:50 +02002354 break;
2355 case SNS_PDUT_CHANGE_WEIGHT:
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002356 osmo_fsm_inst_dispatch(fi, NS2_SNS_EV_RX_CHANGE_WEIGHT, tp);
Alexander Couzens6a161492020-07-12 13:45:50 +02002357 break;
2358 case SNS_PDUT_ACK:
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002359 osmo_fsm_inst_dispatch(fi, NS2_SNS_EV_RX_ACK, tp);
Alexander Couzens6a161492020-07-12 13:45:50 +02002360 break;
2361 default:
Harald Weltef2949742021-01-20 14:54:14 +01002362 LOGPFSML(fi, LOGL_ERROR, "NSEI=%u Rx unknown SNS PDU type %s\n", nsei,
2363 get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
Alexander Couzens7619ed42021-03-24 17:44:03 +01002364 rc = -EINVAL;
Alexander Couzens6a161492020-07-12 13:45:50 +02002365 }
2366
Alexander Couzens7619ed42021-03-24 17:44:03 +01002367out:
2368 msgb_free(msg);
2369
2370 return rc;
Alexander Couzens6a161492020-07-12 13:45:50 +02002371}
2372
2373#include <osmocom/vty/vty.h>
2374#include <osmocom/vty/misc.h>
2375
Harald Welte1262c4f2021-01-19 20:58:33 +01002376static 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 +02002377{
2378 struct in_addr in = { .s_addr = ip4->ip_addr };
Harald Welte1262c4f2021-01-19 20:58:33 +01002379 vty_out(vty, "%s %s:%u, Signalling Weight: %u, Data Weight: %u%s", prefix,
Alexander Couzens6a161492020-07-12 13:45:50 +02002380 inet_ntoa(in), ntohs(ip4->udp_port), ip4->sig_weight, ip4->data_weight, VTY_NEWLINE);
2381}
2382
Harald Welte1262c4f2021-01-19 20:58:33 +01002383static 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 +02002384{
2385 char ip_addr[INET6_ADDRSTRLEN] = {};
2386 if (!inet_ntop(AF_INET6, &ip6->ip_addr, ip_addr, (INET6_ADDRSTRLEN)))
2387 strcpy(ip_addr, "Invalid IPv6");
2388
Harald Welte1262c4f2021-01-19 20:58:33 +01002389 vty_out(vty, "%s %s:%u, Signalling Weight: %u, Data Weight: %u%s", prefix,
Alexander Couzens6a161492020-07-12 13:45:50 +02002390 ip_addr, ntohs(ip6->udp_port), ip6->sig_weight, ip6->data_weight, VTY_NEWLINE);
2391}
2392
Harald Welte5bef2cc2020-09-18 22:33:24 +02002393/*! Dump the IP-SNS state to a vty.
2394 * \param[in] vty VTY to which the state shall be printed
Harald Welte1262c4f2021-01-19 20:58:33 +01002395 * \param[in] prefix prefix to print at start of each line (typically indenting)
Harald Welte5bef2cc2020-09-18 22:33:24 +02002396 * \param[in] nse NS Entity whose IP-SNS state shall be printed
2397 * \param[in] stats Whether or not statistics shall also be printed */
Alexander Couzens8dfc24c2021-01-25 16:09:23 +01002398void 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 +02002399{
2400 struct ns2_sns_state *gss;
2401 unsigned int i;
2402
2403 if (!nse->bss_sns_fi)
2404 return;
2405
Harald Welte1262c4f2021-01-19 20:58:33 +01002406 vty_out_fsm_inst2(vty, prefix, nse->bss_sns_fi);
Alexander Couzens6a161492020-07-12 13:45:50 +02002407 gss = (struct ns2_sns_state *) nse->bss_sns_fi->priv;
2408
Harald Welte1262c4f2021-01-19 20:58:33 +01002409 vty_out(vty, "%sMaximum number of remote NS-VCs: %zu, IPv4 Endpoints: %zu, IPv6 Endpoints: %zu%s",
2410 prefix, gss->num_max_nsvcs, gss->num_max_ip4_remote, gss->num_max_ip6_remote, VTY_NEWLINE);
Alexander Couzens6a161492020-07-12 13:45:50 +02002411
Alexander Couzens71128672021-06-05 18:44:01 +02002412 if (gss->local.num_ip4 && gss->remote.num_ip4) {
Harald Welte1262c4f2021-01-19 20:58:33 +01002413 vty_out(vty, "%sLocal IPv4 Endpoints:%s", prefix, VTY_NEWLINE);
Alexander Couzens71128672021-06-05 18:44:01 +02002414 for (i = 0; i < gss->local.num_ip4; i++)
2415 vty_dump_sns_ip4(vty, prefix, &gss->local.ip4[i]);
Alexander Couzens6a161492020-07-12 13:45:50 +02002416
Harald Welte1262c4f2021-01-19 20:58:33 +01002417 vty_out(vty, "%sRemote IPv4 Endpoints:%s", prefix, VTY_NEWLINE);
Alexander Couzens71128672021-06-05 18:44:01 +02002418 for (i = 0; i < gss->remote.num_ip4; i++)
2419 vty_dump_sns_ip4(vty, prefix, &gss->remote.ip4[i]);
Alexander Couzens6a161492020-07-12 13:45:50 +02002420 }
2421
Alexander Couzens71128672021-06-05 18:44:01 +02002422 if (gss->local.num_ip6 && gss->remote.num_ip6) {
Harald Welte1262c4f2021-01-19 20:58:33 +01002423 vty_out(vty, "%sLocal IPv6 Endpoints:%s", prefix, VTY_NEWLINE);
Alexander Couzens71128672021-06-05 18:44:01 +02002424 for (i = 0; i < gss->local.num_ip6; i++)
2425 vty_dump_sns_ip6(vty, prefix, &gss->local.ip6[i]);
Alexander Couzens6a161492020-07-12 13:45:50 +02002426
Harald Welte1262c4f2021-01-19 20:58:33 +01002427 vty_out(vty, "%sRemote IPv6 Endpoints:%s", prefix, VTY_NEWLINE);
Alexander Couzens71128672021-06-05 18:44:01 +02002428 for (i = 0; i < gss->remote.num_ip6; i++)
2429 vty_dump_sns_ip6(vty, prefix, &gss->remote.ip6[i]);
Alexander Couzens6a161492020-07-12 13:45:50 +02002430 }
2431}
2432
Alexander Couzens412bc342020-11-19 05:24:37 +01002433/*! write IP-SNS to a vty
2434 * \param[in] vty VTY to which the state shall be printed
2435 * \param[in] nse NS Entity whose IP-SNS state shall be printed */
Alexander Couzens8dfc24c2021-01-25 16:09:23 +01002436void ns2_sns_write_vty(struct vty *vty, const struct gprs_ns2_nse *nse)
Alexander Couzens412bc342020-11-19 05:24:37 +01002437{
2438 struct ns2_sns_state *gss;
2439 struct osmo_sockaddr_str addr_str;
2440 struct sns_endpoint *endpoint;
2441
2442 if (!nse->bss_sns_fi)
2443 return;
2444
2445 gss = (struct ns2_sns_state *) nse->bss_sns_fi->priv;
2446 llist_for_each_entry(endpoint, &gss->sns_endpoints, list) {
Vadim Yanitskiyd8b70032021-01-05 14:24:09 +01002447 /* It's unlikely that an error happens, but let's better be safe. */
2448 if (osmo_sockaddr_str_from_sockaddr(&addr_str, &endpoint->saddr.u.sas) != 0)
2449 addr_str = (struct osmo_sockaddr_str) { .ip = "<INVALID>" };
Alexander Couzens5fa431c2021-02-08 23:21:54 +01002450 vty_out(vty, " ip-sns-remote %s %u%s", addr_str.ip, addr_str.port, VTY_NEWLINE);
Alexander Couzens412bc342020-11-19 05:24:37 +01002451 }
2452}
2453
Alexander Couzense769f522020-12-07 07:37:07 +01002454static struct sns_endpoint *ns2_get_sns_endpoint(struct ns2_sns_state *state,
2455 const struct osmo_sockaddr *saddr)
2456{
2457 struct sns_endpoint *endpoint;
2458
2459 llist_for_each_entry(endpoint, &state->sns_endpoints, list) {
2460 if (!osmo_sockaddr_cmp(saddr, &endpoint->saddr))
2461 return endpoint;
2462 }
2463
2464 return NULL;
2465}
2466
2467/*! gprs_ns2_sns_add_endpoint
2468 * \param[in] nse
2469 * \param[in] sockaddr
2470 * \return
2471 */
2472int gprs_ns2_sns_add_endpoint(struct gprs_ns2_nse *nse,
2473 const struct osmo_sockaddr *saddr)
2474{
2475 struct ns2_sns_state *gss;
2476 struct sns_endpoint *endpoint;
2477 bool do_selection = false;
2478
2479 if (nse->ll != GPRS_NS2_LL_UDP) {
2480 return -EINVAL;
2481 }
2482
Alexander Couzens138b96f2021-01-25 16:23:29 +01002483 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
Alexander Couzense769f522020-12-07 07:37:07 +01002484 return -EINVAL;
2485 }
2486
2487 gss = nse->bss_sns_fi->priv;
2488
2489 if (ns2_get_sns_endpoint(gss, saddr))
2490 return -EADDRINUSE;
2491
2492 endpoint = talloc_zero(nse->bss_sns_fi->priv, struct sns_endpoint);
2493 if (!endpoint)
2494 return -ENOMEM;
2495
2496 endpoint->saddr = *saddr;
2497 if (llist_empty(&gss->sns_endpoints))
2498 do_selection = true;
2499
2500 llist_add_tail(&endpoint->list, &gss->sns_endpoints);
2501 if (do_selection)
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002502 osmo_fsm_inst_dispatch(nse->bss_sns_fi, NS2_SNS_EV_REQ_SELECT_ENDPOINT, NULL);
Alexander Couzense769f522020-12-07 07:37:07 +01002503
2504 return 0;
2505}
2506
2507/*! gprs_ns2_sns_del_endpoint
2508 * \param[in] nse
2509 * \param[in] sockaddr
2510 * \return 0 on success, otherwise < 0
2511 */
2512int gprs_ns2_sns_del_endpoint(struct gprs_ns2_nse *nse,
2513 const struct osmo_sockaddr *saddr)
2514{
2515 struct ns2_sns_state *gss;
2516 struct sns_endpoint *endpoint;
2517
2518 if (nse->ll != GPRS_NS2_LL_UDP) {
2519 return -EINVAL;
2520 }
2521
Alexander Couzens138b96f2021-01-25 16:23:29 +01002522 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
Alexander Couzense769f522020-12-07 07:37:07 +01002523 return -EINVAL;
2524 }
2525
2526 gss = nse->bss_sns_fi->priv;
2527 endpoint = ns2_get_sns_endpoint(gss, saddr);
2528 if (!endpoint)
2529 return -ENOENT;
2530
2531 /* if this is an unused SNS endpoint it's done */
2532 if (gss->initial != endpoint) {
2533 llist_del(&endpoint->list);
2534 talloc_free(endpoint);
2535 return 0;
2536 }
2537
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002538 /* gprs_ns2_free_nsvcs() will trigger NS2_SNS_EV_REQ_NO_NSVC on the last NS-VC
Alexander Couzense769f522020-12-07 07:37:07 +01002539 * and restart SNS SIZE procedure which selects a new initial */
Harald Weltef2949742021-01-20 14:54:14 +01002540 LOGNSE(nse, LOGL_INFO, "Current in-use SNS endpoint is being removed."
Alexander Couzense769f522020-12-07 07:37:07 +01002541 "Closing all NS-VC and restart SNS-SIZE procedure"
2542 "with a remaining SNS endpoint.\n");
2543
2544 /* Continue with the next endpoint in the list.
2545 * Special case if the endpoint is at the start or end of the list */
2546 if (endpoint->list.prev == &gss->sns_endpoints ||
2547 endpoint->list.next == &gss->sns_endpoints)
2548 gss->initial = NULL;
2549 else
2550 gss->initial = llist_entry(endpoint->list.next->prev,
2551 struct sns_endpoint,
2552 list);
2553
2554 llist_del(&endpoint->list);
2555 gprs_ns2_free_nsvcs(nse);
2556 talloc_free(endpoint);
2557
2558 return 0;
2559}
2560
2561/*! gprs_ns2_sns_count
2562 * \param[in] nse NS Entity whose IP-SNS endpoints shall be printed
2563 * \return the count of endpoints or < 0 if NSE doesn't contain sns.
2564 */
2565int gprs_ns2_sns_count(struct gprs_ns2_nse *nse)
2566{
2567 struct ns2_sns_state *gss;
2568 struct sns_endpoint *endpoint;
2569 int count = 0;
2570
2571 if (nse->ll != GPRS_NS2_LL_UDP) {
2572 return -EINVAL;
2573 }
2574
Alexander Couzens138b96f2021-01-25 16:23:29 +01002575 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
Alexander Couzense769f522020-12-07 07:37:07 +01002576 return -EINVAL;
2577 }
2578
2579 gss = nse->bss_sns_fi->priv;
2580 llist_for_each_entry(endpoint, &gss->sns_endpoints, list)
2581 count++;
2582
2583 return count;
2584}
2585
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01002586void ns2_sns_notify_alive(struct gprs_ns2_nse *nse, struct gprs_ns2_vc *nsvc, bool alive)
2587{
2588 struct ns2_sns_state *gss;
2589 struct gprs_ns2_vc *tmp;
2590
2591 if (!nse->bss_sns_fi)
2592 return;
2593
2594 gss = nse->bss_sns_fi->priv;
Alexander Couzens1f3193d2021-06-05 22:08:11 +02002595 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 +01002596 return;
2597
Alexander Couzensdb07a442021-06-06 18:58:01 +02002598 if (gss->block_no_nsvc_events)
2599 return;
2600
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01002601 if (alive == gss->alive)
2602 return;
2603
2604 /* check if this is the current SNS NS-VC */
2605 if (nsvc == gss->sns_nsvc) {
2606 /* only replace the SNS NS-VC if there are other alive NS-VC.
2607 * There aren't any other alive NS-VC when the SNS fsm just reached CONFIGURED
2608 * and couldn't confirm yet if the NS-VC comes up */
2609 if (gss->alive && !alive)
2610 ns2_sns_replace_nsvc(nsvc);
2611 }
2612
2613 if (alive) {
2614 gss->alive = true;
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002615 osmo_fsm_inst_dispatch(nse->bss_sns_fi, NS2_SNS_EV_REQ_NSVC_ALIVE, NULL);
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01002616 } else {
2617 /* is there at least another alive nsvc? */
2618 llist_for_each_entry(tmp, &nse->nsvc, list) {
2619 if (ns2_vc_is_unblocked(tmp))
2620 return;
2621 }
2622
2623 /* all NS-VC have failed */
2624 gss->alive = false;
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002625 osmo_fsm_inst_dispatch(nse->bss_sns_fi, NS2_SNS_EV_REQ_NO_NSVC, NULL);
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01002626 }
2627}
2628
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002629int gprs_ns2_sns_add_bind(struct gprs_ns2_nse *nse,
2630 struct gprs_ns2_vc_bind *bind)
2631{
2632 struct ns2_sns_state *gss;
2633 struct ns2_sns_bind *tmp;
2634
2635 OSMO_ASSERT(nse->bss_sns_fi);
2636 gss = nse->bss_sns_fi->priv;
2637
2638 if (!gprs_ns2_is_ip_bind(bind)) {
2639 return -EINVAL;
2640 }
2641
2642 if (!llist_empty(&gss->binds)) {
2643 llist_for_each_entry(tmp, &gss->binds, list) {
2644 if (tmp->bind == bind)
2645 return -EALREADY;
2646 }
2647 }
2648
2649 tmp = talloc_zero(gss, struct ns2_sns_bind);
2650 if (!tmp)
2651 return -ENOMEM;
2652 tmp->bind = bind;
2653 llist_add_tail(&tmp->list, &gss->binds);
2654
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002655 osmo_fsm_inst_dispatch(nse->bss_sns_fi, NS2_SNS_EV_REQ_ADD_BIND, tmp);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002656 return 0;
2657}
2658
2659/* Remove a bind from the SNS. All assosiated NSVC must be removed. */
2660int gprs_ns2_sns_del_bind(struct gprs_ns2_nse *nse,
2661 struct gprs_ns2_vc_bind *bind)
2662{
2663 struct ns2_sns_state *gss;
2664 struct ns2_sns_bind *tmp, *tmp2;
2665 bool found = false;
2666
2667 if (!nse->bss_sns_fi)
2668 return -EINVAL;
2669
2670 gss = nse->bss_sns_fi->priv;
2671 if (gss->initial_bind && gss->initial_bind->bind == bind) {
2672 if (gss->initial_bind->list.prev == &gss->binds)
2673 gss->initial_bind = NULL;
2674 else
2675 gss->initial_bind = llist_entry(gss->initial_bind->list.prev, struct ns2_sns_bind, list);
2676 }
2677
2678 llist_for_each_entry_safe(tmp, tmp2, &gss->binds, list) {
2679 if (tmp->bind == bind) {
2680 llist_del(&tmp->list);
2681 found = true;
Alexander Couzensa35c2962021-04-19 03:30:15 +02002682 break;
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002683 }
2684 }
2685
2686 if (!found)
2687 return -ENOENT;
2688
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002689 osmo_fsm_inst_dispatch(nse->bss_sns_fi, NS2_SNS_EV_REQ_DELETE_BIND, tmp);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002690 return 0;
2691}
2692
Alexander Couzens71128672021-06-05 18:44:01 +02002693/* Update SNS weights for a bind (local endpoint).
2694 * \param[in] bind the bind which has been updated
Alexander Couzensc4704762021-02-08 23:13:12 +01002695 */
2696void ns2_sns_update_weights(struct gprs_ns2_vc_bind *bind)
2697{
Alexander Couzens1f3193d2021-06-05 22:08:11 +02002698 struct ns2_sns_bind *sbind;
2699 struct gprs_ns2_nse *nse;
2700 struct ns2_sns_state *gss;
2701 const struct osmo_sockaddr *addr = gprs_ns2_ip_bind_sockaddr(bind);
2702
2703 llist_for_each_entry(nse, &bind->nsi->nse, list) {
2704 if (!nse->bss_sns_fi)
2705 continue;
2706
2707 gss = nse->bss_sns_fi->priv;
2708 if (addr->u.sa.sa_family != gss->family)
2709 return;
2710
2711 llist_for_each_entry(sbind, &gss->binds, list) {
2712 if (sbind->bind == bind) {
2713 osmo_fsm_inst_dispatch(gss->nse->bss_sns_fi, NS2_SNS_EV_REQ_CHANGE_WEIGHT, sbind);
2714 break;
2715 }
2716 }
2717 }
Alexander Couzensc4704762021-02-08 23:13:12 +01002718}
2719
Harald Welte4f127462021-03-02 20:49:10 +01002720
2721
2722
2723/***********************************************************************
2724 * SGSN role
2725 ***********************************************************************/
2726
Alexander Couzensa2707822021-07-20 18:59:40 +02002727/* cleanup all state. If nsvc is given, don't remove this nsvc. (nsvc is given when a SIZE PDU received) */
2728static void ns2_clear_sgsn(struct ns2_sns_state *gss, struct gprs_ns2_vc *size_nsvc)
2729{
2730 struct gprs_ns2_vc *nsvc, *nsvc2;
2731
Alexander Couzens1f3193d2021-06-05 22:08:11 +02002732 ns2_clear_procedures(gss);
Alexander Couzensa2707822021-07-20 18:59:40 +02002733 ns2_clear_elems(&gss->local);
2734 ns2_clear_elems(&gss->remote);
Alexander Couzensc2fec692021-09-04 01:10:46 +02002735 gss->block_no_nsvc_events = true;
Alexander Couzensa2707822021-07-20 18:59:40 +02002736 llist_for_each_entry_safe(nsvc, nsvc2, &gss->nse->nsvc, list) {
2737 /* Ignore the NSVC over which the SIZE PDU got received */
2738 if (size_nsvc && size_nsvc == nsvc)
2739 continue;
2740
2741 gprs_ns2_free_nsvc(nsvc);
2742 }
Alexander Couzensc2fec692021-09-04 01:10:46 +02002743 gss->block_no_nsvc_events = false;
Alexander Couzensa2707822021-07-20 18:59:40 +02002744}
2745
2746static void ns2_sns_st_sgsn_unconfigured_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
2747{
2748 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
2749
2750 ns2_clear_sgsn(gss, NULL);
2751}
2752
Harald Welte4f127462021-03-02 20:49:10 +01002753static void ns2_sns_st_sgsn_unconfigured(struct osmo_fsm_inst *fi, uint32_t event, void *data)
2754{
2755 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
2756 OSMO_ASSERT(gss->role == GPRS_SNS_ROLE_SGSN);
2757 /* do nothing; Rx SNS-SIZE handled in ns2_sns_st_all_action_sgsn() */
2758}
2759
2760/* We're waiting for inbound SNS-CONFIG from the BSS */
2761static void ns2_sns_st_sgsn_wait_config(struct osmo_fsm_inst *fi, uint32_t event, void *data)
2762{
2763 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
2764 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
2765 struct gprs_ns2_inst *nsi = nse->nsi;
2766 uint8_t cause;
2767 int rc;
2768
2769 OSMO_ASSERT(gss->role == GPRS_SNS_ROLE_SGSN);
2770
2771 switch (event) {
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002772 case NS2_SNS_EV_RX_CONFIG:
2773 case NS2_SNS_EV_RX_CONFIG_END:
Harald Welte4f127462021-03-02 20:49:10 +01002774 rc = ns_sns_append_remote_eps(fi, data);
2775 if (rc < 0) {
2776 cause = -rc;
2777 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
2778 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
2779 return;
2780 }
2781 /* only change state if last CONFIG was received */
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002782 if (event == NS2_SNS_EV_RX_CONFIG_END) {
Harald Welte4f127462021-03-02 20:49:10 +01002783 /* ensure sum of data weight / sig weights is > 0 */
Alexander Couzens019da4b2021-06-06 02:48:18 +02002784 if (ip46_weight_sum_data(&gss->remote) == 0 || ip46_weight_sum_sig(&gss->remote) == 0) {
Harald Welte4f127462021-03-02 20:49:10 +01002785 cause = NS_CAUSE_INVAL_WEIGH;
2786 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
2787 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
2788 break;
2789 }
2790 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
2791 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_SGSN_WAIT_CONFIG_ACK, nsi->timeout[NS_TOUT_TSNS_PROV], 3);
2792 } else {
2793 /* just send CONFIG-ACK */
2794 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
2795 osmo_timer_schedule(&fi->timer, nse->nsi->timeout[NS_TOUT_TSNS_PROV], 0);
2796 }
2797 break;
2798 }
2799}
2800
2801static void ns2_sns_st_sgsn_wait_config_ack_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
2802{
2803 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
2804 OSMO_ASSERT(gss->role == GPRS_SNS_ROLE_SGSN);
2805
Harald Welte4f127462021-03-02 20:49:10 +01002806 /* transmit SGSN-oriented SNS-CONFIG */
Alexander Couzens71128672021-06-05 18:44:01 +02002807 ns2_tx_sns_config(gss->sns_nsvc, true, gss->local.ip4, gss->local.num_ip4,
2808 gss->local.ip6, gss->local.num_ip6);
Harald Welte4f127462021-03-02 20:49:10 +01002809}
2810
2811/* We're waiting for SNS-CONFIG-ACK from the BSS (in response to our outbound SNS-CONFIG) */
2812static void ns2_sns_st_sgsn_wait_config_ack(struct osmo_fsm_inst *fi, uint32_t event, void *data)
2813{
2814 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
2815 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
2816 struct tlv_parsed *tp = NULL;
2817
2818 OSMO_ASSERT(gss->role == GPRS_SNS_ROLE_SGSN);
2819
2820 switch (event) {
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002821 case NS2_SNS_EV_RX_CONFIG_ACK:
Harald Welte4f127462021-03-02 20:49:10 +01002822 tp = data;
2823 if (TLVP_VAL_MINLEN(tp, NS_IE_CAUSE, 1)) {
2824 LOGPFSML(fi, LOGL_ERROR, "Rx SNS-CONFIG-ACK with cause %s\n",
2825 gprs_ns2_cause_str(*TLVP_VAL(tp, NS_IE_CAUSE)));
2826 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
2827 break;
2828 }
2829 /* we currently only send one SNS-CONFIG with END FLAG */
2830 if (true) {
2831 create_missing_nsvcs(fi);
2832 /* start the test procedure on ALL NSVCs! */
2833 gprs_ns2_start_alive_all_nsvcs(nse);
2834 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIGURED, ns_sns_configured_timeout(fi), 4);
2835 }
2836 break;
2837 }
2838}
2839
2840/* SGSN-side SNS state machine */
2841static const struct osmo_fsm_state ns2_sns_sgsn_states[] = {
2842 [GPRS_SNS_ST_UNCONFIGURED] = {
2843 .in_event_mask = 0, /* handled by all_state_action */
2844 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
2845 S(GPRS_SNS_ST_SGSN_WAIT_CONFIG),
2846 .name = "UNCONFIGURED",
2847 .action = ns2_sns_st_sgsn_unconfigured,
Alexander Couzensa2707822021-07-20 18:59:40 +02002848 .onenter = ns2_sns_st_sgsn_unconfigured_onenter,
Harald Welte4f127462021-03-02 20:49:10 +01002849 },
2850 [GPRS_SNS_ST_SGSN_WAIT_CONFIG] = {
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002851 .in_event_mask = S(NS2_SNS_EV_RX_CONFIG) |
2852 S(NS2_SNS_EV_RX_CONFIG_END),
Harald Welte4f127462021-03-02 20:49:10 +01002853 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
2854 S(GPRS_SNS_ST_SGSN_WAIT_CONFIG) |
2855 S(GPRS_SNS_ST_SGSN_WAIT_CONFIG_ACK),
2856 .name = "SGSN_WAIT_CONFIG",
2857 .action = ns2_sns_st_sgsn_wait_config,
2858 },
2859 [GPRS_SNS_ST_SGSN_WAIT_CONFIG_ACK] = {
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002860 .in_event_mask = S(NS2_SNS_EV_RX_CONFIG_ACK),
Harald Welte4f127462021-03-02 20:49:10 +01002861 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
Alexander Couzensa2707822021-07-20 18:59:40 +02002862 S(GPRS_SNS_ST_SGSN_WAIT_CONFIG) |
Harald Welte4f127462021-03-02 20:49:10 +01002863 S(GPRS_SNS_ST_SGSN_WAIT_CONFIG_ACK) |
2864 S(GPRS_SNS_ST_CONFIGURED),
2865 .name = "SGSN_WAIT_CONFIG_ACK",
2866 .action = ns2_sns_st_sgsn_wait_config_ack,
2867 .onenter = ns2_sns_st_sgsn_wait_config_ack_onenter,
2868 },
2869 [GPRS_SNS_ST_CONFIGURED] = {
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002870 .in_event_mask = S(NS2_SNS_EV_RX_ADD) |
2871 S(NS2_SNS_EV_RX_DELETE) |
2872 S(NS2_SNS_EV_RX_CHANGE_WEIGHT) |
2873 S(NS2_SNS_EV_REQ_NSVC_ALIVE),
Alexander Couzensa2707822021-07-20 18:59:40 +02002874 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
Alexander Couzens1f3193d2021-06-05 22:08:11 +02002875 S(GPRS_SNS_ST_SGSN_WAIT_CONFIG) |
2876 S(GPRS_SNS_ST_LOCAL_PROCEDURE),
Harald Welte4f127462021-03-02 20:49:10 +01002877 .name = "CONFIGURED",
2878 /* shared with BSS side; once configured there's no difference */
2879 .action = ns2_sns_st_configured,
2880 .onenter = ns2_sns_st_configured_onenter,
2881 },
Alexander Couzens1f3193d2021-06-05 22:08:11 +02002882 [GPRS_SNS_ST_LOCAL_PROCEDURE] = {
2883 .in_event_mask = S(NS2_SNS_EV_RX_ADD) |
2884 S(NS2_SNS_EV_RX_DELETE) |
2885 S(NS2_SNS_EV_RX_CHANGE_WEIGHT) |
2886 S(NS2_SNS_EV_RX_ACK) |
2887 S(NS2_SNS_EV_REQ_CHANGE_WEIGHT) |
2888 S(NS2_SNS_EV_REQ_NSVC_ALIVE),
2889 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
2890 S(GPRS_SNS_ST_CONFIGURED) |
2891 S(GPRS_SNS_ST_LOCAL_PROCEDURE),
2892 .name = "LOCAL_PROCEDURE",
2893 /* shared with BSS side; once configured there's no difference */
2894 .action = ns2_sns_st_local_procedure,
2895 .onenter = ns2_sns_st_local_procedure_onenter,
2896 },
Harald Welte4f127462021-03-02 20:49:10 +01002897};
2898
2899static int ns2_sns_fsm_sgsn_timer_cb(struct osmo_fsm_inst *fi)
2900{
2901 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
2902 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
2903 struct gprs_ns2_inst *nsi = nse->nsi;
2904
2905 gss->N++;
2906 switch (fi->T) {
2907 case 3:
2908 if (gss->N >= nsi->timeout[NS_TOUT_TSNS_CONFIG_RETRIES]) {
2909 LOGPFSML(fi, LOGL_ERROR, "NSE %d: SGSN Config retries failed. Giving up.\n", nse->nsei);
2910 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, nsi->timeout[NS_TOUT_TSNS_PROV], 3);
2911 } else {
2912 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_SGSN_WAIT_CONFIG_ACK, nsi->timeout[NS_TOUT_TSNS_PROV], 3);
2913 }
2914 break;
2915 case 4:
2916 LOGPFSML(fi, LOGL_ERROR, "NSE %d: Config succeeded but no NS-VC came online.\n", nse->nsei);
2917 break;
Alexander Couzens1f3193d2021-06-05 22:08:11 +02002918 case 5:
2919 if (gss->N >= nsi->timeout[NS_TOUT_TSNS_PROCEDURES_RETRIES]) {
2920 sns_failed(fi, "SNS Procedure retries failed.");
2921 } else {
2922 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_LOCAL_PROCEDURE, nsi->timeout[NS_TOUT_TSNS_PROV],
2923 fi->T);
2924 }
2925 break;
Harald Welte4f127462021-03-02 20:49:10 +01002926 }
Alexander Couzens1f3193d2021-06-05 22:08:11 +02002927
Harald Welte4f127462021-03-02 20:49:10 +01002928 return 0;
2929}
2930
Harald Welte4f127462021-03-02 20:49:10 +01002931/* allstate-action for SGSN role */
2932static void ns2_sns_st_all_action_sgsn(struct osmo_fsm_inst *fi, uint32_t event, void *data)
2933{
2934 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
2935 struct tlv_parsed *tp = NULL;
Harald Welte01fa6a32021-03-04 19:49:38 +01002936 size_t num_local_eps, num_remote_eps;
Harald Welte4f127462021-03-02 20:49:10 +01002937 uint8_t flag;
Harald Weltea2c5af52021-03-04 17:59:35 +01002938 uint8_t cause;
Harald Welte4f127462021-03-02 20:49:10 +01002939
2940 OSMO_ASSERT(gss->role == GPRS_SNS_ROLE_SGSN);
2941
2942 switch (event) {
Alexander Couzens175eb7b2021-07-20 18:41:14 +02002943 case NS2_SNS_EV_RX_SIZE:
Harald Welte4f127462021-03-02 20:49:10 +01002944 tp = (struct tlv_parsed *) data;
Harald Weltea2c5af52021-03-04 17:59:35 +01002945 /* check for mandatory / conditional IEs */
2946 if (!TLVP_PRES_LEN(tp, NS_IE_RESET_FLAG, 1) ||
2947 !TLVP_PRES_LEN(tp, NS_IE_MAX_NR_NSVC, 2)) {
2948 cause = NS_CAUSE_MISSING_ESSENT_IE;
2949 ns2_tx_sns_size_ack(gss->sns_nsvc, &cause);
Alexander Couzens1c405252021-06-13 00:14:48 +02002950 if (fi->state == GPRS_SNS_ST_UNCONFIGURED)
2951 sns_failed(fi, "Rx Size: Missing essential IE");
Harald Weltea2c5af52021-03-04 17:59:35 +01002952 break;
2953 }
2954 if (!TLVP_PRES_LEN(tp, NS_IE_IPv4_EP_NR, 2) &&
2955 !TLVP_PRES_LEN(tp, NS_IE_IPv6_EP_NR, 2)) {
2956 cause = NS_CAUSE_MISSING_ESSENT_IE;
Harald Welte4f127462021-03-02 20:49:10 +01002957 ns2_tx_sns_size_ack(gss->sns_nsvc, &cause);
Alexander Couzens1c405252021-06-13 00:14:48 +02002958 if (fi->state == GPRS_SNS_ST_UNCONFIGURED)
2959 sns_failed(fi, "Rx Size: Missing essential IE");
Harald Welte4f127462021-03-02 20:49:10 +01002960 break;
2961 }
Harald Welte01fa6a32021-03-04 19:49:38 +01002962 if (TLVP_PRES_LEN(tp, NS_IE_IPv4_EP_NR, 2))
2963 gss->num_max_ip4_remote = tlvp_val16be(tp, NS_IE_IPv4_EP_NR);
2964 if (TLVP_PRES_LEN(tp, NS_IE_IPv6_EP_NR, 2))
2965 gss->num_max_ip6_remote = tlvp_val16be(tp, NS_IE_IPv6_EP_NR);
2966 /* decide if we go for IPv4 or IPv6 */
Alexander Couzens077ce5a2021-06-06 01:32:45 +02002967 if (gss->num_max_ip6_remote && ns2_sns_count_num_local_ep(fi, AF_INET6)) {
2968 gss->family = AF_INET6;
Harald Welte2d807b62021-03-24 01:57:30 +01002969 ns2_sns_compute_local_ep_from_binds(fi);
Alexander Couzens71128672021-06-05 18:44:01 +02002970 num_local_eps = gss->local.num_ip6;
Harald Welte01fa6a32021-03-04 19:49:38 +01002971 num_remote_eps = gss->num_max_ip6_remote;
Alexander Couzens077ce5a2021-06-06 01:32:45 +02002972 } else if (gss->num_max_ip4_remote && ns2_sns_count_num_local_ep(fi, AF_INET)) {
2973 gss->family = AF_INET;
Harald Welte2d807b62021-03-24 01:57:30 +01002974 ns2_sns_compute_local_ep_from_binds(fi);
Alexander Couzens71128672021-06-05 18:44:01 +02002975 num_local_eps = gss->local.num_ip4;
Harald Welte01fa6a32021-03-04 19:49:38 +01002976 num_remote_eps = gss->num_max_ip4_remote;
2977 } else {
Alexander Couzens71128672021-06-05 18:44:01 +02002978 if (gss->local.num_ip4 && !gss->num_max_ip4_remote)
Harald Welte01fa6a32021-03-04 19:49:38 +01002979 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
2980 else
2981 cause = NS_CAUSE_INVAL_NR_IPv6_EP;
2982 ns2_tx_sns_size_ack(gss->sns_nsvc, &cause);
Alexander Couzens1c405252021-06-13 00:14:48 +02002983 if (fi->state == GPRS_SNS_ST_UNCONFIGURED)
2984 sns_failed(fi, "Rx Size: Invalid Nr of IPv4/IPv6 EPs");
Harald Welte01fa6a32021-03-04 19:49:38 +01002985 break;
2986 }
Harald Welte01fa6a32021-03-04 19:49:38 +01002987 /* ensure number of NS-VCs is sufficient for full mesh */
2988 gss->num_max_nsvcs = tlvp_val16be(tp, NS_IE_MAX_NR_NSVC);
2989 if (gss->num_max_nsvcs < num_remote_eps * num_local_eps) {
2990 LOGPFSML(fi, LOGL_ERROR, "%zu local and %zu remote EPs, requires %zu NS-VC, "
2991 "but BSS supports only %zu maximum NS-VCs\n", num_local_eps,
2992 num_remote_eps, num_local_eps * num_remote_eps, gss->num_max_nsvcs);
2993 cause = NS_CAUSE_INVAL_NR_NS_VC;
2994 ns2_tx_sns_size_ack(gss->sns_nsvc, &cause);
Alexander Couzens1c405252021-06-13 00:14:48 +02002995 if (fi->state == GPRS_SNS_ST_UNCONFIGURED)
2996 sns_failed(fi, NULL);
Harald Welte01fa6a32021-03-04 19:49:38 +01002997 break;
2998 }
2999 /* perform state reset, if requested */
Harald Welte4f127462021-03-02 20:49:10 +01003000 flag = *TLVP_VAL(tp, NS_IE_RESET_FLAG);
3001 if (flag & 1) {
Harald Welte4f127462021-03-02 20:49:10 +01003002 /* clear all state */
Alexander Couzensa2707822021-07-20 18:59:40 +02003003 /* TODO: ensure gss->sns_nsvc is always the NSVC on which we received the SIZE PDU */
Harald Welte4f127462021-03-02 20:49:10 +01003004 gss->N = 0;
Alexander Couzensa2707822021-07-20 18:59:40 +02003005 ns2_clear_sgsn(gss, gss->sns_nsvc);
3006 /* keep the NSVC we need for SNS, but unconfigure it */
3007 gss->sns_nsvc->sig_weight = 0;
3008 gss->sns_nsvc->data_weight = 0;
3009 ns2_vc_force_unconfigured(gss->sns_nsvc);
Harald Welte2d807b62021-03-24 01:57:30 +01003010 ns2_sns_compute_local_ep_from_binds(fi);
Harald Welte4f127462021-03-02 20:49:10 +01003011 }
Alexander Couzens1c405252021-06-13 00:14:48 +02003012
3013 if (fi->state == GPRS_SNS_ST_UNCONFIGURED && !(flag & 1)) {
3014 sns_failed(fi, "Rx Size without Reset flag, but NSE is unknown");
3015 break;
3016 }
3017
Harald Welte4f127462021-03-02 20:49:10 +01003018 /* send SIZE_ACK */
3019 ns2_tx_sns_size_ack(gss->sns_nsvc, NULL);
3020 /* only wait for SNS-CONFIG in case of Reset flag */
3021 if (flag & 1)
3022 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_SGSN_WAIT_CONFIG, 0, 0);
3023 break;
Alexander Couzens83f06ce2021-08-06 19:50:09 +02003024 case NS2_SNS_EV_REQ_FREE_NSVCS:
3025 sns_failed(fi, "On user request to free all NSVCs");
3026 break;
Harald Welte4f127462021-03-02 20:49:10 +01003027 default:
3028 ns2_sns_st_all_action(fi, event, data);
3029 break;
3030 }
3031}
3032
3033static struct osmo_fsm gprs_ns2_sns_sgsn_fsm = {
3034 .name = "GPRS-NS2-SNS-SGSN",
3035 .states = ns2_sns_sgsn_states,
3036 .num_states = ARRAY_SIZE(ns2_sns_sgsn_states),
Alexander Couzens175eb7b2021-07-20 18:41:14 +02003037 .allstate_event_mask = S(NS2_SNS_EV_RX_SIZE) |
3038 S(NS2_SNS_EV_REQ_NO_NSVC) |
Alexander Couzens83f06ce2021-08-06 19:50:09 +02003039 S(NS2_SNS_EV_REQ_FREE_NSVCS) |
Alexander Couzens175eb7b2021-07-20 18:41:14 +02003040 S(NS2_SNS_EV_REQ_ADD_BIND) |
Alexander Couzens1f3193d2021-06-05 22:08:11 +02003041 S(NS2_SNS_EV_REQ_CHANGE_WEIGHT) |
Alexander Couzens175eb7b2021-07-20 18:41:14 +02003042 S(NS2_SNS_EV_REQ_DELETE_BIND),
Harald Welte4f127462021-03-02 20:49:10 +01003043 .allstate_action = ns2_sns_st_all_action_sgsn,
3044 .cleanup = NULL,
3045 .timer_cb = ns2_sns_fsm_sgsn_timer_cb,
3046 .event_names = gprs_sns_event_names,
3047 .pre_term = NULL,
3048 .log_subsys = DLNS,
3049};
3050
3051/*! Allocate an IP-SNS FSM for the SGSN side.
3052 * \param[in] nse NS Entity in which the FSM runs
3053 * \param[in] id string identifier
3054 * \returns FSM instance on success; NULL on error */
3055struct osmo_fsm_inst *ns2_sns_sgsn_fsm_alloc(struct gprs_ns2_nse *nse, const char *id)
3056{
3057 struct osmo_fsm_inst *fi;
3058 struct ns2_sns_state *gss;
3059
3060 fi = osmo_fsm_inst_alloc(&gprs_ns2_sns_sgsn_fsm, nse, NULL, LOGL_DEBUG, id);
3061 if (!fi)
3062 return fi;
3063
3064 gss = talloc_zero(fi, struct ns2_sns_state);
3065 if (!gss)
3066 goto err;
3067
3068 fi->priv = gss;
3069 gss->nse = nse;
3070 gss->role = GPRS_SNS_ROLE_SGSN;
3071 INIT_LLIST_HEAD(&gss->sns_endpoints);
3072 INIT_LLIST_HEAD(&gss->binds);
Alexander Couzens1f3193d2021-06-05 22:08:11 +02003073 INIT_LLIST_HEAD(&gss->procedures);
Harald Welte4f127462021-03-02 20:49:10 +01003074
3075 return fi;
3076err:
3077 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
3078 return NULL;
3079}
3080
3081
3082
3083
Alexander Couzens6a161492020-07-12 13:45:50 +02003084/* initialize osmo_ctx on main tread */
3085static __attribute__((constructor)) void on_dso_load_ctx(void)
3086{
3087 OSMO_ASSERT(osmo_fsm_register(&gprs_ns2_sns_bss_fsm) == 0);
Harald Welte4f127462021-03-02 20:49:10 +01003088 OSMO_ASSERT(osmo_fsm_register(&gprs_ns2_sns_sgsn_fsm) == 0);
Alexander Couzens6a161492020-07-12 13:45:50 +02003089}