blob: d061eed27d089d63cb2586f062f7661ab9927e8d [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
6/* (C) 2018 by Harald Welte <laforge@gnumonks.org>
7 * (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
59enum ns2_sns_type {
60 IPv4,
61 IPv6,
62};
63
64enum gprs_sns_bss_state {
65 GPRS_SNS_ST_UNCONFIGURED,
66 GPRS_SNS_ST_SIZE, /*!< SNS-SIZE procedure ongoing */
67 GPRS_SNS_ST_CONFIG_BSS, /*!< SNS-CONFIG procedure (BSS->SGSN) ongoing */
68 GPRS_SNS_ST_CONFIG_SGSN, /*!< SNS-CONFIG procedure (SGSN->BSS) ongoing */
69 GPRS_SNS_ST_CONFIGURED,
70};
71
72enum gprs_sns_event {
Alexander Couzense769f522020-12-07 07:37:07 +010073 GPRS_SNS_EV_SELECT_ENDPOINT, /*!< Select a SNS endpoint from the list */
Alexander Couzens6a161492020-07-12 13:45:50 +020074 GPRS_SNS_EV_SIZE,
75 GPRS_SNS_EV_SIZE_ACK,
76 GPRS_SNS_EV_CONFIG,
77 GPRS_SNS_EV_CONFIG_END, /*!< SNS-CONFIG with end flag received */
78 GPRS_SNS_EV_CONFIG_ACK,
79 GPRS_SNS_EV_ADD,
80 GPRS_SNS_EV_DELETE,
81 GPRS_SNS_EV_CHANGE_WEIGHT,
82 GPRS_SNS_EV_NO_NSVC,
Alexander Couzensbe7cecc2021-02-03 18:25:27 +010083 GPRS_SNS_EV_NSVC_ALIVE, /*!< a NS-VC became alive */
Alexander Couzens6a161492020-07-12 13:45:50 +020084};
85
86static const struct value_string gprs_sns_event_names[] = {
Alexander Couzense769f522020-12-07 07:37:07 +010087 { GPRS_SNS_EV_SELECT_ENDPOINT, "SELECT_ENDPOINT" },
Alexander Couzens6a161492020-07-12 13:45:50 +020088 { GPRS_SNS_EV_SIZE, "SIZE" },
89 { GPRS_SNS_EV_SIZE_ACK, "SIZE_ACK" },
90 { GPRS_SNS_EV_CONFIG, "CONFIG" },
91 { GPRS_SNS_EV_CONFIG_END, "CONFIG_END" },
92 { GPRS_SNS_EV_CONFIG_ACK, "CONFIG_ACK" },
93 { GPRS_SNS_EV_ADD, "ADD" },
94 { GPRS_SNS_EV_DELETE, "DELETE" },
95 { GPRS_SNS_EV_CHANGE_WEIGHT, "CHANGE_WEIGHT" },
Pau Espin Pedrol0a446a12020-10-27 13:30:08 +010096 { GPRS_SNS_EV_NO_NSVC, "NO_NSVC" },
Alexander Couzensbe7cecc2021-02-03 18:25:27 +010097 { GPRS_SNS_EV_NSVC_ALIVE, "NSVC_ALIVE"},
Alexander Couzens6a161492020-07-12 13:45:50 +020098 { 0, NULL }
99};
100
Alexander Couzense769f522020-12-07 07:37:07 +0100101struct sns_endpoint {
102 struct llist_head list;
103 struct osmo_sockaddr saddr;
104};
105
Alexander Couzens6a161492020-07-12 13:45:50 +0200106struct ns2_sns_state {
107 struct gprs_ns2_nse *nse;
108
109 enum ns2_sns_type ip;
110
Alexander Couzense769f522020-12-07 07:37:07 +0100111 /* holds the list of initial SNS endpoints */
112 struct llist_head sns_endpoints;
113 /* prevent recursive reselection */
114 bool reselection_running;
115
116 /* The current initial SNS endpoints.
117 * The initial connection will be moved into the NSE
118 * if configured via SNS. Otherwise it will be removed
119 * in configured state. */
120 struct sns_endpoint *initial;
Alexander Couzens6a161492020-07-12 13:45:50 +0200121 /* all SNS PDU will be sent over this nsvc */
122 struct gprs_ns2_vc *sns_nsvc;
Alexander Couzens81ae0aa2020-12-07 05:49:43 +0100123 /* iterate over the binds after all remote has been tested */
124 int bind_offset;
Alexander Couzens90ee9632020-12-07 06:18:32 +0100125 /* timer N */
126 int N;
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100127 /* true if at least one nsvc is alive */
128 bool alive;
Alexander Couzens6a161492020-07-12 13:45:50 +0200129
130 /* local configuration to send to the remote end */
131 struct gprs_ns_ie_ip4_elem *ip4_local;
132 size_t num_ip4_local;
133
134 /* local configuration to send to the remote end */
135 struct gprs_ns_ie_ip6_elem *ip6_local;
136 size_t num_ip6_local;
137
138 /* local configuration about our capabilities in terms of connections to
139 * remote (SGSN) side */
140 size_t num_max_nsvcs;
141 size_t num_max_ip4_remote;
142 size_t num_max_ip6_remote;
143
144 /* remote configuration as received */
145 struct gprs_ns_ie_ip4_elem *ip4_remote;
146 unsigned int num_ip4_remote;
147
148 /* remote configuration as received */
149 struct gprs_ns_ie_ip6_elem *ip6_remote;
150 unsigned int num_ip6_remote;
151};
152
153static inline struct gprs_ns2_nse *nse_inst_from_fi(struct osmo_fsm_inst *fi)
154{
155 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
156 return gss->nse;
157}
158
159/* helper function to compute the sum of all (data or signaling) weights */
160static int ip4_weight_sum(const struct gprs_ns_ie_ip4_elem *ip4, unsigned int num,
161 bool data_weight)
162{
163 unsigned int i;
164 int weight_sum = 0;
165
166 for (i = 0; i < num; i++) {
167 if (data_weight)
168 weight_sum += ip4[i].data_weight;
169 else
170 weight_sum += ip4[i].sig_weight;
171 }
172 return weight_sum;
173}
174#define ip4_weight_sum_data(x,y) ip4_weight_sum(x, y, true)
175#define ip4_weight_sum_sig(x,y) ip4_weight_sum(x, y, false)
176
177/* helper function to compute the sum of all (data or signaling) weights */
178static int ip6_weight_sum(const struct gprs_ns_ie_ip6_elem *ip6, unsigned int num,
179 bool data_weight)
180{
181 unsigned int i;
182 int weight_sum = 0;
183
184 for (i = 0; i < num; i++) {
185 if (data_weight)
186 weight_sum += ip6[i].data_weight;
187 else
188 weight_sum += ip6[i].sig_weight;
189 }
190 return weight_sum;
191}
192#define ip6_weight_sum_data(x,y) ip6_weight_sum(x, y, true)
193#define ip6_weight_sum_sig(x,y) ip6_weight_sum(x, y, false)
194
195static struct gprs_ns2_vc *nsvc_by_ip4_elem(struct gprs_ns2_nse *nse,
196 const struct gprs_ns_ie_ip4_elem *ip4)
197{
198 struct osmo_sockaddr sa;
199 /* copy over. Both data structures use network byte order */
200 sa.u.sin.sin_addr.s_addr = ip4->ip_addr;
201 sa.u.sin.sin_port = ip4->udp_port;
202 sa.u.sin.sin_family = AF_INET;
203
Alexander Couzens38b19e82020-09-23 23:56:37 +0200204 return gprs_ns2_nsvc_by_sockaddr_nse(nse, &sa);
Alexander Couzens6a161492020-07-12 13:45:50 +0200205}
206
207static struct gprs_ns2_vc *nsvc_by_ip6_elem(struct gprs_ns2_nse *nse,
208 const struct gprs_ns_ie_ip6_elem *ip6)
209{
210 struct osmo_sockaddr sa;
211 /* copy over. Both data structures use network byte order */
212 sa.u.sin6.sin6_addr = ip6->ip_addr;
213 sa.u.sin6.sin6_port = ip6->udp_port;
214 sa.u.sin6.sin6_family = AF_INET;
215
Alexander Couzens38b19e82020-09-23 23:56:37 +0200216 return gprs_ns2_nsvc_by_sockaddr_nse(nse, &sa);
Alexander Couzens6a161492020-07-12 13:45:50 +0200217}
218
Alexander Couzens125298f2020-10-11 21:22:42 +0200219/*! Return the initial SNS remote socket address
220 * \param nse NS Entity
221 * \return address of the initial SNS connection; NULL in case of error
222 */
223const struct osmo_sockaddr *gprs_ns2_nse_sns_remote(struct gprs_ns2_nse *nse)
224{
225 struct ns2_sns_state *gss;
226
227 if (!nse->bss_sns_fi)
228 return NULL;
229
230 gss = (struct ns2_sns_state *) nse->bss_sns_fi->priv;
Alexander Couzense769f522020-12-07 07:37:07 +0100231 return &gss->initial->saddr;
Alexander Couzens125298f2020-10-11 21:22:42 +0200232}
233
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100234/*! called when a nsvc is beeing freed or the nsvc became dead */
235void ns2_sns_replace_nsvc(struct gprs_ns2_vc *nsvc)
Alexander Couzens6a161492020-07-12 13:45:50 +0200236{
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100237 struct gprs_ns2_nse *nse = nsvc->nse;
Alexander Couzens6a161492020-07-12 13:45:50 +0200238 struct gprs_ns2_vc *tmp;
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100239 struct osmo_fsm_inst *fi = nse->bss_sns_fi;
Alexander Couzens6a161492020-07-12 13:45:50 +0200240 struct ns2_sns_state *gss;
Alexander Couzens6a161492020-07-12 13:45:50 +0200241
242 if (!fi)
243 return;
244
245 gss = (struct ns2_sns_state *) fi->priv;
246 if (nsvc != gss->sns_nsvc)
247 return;
248
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100249 gss->sns_nsvc = NULL;
250 if (gss->alive) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200251 llist_for_each_entry(tmp, &nse->nsvc, list) {
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100252 if (ns2_vc_is_unblocked(tmp)) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200253 gss->sns_nsvc = tmp;
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100254 return;
255 }
Alexander Couzens6a161492020-07-12 13:45:50 +0200256 }
257 } else {
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100258 /* the SNS is waiting for its first NS-VC to come up
259 * choose any other nsvc */
260 llist_for_each_entry(tmp, &nse->nsvc, list) {
261 if (nsvc != tmp) {
262 gss->sns_nsvc = tmp;
263 return;
264 }
265 }
Alexander Couzens6a161492020-07-12 13:45:50 +0200266 }
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100267
268 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_NO_NSVC, NULL);
Alexander Couzens6a161492020-07-12 13:45:50 +0200269}
270
Alexander Couzens7a7b20b2021-01-18 10:47:33 +0100271static void ns2_clear_ipv46_entries(struct ns2_sns_state *gss)
272{
273 TALLOC_FREE(gss->ip4_local);
274 TALLOC_FREE(gss->ip4_remote);
275 TALLOC_FREE(gss->ip6_local);
276 TALLOC_FREE(gss->ip6_remote);
277
278 gss->num_ip4_local = 0;
279 gss->num_ip4_remote = 0;
280 gss->num_ip6_local = 0;
281 gss->num_ip6_remote = 0;
282}
283
Daniel Willmanncf8371a2021-01-16 15:13:51 +0100284static void ns2_vc_create_ip(struct osmo_fsm_inst *fi, struct gprs_ns2_nse *nse, const struct osmo_sockaddr *remote,
285 uint8_t sig_weight, uint8_t data_weight)
Alexander Couzens6a161492020-07-12 13:45:50 +0200286{
287 struct gprs_ns2_inst *nsi = nse->nsi;
288 struct gprs_ns2_vc *nsvc;
289 struct gprs_ns2_vc_bind *bind;
Daniel Willmanncf8371a2021-01-16 15:13:51 +0100290
291 /* for every bind, create a connection if bind type == IP */
292 llist_for_each_entry(bind, &nsi->binding, list) {
293 if (bind->ll != GPRS_NS2_LL_UDP)
294 continue;
295 /* ignore failed connection */
296 nsvc = gprs_ns2_ip_connect_inactive(bind,
297 remote,
298 nse, 0);
299 if (!nsvc) {
300 LOGPFSML(fi, LOGL_ERROR, "SNS-CONFIG: Failed to create NSVC\n");
301 continue;
302 }
303
304 nsvc->sig_weight = sig_weight;
305 nsvc->data_weight = data_weight;
306 }
307}
308
309static void ns2_nsvc_create_ip4(struct osmo_fsm_inst *fi,
310 struct gprs_ns2_nse *nse,
311 const struct gprs_ns_ie_ip4_elem *ip4)
312{
Alexander Couzensc068d862020-10-12 04:11:51 +0200313 struct osmo_sockaddr remote = { };
Alexander Couzens6a161492020-07-12 13:45:50 +0200314 /* copy over. Both data structures use network byte order */
315 remote.u.sin.sin_family = AF_INET;
316 remote.u.sin.sin_addr.s_addr = ip4->ip_addr;
317 remote.u.sin.sin_port = ip4->udp_port;
318
Daniel Willmanncf8371a2021-01-16 15:13:51 +0100319 ns2_vc_create_ip(fi, nse, &remote, ip4->sig_weight, ip4->data_weight);
Alexander Couzens6a161492020-07-12 13:45:50 +0200320}
321
322static void ns2_nsvc_create_ip6(struct osmo_fsm_inst *fi,
323 struct gprs_ns2_nse *nse,
324 const struct gprs_ns_ie_ip6_elem *ip6)
325{
Alexander Couzens6a161492020-07-12 13:45:50 +0200326 struct osmo_sockaddr remote = {};
327 /* copy over. Both data structures use network byte order */
328 remote.u.sin6.sin6_family = AF_INET6;
329 remote.u.sin6.sin6_addr = ip6->ip_addr;
330 remote.u.sin6.sin6_port = ip6->udp_port;
331
Daniel Willmanncf8371a2021-01-16 15:13:51 +0100332 ns2_vc_create_ip(fi, nse, &remote, ip6->sig_weight, ip6->data_weight);
Alexander Couzens6a161492020-07-12 13:45:50 +0200333}
334
335
336static int create_missing_nsvcs(struct osmo_fsm_inst *fi)
337{
338 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
339 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
340 struct gprs_ns2_vc *nsvc;
341 struct gprs_ns2_vc_bind *bind;
342 struct osmo_sockaddr remote = { };
343 unsigned int i;
344
345 for (i = 0; i < gss->num_ip4_remote; i++) {
346 const struct gprs_ns_ie_ip4_elem *ip4 = &gss->ip4_remote[i];
347
348 remote.u.sin.sin_family = AF_INET;
349 remote.u.sin.sin_addr.s_addr = ip4->ip_addr;
350 remote.u.sin.sin_port = ip4->udp_port;
351
352 llist_for_each_entry(bind, &nse->nsi->binding, list) {
353 bool found = false;
Daniel Willmann967e2c12021-01-14 16:58:17 +0100354 if (bind->ll != GPRS_NS2_LL_UDP)
355 continue;
Alexander Couzens6a161492020-07-12 13:45:50 +0200356
357 llist_for_each_entry(nsvc, &nse->nsvc, list) {
358 if (nsvc->bind != bind)
359 continue;
360
Alexander Couzensc4229a42020-10-11 20:58:04 +0200361 if (!osmo_sockaddr_cmp(&remote, gprs_ns2_ip_vc_remote(nsvc))) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200362 found = true;
363 break;
364 }
365 }
366
367 if (!found) {
368 nsvc = gprs_ns2_ip_connect_inactive(bind, &remote, nse, 0);
369 if (!nsvc) {
370 /* TODO: add to a list to send back a NS-STATUS */
371 continue;
372 }
373 }
374
375 /* update data / signalling weight */
376 nsvc->data_weight = ip4->data_weight;
377 nsvc->sig_weight = ip4->sig_weight;
378 nsvc->sns_only = false;
379 }
380 }
381
382 for (i = 0; i < gss->num_ip6_remote; i++) {
383 const struct gprs_ns_ie_ip6_elem *ip6 = &gss->ip6_remote[i];
384
385 remote.u.sin6.sin6_family = AF_INET6;
386 remote.u.sin6.sin6_addr = ip6->ip_addr;
387 remote.u.sin6.sin6_port = ip6->udp_port;
388
389 llist_for_each_entry(bind, &nse->nsi->binding, list) {
390 bool found = false;
Daniel Willmann967e2c12021-01-14 16:58:17 +0100391 if (bind->ll != GPRS_NS2_LL_UDP)
392 continue;
Alexander Couzens6a161492020-07-12 13:45:50 +0200393
394 llist_for_each_entry(nsvc, &nse->nsvc, list) {
395 if (nsvc->bind != bind)
396 continue;
397
Alexander Couzensc4229a42020-10-11 20:58:04 +0200398 if (!osmo_sockaddr_cmp(&remote, gprs_ns2_ip_vc_remote(nsvc))) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200399 found = true;
400 break;
401 }
402 }
403
404 if (!found) {
405 nsvc = gprs_ns2_ip_connect_inactive(bind, &remote, nse, 0);
406 if (!nsvc) {
407 /* TODO: add to a list to send back a NS-STATUS */
408 continue;
409 }
410 }
411
412 /* update data / signalling weight */
413 nsvc->data_weight = ip6->data_weight;
414 nsvc->sig_weight = ip6->sig_weight;
415 nsvc->sns_only = false;
416 }
417 }
418
419
420 return 0;
421}
422
423/* Add a given remote IPv4 element to gprs_sns_state */
424static int add_remote_ip4_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip4_elem *ip4)
425{
426 unsigned int i;
427
428 if (gss->num_ip4_remote >= gss->num_max_ip4_remote)
429 return -NS_CAUSE_INVAL_NR_NS_VC;
430
431 /* check for duplicates */
432 for (i = 0; i < gss->num_ip4_remote; i++) {
433 if (memcmp(&gss->ip4_remote[i], ip4, sizeof(*ip4)))
434 continue;
435 /* TODO: log message duplicate */
436 /* TODO: check if this is the correct cause code */
437 return -NS_CAUSE_PROTO_ERR_UNSPEC;
438 }
439
440 gss->ip4_remote = talloc_realloc(gss, gss->ip4_remote, struct gprs_ns_ie_ip4_elem,
441 gss->num_ip4_remote+1);
442 gss->ip4_remote[gss->num_ip4_remote] = *ip4;
443 gss->num_ip4_remote += 1;
444 return 0;
445}
446
447/* Remove a given remote IPv4 element from gprs_sns_state */
448static int remove_remote_ip4_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip4_elem *ip4)
449{
450 unsigned int i;
451
452 for (i = 0; i < gss->num_ip4_remote; i++) {
453 if (memcmp(&gss->ip4_remote[i], ip4, sizeof(*ip4)))
454 continue;
455 /* all array elements < i remain as they are; all > i are shifted left by one */
456 memmove(&gss->ip4_remote[i], &gss->ip4_remote[i+1], gss->num_ip4_remote-i-1);
457 gss->num_ip4_remote -= 1;
458 return 0;
459 }
460 return -1;
461}
462
463/* update the weights for specified remote IPv4 */
464static int update_remote_ip4_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip4_elem *ip4)
465{
466 unsigned int i;
467
468 for (i = 0; i < gss->num_ip4_remote; i++) {
469 if (gss->ip4_remote[i].ip_addr != ip4->ip_addr ||
470 gss->ip4_remote[i].udp_port != ip4->udp_port)
471 continue;
472
473 gss->ip4_remote[i].sig_weight = ip4->sig_weight;
474 gss->ip4_remote[i].data_weight = ip4->data_weight;
475 return 0;
476 }
477 return -1;
478}
479
480/* Add a given remote IPv6 element to gprs_sns_state */
481static int add_remote_ip6_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip6_elem *ip6)
482{
483 if (gss->num_ip6_remote >= gss->num_max_ip6_remote)
484 return -NS_CAUSE_INVAL_NR_NS_VC;
485
486 gss->ip6_remote = talloc_realloc(gss, gss->ip6_remote, struct gprs_ns_ie_ip6_elem,
487 gss->num_ip6_remote+1);
488 gss->ip6_remote[gss->num_ip6_remote] = *ip6;
489 gss->num_ip6_remote += 1;
490 return 0;
491}
492
493/* Remove a given remote IPv6 element from gprs_sns_state */
494static int remove_remote_ip6_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip6_elem *ip6)
495{
496 unsigned int i;
497
498 for (i = 0; i < gss->num_ip6_remote; i++) {
499 if (memcmp(&gss->ip6_remote[i], ip6, sizeof(*ip6)))
500 continue;
501 /* all array elements < i remain as they are; all > i are shifted left by one */
502 memmove(&gss->ip6_remote[i], &gss->ip6_remote[i+1], gss->num_ip6_remote-i-1);
503 gss->num_ip6_remote -= 1;
504 return 0;
505 }
506 return -1;
507}
508
509/* update the weights for specified remote IPv6 */
510static int update_remote_ip6_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip6_elem *ip6)
511{
512 unsigned int i;
513
514 for (i = 0; i < gss->num_ip6_remote; i++) {
515 if (memcmp(&gss->ip6_remote[i].ip_addr, &ip6->ip_addr, sizeof(ip6->ip_addr)) ||
516 gss->ip6_remote[i].udp_port != ip6->udp_port)
517 continue;
518 gss->ip6_remote[i].sig_weight = ip6->sig_weight;
519 gss->ip6_remote[i].data_weight = ip6->data_weight;
520 return 0;
521 }
522 return -1;
523}
524
525static 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)
526{
527 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
528 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
529 struct gprs_ns2_vc *nsvc;
530 struct osmo_sockaddr sa = {};
Alexander Couzens9a4cf272020-10-11 20:48:04 +0200531 const struct osmo_sockaddr *remote;
Alexander Couzens6a161492020-07-12 13:45:50 +0200532 uint8_t new_signal;
533 uint8_t new_data;
534
535 /* TODO: Upon receiving an SNS-CHANGEWEIGHT PDU, if the resulting sum of the
536 * signalling weights of all the peer IP endpoints configured for this NSE is
537 * equal to zero or if the resulting sum of the data weights of all the peer IP
538 * endpoints configured for this NSE is equal to zero, the BSS/SGSN shall send an
539 * SNS-ACK PDU with a cause code of "Invalid weights". */
540
541 if (ip4) {
542 if (update_remote_ip4_elem(gss, ip4))
543 return -NS_CAUSE_UNKN_IP_EP;
544
545 /* copy over. Both data structures use network byte order */
546 sa.u.sin.sin_addr.s_addr = ip4->ip_addr;
547 sa.u.sin.sin_port = ip4->udp_port;
548 sa.u.sin.sin_family = AF_INET;
549 new_signal = ip4->sig_weight;
550 new_data = ip4->data_weight;
551 } else if (ip6) {
552 if (update_remote_ip6_elem(gss, ip6))
553 return -NS_CAUSE_UNKN_IP_EP;
554
555 /* copy over. Both data structures use network byte order */
556 sa.u.sin6.sin6_addr = ip6->ip_addr;
557 sa.u.sin6.sin6_port = ip6->udp_port;
558 sa.u.sin6.sin6_family = AF_INET6;
559 new_signal = ip6->sig_weight;
560 new_data = ip6->data_weight;
561 } else {
562 OSMO_ASSERT(false);
563 }
564
565 llist_for_each_entry(nsvc, &nse->nsvc, list) {
Alexander Couzensc4229a42020-10-11 20:58:04 +0200566 remote = gprs_ns2_ip_vc_remote(nsvc);
Alexander Couzens6a161492020-07-12 13:45:50 +0200567 /* all nsvc in NSE should be IP/UDP nsvc */
568 OSMO_ASSERT(remote);
569
570 if (osmo_sockaddr_cmp(&sa, remote))
571 continue;
572
573 LOGPFSML(fi, LOGL_INFO, "CHANGE-WEIGHT NS-VC %s data_weight %u->%u, sig_weight %u->%u\n",
574 gprs_ns2_ll_str(nsvc), nsvc->data_weight, new_data,
575 nsvc->sig_weight, new_signal);
576
577 nsvc->data_weight = new_data;
578 nsvc->sig_weight = new_signal;
579 }
580
581 return 0;
582}
583
584static int do_sns_delete(struct osmo_fsm_inst *fi,
585 const struct gprs_ns_ie_ip4_elem *ip4,
586 const struct gprs_ns_ie_ip6_elem *ip6)
587{
588 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
589 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
590 struct gprs_ns2_vc *nsvc, *tmp;
Alexander Couzens9a4cf272020-10-11 20:48:04 +0200591 const struct osmo_sockaddr *remote;
Alexander Couzens6a161492020-07-12 13:45:50 +0200592 struct osmo_sockaddr sa = {};
593
594 if (ip4) {
595 if (remove_remote_ip4_elem(gss, ip4) < 0)
596 return -NS_CAUSE_UNKN_IP_EP;
597 /* copy over. Both data structures use network byte order */
598 sa.u.sin.sin_addr.s_addr = ip4->ip_addr;
599 sa.u.sin.sin_port = ip4->udp_port;
600 sa.u.sin.sin_family = AF_INET;
601 } else if (ip6) {
602 if (remove_remote_ip6_elem(gss, ip6))
603 return -NS_CAUSE_UNKN_IP_EP;
604
605 /* copy over. Both data structures use network byte order */
606 sa.u.sin6.sin6_addr = ip6->ip_addr;
607 sa.u.sin6.sin6_port = ip6->udp_port;
608 sa.u.sin6.sin6_family = AF_INET6;
609 } else {
610 OSMO_ASSERT(false);
611 }
612
613 llist_for_each_entry_safe(nsvc, tmp, &nse->nsvc, list) {
Alexander Couzensc4229a42020-10-11 20:58:04 +0200614 remote = gprs_ns2_ip_vc_remote(nsvc);
Alexander Couzens6a161492020-07-12 13:45:50 +0200615 /* all nsvc in NSE should be IP/UDP nsvc */
616 OSMO_ASSERT(remote);
617 if (osmo_sockaddr_cmp(&sa, remote))
618 continue;
619
620 LOGPFSML(fi, LOGL_INFO, "DELETE NS-VC %s\n", gprs_ns2_ll_str(nsvc));
621 gprs_ns2_free_nsvc(nsvc);
622 }
623
624 return 0;
625}
626
627static int do_sns_add(struct osmo_fsm_inst *fi,
628 const struct gprs_ns_ie_ip4_elem *ip4,
629 const struct gprs_ns_ie_ip6_elem *ip6)
630{
631 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
632 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
633 struct gprs_ns2_vc *nsvc;
634 int rc = 0;
635
636 /* Upon receiving an SNS-ADD PDU, if the consequent number of IPv4 endpoints
637 * exceeds the number of IPv4 endpoints supported by the NSE, the NSE shall send
638 * an SNS-ACK PDU with a cause code set to "Invalid number of IP4 Endpoints". */
639 switch (gss->ip) {
640 case IPv4:
641 rc = add_remote_ip4_elem(gss, ip4);
642 break;
643 case IPv6:
644 rc = add_remote_ip6_elem(gss, ip6);
645 break;
646 default:
647 /* the gss->ip is initialized with the bss */
648 OSMO_ASSERT(false);
649 }
650
651 if (rc)
652 return rc;
653
654 /* Upon receiving an SNS-ADD PDU containing an already configured IP endpoint the
655 * NSE shall send an SNS-ACK PDU with the cause code "Protocol error -
656 * unspecified" */
657 switch (gss->ip) {
658 case IPv4:
659 nsvc = nsvc_by_ip4_elem(nse, ip4);
660 if (nsvc) {
661 /* the nsvc should be already in sync with the ip4 / ip6 elements */
662 return -NS_CAUSE_PROTO_ERR_UNSPEC;
663 }
664
665 /* TODO: failure case */
666 ns2_nsvc_create_ip4(fi, nse, ip4);
667 break;
668 case IPv6:
669 nsvc = nsvc_by_ip6_elem(nse, ip6);
670 if (nsvc) {
671 /* the nsvc should be already in sync with the ip4 / ip6 elements */
672 return -NS_CAUSE_PROTO_ERR_UNSPEC;
673 }
674
675 /* TODO: failure case */
676 ns2_nsvc_create_ip6(fi, nse, ip6);
677 break;
678 }
679
680 gprs_ns2_start_alive_all_nsvcs(nse);
681
682 return 0;
683}
684
685
686static void ns2_sns_st_unconfigured(struct osmo_fsm_inst *fi, uint32_t event, void *data)
687{
Alexander Couzense769f522020-12-07 07:37:07 +0100688 /* empty state - SNS Select will start by ns2_sns_st_all_action() */
Alexander Couzens6a161492020-07-12 13:45:50 +0200689}
690
691static void ns2_sns_st_size(struct osmo_fsm_inst *fi, uint32_t event, void *data)
692{
693 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
694 struct gprs_ns2_inst *nsi = nse->nsi;
695 struct tlv_parsed *tp = NULL;
696
697 switch (event) {
698 case GPRS_SNS_EV_SIZE_ACK:
699 tp = data;
700 if (TLVP_VAL_MINLEN(tp, NS_IE_CAUSE, 1)) {
701 LOGPFSML(fi, LOGL_ERROR, "SNS-SIZE-ACK with cause %s\n",
702 gprs_ns2_cause_str(*TLVP_VAL(tp, NS_IE_CAUSE)));
703 /* TODO: What to do? */
704 } else {
705 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIG_BSS,
706 nsi->timeout[NS_TOUT_TSNS_PROV], 2);
707 }
708 break;
709 default:
710 OSMO_ASSERT(0);
711 }
712}
713
Alexander Couzense769f522020-12-07 07:37:07 +0100714/* setup all dynamic SNS settings, create a new nsvc and send the SIZE */
Alexander Couzens6a161492020-07-12 13:45:50 +0200715static void ns2_sns_st_size_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
716{
717 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
Alexander Couzense769f522020-12-07 07:37:07 +0100718 struct gprs_ns_ie_ip4_elem *ip4_elems;
719 struct gprs_ns_ie_ip6_elem *ip6_elems;
720 struct gprs_ns2_vc_bind *bind;
721 struct gprs_ns2_inst *nsi = gss->nse->nsi;
722 struct osmo_sockaddr *remote;
723 const struct osmo_sockaddr *sa;
724 struct osmo_sockaddr local;
725 int count;
Alexander Couzens6a161492020-07-12 13:45:50 +0200726
Alexander Couzense769f522020-12-07 07:37:07 +0100727 /* on a generic failure, the timer callback will recover */
Alexander Couzens6a161492020-07-12 13:45:50 +0200728 if (old_state != GPRS_SNS_ST_UNCONFIGURED)
Alexander Couzens138b96f2021-01-25 16:23:29 +0100729 ns2_prim_status_ind(gss->nse, NULL, 0, GPRS_NS2_AFF_CAUSE_SNS_FAILURE);
Alexander Couzens790a9632021-02-05 17:18:39 +0100730 if (old_state != GPRS_SNS_ST_SIZE)
731 gss->N = 0;
732
Alexander Couzens6a161492020-07-12 13:45:50 +0200733
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100734 gss->alive = false;
Alexander Couzens7a7b20b2021-01-18 10:47:33 +0100735 ns2_clear_ipv46_entries(gss);
736
Alexander Couzense769f522020-12-07 07:37:07 +0100737 /* no initial available */
738 if (!gss->initial)
739 return;
740
741 remote = &gss->initial->saddr;
742
743 /* count how many bindings are available (only UDP binds) */
744 count = ns2_ip_count_bind(nsi, remote);
745 if (count == 0) {
746 /* TODO: logging */
747 return;
748 }
749
Alexander Couzens81ae0aa2020-12-07 05:49:43 +0100750 bind = ns2_ip_get_bind_by_index(nsi, remote, gss->bind_offset);
Alexander Couzense769f522020-12-07 07:37:07 +0100751 if (!bind) {
Alexander Couzens81ae0aa2020-12-07 05:49:43 +0100752 if (gss->bind_offset) {
753 gss->bind_offset = 0;
754 bind = ns2_ip_get_bind_by_index(nsi, remote, gss->bind_offset);
755 }
756
757 if (!bind)
758 return;
Alexander Couzense769f522020-12-07 07:37:07 +0100759 }
760
761 /* setup the NSVC */
762 if (!gss->sns_nsvc) {
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100763 gss->sns_nsvc = ns2_ip_bind_connect(bind, gss->nse, remote);
Alexander Couzense769f522020-12-07 07:37:07 +0100764 if (!gss->sns_nsvc)
765 return;
766 gss->sns_nsvc->sns_only = true;
767 }
768
769 switch (gss->ip) {
770 case IPv4:
771 ip4_elems = talloc_zero_size(fi, sizeof(struct gprs_ns_ie_ip4_elem) * count);
772 if (!ip4_elems)
773 return;
774
775 gss->ip4_local = ip4_elems;
776
777 llist_for_each_entry(bind, &nsi->binding, list) {
778 if (!gprs_ns2_is_ip_bind(bind))
779 continue;
780
781 sa = gprs_ns2_ip_bind_sockaddr(bind);
782 if (!sa)
783 continue;
784
785 if (sa->u.sas.ss_family != AF_INET)
786 continue;
787
788 /* check if this is an specific bind */
789 if (sa->u.sin.sin_addr.s_addr == 0) {
790 if (osmo_sockaddr_local_ip(&local, remote))
791 continue;
792
793 ip4_elems->ip_addr = local.u.sin.sin_addr.s_addr;
794 } else {
795 ip4_elems->ip_addr = sa->u.sin.sin_addr.s_addr;
796 }
797
798 ip4_elems->udp_port = sa->u.sin.sin_port;
Alexander Couzensc4704762021-02-08 23:13:12 +0100799 ip4_elems->sig_weight = bind->sns_sig_weight;
800 ip4_elems->data_weight = bind->sns_data_weight;
Alexander Couzense769f522020-12-07 07:37:07 +0100801 ip4_elems++;
802 }
803
804 gss->num_ip4_local = count;
805 gss->num_max_ip4_remote = 4;
806 gss->num_max_nsvcs = OSMO_MAX(gss->num_max_ip4_remote * gss->num_ip4_local, 8);
807 break;
808 case IPv6:
809 /* IPv6 */
810 ip6_elems = talloc_zero_size(fi, sizeof(struct gprs_ns_ie_ip6_elem) * count);
811 if (!ip6_elems)
812 return;
813
814 gss->ip6_local = ip6_elems;
815
816 llist_for_each_entry(bind, &nsi->binding, list) {
817 if (!gprs_ns2_is_ip_bind(bind))
818 continue;
819
820 sa = gprs_ns2_ip_bind_sockaddr(bind);
821 if (!sa)
822 continue;
823
824 if (sa->u.sas.ss_family != AF_INET6)
825 continue;
826
827 /* check if this is an specific bind */
828 if (IN6_IS_ADDR_UNSPECIFIED(&sa->u.sin6.sin6_addr)) {
829 if (osmo_sockaddr_local_ip(&local, remote))
830 continue;
831
832 ip6_elems->ip_addr = local.u.sin6.sin6_addr;
833 } else {
834 ip6_elems->ip_addr = sa->u.sin6.sin6_addr;
835 }
836
837 ip6_elems->udp_port = sa->u.sin.sin_port;
Alexander Couzensc4704762021-02-08 23:13:12 +0100838 ip6_elems->sig_weight = bind->sns_sig_weight;
839 ip6_elems->data_weight = bind->sns_data_weight;
Alexander Couzense769f522020-12-07 07:37:07 +0100840
841 ip6_elems++;
842 }
843 gss->num_ip6_local = count;
844 gss->num_max_ip6_remote = 4;
845 gss->num_max_nsvcs = OSMO_MAX(gss->num_max_ip6_remote * gss->num_ip6_local, 8);
846 break;
847 }
848
Alexander Couzens6a161492020-07-12 13:45:50 +0200849 if (gss->num_max_ip4_remote > 0)
850 ns2_tx_sns_size(gss->sns_nsvc, true, gss->num_max_nsvcs, gss->num_max_ip4_remote, -1);
851 else
852 ns2_tx_sns_size(gss->sns_nsvc, true, gss->num_max_nsvcs, -1, gss->num_max_ip6_remote);
Alexander Couzens6a161492020-07-12 13:45:50 +0200853}
854
855static void ns2_sns_st_config_bss(struct osmo_fsm_inst *fi, uint32_t event, void *data)
856{
857 struct tlv_parsed *tp = NULL;
Alexander Couzens3df58862021-02-05 17:18:08 +0100858 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
Alexander Couzens6a161492020-07-12 13:45:50 +0200859
860 switch (event) {
861 case GPRS_SNS_EV_CONFIG_ACK:
862 tp = (struct tlv_parsed *) data;
863 if (TLVP_VAL_MINLEN(tp, NS_IE_CAUSE, 1)) {
864 LOGPFSML(fi, LOGL_ERROR, "SNS-CONFIG-ACK with cause %s\n",
865 gprs_ns2_cause_str(*TLVP_VAL(tp, NS_IE_CAUSE)));
866 /* TODO: What to do? */
867 } else {
Alexander Couzens3df58862021-02-05 17:18:08 +0100868 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIG_SGSN, nse->nsi->timeout[NS_TOUT_TSNS_PROV], 3);
Alexander Couzens6a161492020-07-12 13:45:50 +0200869 }
870 break;
871 default:
872 OSMO_ASSERT(0);
873 }
874}
875
876static void ns2_sns_st_config_bss_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
877{
878 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
Alexander Couzens790a9632021-02-05 17:18:39 +0100879
880 if (old_state != GPRS_SNS_ST_CONFIG_BSS)
881 gss->N = 0;
882
Alexander Couzens6a161492020-07-12 13:45:50 +0200883 /* Transmit SNS-CONFIG */
Alexander Couzens6a161492020-07-12 13:45:50 +0200884 switch (gss->ip) {
885 case IPv4:
886 ns2_tx_sns_config(gss->sns_nsvc, true,
Alexander Couzense78207f2020-12-07 06:19:29 +0100887 gss->ip4_local, gss->num_ip4_local,
888 NULL, 0);
Alexander Couzens6a161492020-07-12 13:45:50 +0200889 break;
890 case IPv6:
891 ns2_tx_sns_config(gss->sns_nsvc, true,
Alexander Couzense78207f2020-12-07 06:19:29 +0100892 NULL, 0,
893 gss->ip6_local, gss->num_ip6_local);
Alexander Couzens6a161492020-07-12 13:45:50 +0200894 break;
895 }
896}
897
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100898/* calculate the timeout of the configured state. the configured
899 * state will fail if not at least one NS-VC is alive within X second.
900 */
901static inline int ns_sns_configured_timeout(struct osmo_fsm_inst *fi)
902{
903 int secs;
904 struct gprs_ns2_inst *nsi = nse_inst_from_fi(fi)->nsi;
905 secs = nsi->timeout[NS_TOUT_TNS_ALIVE] * nsi->timeout[NS_TOUT_TNS_ALIVE_RETRIES];
906 secs += nsi->timeout[NS_TOUT_TNS_TEST];
907
908 return secs;
909}
Alexander Couzens6a161492020-07-12 13:45:50 +0200910
911static void ns_sns_st_config_sgsn_ip4(struct osmo_fsm_inst *fi, uint32_t event, void *data)
912{
913 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
914 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
915 const struct gprs_ns_ie_ip4_elem *v4_list;
916 unsigned int num_v4;
917 struct tlv_parsed *tp = NULL;
918
919 uint8_t cause;
920
921 tp = (struct tlv_parsed *) data;
922
923 if (!TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
924 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
925 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
926 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
927 return;
928 }
929 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
930 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
931 /* realloc to the new size */
932 gss->ip4_remote = talloc_realloc(gss, gss->ip4_remote,
933 struct gprs_ns_ie_ip4_elem,
934 gss->num_ip4_remote+num_v4);
935 /* append the new entries to the end of the list */
936 memcpy(&gss->ip4_remote[gss->num_ip4_remote], v4_list, num_v4*sizeof(*v4_list));
937 gss->num_ip4_remote += num_v4;
938
939 LOGPFSML(fi, LOGL_INFO, "Rx SNS-CONFIG: Remote IPv4 list now %u entries\n",
940 gss->num_ip4_remote);
941 if (event == GPRS_SNS_EV_CONFIG_END) {
942 /* check if sum of data / sig weights == 0 */
943 if (ip4_weight_sum_data(gss->ip4_remote, gss->num_ip4_remote) == 0 ||
944 ip4_weight_sum_sig(gss->ip4_remote, gss->num_ip4_remote) == 0) {
945 cause = NS_CAUSE_INVAL_WEIGH;
946 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
947 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
948 return;
949 }
950 create_missing_nsvcs(fi);
951 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
952 /* start the test procedure on ALL NSVCs! */
953 gprs_ns2_start_alive_all_nsvcs(nse);
Alexander Couzens3df58862021-02-05 17:18:08 +0100954 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIGURED, ns_sns_configured_timeout(fi), 4);
Alexander Couzens6a161492020-07-12 13:45:50 +0200955 } else {
956 /* just send CONFIG-ACK */
957 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
Alexander Couzens3df58862021-02-05 17:18:08 +0100958 osmo_timer_schedule(&fi->timer, nse->nsi->timeout[NS_TOUT_TSNS_PROV], 0);
Alexander Couzens6a161492020-07-12 13:45:50 +0200959 }
960}
961
962static void ns_sns_st_config_sgsn_ip6(struct osmo_fsm_inst *fi, uint32_t event, void *data)
963{
964 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
965 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
966 const struct gprs_ns_ie_ip6_elem *v6_list;
967 unsigned int num_v6;
968 struct tlv_parsed *tp = NULL;
969
970 uint8_t cause;
971
972 tp = (struct tlv_parsed *) data;
973
974 if (!TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
975 cause = NS_CAUSE_INVAL_NR_IPv6_EP;
976 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
977 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
978 return;
979 }
980 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
981 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
982 /* realloc to the new size */
983 gss->ip6_remote = talloc_realloc(gss, gss->ip6_remote,
984 struct gprs_ns_ie_ip6_elem,
985 gss->num_ip6_remote+num_v6);
986 /* append the new entries to the end of the list */
987 memcpy(&gss->ip6_remote[gss->num_ip6_remote], v6_list, num_v6*sizeof(*v6_list));
988 gss->num_ip6_remote += num_v6;
989
990 LOGPFSML(fi, LOGL_INFO, "Rx SNS-CONFIG: Remote IPv6 list now %u entries\n",
991 gss->num_ip6_remote);
992 if (event == GPRS_SNS_EV_CONFIG_END) {
993 /* check if sum of data / sig weights == 0 */
994 if (ip6_weight_sum_data(gss->ip6_remote, gss->num_ip6_remote) == 0 ||
995 ip6_weight_sum_sig(gss->ip6_remote, gss->num_ip6_remote) == 0) {
996 cause = NS_CAUSE_INVAL_WEIGH;
997 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
998 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
999 return;
1000 }
1001 create_missing_nsvcs(fi);
1002 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
1003 /* start the test procedure on ALL NSVCs! */
1004 gprs_ns2_start_alive_all_nsvcs(nse);
1005 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIGURED, 0, 0);
1006 } else {
1007 /* just send CONFIG-ACK */
1008 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
Alexander Couzens790a9632021-02-05 17:18:39 +01001009 osmo_timer_schedule(&fi->timer, nse->nsi->timeout[NS_TOUT_TSNS_PROV], 0);
Alexander Couzens6a161492020-07-12 13:45:50 +02001010 }
1011}
1012
Alexander Couzens790a9632021-02-05 17:18:39 +01001013static void ns2_sns_st_config_sgsn_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
1014{
1015 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
1016
1017 if (old_state != GPRS_SNS_ST_CONFIG_SGSN)
1018 gss->N = 0;
1019}
1020
Alexander Couzens6a161492020-07-12 13:45:50 +02001021static void ns2_sns_st_config_sgsn(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1022{
1023 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
1024
1025 switch (event) {
1026 case GPRS_SNS_EV_CONFIG_END:
1027 case GPRS_SNS_EV_CONFIG:
1028
1029#if 0 /* part of incoming SNS-SIZE (doesn't happen on BSS side */
1030 if (TLVP_PRESENT(tp, NS_IE_RESET_FLAG)) {
1031 /* reset all existing config */
1032 if (gss->ip4_remote)
1033 talloc_free(gss->ip4_remote);
1034 gss->num_ip4_remote = 0;
1035 }
1036#endif
1037 /* TODO: reject IPv6 elements on IPv4 mode and vice versa */
1038 switch (gss->ip) {
1039 case IPv4:
1040 ns_sns_st_config_sgsn_ip4(fi, event, data);
1041 break;
1042 case IPv6:
1043 ns_sns_st_config_sgsn_ip6(fi, event, data);
1044 break;
1045 default:
1046 OSMO_ASSERT(0);
1047 }
1048 break;
1049 default:
1050 OSMO_ASSERT(0);
1051 }
1052}
1053
1054/* called when receiving GPRS_SNS_EV_ADD in state configure */
1055static void ns2_sns_st_configured_add(struct osmo_fsm_inst *fi,
1056 struct ns2_sns_state *gss,
1057 struct tlv_parsed *tp)
1058{
1059 const struct gprs_ns_ie_ip4_elem *v4_list = NULL;
1060 const struct gprs_ns_ie_ip6_elem *v6_list = NULL;
1061 int num_v4 = 0, num_v6 = 0;
1062 uint8_t trans_id, cause = 0xff;
Harald Welte7da6ace2020-09-18 09:48:05 +02001063 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +02001064 int rc = 0;
1065
1066 /* TODO: refactor EV_ADD/CHANGE/REMOVE by
1067 * check uniqueness within the lists (no doublicate entries)
1068 * check not-known-by-us and sent back a list of unknown/known values
1069 * (abnormal behaviour according to 48.016)
1070 */
1071
1072 trans_id = *TLVP_VAL(tp, NS_IE_TRANS_ID);
1073 if (gss->ip == IPv4) {
1074 if (!TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
1075 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
1076 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1077 return;
1078 }
1079
1080 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
1081 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001082 for (i = 0; i < num_v4; i++) {
1083 unsigned int j;
Alexander Couzens6a161492020-07-12 13:45:50 +02001084 rc = do_sns_add(fi, &v4_list[i], NULL);
1085 if (rc < 0) {
1086 /* rollback/undo to restore previous state */
Harald Welte7da6ace2020-09-18 09:48:05 +02001087 for (j = 0; j < i; j++)
Alexander Couzens6a161492020-07-12 13:45:50 +02001088 do_sns_delete(fi, &v4_list[j], NULL);
1089 cause = -rc;
1090 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1091 break;
1092 }
1093 }
1094 } else { /* IPv6 */
1095 if (!TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
1096 cause = NS_CAUSE_INVAL_NR_IPv6_EP;
1097 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1098 return;
1099 }
1100
1101 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
1102 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001103 for (i = 0; i < num_v6; i++) {
1104 unsigned int j;
Alexander Couzens6a161492020-07-12 13:45:50 +02001105 rc = do_sns_add(fi, NULL, &v6_list[i]);
1106 if (rc < 0) {
1107 /* rollback/undo to restore previous state */
Harald Welte7da6ace2020-09-18 09:48:05 +02001108 for (j = 0; j < i; j++)
Alexander Couzens6a161492020-07-12 13:45:50 +02001109 do_sns_delete(fi, NULL, &v6_list[j]);
1110 cause = -rc;
1111 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1112 break;
1113 }
1114 }
1115 }
1116
1117 /* TODO: correct behaviour is to answer to the *same* NSVC from which the SNS_ADD was received */
1118 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, NULL, v4_list, num_v4, v6_list, num_v6);
1119}
1120
1121static void ns2_sns_st_configured_delete(struct osmo_fsm_inst *fi,
1122 struct ns2_sns_state *gss,
1123 struct tlv_parsed *tp)
1124{
1125 const struct gprs_ns_ie_ip4_elem *v4_list = NULL;
1126 const struct gprs_ns_ie_ip6_elem *v6_list = NULL;
1127 int num_v4 = 0, num_v6 = 0;
1128 uint8_t trans_id, cause = 0xff;
Harald Welte7da6ace2020-09-18 09:48:05 +02001129 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +02001130 int rc = 0;
1131
1132 /* TODO: split up delete into v4 + v6
1133 * TODO: check if IPv4_LIST or IP_ADDR(v4) is present on IPv6 and vice versa
1134 * TODO: check if IPv4_LIST/IPv6_LIST and IP_ADDR is present at the same time
1135 */
1136 trans_id = *TLVP_VAL(tp, NS_IE_TRANS_ID);
1137 if (gss->ip == IPv4) {
1138 if (TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
1139 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
1140 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001141 for ( i = 0; i < num_v4; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001142 rc = do_sns_delete(fi, &v4_list[i], NULL);
1143 if (rc < 0) {
1144 cause = -rc;
1145 /* continue to delete others */
1146 }
1147 }
1148 if (cause != 0xff) {
1149 /* TODO: create list of not-deleted and return it */
1150 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1151 return;
1152 }
1153
1154 } else if (TLVP_PRESENT(tp, NS_IE_IP_ADDR) && TLVP_LEN(tp, NS_IE_IP_ADDR) == 5) {
1155 /* delete all NS-VCs for given IPv4 address */
1156 const uint8_t *ie = TLVP_VAL(tp, NS_IE_IP_ADDR);
1157 struct gprs_ns_ie_ip4_elem *ip4_remote;
1158 uint32_t ip_addr = *(uint32_t *)(ie+1);
1159 if (ie[0] != 0x01) { /* Address Type != IPv4 */
1160 cause = NS_CAUSE_UNKN_IP_ADDR;
1161 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1162 return;
1163 }
1164 /* make a copy as do_sns_delete() will change the array underneath us */
1165 ip4_remote = talloc_memdup(fi, gss->ip4_remote,
1166 gss->num_ip4_remote * sizeof(*v4_list));
Harald Welte7da6ace2020-09-18 09:48:05 +02001167 for (i = 0; i < gss->num_ip4_remote; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001168 if (ip4_remote[i].ip_addr == ip_addr) {
1169 rc = do_sns_delete(fi, &ip4_remote[i], NULL);
1170 if (rc < 0) {
1171 cause = -rc;
1172 /* continue to delete others */
1173 }
1174 }
1175 }
1176 talloc_free(ip4_remote);
1177 if (cause != 0xff) {
1178 /* TODO: create list of not-deleted and return it */
1179 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1180 return;
1181 }
1182 } else {
1183 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
1184 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1185 return;
1186 }
1187 } else { /* IPv6 */
1188 if (TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
1189 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
1190 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001191 for (i = 0; i < num_v6; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001192 rc = do_sns_delete(fi, NULL, &v6_list[i]);
1193 if (rc < 0) {
1194 cause = -rc;
1195 /* continue to delete others */
1196 }
1197 }
1198 if (cause != 0xff) {
1199 /* TODO: create list of not-deleted and return it */
1200 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1201 return;
1202 }
1203 } else if (TLVP_PRES_LEN(tp, NS_IE_IP_ADDR, 17)) {
1204 /* delete all NS-VCs for given IPv4 address */
1205 const uint8_t *ie = TLVP_VAL(tp, NS_IE_IP_ADDR);
1206 struct gprs_ns_ie_ip6_elem *ip6_remote;
1207 struct in6_addr ip6_addr;
Harald Welte7da6ace2020-09-18 09:48:05 +02001208 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +02001209 if (ie[0] != 0x02) { /* Address Type != IPv6 */
1210 cause = NS_CAUSE_UNKN_IP_ADDR;
1211 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1212 return;
1213 }
1214 memcpy(&ip6_addr, (ie+1), sizeof(struct in6_addr));
1215 /* make a copy as do_sns_delete() will change the array underneath us */
1216 ip6_remote = talloc_memdup(fi, gss->ip6_remote,
1217 gss->num_ip6_remote * sizeof(*v4_list));
Harald Welte7da6ace2020-09-18 09:48:05 +02001218 for (i = 0; i < gss->num_ip6_remote; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001219 if (!memcmp(&ip6_remote[i].ip_addr, &ip6_addr, sizeof(struct in6_addr))) {
1220 rc = do_sns_delete(fi, NULL, &ip6_remote[i]);
1221 if (rc < 0) {
1222 cause = -rc;
1223 /* continue to delete others */
1224 }
1225 }
1226 }
1227
1228 talloc_free(ip6_remote);
1229 if (cause != 0xff) {
1230 /* TODO: create list of not-deleted and return it */
1231 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1232 return;
1233 }
1234 } else {
1235 cause = NS_CAUSE_INVAL_NR_IPv6_EP;
1236 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1237 return;
1238 }
1239 }
1240 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, NULL, v4_list, num_v4, v6_list, num_v6);
1241}
1242
1243static void ns2_sns_st_configured_change(struct osmo_fsm_inst *fi,
1244 struct ns2_sns_state *gss,
1245 struct tlv_parsed *tp)
1246{
1247 const struct gprs_ns_ie_ip4_elem *v4_list = NULL;
1248 const struct gprs_ns_ie_ip6_elem *v6_list = NULL;
1249 int num_v4 = 0, num_v6 = 0;
1250 uint8_t trans_id, cause = 0xff;
1251 int rc = 0;
Harald Welte7da6ace2020-09-18 09:48:05 +02001252 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +02001253
1254 trans_id = *TLVP_VAL(tp, NS_IE_TRANS_ID);
1255 if (TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
1256 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
1257 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001258 for (i = 0; i < num_v4; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001259 rc = do_sns_change_weight(fi, &v4_list[i], NULL);
1260 if (rc < 0) {
1261 cause = -rc;
1262 /* continue to others */
1263 }
1264 }
1265 if (cause != 0xff) {
1266 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1267 return;
1268 }
1269 } else if (TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
1270 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
1271 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001272 for (i = 0; i < num_v6; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001273 rc = do_sns_change_weight(fi, NULL, &v6_list[i]);
1274 if (rc < 0) {
1275 cause = -rc;
1276 /* continue to others */
1277 }
1278 }
1279 if (cause != 0xff) {
1280 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1281 return;
1282 }
1283 } else {
1284 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
1285 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1286 return;
1287 }
1288 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, NULL, v4_list, num_v4, v6_list, num_v6);
1289}
1290
1291static void ns2_sns_st_configured(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1292{
1293 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
1294 struct tlv_parsed *tp = data;
1295
1296 switch (event) {
1297 case GPRS_SNS_EV_ADD:
1298 ns2_sns_st_configured_add(fi, gss, tp);
1299 break;
1300 case GPRS_SNS_EV_DELETE:
1301 ns2_sns_st_configured_delete(fi, gss, tp);
1302 break;
1303 case GPRS_SNS_EV_CHANGE_WEIGHT:
1304 ns2_sns_st_configured_change(fi, gss, tp);
1305 break;
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01001306 case GPRS_SNS_EV_NSVC_ALIVE:
1307 osmo_timer_del(&fi->timer);
1308 break;
Alexander Couzens6a161492020-07-12 13:45:50 +02001309 }
1310}
1311
1312static void ns2_sns_st_configured_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
1313{
1314 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
Alexander Couzens138b96f2021-01-25 16:23:29 +01001315 ns2_prim_status_ind(nse, NULL, 0, GPRS_NS2_AFF_CAUSE_SNS_CONFIGURED);
Alexander Couzens6a161492020-07-12 13:45:50 +02001316}
1317
1318static const struct osmo_fsm_state ns2_sns_bss_states[] = {
1319 [GPRS_SNS_ST_UNCONFIGURED] = {
Alexander Couzense769f522020-12-07 07:37:07 +01001320 .in_event_mask = 0, /* handled by all_state_action */
Alexander Couzens6a161492020-07-12 13:45:50 +02001321 .out_state_mask = S(GPRS_SNS_ST_SIZE),
1322 .name = "UNCONFIGURED",
1323 .action = ns2_sns_st_unconfigured,
1324 },
1325 [GPRS_SNS_ST_SIZE] = {
1326 .in_event_mask = S(GPRS_SNS_EV_SIZE_ACK),
1327 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
1328 S(GPRS_SNS_ST_SIZE) |
1329 S(GPRS_SNS_ST_CONFIG_BSS),
1330 .name = "SIZE",
1331 .action = ns2_sns_st_size,
1332 .onenter = ns2_sns_st_size_onenter,
1333 },
1334 [GPRS_SNS_ST_CONFIG_BSS] = {
1335 .in_event_mask = S(GPRS_SNS_EV_CONFIG_ACK),
1336 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
1337 S(GPRS_SNS_ST_CONFIG_BSS) |
1338 S(GPRS_SNS_ST_CONFIG_SGSN) |
1339 S(GPRS_SNS_ST_SIZE),
1340 .name = "CONFIG_BSS",
1341 .action = ns2_sns_st_config_bss,
1342 .onenter = ns2_sns_st_config_bss_onenter,
1343 },
1344 [GPRS_SNS_ST_CONFIG_SGSN] = {
1345 .in_event_mask = S(GPRS_SNS_EV_CONFIG) |
1346 S(GPRS_SNS_EV_CONFIG_END),
1347 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
1348 S(GPRS_SNS_ST_CONFIG_SGSN) |
1349 S(GPRS_SNS_ST_CONFIGURED) |
1350 S(GPRS_SNS_ST_SIZE),
1351 .name = "CONFIG_SGSN",
1352 .action = ns2_sns_st_config_sgsn,
Alexander Couzens790a9632021-02-05 17:18:39 +01001353 .onenter = ns2_sns_st_config_sgsn_onenter,
Alexander Couzens6a161492020-07-12 13:45:50 +02001354 },
1355 [GPRS_SNS_ST_CONFIGURED] = {
1356 .in_event_mask = S(GPRS_SNS_EV_ADD) |
1357 S(GPRS_SNS_EV_DELETE) |
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01001358 S(GPRS_SNS_EV_CHANGE_WEIGHT) |
1359 S(GPRS_SNS_EV_NSVC_ALIVE),
Alexander Couzense03d8632020-12-06 03:31:44 +01001360 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
1361 S(GPRS_SNS_ST_SIZE),
Alexander Couzens6a161492020-07-12 13:45:50 +02001362 .name = "CONFIGURED",
1363 .action = ns2_sns_st_configured,
1364 .onenter = ns2_sns_st_configured_onenter,
1365 },
1366};
1367
1368static int ns2_sns_fsm_bss_timer_cb(struct osmo_fsm_inst *fi)
1369{
Alexander Couzens90ee9632020-12-07 06:18:32 +01001370 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
Alexander Couzens6a161492020-07-12 13:45:50 +02001371 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
1372 struct gprs_ns2_inst *nsi = nse->nsi;
1373
Alexander Couzens90ee9632020-12-07 06:18:32 +01001374 gss->N++;
Alexander Couzens6a161492020-07-12 13:45:50 +02001375 switch (fi->T) {
1376 case 1:
Alexander Couzensa367d082020-12-21 14:06:24 +01001377 if (gss->N >= nsi->timeout[NS_TOUT_TSNS_SIZE_RETRIES]) {
1378 LOGPFSML(fi, LOGL_ERROR, "NSE %d: Size retries failed. Selecting next IP-SNS endpoint.\n", nse->nsei);
Alexander Couzens90ee9632020-12-07 06:18:32 +01001379 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_SELECT_ENDPOINT, NULL);
Alexander Couzensa367d082020-12-21 14:06:24 +01001380 } else {
Alexander Couzenscc65a252020-12-21 14:03:58 +01001381 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_SIZE, nsi->timeout[NS_TOUT_TSNS_PROV], 1);
Alexander Couzensa367d082020-12-21 14:06:24 +01001382 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001383 break;
1384 case 2:
Alexander Couzensa367d082020-12-21 14:06:24 +01001385 if (gss->N >= nsi->timeout[NS_TOUT_TSNS_CONFIG_RETRIES]) {
Alexander Couzens3df58862021-02-05 17:18:08 +01001386 LOGPFSML(fi, LOGL_ERROR, "NSE %d: BSS Config retries failed. Selecting next IP-SNS endpoint.\n", nse->nsei);
Alexander Couzens90ee9632020-12-07 06:18:32 +01001387 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_SELECT_ENDPOINT, NULL);
Alexander Couzensa367d082020-12-21 14:06:24 +01001388 } else {
Alexander Couzenscc65a252020-12-21 14:03:58 +01001389 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIG_BSS, nsi->timeout[NS_TOUT_TSNS_PROV], 2);
Alexander Couzensa367d082020-12-21 14:06:24 +01001390 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001391 break;
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01001392 case 3:
Alexander Couzens3df58862021-02-05 17:18:08 +01001393 if (gss->N >= nsi->timeout[NS_TOUT_TSNS_CONFIG_RETRIES]) {
1394 LOGPFSML(fi, LOGL_ERROR, "NSE %d: SGSN Config retries failed. Selecting next IP-SNS endpoint.\n", nse->nsei);
1395 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_SELECT_ENDPOINT, NULL);
1396 } else {
1397 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIG_SGSN, nsi->timeout[NS_TOUT_TSNS_PROV], 3);
1398 }
1399 break;
1400 case 4:
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01001401 LOGPFSML(fi, LOGL_ERROR, "NSE %d: Config succeeded but no NS-VC came online. Selecting next IP-SNS endpoint.\n", nse->nsei);
1402 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_SELECT_ENDPOINT, NULL);
1403 break;
Alexander Couzens6a161492020-07-12 13:45:50 +02001404 }
1405 return 0;
1406}
1407
1408static void ns2_sns_st_all_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1409{
Alexander Couzense769f522020-12-07 07:37:07 +01001410 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
Alexander Couzens6a161492020-07-12 13:45:50 +02001411 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
1412
1413 /* reset when receiving GPRS_SNS_EV_NO_NSVC */
Alexander Couzense769f522020-12-07 07:37:07 +01001414 switch (event) {
1415 case GPRS_SNS_EV_NO_NSVC:
Alexander Couzens3ad73362020-12-21 13:53:00 +01001416 /* ignore reselection running */
1417 if (gss->reselection_running)
1418 break;
1419
1420 LOGPFSML(fi, LOGL_ERROR, "NSE %d: no remaining NSVC, resetting SNS FSM\n", nse->nsei);
1421 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_SELECT_ENDPOINT, NULL);
Alexander Couzense769f522020-12-07 07:37:07 +01001422 break;
1423 case GPRS_SNS_EV_SELECT_ENDPOINT:
1424 /* tear down previous state
1425 * gprs_ns2_free_nsvcs() will trigger NO_NSVC, prevent this from triggering a reselection */
1426 gss->reselection_running = true;
1427 gprs_ns2_free_nsvcs(nse);
Alexander Couzens7a7b20b2021-01-18 10:47:33 +01001428 ns2_clear_ipv46_entries(gss);
Alexander Couzense769f522020-12-07 07:37:07 +01001429
1430 /* Choose the next sns endpoint. */
1431 if (llist_empty(&gss->sns_endpoints)) {
1432 gss->initial = NULL;
Alexander Couzens138b96f2021-01-25 16:23:29 +01001433 ns2_prim_status_ind(gss->nse, NULL, 0, GPRS_NS2_AFF_CAUSE_SNS_NO_ENDPOINTS);
Alexander Couzense769f522020-12-07 07:37:07 +01001434 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 3);
1435 return;
1436 } else if (!gss->initial) {
1437 gss->initial = llist_first_entry(&gss->sns_endpoints, struct sns_endpoint, list);
Alexander Couzens81ae0aa2020-12-07 05:49:43 +01001438 gss->bind_offset = 0;
Alexander Couzense769f522020-12-07 07:37:07 +01001439 } else if (gss->initial->list.next == &gss->sns_endpoints) {
1440 /* last entry, continue with first */
1441 gss->initial = llist_first_entry(&gss->sns_endpoints, struct sns_endpoint, list);
Alexander Couzens81ae0aa2020-12-07 05:49:43 +01001442 gss->bind_offset++;
1443 gss->bind_offset %= ns2_ip_count_bind(nse->nsi, &gss->initial->saddr);
Alexander Couzense769f522020-12-07 07:37:07 +01001444 } else {
1445 /* next element is an entry */
1446 gss->initial = llist_entry(gss->initial->list.next, struct sns_endpoint, list);
1447 }
1448
1449 gss->reselection_running = false;
1450 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_SIZE, nse->nsi->timeout[NS_TOUT_TSNS_PROV], 1);
1451 break;
1452 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001453}
1454
1455static struct osmo_fsm gprs_ns2_sns_bss_fsm = {
1456 .name = "GPRS-NS2-SNS-BSS",
1457 .states = ns2_sns_bss_states,
1458 .num_states = ARRAY_SIZE(ns2_sns_bss_states),
Alexander Couzense769f522020-12-07 07:37:07 +01001459 .allstate_event_mask = S(GPRS_SNS_EV_NO_NSVC) |
1460 S(GPRS_SNS_EV_SELECT_ENDPOINT),
Alexander Couzens6a161492020-07-12 13:45:50 +02001461 .allstate_action = ns2_sns_st_all_action,
1462 .cleanup = NULL,
1463 .timer_cb = ns2_sns_fsm_bss_timer_cb,
1464 /* .log_subsys = DNS, "is not constant" */
1465 .event_names = gprs_sns_event_names,
1466 .pre_term = NULL,
1467 .log_subsys = DLNS,
1468};
1469
Harald Welte5bef2cc2020-09-18 22:33:24 +02001470/*! Allocate an IP-SNS FSM for the BSS side.
1471 * \param[in] nse NS Entity in which the FSM runs
1472 * \param[in] id string identifier
1473 * \retruns FSM instance on success; NULL on error */
Alexander Couzens6a161492020-07-12 13:45:50 +02001474struct osmo_fsm_inst *ns2_sns_bss_fsm_alloc(struct gprs_ns2_nse *nse,
1475 const char *id)
1476{
1477 struct osmo_fsm_inst *fi;
1478 struct ns2_sns_state *gss;
1479
1480 fi = osmo_fsm_inst_alloc(&gprs_ns2_sns_bss_fsm, nse, NULL, LOGL_DEBUG, id);
1481 if (!fi)
1482 return fi;
1483
1484 gss = talloc_zero(fi, struct ns2_sns_state);
1485 if (!gss)
1486 goto err;
1487
1488 fi->priv = gss;
1489 gss->nse = nse;
Alexander Couzense769f522020-12-07 07:37:07 +01001490 INIT_LLIST_HEAD(&gss->sns_endpoints);
Alexander Couzens6a161492020-07-12 13:45:50 +02001491
1492 return fi;
1493err:
1494 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
1495 return NULL;
1496}
1497
Harald Welte5bef2cc2020-09-18 22:33:24 +02001498/*! main entry point for receiving SNS messages from the network.
1499 * \param[in] nsvc NS-VC on which the message was received
1500 * \param[in] msg message buffer of the IP-SNS message
1501 * \param[in] tp parsed TLV structure of message
1502 * \retruns 0 on success; negative on error */
Alexander Couzens8dfc24c2021-01-25 16:09:23 +01001503int ns2_sns_rx(struct gprs_ns2_vc *nsvc, struct msgb *msg, struct tlv_parsed *tp)
Alexander Couzens6a161492020-07-12 13:45:50 +02001504{
1505 struct gprs_ns2_nse *nse = nsvc->nse;
1506 struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h;
1507 uint16_t nsei = nsvc->nse->nsei;
1508 struct osmo_fsm_inst *fi;
1509
1510 if (!nse->bss_sns_fi) {
Harald Weltef2949742021-01-20 14:54:14 +01001511 LOGNSVC(nsvc, LOGL_NOTICE, "Rx %s for NS Instance that has no SNS!\n",
1512 get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
Alexander Couzens6a161492020-07-12 13:45:50 +02001513 return -EINVAL;
1514 }
1515
Alexander Couzens6a161492020-07-12 13:45:50 +02001516 /* FIXME: how to resolve SNS FSM Instance by NSEI (SGSN)? */
1517 fi = nse->bss_sns_fi;
1518
Harald Weltef2949742021-01-20 14:54:14 +01001519 LOGPFSML(fi, LOGL_DEBUG, "NSEI=%u Rx SNS PDU type %s\n", nsei,
1520 get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
1521
Alexander Couzens6a161492020-07-12 13:45:50 +02001522 switch (nsh->pdu_type) {
1523 case SNS_PDUT_SIZE:
1524 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_SIZE, tp);
1525 break;
1526 case SNS_PDUT_SIZE_ACK:
1527 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_SIZE_ACK, tp);
1528 break;
1529 case SNS_PDUT_CONFIG:
1530 if (nsh->data[0] & 0x01)
1531 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_CONFIG_END, tp);
1532 else
1533 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_CONFIG, tp);
1534 break;
1535 case SNS_PDUT_CONFIG_ACK:
1536 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_CONFIG_ACK, tp);
1537 break;
1538 case SNS_PDUT_ADD:
1539 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_ADD, tp);
1540 break;
1541 case SNS_PDUT_DELETE:
1542 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_DELETE, tp);
1543 break;
1544 case SNS_PDUT_CHANGE_WEIGHT:
1545 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_CHANGE_WEIGHT, tp);
1546 break;
1547 case SNS_PDUT_ACK:
Harald Weltef2949742021-01-20 14:54:14 +01001548 LOGPFSML(fi, LOGL_NOTICE, "NSEI=%u Rx unsupported SNS PDU type %s\n", nsei,
1549 get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
Alexander Couzens6a161492020-07-12 13:45:50 +02001550 break;
1551 default:
Harald Weltef2949742021-01-20 14:54:14 +01001552 LOGPFSML(fi, LOGL_ERROR, "NSEI=%u Rx unknown SNS PDU type %s\n", nsei,
1553 get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
Alexander Couzens6a161492020-07-12 13:45:50 +02001554 return -EINVAL;
1555 }
1556
1557 return 0;
1558}
1559
1560#include <osmocom/vty/vty.h>
1561#include <osmocom/vty/misc.h>
1562
Harald Welte1262c4f2021-01-19 20:58:33 +01001563static 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 +02001564{
1565 struct in_addr in = { .s_addr = ip4->ip_addr };
Harald Welte1262c4f2021-01-19 20:58:33 +01001566 vty_out(vty, "%s %s:%u, Signalling Weight: %u, Data Weight: %u%s", prefix,
Alexander Couzens6a161492020-07-12 13:45:50 +02001567 inet_ntoa(in), ntohs(ip4->udp_port), ip4->sig_weight, ip4->data_weight, VTY_NEWLINE);
1568}
1569
Harald Welte1262c4f2021-01-19 20:58:33 +01001570static 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 +02001571{
1572 char ip_addr[INET6_ADDRSTRLEN] = {};
1573 if (!inet_ntop(AF_INET6, &ip6->ip_addr, ip_addr, (INET6_ADDRSTRLEN)))
1574 strcpy(ip_addr, "Invalid IPv6");
1575
Harald Welte1262c4f2021-01-19 20:58:33 +01001576 vty_out(vty, "%s %s:%u, Signalling Weight: %u, Data Weight: %u%s", prefix,
Alexander Couzens6a161492020-07-12 13:45:50 +02001577 ip_addr, ntohs(ip6->udp_port), ip6->sig_weight, ip6->data_weight, VTY_NEWLINE);
1578}
1579
Harald Welte5bef2cc2020-09-18 22:33:24 +02001580/*! Dump the IP-SNS state to a vty.
1581 * \param[in] vty VTY to which the state shall be printed
Harald Welte1262c4f2021-01-19 20:58:33 +01001582 * \param[in] prefix prefix to print at start of each line (typically indenting)
Harald Welte5bef2cc2020-09-18 22:33:24 +02001583 * \param[in] nse NS Entity whose IP-SNS state shall be printed
1584 * \param[in] stats Whether or not statistics shall also be printed */
Alexander Couzens8dfc24c2021-01-25 16:09:23 +01001585void 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 +02001586{
1587 struct ns2_sns_state *gss;
1588 unsigned int i;
1589
1590 if (!nse->bss_sns_fi)
1591 return;
1592
Harald Welte1262c4f2021-01-19 20:58:33 +01001593 vty_out_fsm_inst2(vty, prefix, nse->bss_sns_fi);
Alexander Couzens6a161492020-07-12 13:45:50 +02001594 gss = (struct ns2_sns_state *) nse->bss_sns_fi->priv;
1595
Harald Welte1262c4f2021-01-19 20:58:33 +01001596 vty_out(vty, "%sMaximum number of remote NS-VCs: %zu, IPv4 Endpoints: %zu, IPv6 Endpoints: %zu%s",
1597 prefix, gss->num_max_nsvcs, gss->num_max_ip4_remote, gss->num_max_ip6_remote, VTY_NEWLINE);
Alexander Couzens6a161492020-07-12 13:45:50 +02001598
1599 if (gss->num_ip4_local && gss->num_ip4_remote) {
Harald Welte1262c4f2021-01-19 20:58:33 +01001600 vty_out(vty, "%sLocal IPv4 Endpoints:%s", prefix, VTY_NEWLINE);
Alexander Couzens6a161492020-07-12 13:45:50 +02001601 for (i = 0; i < gss->num_ip4_local; i++)
Harald Welte1262c4f2021-01-19 20:58:33 +01001602 vty_dump_sns_ip4(vty, prefix, &gss->ip4_local[i]);
Alexander Couzens6a161492020-07-12 13:45:50 +02001603
Harald Welte1262c4f2021-01-19 20:58:33 +01001604 vty_out(vty, "%sRemote IPv4 Endpoints:%s", prefix, VTY_NEWLINE);
Alexander Couzens6a161492020-07-12 13:45:50 +02001605 for (i = 0; i < gss->num_ip4_remote; i++)
Harald Welte1262c4f2021-01-19 20:58:33 +01001606 vty_dump_sns_ip4(vty, prefix, &gss->ip4_remote[i]);
Alexander Couzens6a161492020-07-12 13:45:50 +02001607 }
1608
1609 if (gss->num_ip6_local && gss->num_ip6_remote) {
Harald Welte1262c4f2021-01-19 20:58:33 +01001610 vty_out(vty, "%sLocal IPv6 Endpoints:%s", prefix, VTY_NEWLINE);
Alexander Couzens6a161492020-07-12 13:45:50 +02001611 for (i = 0; i < gss->num_ip6_local; i++)
Harald Welte1262c4f2021-01-19 20:58:33 +01001612 vty_dump_sns_ip6(vty, prefix, &gss->ip6_local[i]);
Alexander Couzens6a161492020-07-12 13:45:50 +02001613
Harald Welte1262c4f2021-01-19 20:58:33 +01001614 vty_out(vty, "%sRemote IPv6 Endpoints:%s", prefix, VTY_NEWLINE);
Alexander Couzens6a161492020-07-12 13:45:50 +02001615 for (i = 0; i < gss->num_ip6_remote; i++)
Harald Welte1262c4f2021-01-19 20:58:33 +01001616 vty_dump_sns_ip6(vty, prefix, &gss->ip6_remote[i]);
Alexander Couzens6a161492020-07-12 13:45:50 +02001617 }
1618}
1619
Alexander Couzens412bc342020-11-19 05:24:37 +01001620/*! write IP-SNS to a vty
1621 * \param[in] vty VTY to which the state shall be printed
1622 * \param[in] nse NS Entity whose IP-SNS state shall be printed */
Alexander Couzens8dfc24c2021-01-25 16:09:23 +01001623void ns2_sns_write_vty(struct vty *vty, const struct gprs_ns2_nse *nse)
Alexander Couzens412bc342020-11-19 05:24:37 +01001624{
1625 struct ns2_sns_state *gss;
1626 struct osmo_sockaddr_str addr_str;
1627 struct sns_endpoint *endpoint;
1628
1629 if (!nse->bss_sns_fi)
1630 return;
1631
1632 gss = (struct ns2_sns_state *) nse->bss_sns_fi->priv;
1633 llist_for_each_entry(endpoint, &gss->sns_endpoints, list) {
Vadim Yanitskiyd8b70032021-01-05 14:24:09 +01001634 /* It's unlikely that an error happens, but let's better be safe. */
1635 if (osmo_sockaddr_str_from_sockaddr(&addr_str, &endpoint->saddr.u.sas) != 0)
1636 addr_str = (struct osmo_sockaddr_str) { .ip = "<INVALID>" };
Alexander Couzens5fa431c2021-02-08 23:21:54 +01001637 vty_out(vty, " ip-sns-remote %s %u%s", addr_str.ip, addr_str.port, VTY_NEWLINE);
Alexander Couzens412bc342020-11-19 05:24:37 +01001638 }
1639}
1640
Alexander Couzense769f522020-12-07 07:37:07 +01001641static struct sns_endpoint *ns2_get_sns_endpoint(struct ns2_sns_state *state,
1642 const struct osmo_sockaddr *saddr)
1643{
1644 struct sns_endpoint *endpoint;
1645
1646 llist_for_each_entry(endpoint, &state->sns_endpoints, list) {
1647 if (!osmo_sockaddr_cmp(saddr, &endpoint->saddr))
1648 return endpoint;
1649 }
1650
1651 return NULL;
1652}
1653
1654/*! gprs_ns2_sns_add_endpoint
1655 * \param[in] nse
1656 * \param[in] sockaddr
1657 * \return
1658 */
1659int gprs_ns2_sns_add_endpoint(struct gprs_ns2_nse *nse,
1660 const struct osmo_sockaddr *saddr)
1661{
1662 struct ns2_sns_state *gss;
1663 struct sns_endpoint *endpoint;
1664 bool do_selection = false;
1665
1666 if (nse->ll != GPRS_NS2_LL_UDP) {
1667 return -EINVAL;
1668 }
1669
Alexander Couzens138b96f2021-01-25 16:23:29 +01001670 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
Alexander Couzense769f522020-12-07 07:37:07 +01001671 return -EINVAL;
1672 }
1673
1674 gss = nse->bss_sns_fi->priv;
1675
1676 if (ns2_get_sns_endpoint(gss, saddr))
1677 return -EADDRINUSE;
1678
1679 endpoint = talloc_zero(nse->bss_sns_fi->priv, struct sns_endpoint);
1680 if (!endpoint)
1681 return -ENOMEM;
1682
1683 endpoint->saddr = *saddr;
1684 if (llist_empty(&gss->sns_endpoints))
1685 do_selection = true;
1686
1687 llist_add_tail(&endpoint->list, &gss->sns_endpoints);
1688 if (do_selection)
1689 osmo_fsm_inst_dispatch(nse->bss_sns_fi, GPRS_SNS_EV_SELECT_ENDPOINT, NULL);
1690
1691 return 0;
1692}
1693
1694/*! gprs_ns2_sns_del_endpoint
1695 * \param[in] nse
1696 * \param[in] sockaddr
1697 * \return 0 on success, otherwise < 0
1698 */
1699int gprs_ns2_sns_del_endpoint(struct gprs_ns2_nse *nse,
1700 const struct osmo_sockaddr *saddr)
1701{
1702 struct ns2_sns_state *gss;
1703 struct sns_endpoint *endpoint;
1704
1705 if (nse->ll != GPRS_NS2_LL_UDP) {
1706 return -EINVAL;
1707 }
1708
Alexander Couzens138b96f2021-01-25 16:23:29 +01001709 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
Alexander Couzense769f522020-12-07 07:37:07 +01001710 return -EINVAL;
1711 }
1712
1713 gss = nse->bss_sns_fi->priv;
1714 endpoint = ns2_get_sns_endpoint(gss, saddr);
1715 if (!endpoint)
1716 return -ENOENT;
1717
1718 /* if this is an unused SNS endpoint it's done */
1719 if (gss->initial != endpoint) {
1720 llist_del(&endpoint->list);
1721 talloc_free(endpoint);
1722 return 0;
1723 }
1724
1725 /* gprs_ns2_free_nsvcs() will trigger GPRS_SNS_EV_NO_NSVC on the last NS-VC
1726 * and restart SNS SIZE procedure which selects a new initial */
Harald Weltef2949742021-01-20 14:54:14 +01001727 LOGNSE(nse, LOGL_INFO, "Current in-use SNS endpoint is being removed."
Alexander Couzense769f522020-12-07 07:37:07 +01001728 "Closing all NS-VC and restart SNS-SIZE procedure"
1729 "with a remaining SNS endpoint.\n");
1730
1731 /* Continue with the next endpoint in the list.
1732 * Special case if the endpoint is at the start or end of the list */
1733 if (endpoint->list.prev == &gss->sns_endpoints ||
1734 endpoint->list.next == &gss->sns_endpoints)
1735 gss->initial = NULL;
1736 else
1737 gss->initial = llist_entry(endpoint->list.next->prev,
1738 struct sns_endpoint,
1739 list);
1740
1741 llist_del(&endpoint->list);
1742 gprs_ns2_free_nsvcs(nse);
1743 talloc_free(endpoint);
1744
1745 return 0;
1746}
1747
1748/*! gprs_ns2_sns_count
1749 * \param[in] nse NS Entity whose IP-SNS endpoints shall be printed
1750 * \return the count of endpoints or < 0 if NSE doesn't contain sns.
1751 */
1752int gprs_ns2_sns_count(struct gprs_ns2_nse *nse)
1753{
1754 struct ns2_sns_state *gss;
1755 struct sns_endpoint *endpoint;
1756 int count = 0;
1757
1758 if (nse->ll != GPRS_NS2_LL_UDP) {
1759 return -EINVAL;
1760 }
1761
Alexander Couzens138b96f2021-01-25 16:23:29 +01001762 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
Alexander Couzense769f522020-12-07 07:37:07 +01001763 return -EINVAL;
1764 }
1765
1766 gss = nse->bss_sns_fi->priv;
1767 llist_for_each_entry(endpoint, &gss->sns_endpoints, list)
1768 count++;
1769
1770 return count;
1771}
1772
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01001773void ns2_sns_notify_alive(struct gprs_ns2_nse *nse, struct gprs_ns2_vc *nsvc, bool alive)
1774{
1775 struct ns2_sns_state *gss;
1776 struct gprs_ns2_vc *tmp;
1777
1778 if (!nse->bss_sns_fi)
1779 return;
1780
1781 gss = nse->bss_sns_fi->priv;
1782 if(nse->bss_sns_fi->state != GPRS_SNS_ST_CONFIGURED)
1783 return;
1784
1785 if (alive == gss->alive)
1786 return;
1787
1788 /* check if this is the current SNS NS-VC */
1789 if (nsvc == gss->sns_nsvc) {
1790 /* only replace the SNS NS-VC if there are other alive NS-VC.
1791 * There aren't any other alive NS-VC when the SNS fsm just reached CONFIGURED
1792 * and couldn't confirm yet if the NS-VC comes up */
1793 if (gss->alive && !alive)
1794 ns2_sns_replace_nsvc(nsvc);
1795 }
1796
1797 if (alive) {
1798 gss->alive = true;
1799 osmo_fsm_inst_dispatch(nse->bss_sns_fi, GPRS_SNS_EV_NSVC_ALIVE, NULL);
1800 } else {
1801 /* is there at least another alive nsvc? */
1802 llist_for_each_entry(tmp, &nse->nsvc, list) {
1803 if (ns2_vc_is_unblocked(tmp))
1804 return;
1805 }
1806
1807 /* all NS-VC have failed */
1808 gss->alive = false;
1809 osmo_fsm_inst_dispatch(nse->bss_sns_fi, GPRS_SNS_EV_NO_NSVC, NULL);
1810 }
1811}
1812
Alexander Couzensc4704762021-02-08 23:13:12 +01001813/* Update SNS weights
1814 * \param[in] nsvc the NSVC which should be updated
1815 */
1816void ns2_sns_update_weights(struct gprs_ns2_vc_bind *bind)
1817{
1818 /* TODO: implement weights after binds per sns implemented */
1819}
1820
Alexander Couzens6a161492020-07-12 13:45:50 +02001821/* initialize osmo_ctx on main tread */
1822static __attribute__((constructor)) void on_dso_load_ctx(void)
1823{
1824 OSMO_ASSERT(osmo_fsm_register(&gprs_ns2_sns_bss_fsm) == 0);
1825}