blob: dfa9afe2d031dffead1899afbb6e446e7f807244 [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 Couzens6b9d2322021-02-12 03:17:59 +010084 GPRS_SNS_EV_REQ_ADD_BIND,
85 GPRS_SNS_EV_REQ_DELETE_BIND,
Alexander Couzens6a161492020-07-12 13:45:50 +020086};
87
88static const struct value_string gprs_sns_event_names[] = {
Alexander Couzense769f522020-12-07 07:37:07 +010089 { GPRS_SNS_EV_SELECT_ENDPOINT, "SELECT_ENDPOINT" },
Alexander Couzens6a161492020-07-12 13:45:50 +020090 { GPRS_SNS_EV_SIZE, "SIZE" },
91 { GPRS_SNS_EV_SIZE_ACK, "SIZE_ACK" },
92 { GPRS_SNS_EV_CONFIG, "CONFIG" },
93 { GPRS_SNS_EV_CONFIG_END, "CONFIG_END" },
94 { GPRS_SNS_EV_CONFIG_ACK, "CONFIG_ACK" },
95 { GPRS_SNS_EV_ADD, "ADD" },
96 { GPRS_SNS_EV_DELETE, "DELETE" },
97 { GPRS_SNS_EV_CHANGE_WEIGHT, "CHANGE_WEIGHT" },
Pau Espin Pedrol0a446a12020-10-27 13:30:08 +010098 { GPRS_SNS_EV_NO_NSVC, "NO_NSVC" },
Alexander Couzensbe7cecc2021-02-03 18:25:27 +010099 { GPRS_SNS_EV_NSVC_ALIVE, "NSVC_ALIVE"},
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100100 { GPRS_SNS_EV_REQ_ADD_BIND, "ADD_BIND"},
101 { GPRS_SNS_EV_REQ_DELETE_BIND, "DELETE_BIND"},
Alexander Couzens6a161492020-07-12 13:45:50 +0200102 { 0, NULL }
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;
113};
114
Alexander Couzens6a161492020-07-12 13:45:50 +0200115struct ns2_sns_state {
116 struct gprs_ns2_nse *nse;
117
118 enum ns2_sns_type ip;
119
Alexander Couzense769f522020-12-07 07:37:07 +0100120 /* holds the list of initial SNS endpoints */
121 struct llist_head sns_endpoints;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100122 /* list of used struct ns2_sns_bind */
123 struct llist_head binds;
124 /* pointer to the bind which was used to initiate the SNS connection */
125 struct ns2_sns_bind *initial_bind;
Alexander Couzense769f522020-12-07 07:37:07 +0100126 /* prevent recursive reselection */
127 bool reselection_running;
128
129 /* The current initial SNS endpoints.
130 * The initial connection will be moved into the NSE
131 * if configured via SNS. Otherwise it will be removed
132 * in configured state. */
133 struct sns_endpoint *initial;
Alexander Couzens6a161492020-07-12 13:45:50 +0200134 /* all SNS PDU will be sent over this nsvc */
135 struct gprs_ns2_vc *sns_nsvc;
Alexander Couzens90ee9632020-12-07 06:18:32 +0100136 /* timer N */
137 int N;
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100138 /* true if at least one nsvc is alive */
139 bool alive;
Alexander Couzens6a161492020-07-12 13:45:50 +0200140
141 /* local configuration to send to the remote end */
142 struct gprs_ns_ie_ip4_elem *ip4_local;
143 size_t num_ip4_local;
144
145 /* local configuration to send to the remote end */
146 struct gprs_ns_ie_ip6_elem *ip6_local;
147 size_t num_ip6_local;
148
149 /* local configuration about our capabilities in terms of connections to
150 * remote (SGSN) side */
151 size_t num_max_nsvcs;
152 size_t num_max_ip4_remote;
153 size_t num_max_ip6_remote;
154
155 /* remote configuration as received */
156 struct gprs_ns_ie_ip4_elem *ip4_remote;
157 unsigned int num_ip4_remote;
158
159 /* remote configuration as received */
160 struct gprs_ns_ie_ip6_elem *ip6_remote;
161 unsigned int num_ip6_remote;
162};
163
164static inline struct gprs_ns2_nse *nse_inst_from_fi(struct osmo_fsm_inst *fi)
165{
166 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
167 return gss->nse;
168}
169
170/* helper function to compute the sum of all (data or signaling) weights */
171static int ip4_weight_sum(const struct gprs_ns_ie_ip4_elem *ip4, unsigned int num,
172 bool data_weight)
173{
174 unsigned int i;
175 int weight_sum = 0;
176
177 for (i = 0; i < num; i++) {
178 if (data_weight)
179 weight_sum += ip4[i].data_weight;
180 else
181 weight_sum += ip4[i].sig_weight;
182 }
183 return weight_sum;
184}
185#define ip4_weight_sum_data(x,y) ip4_weight_sum(x, y, true)
186#define ip4_weight_sum_sig(x,y) ip4_weight_sum(x, y, false)
187
188/* helper function to compute the sum of all (data or signaling) weights */
189static int ip6_weight_sum(const struct gprs_ns_ie_ip6_elem *ip6, unsigned int num,
190 bool data_weight)
191{
192 unsigned int i;
193 int weight_sum = 0;
194
195 for (i = 0; i < num; i++) {
196 if (data_weight)
197 weight_sum += ip6[i].data_weight;
198 else
199 weight_sum += ip6[i].sig_weight;
200 }
201 return weight_sum;
202}
203#define ip6_weight_sum_data(x,y) ip6_weight_sum(x, y, true)
204#define ip6_weight_sum_sig(x,y) ip6_weight_sum(x, y, false)
205
206static struct gprs_ns2_vc *nsvc_by_ip4_elem(struct gprs_ns2_nse *nse,
207 const struct gprs_ns_ie_ip4_elem *ip4)
208{
209 struct osmo_sockaddr sa;
210 /* copy over. Both data structures use network byte order */
211 sa.u.sin.sin_addr.s_addr = ip4->ip_addr;
212 sa.u.sin.sin_port = ip4->udp_port;
213 sa.u.sin.sin_family = AF_INET;
214
Alexander Couzens38b19e82020-09-23 23:56:37 +0200215 return gprs_ns2_nsvc_by_sockaddr_nse(nse, &sa);
Alexander Couzens6a161492020-07-12 13:45:50 +0200216}
217
218static struct gprs_ns2_vc *nsvc_by_ip6_elem(struct gprs_ns2_nse *nse,
219 const struct gprs_ns_ie_ip6_elem *ip6)
220{
221 struct osmo_sockaddr sa;
222 /* copy over. Both data structures use network byte order */
223 sa.u.sin6.sin6_addr = ip6->ip_addr;
224 sa.u.sin6.sin6_port = ip6->udp_port;
225 sa.u.sin6.sin6_family = AF_INET;
226
Alexander Couzens38b19e82020-09-23 23:56:37 +0200227 return gprs_ns2_nsvc_by_sockaddr_nse(nse, &sa);
Alexander Couzens6a161492020-07-12 13:45:50 +0200228}
229
Alexander Couzens125298f2020-10-11 21:22:42 +0200230/*! Return the initial SNS remote socket address
231 * \param nse NS Entity
232 * \return address of the initial SNS connection; NULL in case of error
233 */
234const struct osmo_sockaddr *gprs_ns2_nse_sns_remote(struct gprs_ns2_nse *nse)
235{
236 struct ns2_sns_state *gss;
237
238 if (!nse->bss_sns_fi)
239 return NULL;
240
241 gss = (struct ns2_sns_state *) nse->bss_sns_fi->priv;
Alexander Couzense769f522020-12-07 07:37:07 +0100242 return &gss->initial->saddr;
Alexander Couzens125298f2020-10-11 21:22:42 +0200243}
244
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100245/*! called when a nsvc is beeing freed or the nsvc became dead */
246void ns2_sns_replace_nsvc(struct gprs_ns2_vc *nsvc)
Alexander Couzens6a161492020-07-12 13:45:50 +0200247{
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100248 struct gprs_ns2_nse *nse = nsvc->nse;
Alexander Couzens6a161492020-07-12 13:45:50 +0200249 struct gprs_ns2_vc *tmp;
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100250 struct osmo_fsm_inst *fi = nse->bss_sns_fi;
Alexander Couzens6a161492020-07-12 13:45:50 +0200251 struct ns2_sns_state *gss;
Alexander Couzens6a161492020-07-12 13:45:50 +0200252
253 if (!fi)
254 return;
255
256 gss = (struct ns2_sns_state *) fi->priv;
257 if (nsvc != gss->sns_nsvc)
258 return;
259
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100260 gss->sns_nsvc = NULL;
261 if (gss->alive) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200262 llist_for_each_entry(tmp, &nse->nsvc, list) {
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100263 if (ns2_vc_is_unblocked(tmp)) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200264 gss->sns_nsvc = tmp;
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100265 return;
266 }
Alexander Couzens6a161492020-07-12 13:45:50 +0200267 }
268 } else {
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100269 /* the SNS is waiting for its first NS-VC to come up
270 * choose any other nsvc */
271 llist_for_each_entry(tmp, &nse->nsvc, list) {
272 if (nsvc != tmp) {
273 gss->sns_nsvc = tmp;
274 return;
275 }
276 }
Alexander Couzens6a161492020-07-12 13:45:50 +0200277 }
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100278
279 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_NO_NSVC, NULL);
Alexander Couzens6a161492020-07-12 13:45:50 +0200280}
281
Alexander Couzens7a7b20b2021-01-18 10:47:33 +0100282static void ns2_clear_ipv46_entries(struct ns2_sns_state *gss)
283{
284 TALLOC_FREE(gss->ip4_local);
285 TALLOC_FREE(gss->ip4_remote);
286 TALLOC_FREE(gss->ip6_local);
287 TALLOC_FREE(gss->ip6_remote);
288
289 gss->num_ip4_local = 0;
290 gss->num_ip4_remote = 0;
291 gss->num_ip6_local = 0;
292 gss->num_ip6_remote = 0;
293}
294
Daniel Willmanncf8371a2021-01-16 15:13:51 +0100295static void ns2_vc_create_ip(struct osmo_fsm_inst *fi, struct gprs_ns2_nse *nse, const struct osmo_sockaddr *remote,
296 uint8_t sig_weight, uint8_t data_weight)
Alexander Couzens6a161492020-07-12 13:45:50 +0200297{
298 struct gprs_ns2_inst *nsi = nse->nsi;
299 struct gprs_ns2_vc *nsvc;
300 struct gprs_ns2_vc_bind *bind;
Daniel Willmanncf8371a2021-01-16 15:13:51 +0100301
302 /* for every bind, create a connection if bind type == IP */
303 llist_for_each_entry(bind, &nsi->binding, list) {
304 if (bind->ll != GPRS_NS2_LL_UDP)
305 continue;
306 /* ignore failed connection */
307 nsvc = gprs_ns2_ip_connect_inactive(bind,
308 remote,
309 nse, 0);
310 if (!nsvc) {
311 LOGPFSML(fi, LOGL_ERROR, "SNS-CONFIG: Failed to create NSVC\n");
312 continue;
313 }
314
315 nsvc->sig_weight = sig_weight;
316 nsvc->data_weight = data_weight;
317 }
318}
319
320static void ns2_nsvc_create_ip4(struct osmo_fsm_inst *fi,
321 struct gprs_ns2_nse *nse,
322 const struct gprs_ns_ie_ip4_elem *ip4)
323{
Alexander Couzensc068d862020-10-12 04:11:51 +0200324 struct osmo_sockaddr remote = { };
Alexander Couzens6a161492020-07-12 13:45:50 +0200325 /* copy over. Both data structures use network byte order */
326 remote.u.sin.sin_family = AF_INET;
327 remote.u.sin.sin_addr.s_addr = ip4->ip_addr;
328 remote.u.sin.sin_port = ip4->udp_port;
329
Daniel Willmanncf8371a2021-01-16 15:13:51 +0100330 ns2_vc_create_ip(fi, nse, &remote, ip4->sig_weight, ip4->data_weight);
Alexander Couzens6a161492020-07-12 13:45:50 +0200331}
332
333static void ns2_nsvc_create_ip6(struct osmo_fsm_inst *fi,
334 struct gprs_ns2_nse *nse,
335 const struct gprs_ns_ie_ip6_elem *ip6)
336{
Alexander Couzens6a161492020-07-12 13:45:50 +0200337 struct osmo_sockaddr remote = {};
338 /* copy over. Both data structures use network byte order */
339 remote.u.sin6.sin6_family = AF_INET6;
340 remote.u.sin6.sin6_addr = ip6->ip_addr;
341 remote.u.sin6.sin6_port = ip6->udp_port;
342
Daniel Willmanncf8371a2021-01-16 15:13:51 +0100343 ns2_vc_create_ip(fi, nse, &remote, ip6->sig_weight, ip6->data_weight);
Alexander Couzens6a161492020-07-12 13:45:50 +0200344}
345
346
347static int create_missing_nsvcs(struct osmo_fsm_inst *fi)
348{
349 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
350 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
351 struct gprs_ns2_vc *nsvc;
352 struct gprs_ns2_vc_bind *bind;
353 struct osmo_sockaddr remote = { };
354 unsigned int i;
355
356 for (i = 0; i < gss->num_ip4_remote; i++) {
357 const struct gprs_ns_ie_ip4_elem *ip4 = &gss->ip4_remote[i];
358
359 remote.u.sin.sin_family = AF_INET;
360 remote.u.sin.sin_addr.s_addr = ip4->ip_addr;
361 remote.u.sin.sin_port = ip4->udp_port;
362
363 llist_for_each_entry(bind, &nse->nsi->binding, list) {
364 bool found = false;
Daniel Willmann967e2c12021-01-14 16:58:17 +0100365 if (bind->ll != GPRS_NS2_LL_UDP)
366 continue;
Alexander Couzens6a161492020-07-12 13:45:50 +0200367
368 llist_for_each_entry(nsvc, &nse->nsvc, list) {
369 if (nsvc->bind != bind)
370 continue;
371
Alexander Couzensc4229a42020-10-11 20:58:04 +0200372 if (!osmo_sockaddr_cmp(&remote, gprs_ns2_ip_vc_remote(nsvc))) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200373 found = true;
374 break;
375 }
376 }
377
378 if (!found) {
379 nsvc = gprs_ns2_ip_connect_inactive(bind, &remote, nse, 0);
380 if (!nsvc) {
381 /* TODO: add to a list to send back a NS-STATUS */
382 continue;
383 }
384 }
385
386 /* update data / signalling weight */
387 nsvc->data_weight = ip4->data_weight;
388 nsvc->sig_weight = ip4->sig_weight;
389 nsvc->sns_only = false;
390 }
391 }
392
393 for (i = 0; i < gss->num_ip6_remote; i++) {
394 const struct gprs_ns_ie_ip6_elem *ip6 = &gss->ip6_remote[i];
395
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
400 llist_for_each_entry(bind, &nse->nsi->binding, list) {
401 bool found = false;
Daniel Willmann967e2c12021-01-14 16:58:17 +0100402 if (bind->ll != GPRS_NS2_LL_UDP)
403 continue;
Alexander Couzens6a161492020-07-12 13:45:50 +0200404
405 llist_for_each_entry(nsvc, &nse->nsvc, list) {
406 if (nsvc->bind != bind)
407 continue;
408
Alexander Couzensc4229a42020-10-11 20:58:04 +0200409 if (!osmo_sockaddr_cmp(&remote, gprs_ns2_ip_vc_remote(nsvc))) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200410 found = true;
411 break;
412 }
413 }
414
415 if (!found) {
416 nsvc = gprs_ns2_ip_connect_inactive(bind, &remote, nse, 0);
417 if (!nsvc) {
418 /* TODO: add to a list to send back a NS-STATUS */
419 continue;
420 }
421 }
422
423 /* update data / signalling weight */
424 nsvc->data_weight = ip6->data_weight;
425 nsvc->sig_weight = ip6->sig_weight;
426 nsvc->sns_only = false;
427 }
428 }
429
430
431 return 0;
432}
433
434/* Add a given remote IPv4 element to gprs_sns_state */
435static int add_remote_ip4_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip4_elem *ip4)
436{
437 unsigned int i;
438
439 if (gss->num_ip4_remote >= gss->num_max_ip4_remote)
440 return -NS_CAUSE_INVAL_NR_NS_VC;
441
442 /* check for duplicates */
443 for (i = 0; i < gss->num_ip4_remote; i++) {
444 if (memcmp(&gss->ip4_remote[i], ip4, sizeof(*ip4)))
445 continue;
446 /* TODO: log message duplicate */
447 /* TODO: check if this is the correct cause code */
448 return -NS_CAUSE_PROTO_ERR_UNSPEC;
449 }
450
451 gss->ip4_remote = talloc_realloc(gss, gss->ip4_remote, struct gprs_ns_ie_ip4_elem,
452 gss->num_ip4_remote+1);
453 gss->ip4_remote[gss->num_ip4_remote] = *ip4;
454 gss->num_ip4_remote += 1;
455 return 0;
456}
457
458/* Remove a given remote IPv4 element from gprs_sns_state */
459static int remove_remote_ip4_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip4_elem *ip4)
460{
461 unsigned int i;
462
463 for (i = 0; i < gss->num_ip4_remote; i++) {
464 if (memcmp(&gss->ip4_remote[i], ip4, sizeof(*ip4)))
465 continue;
466 /* all array elements < i remain as they are; all > i are shifted left by one */
467 memmove(&gss->ip4_remote[i], &gss->ip4_remote[i+1], gss->num_ip4_remote-i-1);
468 gss->num_ip4_remote -= 1;
469 return 0;
470 }
471 return -1;
472}
473
474/* update the weights for specified remote IPv4 */
475static int update_remote_ip4_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip4_elem *ip4)
476{
477 unsigned int i;
478
479 for (i = 0; i < gss->num_ip4_remote; i++) {
480 if (gss->ip4_remote[i].ip_addr != ip4->ip_addr ||
481 gss->ip4_remote[i].udp_port != ip4->udp_port)
482 continue;
483
484 gss->ip4_remote[i].sig_weight = ip4->sig_weight;
485 gss->ip4_remote[i].data_weight = ip4->data_weight;
486 return 0;
487 }
488 return -1;
489}
490
491/* Add a given remote IPv6 element to gprs_sns_state */
492static int add_remote_ip6_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip6_elem *ip6)
493{
494 if (gss->num_ip6_remote >= gss->num_max_ip6_remote)
495 return -NS_CAUSE_INVAL_NR_NS_VC;
496
497 gss->ip6_remote = talloc_realloc(gss, gss->ip6_remote, struct gprs_ns_ie_ip6_elem,
498 gss->num_ip6_remote+1);
499 gss->ip6_remote[gss->num_ip6_remote] = *ip6;
500 gss->num_ip6_remote += 1;
501 return 0;
502}
503
504/* Remove a given remote IPv6 element from gprs_sns_state */
505static int remove_remote_ip6_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip6_elem *ip6)
506{
507 unsigned int i;
508
509 for (i = 0; i < gss->num_ip6_remote; i++) {
510 if (memcmp(&gss->ip6_remote[i], ip6, sizeof(*ip6)))
511 continue;
512 /* all array elements < i remain as they are; all > i are shifted left by one */
513 memmove(&gss->ip6_remote[i], &gss->ip6_remote[i+1], gss->num_ip6_remote-i-1);
514 gss->num_ip6_remote -= 1;
515 return 0;
516 }
517 return -1;
518}
519
520/* update the weights for specified remote IPv6 */
521static int update_remote_ip6_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip6_elem *ip6)
522{
523 unsigned int i;
524
525 for (i = 0; i < gss->num_ip6_remote; i++) {
526 if (memcmp(&gss->ip6_remote[i].ip_addr, &ip6->ip_addr, sizeof(ip6->ip_addr)) ||
527 gss->ip6_remote[i].udp_port != ip6->udp_port)
528 continue;
529 gss->ip6_remote[i].sig_weight = ip6->sig_weight;
530 gss->ip6_remote[i].data_weight = ip6->data_weight;
531 return 0;
532 }
533 return -1;
534}
535
536static 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)
537{
538 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
539 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
540 struct gprs_ns2_vc *nsvc;
541 struct osmo_sockaddr sa = {};
Alexander Couzens9a4cf272020-10-11 20:48:04 +0200542 const struct osmo_sockaddr *remote;
Alexander Couzens6a161492020-07-12 13:45:50 +0200543 uint8_t new_signal;
544 uint8_t new_data;
545
546 /* TODO: Upon receiving an SNS-CHANGEWEIGHT PDU, if the resulting sum of the
547 * signalling weights of all the peer IP endpoints configured for this NSE is
548 * equal to zero or if the resulting sum of the data weights of all the peer IP
549 * endpoints configured for this NSE is equal to zero, the BSS/SGSN shall send an
550 * SNS-ACK PDU with a cause code of "Invalid weights". */
551
552 if (ip4) {
553 if (update_remote_ip4_elem(gss, ip4))
554 return -NS_CAUSE_UNKN_IP_EP;
555
556 /* copy over. Both data structures use network byte order */
557 sa.u.sin.sin_addr.s_addr = ip4->ip_addr;
558 sa.u.sin.sin_port = ip4->udp_port;
559 sa.u.sin.sin_family = AF_INET;
560 new_signal = ip4->sig_weight;
561 new_data = ip4->data_weight;
562 } else if (ip6) {
563 if (update_remote_ip6_elem(gss, ip6))
564 return -NS_CAUSE_UNKN_IP_EP;
565
566 /* copy over. Both data structures use network byte order */
567 sa.u.sin6.sin6_addr = ip6->ip_addr;
568 sa.u.sin6.sin6_port = ip6->udp_port;
569 sa.u.sin6.sin6_family = AF_INET6;
570 new_signal = ip6->sig_weight;
571 new_data = ip6->data_weight;
572 } else {
573 OSMO_ASSERT(false);
574 }
575
576 llist_for_each_entry(nsvc, &nse->nsvc, list) {
Alexander Couzensc4229a42020-10-11 20:58:04 +0200577 remote = gprs_ns2_ip_vc_remote(nsvc);
Alexander Couzens6a161492020-07-12 13:45:50 +0200578 /* all nsvc in NSE should be IP/UDP nsvc */
579 OSMO_ASSERT(remote);
580
581 if (osmo_sockaddr_cmp(&sa, remote))
582 continue;
583
584 LOGPFSML(fi, LOGL_INFO, "CHANGE-WEIGHT NS-VC %s data_weight %u->%u, sig_weight %u->%u\n",
585 gprs_ns2_ll_str(nsvc), nsvc->data_weight, new_data,
586 nsvc->sig_weight, new_signal);
587
588 nsvc->data_weight = new_data;
589 nsvc->sig_weight = new_signal;
590 }
591
592 return 0;
593}
594
595static int do_sns_delete(struct osmo_fsm_inst *fi,
596 const struct gprs_ns_ie_ip4_elem *ip4,
597 const struct gprs_ns_ie_ip6_elem *ip6)
598{
599 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
600 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
601 struct gprs_ns2_vc *nsvc, *tmp;
Alexander Couzens9a4cf272020-10-11 20:48:04 +0200602 const struct osmo_sockaddr *remote;
Alexander Couzens6a161492020-07-12 13:45:50 +0200603 struct osmo_sockaddr sa = {};
604
605 if (ip4) {
606 if (remove_remote_ip4_elem(gss, ip4) < 0)
607 return -NS_CAUSE_UNKN_IP_EP;
608 /* copy over. Both data structures use network byte order */
609 sa.u.sin.sin_addr.s_addr = ip4->ip_addr;
610 sa.u.sin.sin_port = ip4->udp_port;
611 sa.u.sin.sin_family = AF_INET;
612 } else if (ip6) {
613 if (remove_remote_ip6_elem(gss, ip6))
614 return -NS_CAUSE_UNKN_IP_EP;
615
616 /* copy over. Both data structures use network byte order */
617 sa.u.sin6.sin6_addr = ip6->ip_addr;
618 sa.u.sin6.sin6_port = ip6->udp_port;
619 sa.u.sin6.sin6_family = AF_INET6;
620 } else {
621 OSMO_ASSERT(false);
622 }
623
624 llist_for_each_entry_safe(nsvc, tmp, &nse->nsvc, list) {
Alexander Couzensc4229a42020-10-11 20:58:04 +0200625 remote = gprs_ns2_ip_vc_remote(nsvc);
Alexander Couzens6a161492020-07-12 13:45:50 +0200626 /* all nsvc in NSE should be IP/UDP nsvc */
627 OSMO_ASSERT(remote);
628 if (osmo_sockaddr_cmp(&sa, remote))
629 continue;
630
631 LOGPFSML(fi, LOGL_INFO, "DELETE NS-VC %s\n", gprs_ns2_ll_str(nsvc));
632 gprs_ns2_free_nsvc(nsvc);
633 }
634
635 return 0;
636}
637
638static int do_sns_add(struct osmo_fsm_inst *fi,
639 const struct gprs_ns_ie_ip4_elem *ip4,
640 const struct gprs_ns_ie_ip6_elem *ip6)
641{
642 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
643 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
644 struct gprs_ns2_vc *nsvc;
645 int rc = 0;
646
647 /* Upon receiving an SNS-ADD PDU, if the consequent number of IPv4 endpoints
648 * exceeds the number of IPv4 endpoints supported by the NSE, the NSE shall send
649 * an SNS-ACK PDU with a cause code set to "Invalid number of IP4 Endpoints". */
650 switch (gss->ip) {
651 case IPv4:
652 rc = add_remote_ip4_elem(gss, ip4);
653 break;
654 case IPv6:
655 rc = add_remote_ip6_elem(gss, ip6);
656 break;
657 default:
658 /* the gss->ip is initialized with the bss */
659 OSMO_ASSERT(false);
660 }
661
662 if (rc)
663 return rc;
664
665 /* Upon receiving an SNS-ADD PDU containing an already configured IP endpoint the
666 * NSE shall send an SNS-ACK PDU with the cause code "Protocol error -
667 * unspecified" */
668 switch (gss->ip) {
669 case IPv4:
670 nsvc = nsvc_by_ip4_elem(nse, ip4);
671 if (nsvc) {
672 /* the nsvc should be already in sync with the ip4 / ip6 elements */
673 return -NS_CAUSE_PROTO_ERR_UNSPEC;
674 }
675
676 /* TODO: failure case */
677 ns2_nsvc_create_ip4(fi, nse, ip4);
678 break;
679 case IPv6:
680 nsvc = nsvc_by_ip6_elem(nse, ip6);
681 if (nsvc) {
682 /* the nsvc should be already in sync with the ip4 / ip6 elements */
683 return -NS_CAUSE_PROTO_ERR_UNSPEC;
684 }
685
686 /* TODO: failure case */
687 ns2_nsvc_create_ip6(fi, nse, ip6);
688 break;
689 }
690
691 gprs_ns2_start_alive_all_nsvcs(nse);
692
693 return 0;
694}
695
696
697static void ns2_sns_st_unconfigured(struct osmo_fsm_inst *fi, uint32_t event, void *data)
698{
Alexander Couzense769f522020-12-07 07:37:07 +0100699 /* empty state - SNS Select will start by ns2_sns_st_all_action() */
Alexander Couzens6a161492020-07-12 13:45:50 +0200700}
701
702static void ns2_sns_st_size(struct osmo_fsm_inst *fi, uint32_t event, void *data)
703{
704 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
705 struct gprs_ns2_inst *nsi = nse->nsi;
706 struct tlv_parsed *tp = NULL;
707
708 switch (event) {
709 case GPRS_SNS_EV_SIZE_ACK:
710 tp = data;
711 if (TLVP_VAL_MINLEN(tp, NS_IE_CAUSE, 1)) {
712 LOGPFSML(fi, LOGL_ERROR, "SNS-SIZE-ACK with cause %s\n",
713 gprs_ns2_cause_str(*TLVP_VAL(tp, NS_IE_CAUSE)));
714 /* TODO: What to do? */
715 } else {
716 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIG_BSS,
717 nsi->timeout[NS_TOUT_TSNS_PROV], 2);
718 }
719 break;
720 default:
721 OSMO_ASSERT(0);
722 }
723}
724
Alexander Couzense769f522020-12-07 07:37:07 +0100725/* setup all dynamic SNS settings, create a new nsvc and send the SIZE */
Alexander Couzens6a161492020-07-12 13:45:50 +0200726static void ns2_sns_st_size_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
727{
728 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
Alexander Couzense769f522020-12-07 07:37:07 +0100729 struct gprs_ns_ie_ip4_elem *ip4_elems;
730 struct gprs_ns_ie_ip6_elem *ip6_elems;
731 struct gprs_ns2_vc_bind *bind;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100732 struct ns2_sns_bind *sbind;
Alexander Couzense769f522020-12-07 07:37:07 +0100733 struct osmo_sockaddr *remote;
734 const struct osmo_sockaddr *sa;
735 struct osmo_sockaddr local;
736 int count;
Alexander Couzens6a161492020-07-12 13:45:50 +0200737
Alexander Couzense769f522020-12-07 07:37:07 +0100738 /* on a generic failure, the timer callback will recover */
Alexander Couzens6a161492020-07-12 13:45:50 +0200739 if (old_state != GPRS_SNS_ST_UNCONFIGURED)
Alexander Couzens138b96f2021-01-25 16:23:29 +0100740 ns2_prim_status_ind(gss->nse, NULL, 0, GPRS_NS2_AFF_CAUSE_SNS_FAILURE);
Alexander Couzens790a9632021-02-05 17:18:39 +0100741 if (old_state != GPRS_SNS_ST_SIZE)
742 gss->N = 0;
743
Alexander Couzens6a161492020-07-12 13:45:50 +0200744
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100745 gss->alive = false;
Alexander Couzens7a7b20b2021-01-18 10:47:33 +0100746 ns2_clear_ipv46_entries(gss);
747
Alexander Couzense769f522020-12-07 07:37:07 +0100748 /* no initial available */
749 if (!gss->initial)
750 return;
751
752 remote = &gss->initial->saddr;
753
754 /* count how many bindings are available (only UDP binds) */
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100755 count = llist_count(&gss->binds);
Alexander Couzense769f522020-12-07 07:37:07 +0100756 if (count == 0) {
757 /* TODO: logging */
758 return;
759 }
760
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100761 /* take the first bind or take the next bind */
762 if (!gss->initial_bind) {
763 gss->initial_bind = llist_first_entry(&gss->binds, struct ns2_sns_bind, list);
764 } else {
765 if (gss->initial_bind->list.next != &gss->binds) {
766 gss->initial_bind = llist_entry(gss->initial_bind->list.next, struct ns2_sns_bind, list);
767 } else {
768 gss->initial_bind = llist_first_entry(&gss->binds, struct ns2_sns_bind, list);
Alexander Couzens81ae0aa2020-12-07 05:49:43 +0100769 }
Alexander Couzense769f522020-12-07 07:37:07 +0100770 }
771
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100772 bind = gss->initial_bind->bind;
773
Alexander Couzense769f522020-12-07 07:37:07 +0100774 /* setup the NSVC */
775 if (!gss->sns_nsvc) {
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100776 gss->sns_nsvc = ns2_ip_bind_connect(bind, gss->nse, remote);
Alexander Couzense769f522020-12-07 07:37:07 +0100777 if (!gss->sns_nsvc)
778 return;
779 gss->sns_nsvc->sns_only = true;
780 }
781
782 switch (gss->ip) {
783 case IPv4:
784 ip4_elems = talloc_zero_size(fi, sizeof(struct gprs_ns_ie_ip4_elem) * count);
785 if (!ip4_elems)
786 return;
787
788 gss->ip4_local = ip4_elems;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100789 llist_for_each_entry(sbind, &gss->binds, list) {
790 bind = sbind->bind;
Alexander Couzense769f522020-12-07 07:37:07 +0100791 sa = gprs_ns2_ip_bind_sockaddr(bind);
792 if (!sa)
793 continue;
794
795 if (sa->u.sas.ss_family != AF_INET)
796 continue;
797
798 /* check if this is an specific bind */
799 if (sa->u.sin.sin_addr.s_addr == 0) {
800 if (osmo_sockaddr_local_ip(&local, remote))
801 continue;
802
803 ip4_elems->ip_addr = local.u.sin.sin_addr.s_addr;
804 } else {
805 ip4_elems->ip_addr = sa->u.sin.sin_addr.s_addr;
806 }
807
808 ip4_elems->udp_port = sa->u.sin.sin_port;
Alexander Couzensc4704762021-02-08 23:13:12 +0100809 ip4_elems->sig_weight = bind->sns_sig_weight;
810 ip4_elems->data_weight = bind->sns_data_weight;
Alexander Couzense769f522020-12-07 07:37:07 +0100811 ip4_elems++;
812 }
813
814 gss->num_ip4_local = count;
815 gss->num_max_ip4_remote = 4;
816 gss->num_max_nsvcs = OSMO_MAX(gss->num_max_ip4_remote * gss->num_ip4_local, 8);
817 break;
818 case IPv6:
819 /* IPv6 */
820 ip6_elems = talloc_zero_size(fi, sizeof(struct gprs_ns_ie_ip6_elem) * count);
821 if (!ip6_elems)
822 return;
823
824 gss->ip6_local = ip6_elems;
825
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100826 llist_for_each_entry(sbind, &gss->binds, list) {
827 bind = sbind->bind;
Alexander Couzense769f522020-12-07 07:37:07 +0100828 sa = gprs_ns2_ip_bind_sockaddr(bind);
829 if (!sa)
830 continue;
831
832 if (sa->u.sas.ss_family != AF_INET6)
833 continue;
834
835 /* check if this is an specific bind */
836 if (IN6_IS_ADDR_UNSPECIFIED(&sa->u.sin6.sin6_addr)) {
837 if (osmo_sockaddr_local_ip(&local, remote))
838 continue;
839
840 ip6_elems->ip_addr = local.u.sin6.sin6_addr;
841 } else {
842 ip6_elems->ip_addr = sa->u.sin6.sin6_addr;
843 }
844
845 ip6_elems->udp_port = sa->u.sin.sin_port;
Alexander Couzensc4704762021-02-08 23:13:12 +0100846 ip6_elems->sig_weight = bind->sns_sig_weight;
847 ip6_elems->data_weight = bind->sns_data_weight;
Alexander Couzense769f522020-12-07 07:37:07 +0100848
849 ip6_elems++;
850 }
851 gss->num_ip6_local = count;
852 gss->num_max_ip6_remote = 4;
853 gss->num_max_nsvcs = OSMO_MAX(gss->num_max_ip6_remote * gss->num_ip6_local, 8);
854 break;
855 }
856
Alexander Couzens6a161492020-07-12 13:45:50 +0200857 if (gss->num_max_ip4_remote > 0)
858 ns2_tx_sns_size(gss->sns_nsvc, true, gss->num_max_nsvcs, gss->num_max_ip4_remote, -1);
859 else
860 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 +0200861}
862
863static void ns2_sns_st_config_bss(struct osmo_fsm_inst *fi, uint32_t event, void *data)
864{
865 struct tlv_parsed *tp = NULL;
Alexander Couzens3df58862021-02-05 17:18:08 +0100866 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
Alexander Couzens6a161492020-07-12 13:45:50 +0200867
868 switch (event) {
869 case GPRS_SNS_EV_CONFIG_ACK:
870 tp = (struct tlv_parsed *) data;
871 if (TLVP_VAL_MINLEN(tp, NS_IE_CAUSE, 1)) {
872 LOGPFSML(fi, LOGL_ERROR, "SNS-CONFIG-ACK with cause %s\n",
873 gprs_ns2_cause_str(*TLVP_VAL(tp, NS_IE_CAUSE)));
874 /* TODO: What to do? */
875 } else {
Alexander Couzens3df58862021-02-05 17:18:08 +0100876 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 +0200877 }
878 break;
879 default:
880 OSMO_ASSERT(0);
881 }
882}
883
884static void ns2_sns_st_config_bss_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
885{
886 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
Alexander Couzens790a9632021-02-05 17:18:39 +0100887
888 if (old_state != GPRS_SNS_ST_CONFIG_BSS)
889 gss->N = 0;
890
Alexander Couzens6a161492020-07-12 13:45:50 +0200891 /* Transmit SNS-CONFIG */
Alexander Couzens6a161492020-07-12 13:45:50 +0200892 switch (gss->ip) {
893 case IPv4:
894 ns2_tx_sns_config(gss->sns_nsvc, true,
Alexander Couzense78207f2020-12-07 06:19:29 +0100895 gss->ip4_local, gss->num_ip4_local,
896 NULL, 0);
Alexander Couzens6a161492020-07-12 13:45:50 +0200897 break;
898 case IPv6:
899 ns2_tx_sns_config(gss->sns_nsvc, true,
Alexander Couzense78207f2020-12-07 06:19:29 +0100900 NULL, 0,
901 gss->ip6_local, gss->num_ip6_local);
Alexander Couzens6a161492020-07-12 13:45:50 +0200902 break;
903 }
904}
905
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100906/* calculate the timeout of the configured state. the configured
907 * state will fail if not at least one NS-VC is alive within X second.
908 */
909static inline int ns_sns_configured_timeout(struct osmo_fsm_inst *fi)
910{
911 int secs;
912 struct gprs_ns2_inst *nsi = nse_inst_from_fi(fi)->nsi;
913 secs = nsi->timeout[NS_TOUT_TNS_ALIVE] * nsi->timeout[NS_TOUT_TNS_ALIVE_RETRIES];
914 secs += nsi->timeout[NS_TOUT_TNS_TEST];
915
916 return secs;
917}
Alexander Couzens6a161492020-07-12 13:45:50 +0200918
919static void ns_sns_st_config_sgsn_ip4(struct osmo_fsm_inst *fi, uint32_t event, void *data)
920{
921 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
922 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
923 const struct gprs_ns_ie_ip4_elem *v4_list;
924 unsigned int num_v4;
925 struct tlv_parsed *tp = NULL;
926
927 uint8_t cause;
928
929 tp = (struct tlv_parsed *) data;
930
931 if (!TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
932 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
933 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
934 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
935 return;
936 }
937 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
938 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
939 /* realloc to the new size */
940 gss->ip4_remote = talloc_realloc(gss, gss->ip4_remote,
941 struct gprs_ns_ie_ip4_elem,
942 gss->num_ip4_remote+num_v4);
943 /* append the new entries to the end of the list */
944 memcpy(&gss->ip4_remote[gss->num_ip4_remote], v4_list, num_v4*sizeof(*v4_list));
945 gss->num_ip4_remote += num_v4;
946
947 LOGPFSML(fi, LOGL_INFO, "Rx SNS-CONFIG: Remote IPv4 list now %u entries\n",
948 gss->num_ip4_remote);
949 if (event == GPRS_SNS_EV_CONFIG_END) {
950 /* check if sum of data / sig weights == 0 */
951 if (ip4_weight_sum_data(gss->ip4_remote, gss->num_ip4_remote) == 0 ||
952 ip4_weight_sum_sig(gss->ip4_remote, gss->num_ip4_remote) == 0) {
953 cause = NS_CAUSE_INVAL_WEIGH;
954 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
955 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
956 return;
957 }
958 create_missing_nsvcs(fi);
959 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
960 /* start the test procedure on ALL NSVCs! */
961 gprs_ns2_start_alive_all_nsvcs(nse);
Alexander Couzens3df58862021-02-05 17:18:08 +0100962 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIGURED, ns_sns_configured_timeout(fi), 4);
Alexander Couzens6a161492020-07-12 13:45:50 +0200963 } else {
964 /* just send CONFIG-ACK */
965 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
Alexander Couzens3df58862021-02-05 17:18:08 +0100966 osmo_timer_schedule(&fi->timer, nse->nsi->timeout[NS_TOUT_TSNS_PROV], 0);
Alexander Couzens6a161492020-07-12 13:45:50 +0200967 }
968}
969
970static void ns_sns_st_config_sgsn_ip6(struct osmo_fsm_inst *fi, uint32_t event, void *data)
971{
972 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
973 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
974 const struct gprs_ns_ie_ip6_elem *v6_list;
975 unsigned int num_v6;
976 struct tlv_parsed *tp = NULL;
977
978 uint8_t cause;
979
980 tp = (struct tlv_parsed *) data;
981
982 if (!TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
983 cause = NS_CAUSE_INVAL_NR_IPv6_EP;
984 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
985 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
986 return;
987 }
988 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
989 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
990 /* realloc to the new size */
991 gss->ip6_remote = talloc_realloc(gss, gss->ip6_remote,
992 struct gprs_ns_ie_ip6_elem,
993 gss->num_ip6_remote+num_v6);
994 /* append the new entries to the end of the list */
995 memcpy(&gss->ip6_remote[gss->num_ip6_remote], v6_list, num_v6*sizeof(*v6_list));
996 gss->num_ip6_remote += num_v6;
997
998 LOGPFSML(fi, LOGL_INFO, "Rx SNS-CONFIG: Remote IPv6 list now %u entries\n",
999 gss->num_ip6_remote);
1000 if (event == GPRS_SNS_EV_CONFIG_END) {
1001 /* check if sum of data / sig weights == 0 */
1002 if (ip6_weight_sum_data(gss->ip6_remote, gss->num_ip6_remote) == 0 ||
1003 ip6_weight_sum_sig(gss->ip6_remote, gss->num_ip6_remote) == 0) {
1004 cause = NS_CAUSE_INVAL_WEIGH;
1005 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
1006 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
1007 return;
1008 }
1009 create_missing_nsvcs(fi);
1010 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
1011 /* start the test procedure on ALL NSVCs! */
1012 gprs_ns2_start_alive_all_nsvcs(nse);
1013 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIGURED, 0, 0);
1014 } else {
1015 /* just send CONFIG-ACK */
1016 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
Alexander Couzens790a9632021-02-05 17:18:39 +01001017 osmo_timer_schedule(&fi->timer, nse->nsi->timeout[NS_TOUT_TSNS_PROV], 0);
Alexander Couzens6a161492020-07-12 13:45:50 +02001018 }
1019}
1020
Alexander Couzens790a9632021-02-05 17:18:39 +01001021static void ns2_sns_st_config_sgsn_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
1022{
1023 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
1024
1025 if (old_state != GPRS_SNS_ST_CONFIG_SGSN)
1026 gss->N = 0;
1027}
1028
Alexander Couzens6a161492020-07-12 13:45:50 +02001029static void ns2_sns_st_config_sgsn(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1030{
1031 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
1032
1033 switch (event) {
1034 case GPRS_SNS_EV_CONFIG_END:
1035 case GPRS_SNS_EV_CONFIG:
1036
1037#if 0 /* part of incoming SNS-SIZE (doesn't happen on BSS side */
1038 if (TLVP_PRESENT(tp, NS_IE_RESET_FLAG)) {
1039 /* reset all existing config */
1040 if (gss->ip4_remote)
1041 talloc_free(gss->ip4_remote);
1042 gss->num_ip4_remote = 0;
1043 }
1044#endif
1045 /* TODO: reject IPv6 elements on IPv4 mode and vice versa */
1046 switch (gss->ip) {
1047 case IPv4:
1048 ns_sns_st_config_sgsn_ip4(fi, event, data);
1049 break;
1050 case IPv6:
1051 ns_sns_st_config_sgsn_ip6(fi, event, data);
1052 break;
1053 default:
1054 OSMO_ASSERT(0);
1055 }
1056 break;
1057 default:
1058 OSMO_ASSERT(0);
1059 }
1060}
1061
1062/* called when receiving GPRS_SNS_EV_ADD in state configure */
1063static void ns2_sns_st_configured_add(struct osmo_fsm_inst *fi,
1064 struct ns2_sns_state *gss,
1065 struct tlv_parsed *tp)
1066{
1067 const struct gprs_ns_ie_ip4_elem *v4_list = NULL;
1068 const struct gprs_ns_ie_ip6_elem *v6_list = NULL;
1069 int num_v4 = 0, num_v6 = 0;
1070 uint8_t trans_id, cause = 0xff;
Harald Welte7da6ace2020-09-18 09:48:05 +02001071 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +02001072 int rc = 0;
1073
1074 /* TODO: refactor EV_ADD/CHANGE/REMOVE by
1075 * check uniqueness within the lists (no doublicate entries)
1076 * check not-known-by-us and sent back a list of unknown/known values
1077 * (abnormal behaviour according to 48.016)
1078 */
1079
1080 trans_id = *TLVP_VAL(tp, NS_IE_TRANS_ID);
1081 if (gss->ip == IPv4) {
1082 if (!TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
1083 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
1084 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1085 return;
1086 }
1087
1088 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
1089 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001090 for (i = 0; i < num_v4; i++) {
1091 unsigned int j;
Alexander Couzens6a161492020-07-12 13:45:50 +02001092 rc = do_sns_add(fi, &v4_list[i], NULL);
1093 if (rc < 0) {
1094 /* rollback/undo to restore previous state */
Harald Welte7da6ace2020-09-18 09:48:05 +02001095 for (j = 0; j < i; j++)
Alexander Couzens6a161492020-07-12 13:45:50 +02001096 do_sns_delete(fi, &v4_list[j], NULL);
1097 cause = -rc;
1098 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1099 break;
1100 }
1101 }
1102 } else { /* IPv6 */
1103 if (!TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
1104 cause = NS_CAUSE_INVAL_NR_IPv6_EP;
1105 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1106 return;
1107 }
1108
1109 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
1110 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001111 for (i = 0; i < num_v6; i++) {
1112 unsigned int j;
Alexander Couzens6a161492020-07-12 13:45:50 +02001113 rc = do_sns_add(fi, NULL, &v6_list[i]);
1114 if (rc < 0) {
1115 /* rollback/undo to restore previous state */
Harald Welte7da6ace2020-09-18 09:48:05 +02001116 for (j = 0; j < i; j++)
Alexander Couzens6a161492020-07-12 13:45:50 +02001117 do_sns_delete(fi, NULL, &v6_list[j]);
1118 cause = -rc;
1119 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1120 break;
1121 }
1122 }
1123 }
1124
1125 /* TODO: correct behaviour is to answer to the *same* NSVC from which the SNS_ADD was received */
1126 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, NULL, v4_list, num_v4, v6_list, num_v6);
1127}
1128
1129static void ns2_sns_st_configured_delete(struct osmo_fsm_inst *fi,
1130 struct ns2_sns_state *gss,
1131 struct tlv_parsed *tp)
1132{
1133 const struct gprs_ns_ie_ip4_elem *v4_list = NULL;
1134 const struct gprs_ns_ie_ip6_elem *v6_list = NULL;
1135 int num_v4 = 0, num_v6 = 0;
1136 uint8_t trans_id, cause = 0xff;
Harald Welte7da6ace2020-09-18 09:48:05 +02001137 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +02001138 int rc = 0;
1139
1140 /* TODO: split up delete into v4 + v6
1141 * TODO: check if IPv4_LIST or IP_ADDR(v4) is present on IPv6 and vice versa
1142 * TODO: check if IPv4_LIST/IPv6_LIST and IP_ADDR is present at the same time
1143 */
1144 trans_id = *TLVP_VAL(tp, NS_IE_TRANS_ID);
1145 if (gss->ip == IPv4) {
1146 if (TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
1147 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
1148 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001149 for ( i = 0; i < num_v4; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001150 rc = do_sns_delete(fi, &v4_list[i], NULL);
1151 if (rc < 0) {
1152 cause = -rc;
1153 /* continue to delete others */
1154 }
1155 }
1156 if (cause != 0xff) {
1157 /* TODO: create list of not-deleted and return it */
1158 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1159 return;
1160 }
1161
1162 } else if (TLVP_PRESENT(tp, NS_IE_IP_ADDR) && TLVP_LEN(tp, NS_IE_IP_ADDR) == 5) {
1163 /* delete all NS-VCs for given IPv4 address */
1164 const uint8_t *ie = TLVP_VAL(tp, NS_IE_IP_ADDR);
1165 struct gprs_ns_ie_ip4_elem *ip4_remote;
1166 uint32_t ip_addr = *(uint32_t *)(ie+1);
1167 if (ie[0] != 0x01) { /* Address Type != IPv4 */
1168 cause = NS_CAUSE_UNKN_IP_ADDR;
1169 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1170 return;
1171 }
1172 /* make a copy as do_sns_delete() will change the array underneath us */
1173 ip4_remote = talloc_memdup(fi, gss->ip4_remote,
1174 gss->num_ip4_remote * sizeof(*v4_list));
Harald Welte7da6ace2020-09-18 09:48:05 +02001175 for (i = 0; i < gss->num_ip4_remote; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001176 if (ip4_remote[i].ip_addr == ip_addr) {
1177 rc = do_sns_delete(fi, &ip4_remote[i], NULL);
1178 if (rc < 0) {
1179 cause = -rc;
1180 /* continue to delete others */
1181 }
1182 }
1183 }
1184 talloc_free(ip4_remote);
1185 if (cause != 0xff) {
1186 /* TODO: create list of not-deleted and return it */
1187 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1188 return;
1189 }
1190 } else {
1191 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
1192 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1193 return;
1194 }
1195 } else { /* IPv6 */
1196 if (TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
1197 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
1198 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001199 for (i = 0; i < num_v6; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001200 rc = do_sns_delete(fi, NULL, &v6_list[i]);
1201 if (rc < 0) {
1202 cause = -rc;
1203 /* continue to delete others */
1204 }
1205 }
1206 if (cause != 0xff) {
1207 /* TODO: create list of not-deleted and return it */
1208 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1209 return;
1210 }
1211 } else if (TLVP_PRES_LEN(tp, NS_IE_IP_ADDR, 17)) {
1212 /* delete all NS-VCs for given IPv4 address */
1213 const uint8_t *ie = TLVP_VAL(tp, NS_IE_IP_ADDR);
1214 struct gprs_ns_ie_ip6_elem *ip6_remote;
1215 struct in6_addr ip6_addr;
Harald Welte7da6ace2020-09-18 09:48:05 +02001216 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +02001217 if (ie[0] != 0x02) { /* Address Type != IPv6 */
1218 cause = NS_CAUSE_UNKN_IP_ADDR;
1219 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1220 return;
1221 }
1222 memcpy(&ip6_addr, (ie+1), sizeof(struct in6_addr));
1223 /* make a copy as do_sns_delete() will change the array underneath us */
1224 ip6_remote = talloc_memdup(fi, gss->ip6_remote,
1225 gss->num_ip6_remote * sizeof(*v4_list));
Harald Welte7da6ace2020-09-18 09:48:05 +02001226 for (i = 0; i < gss->num_ip6_remote; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001227 if (!memcmp(&ip6_remote[i].ip_addr, &ip6_addr, sizeof(struct in6_addr))) {
1228 rc = do_sns_delete(fi, NULL, &ip6_remote[i]);
1229 if (rc < 0) {
1230 cause = -rc;
1231 /* continue to delete others */
1232 }
1233 }
1234 }
1235
1236 talloc_free(ip6_remote);
1237 if (cause != 0xff) {
1238 /* TODO: create list of not-deleted and return it */
1239 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1240 return;
1241 }
1242 } else {
1243 cause = NS_CAUSE_INVAL_NR_IPv6_EP;
1244 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1245 return;
1246 }
1247 }
1248 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, NULL, v4_list, num_v4, v6_list, num_v6);
1249}
1250
1251static void ns2_sns_st_configured_change(struct osmo_fsm_inst *fi,
1252 struct ns2_sns_state *gss,
1253 struct tlv_parsed *tp)
1254{
1255 const struct gprs_ns_ie_ip4_elem *v4_list = NULL;
1256 const struct gprs_ns_ie_ip6_elem *v6_list = NULL;
1257 int num_v4 = 0, num_v6 = 0;
1258 uint8_t trans_id, cause = 0xff;
1259 int rc = 0;
Harald Welte7da6ace2020-09-18 09:48:05 +02001260 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +02001261
1262 trans_id = *TLVP_VAL(tp, NS_IE_TRANS_ID);
1263 if (TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
1264 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
1265 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001266 for (i = 0; i < num_v4; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001267 rc = do_sns_change_weight(fi, &v4_list[i], NULL);
1268 if (rc < 0) {
1269 cause = -rc;
1270 /* continue to others */
1271 }
1272 }
1273 if (cause != 0xff) {
1274 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1275 return;
1276 }
1277 } else if (TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
1278 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
1279 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001280 for (i = 0; i < num_v6; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001281 rc = do_sns_change_weight(fi, NULL, &v6_list[i]);
1282 if (rc < 0) {
1283 cause = -rc;
1284 /* continue to others */
1285 }
1286 }
1287 if (cause != 0xff) {
1288 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1289 return;
1290 }
1291 } else {
1292 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
1293 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1294 return;
1295 }
1296 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, NULL, v4_list, num_v4, v6_list, num_v6);
1297}
1298
1299static void ns2_sns_st_configured(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1300{
1301 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
1302 struct tlv_parsed *tp = data;
1303
1304 switch (event) {
1305 case GPRS_SNS_EV_ADD:
1306 ns2_sns_st_configured_add(fi, gss, tp);
1307 break;
1308 case GPRS_SNS_EV_DELETE:
1309 ns2_sns_st_configured_delete(fi, gss, tp);
1310 break;
1311 case GPRS_SNS_EV_CHANGE_WEIGHT:
1312 ns2_sns_st_configured_change(fi, gss, tp);
1313 break;
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01001314 case GPRS_SNS_EV_NSVC_ALIVE:
1315 osmo_timer_del(&fi->timer);
1316 break;
Alexander Couzens6a161492020-07-12 13:45:50 +02001317 }
1318}
1319
1320static void ns2_sns_st_configured_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
1321{
1322 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
Alexander Couzens138b96f2021-01-25 16:23:29 +01001323 ns2_prim_status_ind(nse, NULL, 0, GPRS_NS2_AFF_CAUSE_SNS_CONFIGURED);
Alexander Couzens6a161492020-07-12 13:45:50 +02001324}
1325
1326static const struct osmo_fsm_state ns2_sns_bss_states[] = {
1327 [GPRS_SNS_ST_UNCONFIGURED] = {
Alexander Couzense769f522020-12-07 07:37:07 +01001328 .in_event_mask = 0, /* handled by all_state_action */
Alexander Couzens6a161492020-07-12 13:45:50 +02001329 .out_state_mask = S(GPRS_SNS_ST_SIZE),
1330 .name = "UNCONFIGURED",
1331 .action = ns2_sns_st_unconfigured,
1332 },
1333 [GPRS_SNS_ST_SIZE] = {
1334 .in_event_mask = S(GPRS_SNS_EV_SIZE_ACK),
1335 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
1336 S(GPRS_SNS_ST_SIZE) |
1337 S(GPRS_SNS_ST_CONFIG_BSS),
1338 .name = "SIZE",
1339 .action = ns2_sns_st_size,
1340 .onenter = ns2_sns_st_size_onenter,
1341 },
1342 [GPRS_SNS_ST_CONFIG_BSS] = {
1343 .in_event_mask = S(GPRS_SNS_EV_CONFIG_ACK),
1344 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
1345 S(GPRS_SNS_ST_CONFIG_BSS) |
1346 S(GPRS_SNS_ST_CONFIG_SGSN) |
1347 S(GPRS_SNS_ST_SIZE),
1348 .name = "CONFIG_BSS",
1349 .action = ns2_sns_st_config_bss,
1350 .onenter = ns2_sns_st_config_bss_onenter,
1351 },
1352 [GPRS_SNS_ST_CONFIG_SGSN] = {
1353 .in_event_mask = S(GPRS_SNS_EV_CONFIG) |
1354 S(GPRS_SNS_EV_CONFIG_END),
1355 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
1356 S(GPRS_SNS_ST_CONFIG_SGSN) |
1357 S(GPRS_SNS_ST_CONFIGURED) |
1358 S(GPRS_SNS_ST_SIZE),
1359 .name = "CONFIG_SGSN",
1360 .action = ns2_sns_st_config_sgsn,
Alexander Couzens790a9632021-02-05 17:18:39 +01001361 .onenter = ns2_sns_st_config_sgsn_onenter,
Alexander Couzens6a161492020-07-12 13:45:50 +02001362 },
1363 [GPRS_SNS_ST_CONFIGURED] = {
1364 .in_event_mask = S(GPRS_SNS_EV_ADD) |
1365 S(GPRS_SNS_EV_DELETE) |
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01001366 S(GPRS_SNS_EV_CHANGE_WEIGHT) |
1367 S(GPRS_SNS_EV_NSVC_ALIVE),
Alexander Couzense03d8632020-12-06 03:31:44 +01001368 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
1369 S(GPRS_SNS_ST_SIZE),
Alexander Couzens6a161492020-07-12 13:45:50 +02001370 .name = "CONFIGURED",
1371 .action = ns2_sns_st_configured,
1372 .onenter = ns2_sns_st_configured_onenter,
1373 },
1374};
1375
1376static int ns2_sns_fsm_bss_timer_cb(struct osmo_fsm_inst *fi)
1377{
Alexander Couzens90ee9632020-12-07 06:18:32 +01001378 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
Alexander Couzens6a161492020-07-12 13:45:50 +02001379 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
1380 struct gprs_ns2_inst *nsi = nse->nsi;
1381
Alexander Couzens90ee9632020-12-07 06:18:32 +01001382 gss->N++;
Alexander Couzens6a161492020-07-12 13:45:50 +02001383 switch (fi->T) {
1384 case 1:
Alexander Couzensa367d082020-12-21 14:06:24 +01001385 if (gss->N >= nsi->timeout[NS_TOUT_TSNS_SIZE_RETRIES]) {
1386 LOGPFSML(fi, LOGL_ERROR, "NSE %d: Size 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_SIZE, nsi->timeout[NS_TOUT_TSNS_PROV], 1);
Alexander Couzensa367d082020-12-21 14:06:24 +01001390 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001391 break;
1392 case 2:
Alexander Couzensa367d082020-12-21 14:06:24 +01001393 if (gss->N >= nsi->timeout[NS_TOUT_TSNS_CONFIG_RETRIES]) {
Alexander Couzens3df58862021-02-05 17:18:08 +01001394 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 +01001395 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_SELECT_ENDPOINT, NULL);
Alexander Couzensa367d082020-12-21 14:06:24 +01001396 } else {
Alexander Couzenscc65a252020-12-21 14:03:58 +01001397 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 +01001398 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001399 break;
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01001400 case 3:
Alexander Couzens3df58862021-02-05 17:18:08 +01001401 if (gss->N >= nsi->timeout[NS_TOUT_TSNS_CONFIG_RETRIES]) {
1402 LOGPFSML(fi, LOGL_ERROR, "NSE %d: SGSN Config retries failed. Selecting next IP-SNS endpoint.\n", nse->nsei);
1403 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_SELECT_ENDPOINT, NULL);
1404 } else {
1405 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIG_SGSN, nsi->timeout[NS_TOUT_TSNS_PROV], 3);
1406 }
1407 break;
1408 case 4:
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01001409 LOGPFSML(fi, LOGL_ERROR, "NSE %d: Config succeeded but no NS-VC came online. Selecting next IP-SNS endpoint.\n", nse->nsei);
1410 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_SELECT_ENDPOINT, NULL);
1411 break;
Alexander Couzens6a161492020-07-12 13:45:50 +02001412 }
1413 return 0;
1414}
1415
1416static void ns2_sns_st_all_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1417{
Alexander Couzense769f522020-12-07 07:37:07 +01001418 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
Alexander Couzens6a161492020-07-12 13:45:50 +02001419 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001420 struct ns2_sns_bind *sbind;
1421 struct gprs_ns2_vc *nsvc, *nsvc2;
Alexander Couzens6a161492020-07-12 13:45:50 +02001422
1423 /* reset when receiving GPRS_SNS_EV_NO_NSVC */
Alexander Couzense769f522020-12-07 07:37:07 +01001424 switch (event) {
1425 case GPRS_SNS_EV_NO_NSVC:
Alexander Couzens3ad73362020-12-21 13:53:00 +01001426 /* ignore reselection running */
1427 if (gss->reselection_running)
1428 break;
1429
1430 LOGPFSML(fi, LOGL_ERROR, "NSE %d: no remaining NSVC, resetting SNS FSM\n", nse->nsei);
1431 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_SELECT_ENDPOINT, NULL);
Alexander Couzense769f522020-12-07 07:37:07 +01001432 break;
1433 case GPRS_SNS_EV_SELECT_ENDPOINT:
1434 /* tear down previous state
1435 * gprs_ns2_free_nsvcs() will trigger NO_NSVC, prevent this from triggering a reselection */
1436 gss->reselection_running = true;
1437 gprs_ns2_free_nsvcs(nse);
Alexander Couzens7a7b20b2021-01-18 10:47:33 +01001438 ns2_clear_ipv46_entries(gss);
Alexander Couzense769f522020-12-07 07:37:07 +01001439
1440 /* Choose the next sns endpoint. */
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001441 if (llist_empty(&gss->sns_endpoints) || llist_empty(&gss->binds)) {
Alexander Couzense769f522020-12-07 07:37:07 +01001442 gss->initial = NULL;
Alexander Couzens138b96f2021-01-25 16:23:29 +01001443 ns2_prim_status_ind(gss->nse, NULL, 0, GPRS_NS2_AFF_CAUSE_SNS_NO_ENDPOINTS);
Alexander Couzense769f522020-12-07 07:37:07 +01001444 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 3);
1445 return;
1446 } else if (!gss->initial) {
1447 gss->initial = llist_first_entry(&gss->sns_endpoints, struct sns_endpoint, list);
1448 } else if (gss->initial->list.next == &gss->sns_endpoints) {
1449 /* last entry, continue with first */
1450 gss->initial = llist_first_entry(&gss->sns_endpoints, struct sns_endpoint, list);
1451 } else {
1452 /* next element is an entry */
1453 gss->initial = llist_entry(gss->initial->list.next, struct sns_endpoint, list);
1454 }
1455
1456 gss->reselection_running = false;
1457 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_SIZE, nse->nsi->timeout[NS_TOUT_TSNS_PROV], 1);
1458 break;
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001459 case GPRS_SNS_EV_REQ_ADD_BIND:
1460 sbind = data;
1461 switch (fi->state) {
1462 case GPRS_SNS_ST_UNCONFIGURED:
1463 osmo_fsm_inst_dispatch(nse->bss_sns_fi, GPRS_SNS_EV_SELECT_ENDPOINT, NULL);
1464 break;
1465 case GPRS_SNS_ST_SIZE:
1466 /* TODO: add the ip4 element to the list */
1467 break;
1468 case GPRS_SNS_ST_CONFIG_BSS:
1469 case GPRS_SNS_ST_CONFIG_SGSN:
1470 case GPRS_SNS_ST_CONFIGURED:
1471 /* TODO: add to SNS-IP procedure queue & add nsvc() */
1472 break;
1473 }
1474 break;
1475 case GPRS_SNS_EV_REQ_DELETE_BIND:
1476 sbind = data;
1477 switch (fi->state) {
1478 case GPRS_SNS_ST_UNCONFIGURED:
1479 break;
1480 case GPRS_SNS_ST_SIZE:
1481 /* TODO: remove the ip4 element from the list */
1482 llist_for_each_entry_safe(nsvc, nsvc2, &nse->nsvc, list) {
1483 if (nsvc->bind == sbind->bind) {
1484 gprs_ns2_free_nsvc(nsvc);
1485 }
1486 }
1487 break;
1488 case GPRS_SNS_ST_CONFIG_BSS:
1489 case GPRS_SNS_ST_CONFIG_SGSN:
1490 case GPRS_SNS_ST_CONFIGURED:
1491 /* TODO: do an delete SNS-IP procedure */
1492 /* TODO: remove the ip4 element to the list */
1493 llist_for_each_entry_safe(nsvc, nsvc2, &nse->nsvc, list) {
1494 if (nsvc->bind == sbind->bind) {
1495 gprs_ns2_free_nsvc(nsvc);
1496 }
1497 }
1498 break;
1499 }
1500 /* if this is the last bind, the free_nsvc() will trigger a reselection */
1501 talloc_free(sbind);
1502 break;
Alexander Couzense769f522020-12-07 07:37:07 +01001503 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001504}
1505
1506static struct osmo_fsm gprs_ns2_sns_bss_fsm = {
1507 .name = "GPRS-NS2-SNS-BSS",
1508 .states = ns2_sns_bss_states,
1509 .num_states = ARRAY_SIZE(ns2_sns_bss_states),
Alexander Couzense769f522020-12-07 07:37:07 +01001510 .allstate_event_mask = S(GPRS_SNS_EV_NO_NSVC) |
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001511 S(GPRS_SNS_EV_SELECT_ENDPOINT) |
1512 S(GPRS_SNS_EV_REQ_ADD_BIND) |
1513 S(GPRS_SNS_EV_REQ_DELETE_BIND),
Alexander Couzens6a161492020-07-12 13:45:50 +02001514 .allstate_action = ns2_sns_st_all_action,
1515 .cleanup = NULL,
1516 .timer_cb = ns2_sns_fsm_bss_timer_cb,
1517 /* .log_subsys = DNS, "is not constant" */
1518 .event_names = gprs_sns_event_names,
1519 .pre_term = NULL,
1520 .log_subsys = DLNS,
1521};
1522
Harald Welte5bef2cc2020-09-18 22:33:24 +02001523/*! Allocate an IP-SNS FSM for the BSS side.
1524 * \param[in] nse NS Entity in which the FSM runs
1525 * \param[in] id string identifier
Alexander Couzens23aec352021-02-15 05:05:15 +01001526 * \returns FSM instance on success; NULL on error */
Alexander Couzens6a161492020-07-12 13:45:50 +02001527struct osmo_fsm_inst *ns2_sns_bss_fsm_alloc(struct gprs_ns2_nse *nse,
1528 const char *id)
1529{
1530 struct osmo_fsm_inst *fi;
1531 struct ns2_sns_state *gss;
1532
1533 fi = osmo_fsm_inst_alloc(&gprs_ns2_sns_bss_fsm, nse, NULL, LOGL_DEBUG, id);
1534 if (!fi)
1535 return fi;
1536
1537 gss = talloc_zero(fi, struct ns2_sns_state);
1538 if (!gss)
1539 goto err;
1540
1541 fi->priv = gss;
1542 gss->nse = nse;
Alexander Couzense769f522020-12-07 07:37:07 +01001543 INIT_LLIST_HEAD(&gss->sns_endpoints);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001544 INIT_LLIST_HEAD(&gss->binds);
Alexander Couzens6a161492020-07-12 13:45:50 +02001545
1546 return fi;
1547err:
1548 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
1549 return NULL;
1550}
1551
Harald Welte5bef2cc2020-09-18 22:33:24 +02001552/*! main entry point for receiving SNS messages from the network.
1553 * \param[in] nsvc NS-VC on which the message was received
1554 * \param[in] msg message buffer of the IP-SNS message
1555 * \param[in] tp parsed TLV structure of message
Alexander Couzens23aec352021-02-15 05:05:15 +01001556 * \returns 0 on success; negative on error */
Alexander Couzens8dfc24c2021-01-25 16:09:23 +01001557int ns2_sns_rx(struct gprs_ns2_vc *nsvc, struct msgb *msg, struct tlv_parsed *tp)
Alexander Couzens6a161492020-07-12 13:45:50 +02001558{
1559 struct gprs_ns2_nse *nse = nsvc->nse;
1560 struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h;
1561 uint16_t nsei = nsvc->nse->nsei;
1562 struct osmo_fsm_inst *fi;
1563
1564 if (!nse->bss_sns_fi) {
Harald Weltef2949742021-01-20 14:54:14 +01001565 LOGNSVC(nsvc, LOGL_NOTICE, "Rx %s for NS Instance that has no SNS!\n",
1566 get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
Alexander Couzens6a161492020-07-12 13:45:50 +02001567 return -EINVAL;
1568 }
1569
Alexander Couzens6a161492020-07-12 13:45:50 +02001570 /* FIXME: how to resolve SNS FSM Instance by NSEI (SGSN)? */
1571 fi = nse->bss_sns_fi;
1572
Harald Weltef2949742021-01-20 14:54:14 +01001573 LOGPFSML(fi, LOGL_DEBUG, "NSEI=%u Rx SNS PDU type %s\n", nsei,
1574 get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
1575
Alexander Couzens6a161492020-07-12 13:45:50 +02001576 switch (nsh->pdu_type) {
1577 case SNS_PDUT_SIZE:
1578 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_SIZE, tp);
1579 break;
1580 case SNS_PDUT_SIZE_ACK:
1581 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_SIZE_ACK, tp);
1582 break;
1583 case SNS_PDUT_CONFIG:
1584 if (nsh->data[0] & 0x01)
1585 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_CONFIG_END, tp);
1586 else
1587 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_CONFIG, tp);
1588 break;
1589 case SNS_PDUT_CONFIG_ACK:
1590 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_CONFIG_ACK, tp);
1591 break;
1592 case SNS_PDUT_ADD:
1593 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_ADD, tp);
1594 break;
1595 case SNS_PDUT_DELETE:
1596 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_DELETE, tp);
1597 break;
1598 case SNS_PDUT_CHANGE_WEIGHT:
1599 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_CHANGE_WEIGHT, tp);
1600 break;
1601 case SNS_PDUT_ACK:
Harald Weltef2949742021-01-20 14:54:14 +01001602 LOGPFSML(fi, LOGL_NOTICE, "NSEI=%u Rx unsupported SNS PDU type %s\n", nsei,
1603 get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
Alexander Couzens6a161492020-07-12 13:45:50 +02001604 break;
1605 default:
Harald Weltef2949742021-01-20 14:54:14 +01001606 LOGPFSML(fi, LOGL_ERROR, "NSEI=%u Rx unknown SNS PDU type %s\n", nsei,
1607 get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
Alexander Couzens6a161492020-07-12 13:45:50 +02001608 return -EINVAL;
1609 }
1610
1611 return 0;
1612}
1613
1614#include <osmocom/vty/vty.h>
1615#include <osmocom/vty/misc.h>
1616
Harald Welte1262c4f2021-01-19 20:58:33 +01001617static 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 +02001618{
1619 struct in_addr in = { .s_addr = ip4->ip_addr };
Harald Welte1262c4f2021-01-19 20:58:33 +01001620 vty_out(vty, "%s %s:%u, Signalling Weight: %u, Data Weight: %u%s", prefix,
Alexander Couzens6a161492020-07-12 13:45:50 +02001621 inet_ntoa(in), ntohs(ip4->udp_port), ip4->sig_weight, ip4->data_weight, VTY_NEWLINE);
1622}
1623
Harald Welte1262c4f2021-01-19 20:58:33 +01001624static 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 +02001625{
1626 char ip_addr[INET6_ADDRSTRLEN] = {};
1627 if (!inet_ntop(AF_INET6, &ip6->ip_addr, ip_addr, (INET6_ADDRSTRLEN)))
1628 strcpy(ip_addr, "Invalid IPv6");
1629
Harald Welte1262c4f2021-01-19 20:58:33 +01001630 vty_out(vty, "%s %s:%u, Signalling Weight: %u, Data Weight: %u%s", prefix,
Alexander Couzens6a161492020-07-12 13:45:50 +02001631 ip_addr, ntohs(ip6->udp_port), ip6->sig_weight, ip6->data_weight, VTY_NEWLINE);
1632}
1633
Harald Welte5bef2cc2020-09-18 22:33:24 +02001634/*! Dump the IP-SNS state to a vty.
1635 * \param[in] vty VTY to which the state shall be printed
Harald Welte1262c4f2021-01-19 20:58:33 +01001636 * \param[in] prefix prefix to print at start of each line (typically indenting)
Harald Welte5bef2cc2020-09-18 22:33:24 +02001637 * \param[in] nse NS Entity whose IP-SNS state shall be printed
1638 * \param[in] stats Whether or not statistics shall also be printed */
Alexander Couzens8dfc24c2021-01-25 16:09:23 +01001639void 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 +02001640{
1641 struct ns2_sns_state *gss;
1642 unsigned int i;
1643
1644 if (!nse->bss_sns_fi)
1645 return;
1646
Harald Welte1262c4f2021-01-19 20:58:33 +01001647 vty_out_fsm_inst2(vty, prefix, nse->bss_sns_fi);
Alexander Couzens6a161492020-07-12 13:45:50 +02001648 gss = (struct ns2_sns_state *) nse->bss_sns_fi->priv;
1649
Harald Welte1262c4f2021-01-19 20:58:33 +01001650 vty_out(vty, "%sMaximum number of remote NS-VCs: %zu, IPv4 Endpoints: %zu, IPv6 Endpoints: %zu%s",
1651 prefix, gss->num_max_nsvcs, gss->num_max_ip4_remote, gss->num_max_ip6_remote, VTY_NEWLINE);
Alexander Couzens6a161492020-07-12 13:45:50 +02001652
1653 if (gss->num_ip4_local && gss->num_ip4_remote) {
Harald Welte1262c4f2021-01-19 20:58:33 +01001654 vty_out(vty, "%sLocal IPv4 Endpoints:%s", prefix, VTY_NEWLINE);
Alexander Couzens6a161492020-07-12 13:45:50 +02001655 for (i = 0; i < gss->num_ip4_local; i++)
Harald Welte1262c4f2021-01-19 20:58:33 +01001656 vty_dump_sns_ip4(vty, prefix, &gss->ip4_local[i]);
Alexander Couzens6a161492020-07-12 13:45:50 +02001657
Harald Welte1262c4f2021-01-19 20:58:33 +01001658 vty_out(vty, "%sRemote IPv4 Endpoints:%s", prefix, VTY_NEWLINE);
Alexander Couzens6a161492020-07-12 13:45:50 +02001659 for (i = 0; i < gss->num_ip4_remote; i++)
Harald Welte1262c4f2021-01-19 20:58:33 +01001660 vty_dump_sns_ip4(vty, prefix, &gss->ip4_remote[i]);
Alexander Couzens6a161492020-07-12 13:45:50 +02001661 }
1662
1663 if (gss->num_ip6_local && gss->num_ip6_remote) {
Harald Welte1262c4f2021-01-19 20:58:33 +01001664 vty_out(vty, "%sLocal IPv6 Endpoints:%s", prefix, VTY_NEWLINE);
Alexander Couzens6a161492020-07-12 13:45:50 +02001665 for (i = 0; i < gss->num_ip6_local; i++)
Harald Welte1262c4f2021-01-19 20:58:33 +01001666 vty_dump_sns_ip6(vty, prefix, &gss->ip6_local[i]);
Alexander Couzens6a161492020-07-12 13:45:50 +02001667
Harald Welte1262c4f2021-01-19 20:58:33 +01001668 vty_out(vty, "%sRemote IPv6 Endpoints:%s", prefix, VTY_NEWLINE);
Alexander Couzens6a161492020-07-12 13:45:50 +02001669 for (i = 0; i < gss->num_ip6_remote; i++)
Harald Welte1262c4f2021-01-19 20:58:33 +01001670 vty_dump_sns_ip6(vty, prefix, &gss->ip6_remote[i]);
Alexander Couzens6a161492020-07-12 13:45:50 +02001671 }
1672}
1673
Alexander Couzens412bc342020-11-19 05:24:37 +01001674/*! write IP-SNS to a vty
1675 * \param[in] vty VTY to which the state shall be printed
1676 * \param[in] nse NS Entity whose IP-SNS state shall be printed */
Alexander Couzens8dfc24c2021-01-25 16:09:23 +01001677void ns2_sns_write_vty(struct vty *vty, const struct gprs_ns2_nse *nse)
Alexander Couzens412bc342020-11-19 05:24:37 +01001678{
1679 struct ns2_sns_state *gss;
1680 struct osmo_sockaddr_str addr_str;
1681 struct sns_endpoint *endpoint;
1682
1683 if (!nse->bss_sns_fi)
1684 return;
1685
1686 gss = (struct ns2_sns_state *) nse->bss_sns_fi->priv;
1687 llist_for_each_entry(endpoint, &gss->sns_endpoints, list) {
Vadim Yanitskiyd8b70032021-01-05 14:24:09 +01001688 /* It's unlikely that an error happens, but let's better be safe. */
1689 if (osmo_sockaddr_str_from_sockaddr(&addr_str, &endpoint->saddr.u.sas) != 0)
1690 addr_str = (struct osmo_sockaddr_str) { .ip = "<INVALID>" };
Alexander Couzens5fa431c2021-02-08 23:21:54 +01001691 vty_out(vty, " ip-sns-remote %s %u%s", addr_str.ip, addr_str.port, VTY_NEWLINE);
Alexander Couzens412bc342020-11-19 05:24:37 +01001692 }
1693}
1694
Alexander Couzense769f522020-12-07 07:37:07 +01001695static struct sns_endpoint *ns2_get_sns_endpoint(struct ns2_sns_state *state,
1696 const struct osmo_sockaddr *saddr)
1697{
1698 struct sns_endpoint *endpoint;
1699
1700 llist_for_each_entry(endpoint, &state->sns_endpoints, list) {
1701 if (!osmo_sockaddr_cmp(saddr, &endpoint->saddr))
1702 return endpoint;
1703 }
1704
1705 return NULL;
1706}
1707
1708/*! gprs_ns2_sns_add_endpoint
1709 * \param[in] nse
1710 * \param[in] sockaddr
1711 * \return
1712 */
1713int gprs_ns2_sns_add_endpoint(struct gprs_ns2_nse *nse,
1714 const struct osmo_sockaddr *saddr)
1715{
1716 struct ns2_sns_state *gss;
1717 struct sns_endpoint *endpoint;
1718 bool do_selection = false;
1719
1720 if (nse->ll != GPRS_NS2_LL_UDP) {
1721 return -EINVAL;
1722 }
1723
Alexander Couzens138b96f2021-01-25 16:23:29 +01001724 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
Alexander Couzense769f522020-12-07 07:37:07 +01001725 return -EINVAL;
1726 }
1727
1728 gss = nse->bss_sns_fi->priv;
1729
1730 if (ns2_get_sns_endpoint(gss, saddr))
1731 return -EADDRINUSE;
1732
1733 endpoint = talloc_zero(nse->bss_sns_fi->priv, struct sns_endpoint);
1734 if (!endpoint)
1735 return -ENOMEM;
1736
1737 endpoint->saddr = *saddr;
1738 if (llist_empty(&gss->sns_endpoints))
1739 do_selection = true;
1740
1741 llist_add_tail(&endpoint->list, &gss->sns_endpoints);
1742 if (do_selection)
1743 osmo_fsm_inst_dispatch(nse->bss_sns_fi, GPRS_SNS_EV_SELECT_ENDPOINT, NULL);
1744
1745 return 0;
1746}
1747
1748/*! gprs_ns2_sns_del_endpoint
1749 * \param[in] nse
1750 * \param[in] sockaddr
1751 * \return 0 on success, otherwise < 0
1752 */
1753int gprs_ns2_sns_del_endpoint(struct gprs_ns2_nse *nse,
1754 const struct osmo_sockaddr *saddr)
1755{
1756 struct ns2_sns_state *gss;
1757 struct sns_endpoint *endpoint;
1758
1759 if (nse->ll != GPRS_NS2_LL_UDP) {
1760 return -EINVAL;
1761 }
1762
Alexander Couzens138b96f2021-01-25 16:23:29 +01001763 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
Alexander Couzense769f522020-12-07 07:37:07 +01001764 return -EINVAL;
1765 }
1766
1767 gss = nse->bss_sns_fi->priv;
1768 endpoint = ns2_get_sns_endpoint(gss, saddr);
1769 if (!endpoint)
1770 return -ENOENT;
1771
1772 /* if this is an unused SNS endpoint it's done */
1773 if (gss->initial != endpoint) {
1774 llist_del(&endpoint->list);
1775 talloc_free(endpoint);
1776 return 0;
1777 }
1778
1779 /* gprs_ns2_free_nsvcs() will trigger GPRS_SNS_EV_NO_NSVC on the last NS-VC
1780 * and restart SNS SIZE procedure which selects a new initial */
Harald Weltef2949742021-01-20 14:54:14 +01001781 LOGNSE(nse, LOGL_INFO, "Current in-use SNS endpoint is being removed."
Alexander Couzense769f522020-12-07 07:37:07 +01001782 "Closing all NS-VC and restart SNS-SIZE procedure"
1783 "with a remaining SNS endpoint.\n");
1784
1785 /* Continue with the next endpoint in the list.
1786 * Special case if the endpoint is at the start or end of the list */
1787 if (endpoint->list.prev == &gss->sns_endpoints ||
1788 endpoint->list.next == &gss->sns_endpoints)
1789 gss->initial = NULL;
1790 else
1791 gss->initial = llist_entry(endpoint->list.next->prev,
1792 struct sns_endpoint,
1793 list);
1794
1795 llist_del(&endpoint->list);
1796 gprs_ns2_free_nsvcs(nse);
1797 talloc_free(endpoint);
1798
1799 return 0;
1800}
1801
1802/*! gprs_ns2_sns_count
1803 * \param[in] nse NS Entity whose IP-SNS endpoints shall be printed
1804 * \return the count of endpoints or < 0 if NSE doesn't contain sns.
1805 */
1806int gprs_ns2_sns_count(struct gprs_ns2_nse *nse)
1807{
1808 struct ns2_sns_state *gss;
1809 struct sns_endpoint *endpoint;
1810 int count = 0;
1811
1812 if (nse->ll != GPRS_NS2_LL_UDP) {
1813 return -EINVAL;
1814 }
1815
Alexander Couzens138b96f2021-01-25 16:23:29 +01001816 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
Alexander Couzense769f522020-12-07 07:37:07 +01001817 return -EINVAL;
1818 }
1819
1820 gss = nse->bss_sns_fi->priv;
1821 llist_for_each_entry(endpoint, &gss->sns_endpoints, list)
1822 count++;
1823
1824 return count;
1825}
1826
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01001827void ns2_sns_notify_alive(struct gprs_ns2_nse *nse, struct gprs_ns2_vc *nsvc, bool alive)
1828{
1829 struct ns2_sns_state *gss;
1830 struct gprs_ns2_vc *tmp;
1831
1832 if (!nse->bss_sns_fi)
1833 return;
1834
1835 gss = nse->bss_sns_fi->priv;
1836 if(nse->bss_sns_fi->state != GPRS_SNS_ST_CONFIGURED)
1837 return;
1838
1839 if (alive == gss->alive)
1840 return;
1841
1842 /* check if this is the current SNS NS-VC */
1843 if (nsvc == gss->sns_nsvc) {
1844 /* only replace the SNS NS-VC if there are other alive NS-VC.
1845 * There aren't any other alive NS-VC when the SNS fsm just reached CONFIGURED
1846 * and couldn't confirm yet if the NS-VC comes up */
1847 if (gss->alive && !alive)
1848 ns2_sns_replace_nsvc(nsvc);
1849 }
1850
1851 if (alive) {
1852 gss->alive = true;
1853 osmo_fsm_inst_dispatch(nse->bss_sns_fi, GPRS_SNS_EV_NSVC_ALIVE, NULL);
1854 } else {
1855 /* is there at least another alive nsvc? */
1856 llist_for_each_entry(tmp, &nse->nsvc, list) {
1857 if (ns2_vc_is_unblocked(tmp))
1858 return;
1859 }
1860
1861 /* all NS-VC have failed */
1862 gss->alive = false;
1863 osmo_fsm_inst_dispatch(nse->bss_sns_fi, GPRS_SNS_EV_NO_NSVC, NULL);
1864 }
1865}
1866
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001867int gprs_ns2_sns_add_bind(struct gprs_ns2_nse *nse,
1868 struct gprs_ns2_vc_bind *bind)
1869{
1870 struct ns2_sns_state *gss;
1871 struct ns2_sns_bind *tmp;
1872
1873 OSMO_ASSERT(nse->bss_sns_fi);
1874 gss = nse->bss_sns_fi->priv;
1875
1876 if (!gprs_ns2_is_ip_bind(bind)) {
1877 return -EINVAL;
1878 }
1879
1880 if (!llist_empty(&gss->binds)) {
1881 llist_for_each_entry(tmp, &gss->binds, list) {
1882 if (tmp->bind == bind)
1883 return -EALREADY;
1884 }
1885 }
1886
1887 tmp = talloc_zero(gss, struct ns2_sns_bind);
1888 if (!tmp)
1889 return -ENOMEM;
1890 tmp->bind = bind;
1891 llist_add_tail(&tmp->list, &gss->binds);
1892
1893 osmo_fsm_inst_dispatch(nse->bss_sns_fi, GPRS_SNS_EV_REQ_ADD_BIND, tmp);
1894 return 0;
1895}
1896
1897/* Remove a bind from the SNS. All assosiated NSVC must be removed. */
1898int gprs_ns2_sns_del_bind(struct gprs_ns2_nse *nse,
1899 struct gprs_ns2_vc_bind *bind)
1900{
1901 struct ns2_sns_state *gss;
1902 struct ns2_sns_bind *tmp, *tmp2;
1903 bool found = false;
1904
1905 if (!nse->bss_sns_fi)
1906 return -EINVAL;
1907
1908 gss = nse->bss_sns_fi->priv;
1909 if (gss->initial_bind && gss->initial_bind->bind == bind) {
1910 if (gss->initial_bind->list.prev == &gss->binds)
1911 gss->initial_bind = NULL;
1912 else
1913 gss->initial_bind = llist_entry(gss->initial_bind->list.prev, struct ns2_sns_bind, list);
1914 }
1915
1916 llist_for_each_entry_safe(tmp, tmp2, &gss->binds, list) {
1917 if (tmp->bind == bind) {
1918 llist_del(&tmp->list);
1919 found = true;
1920 }
1921 }
1922
1923 if (!found)
1924 return -ENOENT;
1925
1926 osmo_fsm_inst_dispatch(nse->bss_sns_fi, GPRS_SNS_EV_REQ_DELETE_BIND, tmp);
1927 return 0;
1928}
1929
Alexander Couzensc4704762021-02-08 23:13:12 +01001930/* Update SNS weights
1931 * \param[in] nsvc the NSVC which should be updated
1932 */
1933void ns2_sns_update_weights(struct gprs_ns2_vc_bind *bind)
1934{
1935 /* TODO: implement weights after binds per sns implemented */
1936}
1937
Alexander Couzens6a161492020-07-12 13:45:50 +02001938/* initialize osmo_ctx on main tread */
1939static __attribute__((constructor)) void on_dso_load_ctx(void)
1940{
1941 OSMO_ASSERT(osmo_fsm_register(&gprs_ns2_sns_bss_fsm) == 0);
1942}