blob: 04cebf49933443dc443e9ca11972a528e4a9770f [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 Couzens67725e22021-02-15 02:37:03 +010073 GPRS_SNS_EV_REQ_SELECT_ENDPOINT, /*!< Select a SNS endpoint from the list */
74 GPRS_SNS_EV_RX_SIZE,
75 GPRS_SNS_EV_RX_SIZE_ACK,
76 GPRS_SNS_EV_RX_CONFIG,
77 GPRS_SNS_EV_RX_CONFIG_END, /*!< SNS-CONFIG with end flag received */
78 GPRS_SNS_EV_RX_CONFIG_ACK,
79 GPRS_SNS_EV_RX_ADD,
80 GPRS_SNS_EV_RX_DELETE,
81 GPRS_SNS_EV_RX_CHANGE_WEIGHT,
Harald Welteb9f23872021-03-02 20:48:54 +010082 GPRS_SNS_EV_RX_ACK, /*!< Rx of SNS-ACK (response to ADD/DELETE/CHG_WEIGHT */
Harald Welte04647e12021-03-02 18:50:40 +010083 GPRS_SNS_EV_REQ_NO_NSVC, /*!< no more NS-VC remaining (all dead) */
Alexander Couzens67725e22021-02-15 02:37:03 +010084 GPRS_SNS_EV_REQ_NSVC_ALIVE, /*!< a NS-VC became alive */
Harald Welte04647e12021-03-02 18:50:40 +010085 GPRS_SNS_EV_REQ_ADD_BIND, /*!< add a new local bind to this NSE */
86 GPRS_SNS_EV_REQ_DELETE_BIND, /*!< remove a local bind from this NSE */
Alexander Couzens6a161492020-07-12 13:45:50 +020087};
88
89static const struct value_string gprs_sns_event_names[] = {
Alexander Couzens67725e22021-02-15 02:37:03 +010090 { GPRS_SNS_EV_REQ_SELECT_ENDPOINT, "REQ_SELECT_ENDPOINT" },
91 { GPRS_SNS_EV_RX_SIZE, "RX_SIZE" },
92 { GPRS_SNS_EV_RX_SIZE_ACK, "RX_SIZE_ACK" },
93 { GPRS_SNS_EV_RX_CONFIG, "RX_CONFIG" },
94 { GPRS_SNS_EV_RX_CONFIG_END, "RX_CONFIG_END" },
95 { GPRS_SNS_EV_RX_CONFIG_ACK, "RX_CONFIG_ACK" },
96 { GPRS_SNS_EV_RX_ADD, "RX_ADD" },
97 { GPRS_SNS_EV_RX_DELETE, "RX_DELETE" },
Harald Welteb9f23872021-03-02 20:48:54 +010098 { GPRS_SNS_EV_RX_ACK, "RX_ACK" },
Alexander Couzens67725e22021-02-15 02:37:03 +010099 { GPRS_SNS_EV_RX_CHANGE_WEIGHT, "RX_CHANGE_WEIGHT" },
100 { GPRS_SNS_EV_REQ_NO_NSVC, "REQ_NO_NSVC" },
101 { GPRS_SNS_EV_REQ_NSVC_ALIVE, "REQ_NSVC_ALIVE"},
102 { GPRS_SNS_EV_REQ_ADD_BIND, "REQ_ADD_BIND"},
103 { GPRS_SNS_EV_REQ_DELETE_BIND, "REQ_DELETE_BIND"},
Alexander Couzens6a161492020-07-12 13:45:50 +0200104 { 0, NULL }
105};
106
Alexander Couzense769f522020-12-07 07:37:07 +0100107struct sns_endpoint {
108 struct llist_head list;
109 struct osmo_sockaddr saddr;
110};
111
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100112struct ns2_sns_bind {
113 struct llist_head list;
114 struct gprs_ns2_vc_bind *bind;
115};
116
Alexander Couzens6a161492020-07-12 13:45:50 +0200117struct ns2_sns_state {
118 struct gprs_ns2_nse *nse;
119
120 enum ns2_sns_type ip;
121
Alexander Couzense769f522020-12-07 07:37:07 +0100122 /* holds the list of initial SNS endpoints */
123 struct llist_head sns_endpoints;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100124 /* list of used struct ns2_sns_bind */
125 struct llist_head binds;
126 /* pointer to the bind which was used to initiate the SNS connection */
127 struct ns2_sns_bind *initial_bind;
Alexander Couzense769f522020-12-07 07:37:07 +0100128 /* prevent recursive reselection */
129 bool reselection_running;
130
131 /* The current initial SNS endpoints.
132 * The initial connection will be moved into the NSE
133 * if configured via SNS. Otherwise it will be removed
134 * in configured state. */
135 struct sns_endpoint *initial;
Alexander Couzens6a161492020-07-12 13:45:50 +0200136 /* all SNS PDU will be sent over this nsvc */
137 struct gprs_ns2_vc *sns_nsvc;
Alexander Couzens90ee9632020-12-07 06:18:32 +0100138 /* timer N */
139 int N;
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100140 /* true if at least one nsvc is alive */
141 bool alive;
Alexander Couzens6a161492020-07-12 13:45:50 +0200142
143 /* local configuration to send to the remote end */
144 struct gprs_ns_ie_ip4_elem *ip4_local;
145 size_t num_ip4_local;
146
147 /* local configuration to send to the remote end */
148 struct gprs_ns_ie_ip6_elem *ip6_local;
149 size_t num_ip6_local;
150
151 /* local configuration about our capabilities in terms of connections to
152 * remote (SGSN) side */
153 size_t num_max_nsvcs;
154 size_t num_max_ip4_remote;
155 size_t num_max_ip6_remote;
156
157 /* remote configuration as received */
158 struct gprs_ns_ie_ip4_elem *ip4_remote;
159 unsigned int num_ip4_remote;
160
161 /* remote configuration as received */
162 struct gprs_ns_ie_ip6_elem *ip6_remote;
163 unsigned int num_ip6_remote;
164};
165
166static inline struct gprs_ns2_nse *nse_inst_from_fi(struct osmo_fsm_inst *fi)
167{
168 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
169 return gss->nse;
170}
171
172/* helper function to compute the sum of all (data or signaling) weights */
173static int ip4_weight_sum(const struct gprs_ns_ie_ip4_elem *ip4, unsigned int num,
174 bool data_weight)
175{
176 unsigned int i;
177 int weight_sum = 0;
178
179 for (i = 0; i < num; i++) {
180 if (data_weight)
181 weight_sum += ip4[i].data_weight;
182 else
183 weight_sum += ip4[i].sig_weight;
184 }
185 return weight_sum;
186}
187#define ip4_weight_sum_data(x,y) ip4_weight_sum(x, y, true)
188#define ip4_weight_sum_sig(x,y) ip4_weight_sum(x, y, false)
189
190/* helper function to compute the sum of all (data or signaling) weights */
191static int ip6_weight_sum(const struct gprs_ns_ie_ip6_elem *ip6, unsigned int num,
192 bool data_weight)
193{
194 unsigned int i;
195 int weight_sum = 0;
196
197 for (i = 0; i < num; i++) {
198 if (data_weight)
199 weight_sum += ip6[i].data_weight;
200 else
201 weight_sum += ip6[i].sig_weight;
202 }
203 return weight_sum;
204}
205#define ip6_weight_sum_data(x,y) ip6_weight_sum(x, y, true)
206#define ip6_weight_sum_sig(x,y) ip6_weight_sum(x, y, false)
207
208static struct gprs_ns2_vc *nsvc_by_ip4_elem(struct gprs_ns2_nse *nse,
209 const struct gprs_ns_ie_ip4_elem *ip4)
210{
211 struct osmo_sockaddr sa;
212 /* copy over. Both data structures use network byte order */
213 sa.u.sin.sin_addr.s_addr = ip4->ip_addr;
214 sa.u.sin.sin_port = ip4->udp_port;
215 sa.u.sin.sin_family = AF_INET;
216
Alexander Couzens38b19e82020-09-23 23:56:37 +0200217 return gprs_ns2_nsvc_by_sockaddr_nse(nse, &sa);
Alexander Couzens6a161492020-07-12 13:45:50 +0200218}
219
220static struct gprs_ns2_vc *nsvc_by_ip6_elem(struct gprs_ns2_nse *nse,
221 const struct gprs_ns_ie_ip6_elem *ip6)
222{
223 struct osmo_sockaddr sa;
224 /* copy over. Both data structures use network byte order */
225 sa.u.sin6.sin6_addr = ip6->ip_addr;
226 sa.u.sin6.sin6_port = ip6->udp_port;
227 sa.u.sin6.sin6_family = AF_INET;
228
Alexander Couzens38b19e82020-09-23 23:56:37 +0200229 return gprs_ns2_nsvc_by_sockaddr_nse(nse, &sa);
Alexander Couzens6a161492020-07-12 13:45:50 +0200230}
231
Alexander Couzens125298f2020-10-11 21:22:42 +0200232/*! Return the initial SNS remote socket address
233 * \param nse NS Entity
234 * \return address of the initial SNS connection; NULL in case of error
235 */
236const struct osmo_sockaddr *gprs_ns2_nse_sns_remote(struct gprs_ns2_nse *nse)
237{
238 struct ns2_sns_state *gss;
239
240 if (!nse->bss_sns_fi)
241 return NULL;
242
243 gss = (struct ns2_sns_state *) nse->bss_sns_fi->priv;
Alexander Couzense769f522020-12-07 07:37:07 +0100244 return &gss->initial->saddr;
Alexander Couzens125298f2020-10-11 21:22:42 +0200245}
246
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100247/*! called when a nsvc is beeing freed or the nsvc became dead */
248void ns2_sns_replace_nsvc(struct gprs_ns2_vc *nsvc)
Alexander Couzens6a161492020-07-12 13:45:50 +0200249{
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100250 struct gprs_ns2_nse *nse = nsvc->nse;
Alexander Couzens6a161492020-07-12 13:45:50 +0200251 struct gprs_ns2_vc *tmp;
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100252 struct osmo_fsm_inst *fi = nse->bss_sns_fi;
Alexander Couzens6a161492020-07-12 13:45:50 +0200253 struct ns2_sns_state *gss;
Alexander Couzens6a161492020-07-12 13:45:50 +0200254
255 if (!fi)
256 return;
257
258 gss = (struct ns2_sns_state *) fi->priv;
259 if (nsvc != gss->sns_nsvc)
260 return;
261
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100262 gss->sns_nsvc = NULL;
263 if (gss->alive) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200264 llist_for_each_entry(tmp, &nse->nsvc, list) {
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100265 if (ns2_vc_is_unblocked(tmp)) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200266 gss->sns_nsvc = tmp;
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100267 return;
268 }
Alexander Couzens6a161492020-07-12 13:45:50 +0200269 }
270 } else {
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100271 /* the SNS is waiting for its first NS-VC to come up
272 * choose any other nsvc */
273 llist_for_each_entry(tmp, &nse->nsvc, list) {
274 if (nsvc != tmp) {
275 gss->sns_nsvc = tmp;
276 return;
277 }
278 }
Alexander Couzens6a161492020-07-12 13:45:50 +0200279 }
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100280
Alexander Couzens67725e22021-02-15 02:37:03 +0100281 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_REQ_NO_NSVC, NULL);
Alexander Couzens6a161492020-07-12 13:45:50 +0200282}
283
Alexander Couzens7a7b20b2021-01-18 10:47:33 +0100284static void ns2_clear_ipv46_entries(struct ns2_sns_state *gss)
285{
286 TALLOC_FREE(gss->ip4_local);
287 TALLOC_FREE(gss->ip4_remote);
288 TALLOC_FREE(gss->ip6_local);
289 TALLOC_FREE(gss->ip6_remote);
290
291 gss->num_ip4_local = 0;
292 gss->num_ip4_remote = 0;
293 gss->num_ip6_local = 0;
294 gss->num_ip6_remote = 0;
295}
296
Daniel Willmanncf8371a2021-01-16 15:13:51 +0100297static void ns2_vc_create_ip(struct osmo_fsm_inst *fi, struct gprs_ns2_nse *nse, const struct osmo_sockaddr *remote,
298 uint8_t sig_weight, uint8_t data_weight)
Alexander Couzens6a161492020-07-12 13:45:50 +0200299{
300 struct gprs_ns2_inst *nsi = nse->nsi;
301 struct gprs_ns2_vc *nsvc;
302 struct gprs_ns2_vc_bind *bind;
Daniel Willmanncf8371a2021-01-16 15:13:51 +0100303
304 /* for every bind, create a connection if bind type == IP */
305 llist_for_each_entry(bind, &nsi->binding, list) {
306 if (bind->ll != GPRS_NS2_LL_UDP)
307 continue;
308 /* ignore failed connection */
309 nsvc = gprs_ns2_ip_connect_inactive(bind,
310 remote,
311 nse, 0);
312 if (!nsvc) {
313 LOGPFSML(fi, LOGL_ERROR, "SNS-CONFIG: Failed to create NSVC\n");
314 continue;
315 }
316
317 nsvc->sig_weight = sig_weight;
318 nsvc->data_weight = data_weight;
319 }
320}
321
322static void ns2_nsvc_create_ip4(struct osmo_fsm_inst *fi,
323 struct gprs_ns2_nse *nse,
324 const struct gprs_ns_ie_ip4_elem *ip4)
325{
Alexander Couzensc068d862020-10-12 04:11:51 +0200326 struct osmo_sockaddr remote = { };
Alexander Couzens6a161492020-07-12 13:45:50 +0200327 /* copy over. Both data structures use network byte order */
328 remote.u.sin.sin_family = AF_INET;
329 remote.u.sin.sin_addr.s_addr = ip4->ip_addr;
330 remote.u.sin.sin_port = ip4->udp_port;
331
Daniel Willmanncf8371a2021-01-16 15:13:51 +0100332 ns2_vc_create_ip(fi, nse, &remote, ip4->sig_weight, ip4->data_weight);
Alexander Couzens6a161492020-07-12 13:45:50 +0200333}
334
335static void ns2_nsvc_create_ip6(struct osmo_fsm_inst *fi,
336 struct gprs_ns2_nse *nse,
337 const struct gprs_ns_ie_ip6_elem *ip6)
338{
Alexander Couzens6a161492020-07-12 13:45:50 +0200339 struct osmo_sockaddr remote = {};
340 /* copy over. Both data structures use network byte order */
341 remote.u.sin6.sin6_family = AF_INET6;
342 remote.u.sin6.sin6_addr = ip6->ip_addr;
343 remote.u.sin6.sin6_port = ip6->udp_port;
344
Daniel Willmanncf8371a2021-01-16 15:13:51 +0100345 ns2_vc_create_ip(fi, nse, &remote, ip6->sig_weight, ip6->data_weight);
Alexander Couzens6a161492020-07-12 13:45:50 +0200346}
347
348
349static int create_missing_nsvcs(struct osmo_fsm_inst *fi)
350{
351 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
352 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
353 struct gprs_ns2_vc *nsvc;
354 struct gprs_ns2_vc_bind *bind;
355 struct osmo_sockaddr remote = { };
356 unsigned int i;
357
358 for (i = 0; i < gss->num_ip4_remote; i++) {
359 const struct gprs_ns_ie_ip4_elem *ip4 = &gss->ip4_remote[i];
360
361 remote.u.sin.sin_family = AF_INET;
362 remote.u.sin.sin_addr.s_addr = ip4->ip_addr;
363 remote.u.sin.sin_port = ip4->udp_port;
364
365 llist_for_each_entry(bind, &nse->nsi->binding, list) {
366 bool found = false;
Daniel Willmann967e2c12021-01-14 16:58:17 +0100367 if (bind->ll != GPRS_NS2_LL_UDP)
368 continue;
Alexander Couzens6a161492020-07-12 13:45:50 +0200369
370 llist_for_each_entry(nsvc, &nse->nsvc, list) {
371 if (nsvc->bind != bind)
372 continue;
373
Alexander Couzensc4229a42020-10-11 20:58:04 +0200374 if (!osmo_sockaddr_cmp(&remote, gprs_ns2_ip_vc_remote(nsvc))) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200375 found = true;
376 break;
377 }
378 }
379
380 if (!found) {
381 nsvc = gprs_ns2_ip_connect_inactive(bind, &remote, nse, 0);
382 if (!nsvc) {
383 /* TODO: add to a list to send back a NS-STATUS */
384 continue;
385 }
386 }
387
388 /* update data / signalling weight */
389 nsvc->data_weight = ip4->data_weight;
390 nsvc->sig_weight = ip4->sig_weight;
391 nsvc->sns_only = false;
392 }
393 }
394
395 for (i = 0; i < gss->num_ip6_remote; i++) {
396 const struct gprs_ns_ie_ip6_elem *ip6 = &gss->ip6_remote[i];
397
398 remote.u.sin6.sin6_family = AF_INET6;
399 remote.u.sin6.sin6_addr = ip6->ip_addr;
400 remote.u.sin6.sin6_port = ip6->udp_port;
401
402 llist_for_each_entry(bind, &nse->nsi->binding, list) {
403 bool found = false;
Daniel Willmann967e2c12021-01-14 16:58:17 +0100404 if (bind->ll != GPRS_NS2_LL_UDP)
405 continue;
Alexander Couzens6a161492020-07-12 13:45:50 +0200406
407 llist_for_each_entry(nsvc, &nse->nsvc, list) {
408 if (nsvc->bind != bind)
409 continue;
410
Alexander Couzensc4229a42020-10-11 20:58:04 +0200411 if (!osmo_sockaddr_cmp(&remote, gprs_ns2_ip_vc_remote(nsvc))) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200412 found = true;
413 break;
414 }
415 }
416
417 if (!found) {
418 nsvc = gprs_ns2_ip_connect_inactive(bind, &remote, nse, 0);
419 if (!nsvc) {
420 /* TODO: add to a list to send back a NS-STATUS */
421 continue;
422 }
423 }
424
425 /* update data / signalling weight */
426 nsvc->data_weight = ip6->data_weight;
427 nsvc->sig_weight = ip6->sig_weight;
428 nsvc->sns_only = false;
429 }
430 }
431
432
433 return 0;
434}
435
436/* Add a given remote IPv4 element to gprs_sns_state */
437static int add_remote_ip4_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip4_elem *ip4)
438{
439 unsigned int i;
440
441 if (gss->num_ip4_remote >= gss->num_max_ip4_remote)
442 return -NS_CAUSE_INVAL_NR_NS_VC;
443
444 /* check for duplicates */
445 for (i = 0; i < gss->num_ip4_remote; i++) {
446 if (memcmp(&gss->ip4_remote[i], ip4, sizeof(*ip4)))
447 continue;
448 /* TODO: log message duplicate */
Alexander Couzens6a161492020-07-12 13:45:50 +0200449 return -NS_CAUSE_PROTO_ERR_UNSPEC;
450 }
451
452 gss->ip4_remote = talloc_realloc(gss, gss->ip4_remote, struct gprs_ns_ie_ip4_elem,
453 gss->num_ip4_remote+1);
454 gss->ip4_remote[gss->num_ip4_remote] = *ip4;
455 gss->num_ip4_remote += 1;
456 return 0;
457}
458
459/* Remove a given remote IPv4 element from gprs_sns_state */
460static int remove_remote_ip4_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip4_elem *ip4)
461{
462 unsigned int i;
463
464 for (i = 0; i < gss->num_ip4_remote; i++) {
465 if (memcmp(&gss->ip4_remote[i], ip4, sizeof(*ip4)))
466 continue;
467 /* all array elements < i remain as they are; all > i are shifted left by one */
468 memmove(&gss->ip4_remote[i], &gss->ip4_remote[i+1], gss->num_ip4_remote-i-1);
469 gss->num_ip4_remote -= 1;
470 return 0;
471 }
472 return -1;
473}
474
475/* update the weights for specified remote IPv4 */
476static int update_remote_ip4_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip4_elem *ip4)
477{
478 unsigned int i;
479
480 for (i = 0; i < gss->num_ip4_remote; i++) {
481 if (gss->ip4_remote[i].ip_addr != ip4->ip_addr ||
482 gss->ip4_remote[i].udp_port != ip4->udp_port)
483 continue;
484
485 gss->ip4_remote[i].sig_weight = ip4->sig_weight;
486 gss->ip4_remote[i].data_weight = ip4->data_weight;
487 return 0;
488 }
489 return -1;
490}
491
492/* Add a given remote IPv6 element to gprs_sns_state */
493static int add_remote_ip6_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip6_elem *ip6)
494{
495 if (gss->num_ip6_remote >= gss->num_max_ip6_remote)
496 return -NS_CAUSE_INVAL_NR_NS_VC;
497
498 gss->ip6_remote = talloc_realloc(gss, gss->ip6_remote, struct gprs_ns_ie_ip6_elem,
499 gss->num_ip6_remote+1);
500 gss->ip6_remote[gss->num_ip6_remote] = *ip6;
501 gss->num_ip6_remote += 1;
502 return 0;
503}
504
505/* Remove a given remote IPv6 element from gprs_sns_state */
506static int remove_remote_ip6_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip6_elem *ip6)
507{
508 unsigned int i;
509
510 for (i = 0; i < gss->num_ip6_remote; i++) {
511 if (memcmp(&gss->ip6_remote[i], ip6, sizeof(*ip6)))
512 continue;
513 /* all array elements < i remain as they are; all > i are shifted left by one */
514 memmove(&gss->ip6_remote[i], &gss->ip6_remote[i+1], gss->num_ip6_remote-i-1);
515 gss->num_ip6_remote -= 1;
516 return 0;
517 }
518 return -1;
519}
520
521/* update the weights for specified remote IPv6 */
522static int update_remote_ip6_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip6_elem *ip6)
523{
524 unsigned int i;
525
526 for (i = 0; i < gss->num_ip6_remote; i++) {
527 if (memcmp(&gss->ip6_remote[i].ip_addr, &ip6->ip_addr, sizeof(ip6->ip_addr)) ||
528 gss->ip6_remote[i].udp_port != ip6->udp_port)
529 continue;
530 gss->ip6_remote[i].sig_weight = ip6->sig_weight;
531 gss->ip6_remote[i].data_weight = ip6->data_weight;
532 return 0;
533 }
534 return -1;
535}
536
537static 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)
538{
539 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
540 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
541 struct gprs_ns2_vc *nsvc;
542 struct osmo_sockaddr sa = {};
Alexander Couzens9a4cf272020-10-11 20:48:04 +0200543 const struct osmo_sockaddr *remote;
Alexander Couzens6a161492020-07-12 13:45:50 +0200544 uint8_t new_signal;
545 uint8_t new_data;
546
547 /* TODO: Upon receiving an SNS-CHANGEWEIGHT PDU, if the resulting sum of the
548 * signalling weights of all the peer IP endpoints configured for this NSE is
549 * equal to zero or if the resulting sum of the data weights of all the peer IP
550 * endpoints configured for this NSE is equal to zero, the BSS/SGSN shall send an
551 * SNS-ACK PDU with a cause code of "Invalid weights". */
552
553 if (ip4) {
554 if (update_remote_ip4_elem(gss, ip4))
555 return -NS_CAUSE_UNKN_IP_EP;
556
557 /* copy over. Both data structures use network byte order */
558 sa.u.sin.sin_addr.s_addr = ip4->ip_addr;
559 sa.u.sin.sin_port = ip4->udp_port;
560 sa.u.sin.sin_family = AF_INET;
561 new_signal = ip4->sig_weight;
562 new_data = ip4->data_weight;
563 } else if (ip6) {
564 if (update_remote_ip6_elem(gss, ip6))
565 return -NS_CAUSE_UNKN_IP_EP;
566
567 /* copy over. Both data structures use network byte order */
568 sa.u.sin6.sin6_addr = ip6->ip_addr;
569 sa.u.sin6.sin6_port = ip6->udp_port;
570 sa.u.sin6.sin6_family = AF_INET6;
571 new_signal = ip6->sig_weight;
572 new_data = ip6->data_weight;
573 } else {
574 OSMO_ASSERT(false);
575 }
576
577 llist_for_each_entry(nsvc, &nse->nsvc, list) {
Alexander Couzensc4229a42020-10-11 20:58:04 +0200578 remote = gprs_ns2_ip_vc_remote(nsvc);
Alexander Couzens6a161492020-07-12 13:45:50 +0200579 /* all nsvc in NSE should be IP/UDP nsvc */
580 OSMO_ASSERT(remote);
581
582 if (osmo_sockaddr_cmp(&sa, remote))
583 continue;
584
585 LOGPFSML(fi, LOGL_INFO, "CHANGE-WEIGHT NS-VC %s data_weight %u->%u, sig_weight %u->%u\n",
586 gprs_ns2_ll_str(nsvc), nsvc->data_weight, new_data,
587 nsvc->sig_weight, new_signal);
588
589 nsvc->data_weight = new_data;
590 nsvc->sig_weight = new_signal;
591 }
592
593 return 0;
594}
595
596static int do_sns_delete(struct osmo_fsm_inst *fi,
597 const struct gprs_ns_ie_ip4_elem *ip4,
598 const struct gprs_ns_ie_ip6_elem *ip6)
599{
600 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
601 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
602 struct gprs_ns2_vc *nsvc, *tmp;
Alexander Couzens9a4cf272020-10-11 20:48:04 +0200603 const struct osmo_sockaddr *remote;
Alexander Couzens6a161492020-07-12 13:45:50 +0200604 struct osmo_sockaddr sa = {};
605
606 if (ip4) {
607 if (remove_remote_ip4_elem(gss, ip4) < 0)
608 return -NS_CAUSE_UNKN_IP_EP;
609 /* copy over. Both data structures use network byte order */
610 sa.u.sin.sin_addr.s_addr = ip4->ip_addr;
611 sa.u.sin.sin_port = ip4->udp_port;
612 sa.u.sin.sin_family = AF_INET;
613 } else if (ip6) {
614 if (remove_remote_ip6_elem(gss, ip6))
615 return -NS_CAUSE_UNKN_IP_EP;
616
617 /* copy over. Both data structures use network byte order */
618 sa.u.sin6.sin6_addr = ip6->ip_addr;
619 sa.u.sin6.sin6_port = ip6->udp_port;
620 sa.u.sin6.sin6_family = AF_INET6;
621 } else {
622 OSMO_ASSERT(false);
623 }
624
625 llist_for_each_entry_safe(nsvc, tmp, &nse->nsvc, list) {
Alexander Couzensc4229a42020-10-11 20:58:04 +0200626 remote = gprs_ns2_ip_vc_remote(nsvc);
Alexander Couzens6a161492020-07-12 13:45:50 +0200627 /* all nsvc in NSE should be IP/UDP nsvc */
628 OSMO_ASSERT(remote);
629 if (osmo_sockaddr_cmp(&sa, remote))
630 continue;
631
632 LOGPFSML(fi, LOGL_INFO, "DELETE NS-VC %s\n", gprs_ns2_ll_str(nsvc));
633 gprs_ns2_free_nsvc(nsvc);
634 }
635
636 return 0;
637}
638
639static int do_sns_add(struct osmo_fsm_inst *fi,
640 const struct gprs_ns_ie_ip4_elem *ip4,
641 const struct gprs_ns_ie_ip6_elem *ip6)
642{
643 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
644 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
645 struct gprs_ns2_vc *nsvc;
646 int rc = 0;
647
648 /* Upon receiving an SNS-ADD PDU, if the consequent number of IPv4 endpoints
649 * exceeds the number of IPv4 endpoints supported by the NSE, the NSE shall send
650 * an SNS-ACK PDU with a cause code set to "Invalid number of IP4 Endpoints". */
651 switch (gss->ip) {
652 case IPv4:
653 rc = add_remote_ip4_elem(gss, ip4);
654 break;
655 case IPv6:
656 rc = add_remote_ip6_elem(gss, ip6);
657 break;
658 default:
659 /* the gss->ip is initialized with the bss */
660 OSMO_ASSERT(false);
661 }
662
663 if (rc)
664 return rc;
665
666 /* Upon receiving an SNS-ADD PDU containing an already configured IP endpoint the
667 * NSE shall send an SNS-ACK PDU with the cause code "Protocol error -
668 * unspecified" */
669 switch (gss->ip) {
670 case IPv4:
671 nsvc = nsvc_by_ip4_elem(nse, ip4);
672 if (nsvc) {
673 /* the nsvc should be already in sync with the ip4 / ip6 elements */
674 return -NS_CAUSE_PROTO_ERR_UNSPEC;
675 }
676
677 /* TODO: failure case */
678 ns2_nsvc_create_ip4(fi, nse, ip4);
679 break;
680 case IPv6:
681 nsvc = nsvc_by_ip6_elem(nse, ip6);
682 if (nsvc) {
683 /* the nsvc should be already in sync with the ip4 / ip6 elements */
684 return -NS_CAUSE_PROTO_ERR_UNSPEC;
685 }
686
687 /* TODO: failure case */
688 ns2_nsvc_create_ip6(fi, nse, ip6);
689 break;
690 }
691
692 gprs_ns2_start_alive_all_nsvcs(nse);
693
694 return 0;
695}
696
697
698static void ns2_sns_st_unconfigured(struct osmo_fsm_inst *fi, uint32_t event, void *data)
699{
Alexander Couzense769f522020-12-07 07:37:07 +0100700 /* empty state - SNS Select will start by ns2_sns_st_all_action() */
Alexander Couzens6a161492020-07-12 13:45:50 +0200701}
702
703static void ns2_sns_st_size(struct osmo_fsm_inst *fi, uint32_t event, void *data)
704{
705 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
706 struct gprs_ns2_inst *nsi = nse->nsi;
707 struct tlv_parsed *tp = NULL;
708
709 switch (event) {
Alexander Couzens67725e22021-02-15 02:37:03 +0100710 case GPRS_SNS_EV_RX_SIZE_ACK:
Alexander Couzens6a161492020-07-12 13:45:50 +0200711 tp = data;
712 if (TLVP_VAL_MINLEN(tp, NS_IE_CAUSE, 1)) {
713 LOGPFSML(fi, LOGL_ERROR, "SNS-SIZE-ACK with cause %s\n",
714 gprs_ns2_cause_str(*TLVP_VAL(tp, NS_IE_CAUSE)));
715 /* TODO: What to do? */
716 } else {
717 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIG_BSS,
718 nsi->timeout[NS_TOUT_TSNS_PROV], 2);
719 }
720 break;
721 default:
722 OSMO_ASSERT(0);
723 }
724}
725
Alexander Couzense769f522020-12-07 07:37:07 +0100726/* setup all dynamic SNS settings, create a new nsvc and send the SIZE */
Alexander Couzens6a161492020-07-12 13:45:50 +0200727static void ns2_sns_st_size_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
728{
729 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
Alexander Couzense769f522020-12-07 07:37:07 +0100730 struct gprs_ns_ie_ip4_elem *ip4_elems;
731 struct gprs_ns_ie_ip6_elem *ip6_elems;
732 struct gprs_ns2_vc_bind *bind;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100733 struct ns2_sns_bind *sbind;
Alexander Couzense769f522020-12-07 07:37:07 +0100734 struct osmo_sockaddr *remote;
735 const struct osmo_sockaddr *sa;
736 struct osmo_sockaddr local;
737 int count;
Alexander Couzens6a161492020-07-12 13:45:50 +0200738
Alexander Couzense769f522020-12-07 07:37:07 +0100739 /* on a generic failure, the timer callback will recover */
Alexander Couzens6a161492020-07-12 13:45:50 +0200740 if (old_state != GPRS_SNS_ST_UNCONFIGURED)
Alexander Couzens138b96f2021-01-25 16:23:29 +0100741 ns2_prim_status_ind(gss->nse, NULL, 0, GPRS_NS2_AFF_CAUSE_SNS_FAILURE);
Alexander Couzens790a9632021-02-05 17:18:39 +0100742 if (old_state != GPRS_SNS_ST_SIZE)
743 gss->N = 0;
744
Alexander Couzens6a161492020-07-12 13:45:50 +0200745
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100746 gss->alive = false;
Alexander Couzens7a7b20b2021-01-18 10:47:33 +0100747 ns2_clear_ipv46_entries(gss);
748
Alexander Couzense769f522020-12-07 07:37:07 +0100749 /* no initial available */
750 if (!gss->initial)
751 return;
752
753 remote = &gss->initial->saddr;
754
755 /* count how many bindings are available (only UDP binds) */
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100756 count = llist_count(&gss->binds);
Alexander Couzense769f522020-12-07 07:37:07 +0100757 if (count == 0) {
Harald Welte05992872021-03-04 15:49:21 +0100758 LOGPFSML(fi, LOGL_ERROR, "No local binds for this NSE -> cannot determine IP endpoints\n");
Alexander Couzense769f522020-12-07 07:37:07 +0100759 return;
760 }
761
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100762 /* take the first bind or take the next bind */
763 if (!gss->initial_bind) {
764 gss->initial_bind = llist_first_entry(&gss->binds, struct ns2_sns_bind, list);
765 } else {
766 if (gss->initial_bind->list.next != &gss->binds) {
767 gss->initial_bind = llist_entry(gss->initial_bind->list.next, struct ns2_sns_bind, list);
768 } else {
769 gss->initial_bind = llist_first_entry(&gss->binds, struct ns2_sns_bind, list);
Alexander Couzens81ae0aa2020-12-07 05:49:43 +0100770 }
Alexander Couzense769f522020-12-07 07:37:07 +0100771 }
772
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100773 bind = gss->initial_bind->bind;
774
Alexander Couzense769f522020-12-07 07:37:07 +0100775 /* setup the NSVC */
776 if (!gss->sns_nsvc) {
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100777 gss->sns_nsvc = ns2_ip_bind_connect(bind, gss->nse, remote);
Alexander Couzense769f522020-12-07 07:37:07 +0100778 if (!gss->sns_nsvc)
779 return;
780 gss->sns_nsvc->sns_only = true;
781 }
782
783 switch (gss->ip) {
784 case IPv4:
785 ip4_elems = talloc_zero_size(fi, sizeof(struct gprs_ns_ie_ip4_elem) * count);
786 if (!ip4_elems)
787 return;
788
789 gss->ip4_local = ip4_elems;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100790 llist_for_each_entry(sbind, &gss->binds, list) {
791 bind = sbind->bind;
Alexander Couzense769f522020-12-07 07:37:07 +0100792 sa = gprs_ns2_ip_bind_sockaddr(bind);
793 if (!sa)
794 continue;
795
796 if (sa->u.sas.ss_family != AF_INET)
797 continue;
798
799 /* check if this is an specific bind */
800 if (sa->u.sin.sin_addr.s_addr == 0) {
801 if (osmo_sockaddr_local_ip(&local, remote))
802 continue;
803
804 ip4_elems->ip_addr = local.u.sin.sin_addr.s_addr;
805 } else {
806 ip4_elems->ip_addr = sa->u.sin.sin_addr.s_addr;
807 }
808
809 ip4_elems->udp_port = sa->u.sin.sin_port;
Alexander Couzensc4704762021-02-08 23:13:12 +0100810 ip4_elems->sig_weight = bind->sns_sig_weight;
811 ip4_elems->data_weight = bind->sns_data_weight;
Alexander Couzense769f522020-12-07 07:37:07 +0100812 ip4_elems++;
813 }
814
815 gss->num_ip4_local = count;
816 gss->num_max_ip4_remote = 4;
817 gss->num_max_nsvcs = OSMO_MAX(gss->num_max_ip4_remote * gss->num_ip4_local, 8);
818 break;
819 case IPv6:
820 /* IPv6 */
821 ip6_elems = talloc_zero_size(fi, sizeof(struct gprs_ns_ie_ip6_elem) * count);
822 if (!ip6_elems)
823 return;
824
825 gss->ip6_local = ip6_elems;
826
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100827 llist_for_each_entry(sbind, &gss->binds, list) {
828 bind = sbind->bind;
Alexander Couzense769f522020-12-07 07:37:07 +0100829 sa = gprs_ns2_ip_bind_sockaddr(bind);
830 if (!sa)
831 continue;
832
833 if (sa->u.sas.ss_family != AF_INET6)
834 continue;
835
836 /* check if this is an specific bind */
837 if (IN6_IS_ADDR_UNSPECIFIED(&sa->u.sin6.sin6_addr)) {
838 if (osmo_sockaddr_local_ip(&local, remote))
839 continue;
840
841 ip6_elems->ip_addr = local.u.sin6.sin6_addr;
842 } else {
843 ip6_elems->ip_addr = sa->u.sin6.sin6_addr;
844 }
845
846 ip6_elems->udp_port = sa->u.sin.sin_port;
Alexander Couzensc4704762021-02-08 23:13:12 +0100847 ip6_elems->sig_weight = bind->sns_sig_weight;
848 ip6_elems->data_weight = bind->sns_data_weight;
Alexander Couzense769f522020-12-07 07:37:07 +0100849
850 ip6_elems++;
851 }
852 gss->num_ip6_local = count;
853 gss->num_max_ip6_remote = 4;
854 gss->num_max_nsvcs = OSMO_MAX(gss->num_max_ip6_remote * gss->num_ip6_local, 8);
855 break;
856 }
857
Alexander Couzens6a161492020-07-12 13:45:50 +0200858 if (gss->num_max_ip4_remote > 0)
859 ns2_tx_sns_size(gss->sns_nsvc, true, gss->num_max_nsvcs, gss->num_max_ip4_remote, -1);
860 else
861 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 +0200862}
863
864static void ns2_sns_st_config_bss(struct osmo_fsm_inst *fi, uint32_t event, void *data)
865{
866 struct tlv_parsed *tp = NULL;
Alexander Couzens3df58862021-02-05 17:18:08 +0100867 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
Alexander Couzens6a161492020-07-12 13:45:50 +0200868
869 switch (event) {
Alexander Couzens67725e22021-02-15 02:37:03 +0100870 case GPRS_SNS_EV_RX_CONFIG_ACK:
Alexander Couzens6a161492020-07-12 13:45:50 +0200871 tp = (struct tlv_parsed *) data;
872 if (TLVP_VAL_MINLEN(tp, NS_IE_CAUSE, 1)) {
873 LOGPFSML(fi, LOGL_ERROR, "SNS-CONFIG-ACK with cause %s\n",
874 gprs_ns2_cause_str(*TLVP_VAL(tp, NS_IE_CAUSE)));
875 /* TODO: What to do? */
876 } else {
Alexander Couzens3df58862021-02-05 17:18:08 +0100877 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 +0200878 }
879 break;
880 default:
881 OSMO_ASSERT(0);
882 }
883}
884
885static void ns2_sns_st_config_bss_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
886{
887 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
Alexander Couzens790a9632021-02-05 17:18:39 +0100888
889 if (old_state != GPRS_SNS_ST_CONFIG_BSS)
890 gss->N = 0;
891
Alexander Couzens6a161492020-07-12 13:45:50 +0200892 /* Transmit SNS-CONFIG */
Alexander Couzens6a161492020-07-12 13:45:50 +0200893 switch (gss->ip) {
894 case IPv4:
895 ns2_tx_sns_config(gss->sns_nsvc, true,
Alexander Couzense78207f2020-12-07 06:19:29 +0100896 gss->ip4_local, gss->num_ip4_local,
897 NULL, 0);
Alexander Couzens6a161492020-07-12 13:45:50 +0200898 break;
899 case IPv6:
900 ns2_tx_sns_config(gss->sns_nsvc, true,
Alexander Couzense78207f2020-12-07 06:19:29 +0100901 NULL, 0,
902 gss->ip6_local, gss->num_ip6_local);
Alexander Couzens6a161492020-07-12 13:45:50 +0200903 break;
904 }
905}
906
Alexander Couzensbe7cecc2021-02-03 18:25:27 +0100907/* calculate the timeout of the configured state. the configured
908 * state will fail if not at least one NS-VC is alive within X second.
909 */
910static inline int ns_sns_configured_timeout(struct osmo_fsm_inst *fi)
911{
912 int secs;
913 struct gprs_ns2_inst *nsi = nse_inst_from_fi(fi)->nsi;
914 secs = nsi->timeout[NS_TOUT_TNS_ALIVE] * nsi->timeout[NS_TOUT_TNS_ALIVE_RETRIES];
915 secs += nsi->timeout[NS_TOUT_TNS_TEST];
916
917 return secs;
918}
Alexander Couzens6a161492020-07-12 13:45:50 +0200919
920static void ns_sns_st_config_sgsn_ip4(struct osmo_fsm_inst *fi, uint32_t event, void *data)
921{
922 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
923 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
924 const struct gprs_ns_ie_ip4_elem *v4_list;
925 unsigned int num_v4;
926 struct tlv_parsed *tp = NULL;
927
928 uint8_t cause;
929
930 tp = (struct tlv_parsed *) data;
931
932 if (!TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
933 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
934 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
935 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
936 return;
937 }
938 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
939 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
940 /* realloc to the new size */
941 gss->ip4_remote = talloc_realloc(gss, gss->ip4_remote,
942 struct gprs_ns_ie_ip4_elem,
943 gss->num_ip4_remote+num_v4);
944 /* append the new entries to the end of the list */
945 memcpy(&gss->ip4_remote[gss->num_ip4_remote], v4_list, num_v4*sizeof(*v4_list));
946 gss->num_ip4_remote += num_v4;
947
948 LOGPFSML(fi, LOGL_INFO, "Rx SNS-CONFIG: Remote IPv4 list now %u entries\n",
949 gss->num_ip4_remote);
Alexander Couzens67725e22021-02-15 02:37:03 +0100950 if (event == GPRS_SNS_EV_RX_CONFIG_END) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200951 /* check if sum of data / sig weights == 0 */
952 if (ip4_weight_sum_data(gss->ip4_remote, gss->num_ip4_remote) == 0 ||
953 ip4_weight_sum_sig(gss->ip4_remote, gss->num_ip4_remote) == 0) {
954 cause = NS_CAUSE_INVAL_WEIGH;
955 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
956 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
957 return;
958 }
959 create_missing_nsvcs(fi);
960 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
961 /* start the test procedure on ALL NSVCs! */
962 gprs_ns2_start_alive_all_nsvcs(nse);
Alexander Couzens3df58862021-02-05 17:18:08 +0100963 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIGURED, ns_sns_configured_timeout(fi), 4);
Alexander Couzens6a161492020-07-12 13:45:50 +0200964 } else {
965 /* just send CONFIG-ACK */
966 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
Alexander Couzens3df58862021-02-05 17:18:08 +0100967 osmo_timer_schedule(&fi->timer, nse->nsi->timeout[NS_TOUT_TSNS_PROV], 0);
Alexander Couzens6a161492020-07-12 13:45:50 +0200968 }
969}
970
971static void ns_sns_st_config_sgsn_ip6(struct osmo_fsm_inst *fi, uint32_t event, void *data)
972{
973 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
974 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
975 const struct gprs_ns_ie_ip6_elem *v6_list;
976 unsigned int num_v6;
977 struct tlv_parsed *tp = NULL;
978
979 uint8_t cause;
980
981 tp = (struct tlv_parsed *) data;
982
983 if (!TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
984 cause = NS_CAUSE_INVAL_NR_IPv6_EP;
985 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
986 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
987 return;
988 }
989 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
990 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
991 /* realloc to the new size */
992 gss->ip6_remote = talloc_realloc(gss, gss->ip6_remote,
993 struct gprs_ns_ie_ip6_elem,
994 gss->num_ip6_remote+num_v6);
995 /* append the new entries to the end of the list */
996 memcpy(&gss->ip6_remote[gss->num_ip6_remote], v6_list, num_v6*sizeof(*v6_list));
997 gss->num_ip6_remote += num_v6;
998
999 LOGPFSML(fi, LOGL_INFO, "Rx SNS-CONFIG: Remote IPv6 list now %u entries\n",
1000 gss->num_ip6_remote);
Alexander Couzens67725e22021-02-15 02:37:03 +01001001 if (event == GPRS_SNS_EV_RX_CONFIG_END) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001002 /* check if sum of data / sig weights == 0 */
1003 if (ip6_weight_sum_data(gss->ip6_remote, gss->num_ip6_remote) == 0 ||
1004 ip6_weight_sum_sig(gss->ip6_remote, gss->num_ip6_remote) == 0) {
1005 cause = NS_CAUSE_INVAL_WEIGH;
1006 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
1007 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
1008 return;
1009 }
1010 create_missing_nsvcs(fi);
1011 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
1012 /* start the test procedure on ALL NSVCs! */
1013 gprs_ns2_start_alive_all_nsvcs(nse);
1014 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIGURED, 0, 0);
1015 } else {
1016 /* just send CONFIG-ACK */
1017 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
Alexander Couzens790a9632021-02-05 17:18:39 +01001018 osmo_timer_schedule(&fi->timer, nse->nsi->timeout[NS_TOUT_TSNS_PROV], 0);
Alexander Couzens6a161492020-07-12 13:45:50 +02001019 }
1020}
1021
Alexander Couzens790a9632021-02-05 17:18:39 +01001022static void ns2_sns_st_config_sgsn_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
1023{
1024 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
1025
1026 if (old_state != GPRS_SNS_ST_CONFIG_SGSN)
1027 gss->N = 0;
1028}
1029
Alexander Couzens6a161492020-07-12 13:45:50 +02001030static void ns2_sns_st_config_sgsn(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1031{
1032 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
1033
1034 switch (event) {
Alexander Couzens67725e22021-02-15 02:37:03 +01001035 case GPRS_SNS_EV_RX_CONFIG_END:
1036 case GPRS_SNS_EV_RX_CONFIG:
Alexander Couzens6a161492020-07-12 13:45:50 +02001037
1038#if 0 /* part of incoming SNS-SIZE (doesn't happen on BSS side */
1039 if (TLVP_PRESENT(tp, NS_IE_RESET_FLAG)) {
1040 /* reset all existing config */
1041 if (gss->ip4_remote)
1042 talloc_free(gss->ip4_remote);
1043 gss->num_ip4_remote = 0;
1044 }
1045#endif
1046 /* TODO: reject IPv6 elements on IPv4 mode and vice versa */
1047 switch (gss->ip) {
1048 case IPv4:
1049 ns_sns_st_config_sgsn_ip4(fi, event, data);
1050 break;
1051 case IPv6:
1052 ns_sns_st_config_sgsn_ip6(fi, event, data);
1053 break;
1054 default:
1055 OSMO_ASSERT(0);
1056 }
1057 break;
1058 default:
1059 OSMO_ASSERT(0);
1060 }
1061}
1062
Alexander Couzens67725e22021-02-15 02:37:03 +01001063/* called when receiving GPRS_SNS_EV_RX_ADD in state configure */
Alexander Couzens6a161492020-07-12 13:45:50 +02001064static void ns2_sns_st_configured_add(struct osmo_fsm_inst *fi,
1065 struct ns2_sns_state *gss,
1066 struct tlv_parsed *tp)
1067{
1068 const struct gprs_ns_ie_ip4_elem *v4_list = NULL;
1069 const struct gprs_ns_ie_ip6_elem *v6_list = NULL;
1070 int num_v4 = 0, num_v6 = 0;
1071 uint8_t trans_id, cause = 0xff;
Harald Welte7da6ace2020-09-18 09:48:05 +02001072 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +02001073 int rc = 0;
1074
1075 /* TODO: refactor EV_ADD/CHANGE/REMOVE by
1076 * check uniqueness within the lists (no doublicate entries)
1077 * check not-known-by-us and sent back a list of unknown/known values
1078 * (abnormal behaviour according to 48.016)
1079 */
1080
1081 trans_id = *TLVP_VAL(tp, NS_IE_TRANS_ID);
1082 if (gss->ip == IPv4) {
1083 if (!TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
1084 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
1085 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1086 return;
1087 }
1088
1089 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
1090 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001091 for (i = 0; i < num_v4; i++) {
1092 unsigned int j;
Alexander Couzens6a161492020-07-12 13:45:50 +02001093 rc = do_sns_add(fi, &v4_list[i], NULL);
1094 if (rc < 0) {
1095 /* rollback/undo to restore previous state */
Harald Welte7da6ace2020-09-18 09:48:05 +02001096 for (j = 0; j < i; j++)
Alexander Couzens6a161492020-07-12 13:45:50 +02001097 do_sns_delete(fi, &v4_list[j], NULL);
1098 cause = -rc;
1099 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1100 break;
1101 }
1102 }
1103 } else { /* IPv6 */
1104 if (!TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
1105 cause = NS_CAUSE_INVAL_NR_IPv6_EP;
1106 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1107 return;
1108 }
1109
1110 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
1111 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001112 for (i = 0; i < num_v6; i++) {
1113 unsigned int j;
Alexander Couzens6a161492020-07-12 13:45:50 +02001114 rc = do_sns_add(fi, NULL, &v6_list[i]);
1115 if (rc < 0) {
1116 /* rollback/undo to restore previous state */
Harald Welte7da6ace2020-09-18 09:48:05 +02001117 for (j = 0; j < i; j++)
Alexander Couzens6a161492020-07-12 13:45:50 +02001118 do_sns_delete(fi, NULL, &v6_list[j]);
1119 cause = -rc;
1120 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1121 break;
1122 }
1123 }
1124 }
1125
1126 /* TODO: correct behaviour is to answer to the *same* NSVC from which the SNS_ADD was received */
1127 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, NULL, v4_list, num_v4, v6_list, num_v6);
1128}
1129
1130static void ns2_sns_st_configured_delete(struct osmo_fsm_inst *fi,
1131 struct ns2_sns_state *gss,
1132 struct tlv_parsed *tp)
1133{
1134 const struct gprs_ns_ie_ip4_elem *v4_list = NULL;
1135 const struct gprs_ns_ie_ip6_elem *v6_list = NULL;
1136 int num_v4 = 0, num_v6 = 0;
1137 uint8_t trans_id, cause = 0xff;
Harald Welte7da6ace2020-09-18 09:48:05 +02001138 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +02001139 int rc = 0;
1140
1141 /* TODO: split up delete into v4 + v6
1142 * TODO: check if IPv4_LIST or IP_ADDR(v4) is present on IPv6 and vice versa
1143 * TODO: check if IPv4_LIST/IPv6_LIST and IP_ADDR is present at the same time
1144 */
1145 trans_id = *TLVP_VAL(tp, NS_IE_TRANS_ID);
1146 if (gss->ip == IPv4) {
1147 if (TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
1148 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
1149 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001150 for ( i = 0; i < num_v4; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001151 rc = do_sns_delete(fi, &v4_list[i], NULL);
1152 if (rc < 0) {
1153 cause = -rc;
1154 /* continue to delete others */
1155 }
1156 }
1157 if (cause != 0xff) {
1158 /* TODO: create list of not-deleted and return it */
1159 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1160 return;
1161 }
1162
1163 } else if (TLVP_PRESENT(tp, NS_IE_IP_ADDR) && TLVP_LEN(tp, NS_IE_IP_ADDR) == 5) {
1164 /* delete all NS-VCs for given IPv4 address */
1165 const uint8_t *ie = TLVP_VAL(tp, NS_IE_IP_ADDR);
1166 struct gprs_ns_ie_ip4_elem *ip4_remote;
1167 uint32_t ip_addr = *(uint32_t *)(ie+1);
1168 if (ie[0] != 0x01) { /* Address Type != IPv4 */
1169 cause = NS_CAUSE_UNKN_IP_ADDR;
1170 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1171 return;
1172 }
1173 /* make a copy as do_sns_delete() will change the array underneath us */
1174 ip4_remote = talloc_memdup(fi, gss->ip4_remote,
1175 gss->num_ip4_remote * sizeof(*v4_list));
Harald Welte7da6ace2020-09-18 09:48:05 +02001176 for (i = 0; i < gss->num_ip4_remote; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001177 if (ip4_remote[i].ip_addr == ip_addr) {
1178 rc = do_sns_delete(fi, &ip4_remote[i], NULL);
1179 if (rc < 0) {
1180 cause = -rc;
1181 /* continue to delete others */
1182 }
1183 }
1184 }
1185 talloc_free(ip4_remote);
1186 if (cause != 0xff) {
1187 /* TODO: create list of not-deleted and return it */
1188 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1189 return;
1190 }
1191 } else {
1192 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
1193 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1194 return;
1195 }
1196 } else { /* IPv6 */
1197 if (TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
1198 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
1199 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001200 for (i = 0; i < num_v6; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001201 rc = do_sns_delete(fi, NULL, &v6_list[i]);
1202 if (rc < 0) {
1203 cause = -rc;
1204 /* continue to delete others */
1205 }
1206 }
1207 if (cause != 0xff) {
1208 /* TODO: create list of not-deleted and return it */
1209 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1210 return;
1211 }
1212 } else if (TLVP_PRES_LEN(tp, NS_IE_IP_ADDR, 17)) {
1213 /* delete all NS-VCs for given IPv4 address */
1214 const uint8_t *ie = TLVP_VAL(tp, NS_IE_IP_ADDR);
1215 struct gprs_ns_ie_ip6_elem *ip6_remote;
1216 struct in6_addr ip6_addr;
Harald Welte7da6ace2020-09-18 09:48:05 +02001217 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +02001218 if (ie[0] != 0x02) { /* Address Type != IPv6 */
1219 cause = NS_CAUSE_UNKN_IP_ADDR;
1220 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1221 return;
1222 }
1223 memcpy(&ip6_addr, (ie+1), sizeof(struct in6_addr));
1224 /* make a copy as do_sns_delete() will change the array underneath us */
1225 ip6_remote = talloc_memdup(fi, gss->ip6_remote,
1226 gss->num_ip6_remote * sizeof(*v4_list));
Harald Welte7da6ace2020-09-18 09:48:05 +02001227 for (i = 0; i < gss->num_ip6_remote; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001228 if (!memcmp(&ip6_remote[i].ip_addr, &ip6_addr, sizeof(struct in6_addr))) {
1229 rc = do_sns_delete(fi, NULL, &ip6_remote[i]);
1230 if (rc < 0) {
1231 cause = -rc;
1232 /* continue to delete others */
1233 }
1234 }
1235 }
1236
1237 talloc_free(ip6_remote);
1238 if (cause != 0xff) {
1239 /* TODO: create list of not-deleted and return it */
1240 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1241 return;
1242 }
1243 } else {
1244 cause = NS_CAUSE_INVAL_NR_IPv6_EP;
1245 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1246 return;
1247 }
1248 }
1249 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, NULL, v4_list, num_v4, v6_list, num_v6);
1250}
1251
1252static void ns2_sns_st_configured_change(struct osmo_fsm_inst *fi,
1253 struct ns2_sns_state *gss,
1254 struct tlv_parsed *tp)
1255{
1256 const struct gprs_ns_ie_ip4_elem *v4_list = NULL;
1257 const struct gprs_ns_ie_ip6_elem *v6_list = NULL;
1258 int num_v4 = 0, num_v6 = 0;
1259 uint8_t trans_id, cause = 0xff;
1260 int rc = 0;
Harald Welte7da6ace2020-09-18 09:48:05 +02001261 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +02001262
1263 trans_id = *TLVP_VAL(tp, NS_IE_TRANS_ID);
1264 if (TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
1265 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
1266 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001267 for (i = 0; i < num_v4; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001268 rc = do_sns_change_weight(fi, &v4_list[i], NULL);
1269 if (rc < 0) {
1270 cause = -rc;
1271 /* continue to others */
1272 }
1273 }
1274 if (cause != 0xff) {
1275 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1276 return;
1277 }
1278 } else if (TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
1279 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
1280 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001281 for (i = 0; i < num_v6; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001282 rc = do_sns_change_weight(fi, NULL, &v6_list[i]);
1283 if (rc < 0) {
1284 cause = -rc;
1285 /* continue to others */
1286 }
1287 }
1288 if (cause != 0xff) {
1289 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1290 return;
1291 }
1292 } else {
1293 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
1294 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1295 return;
1296 }
1297 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, NULL, v4_list, num_v4, v6_list, num_v6);
1298}
1299
1300static void ns2_sns_st_configured(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1301{
1302 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
1303 struct tlv_parsed *tp = data;
1304
1305 switch (event) {
Alexander Couzens67725e22021-02-15 02:37:03 +01001306 case GPRS_SNS_EV_RX_ADD:
Alexander Couzens6a161492020-07-12 13:45:50 +02001307 ns2_sns_st_configured_add(fi, gss, tp);
1308 break;
Alexander Couzens67725e22021-02-15 02:37:03 +01001309 case GPRS_SNS_EV_RX_DELETE:
Alexander Couzens6a161492020-07-12 13:45:50 +02001310 ns2_sns_st_configured_delete(fi, gss, tp);
1311 break;
Alexander Couzens67725e22021-02-15 02:37:03 +01001312 case GPRS_SNS_EV_RX_CHANGE_WEIGHT:
Alexander Couzens6a161492020-07-12 13:45:50 +02001313 ns2_sns_st_configured_change(fi, gss, tp);
1314 break;
Alexander Couzens67725e22021-02-15 02:37:03 +01001315 case GPRS_SNS_EV_REQ_NSVC_ALIVE:
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01001316 osmo_timer_del(&fi->timer);
1317 break;
Alexander Couzens6a161492020-07-12 13:45:50 +02001318 }
1319}
1320
1321static void ns2_sns_st_configured_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
1322{
1323 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
Alexander Couzens138b96f2021-01-25 16:23:29 +01001324 ns2_prim_status_ind(nse, NULL, 0, GPRS_NS2_AFF_CAUSE_SNS_CONFIGURED);
Alexander Couzens6a161492020-07-12 13:45:50 +02001325}
1326
1327static const struct osmo_fsm_state ns2_sns_bss_states[] = {
1328 [GPRS_SNS_ST_UNCONFIGURED] = {
Alexander Couzense769f522020-12-07 07:37:07 +01001329 .in_event_mask = 0, /* handled by all_state_action */
Alexander Couzens6a161492020-07-12 13:45:50 +02001330 .out_state_mask = S(GPRS_SNS_ST_SIZE),
1331 .name = "UNCONFIGURED",
1332 .action = ns2_sns_st_unconfigured,
1333 },
1334 [GPRS_SNS_ST_SIZE] = {
Alexander Couzens67725e22021-02-15 02:37:03 +01001335 .in_event_mask = S(GPRS_SNS_EV_RX_SIZE_ACK),
Alexander Couzens6a161492020-07-12 13:45:50 +02001336 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
1337 S(GPRS_SNS_ST_SIZE) |
1338 S(GPRS_SNS_ST_CONFIG_BSS),
1339 .name = "SIZE",
1340 .action = ns2_sns_st_size,
1341 .onenter = ns2_sns_st_size_onenter,
1342 },
1343 [GPRS_SNS_ST_CONFIG_BSS] = {
Alexander Couzens67725e22021-02-15 02:37:03 +01001344 .in_event_mask = S(GPRS_SNS_EV_RX_CONFIG_ACK),
Alexander Couzens6a161492020-07-12 13:45:50 +02001345 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
1346 S(GPRS_SNS_ST_CONFIG_BSS) |
1347 S(GPRS_SNS_ST_CONFIG_SGSN) |
1348 S(GPRS_SNS_ST_SIZE),
1349 .name = "CONFIG_BSS",
1350 .action = ns2_sns_st_config_bss,
1351 .onenter = ns2_sns_st_config_bss_onenter,
1352 },
1353 [GPRS_SNS_ST_CONFIG_SGSN] = {
Alexander Couzens67725e22021-02-15 02:37:03 +01001354 .in_event_mask = S(GPRS_SNS_EV_RX_CONFIG) |
1355 S(GPRS_SNS_EV_RX_CONFIG_END),
Alexander Couzens6a161492020-07-12 13:45:50 +02001356 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
1357 S(GPRS_SNS_ST_CONFIG_SGSN) |
1358 S(GPRS_SNS_ST_CONFIGURED) |
1359 S(GPRS_SNS_ST_SIZE),
1360 .name = "CONFIG_SGSN",
1361 .action = ns2_sns_st_config_sgsn,
Alexander Couzens790a9632021-02-05 17:18:39 +01001362 .onenter = ns2_sns_st_config_sgsn_onenter,
Alexander Couzens6a161492020-07-12 13:45:50 +02001363 },
1364 [GPRS_SNS_ST_CONFIGURED] = {
Alexander Couzens67725e22021-02-15 02:37:03 +01001365 .in_event_mask = S(GPRS_SNS_EV_RX_ADD) |
1366 S(GPRS_SNS_EV_RX_DELETE) |
1367 S(GPRS_SNS_EV_RX_CHANGE_WEIGHT) |
1368 S(GPRS_SNS_EV_REQ_NSVC_ALIVE),
Alexander Couzense03d8632020-12-06 03:31:44 +01001369 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
1370 S(GPRS_SNS_ST_SIZE),
Alexander Couzens6a161492020-07-12 13:45:50 +02001371 .name = "CONFIGURED",
1372 .action = ns2_sns_st_configured,
1373 .onenter = ns2_sns_st_configured_onenter,
1374 },
1375};
1376
1377static int ns2_sns_fsm_bss_timer_cb(struct osmo_fsm_inst *fi)
1378{
Alexander Couzens90ee9632020-12-07 06:18:32 +01001379 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
Alexander Couzens6a161492020-07-12 13:45:50 +02001380 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
1381 struct gprs_ns2_inst *nsi = nse->nsi;
1382
Alexander Couzens90ee9632020-12-07 06:18:32 +01001383 gss->N++;
Alexander Couzens6a161492020-07-12 13:45:50 +02001384 switch (fi->T) {
1385 case 1:
Alexander Couzensa367d082020-12-21 14:06:24 +01001386 if (gss->N >= nsi->timeout[NS_TOUT_TSNS_SIZE_RETRIES]) {
1387 LOGPFSML(fi, LOGL_ERROR, "NSE %d: Size retries failed. Selecting next IP-SNS endpoint.\n", nse->nsei);
Alexander Couzens67725e22021-02-15 02:37:03 +01001388 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_REQ_SELECT_ENDPOINT, NULL);
Alexander Couzensa367d082020-12-21 14:06:24 +01001389 } else {
Alexander Couzenscc65a252020-12-21 14:03:58 +01001390 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_SIZE, nsi->timeout[NS_TOUT_TSNS_PROV], 1);
Alexander Couzensa367d082020-12-21 14:06:24 +01001391 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001392 break;
1393 case 2:
Alexander Couzensa367d082020-12-21 14:06:24 +01001394 if (gss->N >= nsi->timeout[NS_TOUT_TSNS_CONFIG_RETRIES]) {
Alexander Couzens3df58862021-02-05 17:18:08 +01001395 LOGPFSML(fi, LOGL_ERROR, "NSE %d: BSS Config retries failed. Selecting next IP-SNS endpoint.\n", nse->nsei);
Alexander Couzens67725e22021-02-15 02:37:03 +01001396 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_REQ_SELECT_ENDPOINT, NULL);
Alexander Couzensa367d082020-12-21 14:06:24 +01001397 } else {
Alexander Couzenscc65a252020-12-21 14:03:58 +01001398 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 +01001399 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001400 break;
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01001401 case 3:
Alexander Couzens3df58862021-02-05 17:18:08 +01001402 if (gss->N >= nsi->timeout[NS_TOUT_TSNS_CONFIG_RETRIES]) {
1403 LOGPFSML(fi, LOGL_ERROR, "NSE %d: SGSN Config retries failed. Selecting next IP-SNS endpoint.\n", nse->nsei);
Alexander Couzens67725e22021-02-15 02:37:03 +01001404 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_REQ_SELECT_ENDPOINT, NULL);
Alexander Couzens3df58862021-02-05 17:18:08 +01001405 } else {
1406 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIG_SGSN, nsi->timeout[NS_TOUT_TSNS_PROV], 3);
1407 }
1408 break;
1409 case 4:
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01001410 LOGPFSML(fi, LOGL_ERROR, "NSE %d: Config succeeded but no NS-VC came online. Selecting next IP-SNS endpoint.\n", nse->nsei);
Alexander Couzens67725e22021-02-15 02:37:03 +01001411 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_REQ_SELECT_ENDPOINT, NULL);
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01001412 break;
Alexander Couzens6a161492020-07-12 13:45:50 +02001413 }
1414 return 0;
1415}
1416
1417static void ns2_sns_st_all_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1418{
Alexander Couzense769f522020-12-07 07:37:07 +01001419 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
Alexander Couzens6a161492020-07-12 13:45:50 +02001420 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001421 struct ns2_sns_bind *sbind;
1422 struct gprs_ns2_vc *nsvc, *nsvc2;
Alexander Couzens6a161492020-07-12 13:45:50 +02001423
Alexander Couzens67725e22021-02-15 02:37:03 +01001424 /* reset when receiving GPRS_SNS_EV_REQ_NO_NSVC */
Alexander Couzense769f522020-12-07 07:37:07 +01001425 switch (event) {
Alexander Couzens67725e22021-02-15 02:37:03 +01001426 case GPRS_SNS_EV_REQ_NO_NSVC:
Alexander Couzens3ad73362020-12-21 13:53:00 +01001427 /* ignore reselection running */
1428 if (gss->reselection_running)
1429 break;
1430
1431 LOGPFSML(fi, LOGL_ERROR, "NSE %d: no remaining NSVC, resetting SNS FSM\n", nse->nsei);
Alexander Couzens67725e22021-02-15 02:37:03 +01001432 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_REQ_SELECT_ENDPOINT, NULL);
Alexander Couzense769f522020-12-07 07:37:07 +01001433 break;
Alexander Couzens67725e22021-02-15 02:37:03 +01001434 case GPRS_SNS_EV_REQ_SELECT_ENDPOINT:
Alexander Couzense769f522020-12-07 07:37:07 +01001435 /* tear down previous state
1436 * gprs_ns2_free_nsvcs() will trigger NO_NSVC, prevent this from triggering a reselection */
1437 gss->reselection_running = true;
1438 gprs_ns2_free_nsvcs(nse);
Alexander Couzens7a7b20b2021-01-18 10:47:33 +01001439 ns2_clear_ipv46_entries(gss);
Alexander Couzense769f522020-12-07 07:37:07 +01001440
1441 /* Choose the next sns endpoint. */
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001442 if (llist_empty(&gss->sns_endpoints) || llist_empty(&gss->binds)) {
Alexander Couzense769f522020-12-07 07:37:07 +01001443 gss->initial = NULL;
Alexander Couzens138b96f2021-01-25 16:23:29 +01001444 ns2_prim_status_ind(gss->nse, NULL, 0, GPRS_NS2_AFF_CAUSE_SNS_NO_ENDPOINTS);
Alexander Couzense769f522020-12-07 07:37:07 +01001445 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 3);
1446 return;
1447 } else if (!gss->initial) {
1448 gss->initial = llist_first_entry(&gss->sns_endpoints, struct sns_endpoint, list);
1449 } else if (gss->initial->list.next == &gss->sns_endpoints) {
1450 /* last entry, continue with first */
1451 gss->initial = llist_first_entry(&gss->sns_endpoints, struct sns_endpoint, list);
1452 } else {
1453 /* next element is an entry */
1454 gss->initial = llist_entry(gss->initial->list.next, struct sns_endpoint, list);
1455 }
1456
1457 gss->reselection_running = false;
1458 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_SIZE, nse->nsi->timeout[NS_TOUT_TSNS_PROV], 1);
1459 break;
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001460 case GPRS_SNS_EV_REQ_ADD_BIND:
1461 sbind = data;
1462 switch (fi->state) {
1463 case GPRS_SNS_ST_UNCONFIGURED:
Alexander Couzens67725e22021-02-15 02:37:03 +01001464 osmo_fsm_inst_dispatch(nse->bss_sns_fi, GPRS_SNS_EV_REQ_SELECT_ENDPOINT, NULL);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001465 break;
1466 case GPRS_SNS_ST_SIZE:
1467 /* TODO: add the ip4 element to the list */
1468 break;
1469 case GPRS_SNS_ST_CONFIG_BSS:
1470 case GPRS_SNS_ST_CONFIG_SGSN:
1471 case GPRS_SNS_ST_CONFIGURED:
1472 /* TODO: add to SNS-IP procedure queue & add nsvc() */
1473 break;
1474 }
1475 break;
1476 case GPRS_SNS_EV_REQ_DELETE_BIND:
1477 sbind = data;
1478 switch (fi->state) {
1479 case GPRS_SNS_ST_UNCONFIGURED:
1480 break;
1481 case GPRS_SNS_ST_SIZE:
1482 /* TODO: remove the ip4 element from the list */
1483 llist_for_each_entry_safe(nsvc, nsvc2, &nse->nsvc, list) {
1484 if (nsvc->bind == sbind->bind) {
1485 gprs_ns2_free_nsvc(nsvc);
1486 }
1487 }
1488 break;
1489 case GPRS_SNS_ST_CONFIG_BSS:
1490 case GPRS_SNS_ST_CONFIG_SGSN:
1491 case GPRS_SNS_ST_CONFIGURED:
1492 /* TODO: do an delete SNS-IP procedure */
1493 /* TODO: remove the ip4 element to the list */
1494 llist_for_each_entry_safe(nsvc, nsvc2, &nse->nsvc, list) {
1495 if (nsvc->bind == sbind->bind) {
1496 gprs_ns2_free_nsvc(nsvc);
1497 }
1498 }
1499 break;
1500 }
1501 /* if this is the last bind, the free_nsvc() will trigger a reselection */
1502 talloc_free(sbind);
1503 break;
Alexander Couzense769f522020-12-07 07:37:07 +01001504 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001505}
1506
1507static struct osmo_fsm gprs_ns2_sns_bss_fsm = {
1508 .name = "GPRS-NS2-SNS-BSS",
1509 .states = ns2_sns_bss_states,
1510 .num_states = ARRAY_SIZE(ns2_sns_bss_states),
Alexander Couzens67725e22021-02-15 02:37:03 +01001511 .allstate_event_mask = S(GPRS_SNS_EV_REQ_NO_NSVC) |
1512 S(GPRS_SNS_EV_REQ_SELECT_ENDPOINT) |
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001513 S(GPRS_SNS_EV_REQ_ADD_BIND) |
1514 S(GPRS_SNS_EV_REQ_DELETE_BIND),
Alexander Couzens6a161492020-07-12 13:45:50 +02001515 .allstate_action = ns2_sns_st_all_action,
1516 .cleanup = NULL,
1517 .timer_cb = ns2_sns_fsm_bss_timer_cb,
Alexander Couzens6a161492020-07-12 13:45:50 +02001518 .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:
Alexander Couzens67725e22021-02-15 02:37:03 +01001578 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_RX_SIZE, tp);
Alexander Couzens6a161492020-07-12 13:45:50 +02001579 break;
1580 case SNS_PDUT_SIZE_ACK:
Alexander Couzens67725e22021-02-15 02:37:03 +01001581 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_RX_SIZE_ACK, tp);
Alexander Couzens6a161492020-07-12 13:45:50 +02001582 break;
1583 case SNS_PDUT_CONFIG:
1584 if (nsh->data[0] & 0x01)
Alexander Couzens67725e22021-02-15 02:37:03 +01001585 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_RX_CONFIG_END, tp);
Alexander Couzens6a161492020-07-12 13:45:50 +02001586 else
Alexander Couzens67725e22021-02-15 02:37:03 +01001587 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_RX_CONFIG, tp);
Alexander Couzens6a161492020-07-12 13:45:50 +02001588 break;
1589 case SNS_PDUT_CONFIG_ACK:
Alexander Couzens67725e22021-02-15 02:37:03 +01001590 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_RX_CONFIG_ACK, tp);
Alexander Couzens6a161492020-07-12 13:45:50 +02001591 break;
1592 case SNS_PDUT_ADD:
Alexander Couzens67725e22021-02-15 02:37:03 +01001593 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_RX_ADD, tp);
Alexander Couzens6a161492020-07-12 13:45:50 +02001594 break;
1595 case SNS_PDUT_DELETE:
Alexander Couzens67725e22021-02-15 02:37:03 +01001596 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_RX_DELETE, tp);
Alexander Couzens6a161492020-07-12 13:45:50 +02001597 break;
1598 case SNS_PDUT_CHANGE_WEIGHT:
Alexander Couzens67725e22021-02-15 02:37:03 +01001599 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_RX_CHANGE_WEIGHT, tp);
Alexander Couzens6a161492020-07-12 13:45:50 +02001600 break;
1601 case SNS_PDUT_ACK:
Harald Welteb9f23872021-03-02 20:48:54 +01001602 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_RX_ACK, tp);
Alexander Couzens6a161492020-07-12 13:45:50 +02001603 break;
1604 default:
Harald Weltef2949742021-01-20 14:54:14 +01001605 LOGPFSML(fi, LOGL_ERROR, "NSEI=%u Rx unknown SNS PDU type %s\n", nsei,
1606 get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
Alexander Couzens6a161492020-07-12 13:45:50 +02001607 return -EINVAL;
1608 }
1609
1610 return 0;
1611}
1612
1613#include <osmocom/vty/vty.h>
1614#include <osmocom/vty/misc.h>
1615
Harald Welte1262c4f2021-01-19 20:58:33 +01001616static 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 +02001617{
1618 struct in_addr in = { .s_addr = ip4->ip_addr };
Harald Welte1262c4f2021-01-19 20:58:33 +01001619 vty_out(vty, "%s %s:%u, Signalling Weight: %u, Data Weight: %u%s", prefix,
Alexander Couzens6a161492020-07-12 13:45:50 +02001620 inet_ntoa(in), ntohs(ip4->udp_port), ip4->sig_weight, ip4->data_weight, VTY_NEWLINE);
1621}
1622
Harald Welte1262c4f2021-01-19 20:58:33 +01001623static 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 +02001624{
1625 char ip_addr[INET6_ADDRSTRLEN] = {};
1626 if (!inet_ntop(AF_INET6, &ip6->ip_addr, ip_addr, (INET6_ADDRSTRLEN)))
1627 strcpy(ip_addr, "Invalid IPv6");
1628
Harald Welte1262c4f2021-01-19 20:58:33 +01001629 vty_out(vty, "%s %s:%u, Signalling Weight: %u, Data Weight: %u%s", prefix,
Alexander Couzens6a161492020-07-12 13:45:50 +02001630 ip_addr, ntohs(ip6->udp_port), ip6->sig_weight, ip6->data_weight, VTY_NEWLINE);
1631}
1632
Harald Welte5bef2cc2020-09-18 22:33:24 +02001633/*! Dump the IP-SNS state to a vty.
1634 * \param[in] vty VTY to which the state shall be printed
Harald Welte1262c4f2021-01-19 20:58:33 +01001635 * \param[in] prefix prefix to print at start of each line (typically indenting)
Harald Welte5bef2cc2020-09-18 22:33:24 +02001636 * \param[in] nse NS Entity whose IP-SNS state shall be printed
1637 * \param[in] stats Whether or not statistics shall also be printed */
Alexander Couzens8dfc24c2021-01-25 16:09:23 +01001638void 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 +02001639{
1640 struct ns2_sns_state *gss;
1641 unsigned int i;
1642
1643 if (!nse->bss_sns_fi)
1644 return;
1645
Harald Welte1262c4f2021-01-19 20:58:33 +01001646 vty_out_fsm_inst2(vty, prefix, nse->bss_sns_fi);
Alexander Couzens6a161492020-07-12 13:45:50 +02001647 gss = (struct ns2_sns_state *) nse->bss_sns_fi->priv;
1648
Harald Welte1262c4f2021-01-19 20:58:33 +01001649 vty_out(vty, "%sMaximum number of remote NS-VCs: %zu, IPv4 Endpoints: %zu, IPv6 Endpoints: %zu%s",
1650 prefix, gss->num_max_nsvcs, gss->num_max_ip4_remote, gss->num_max_ip6_remote, VTY_NEWLINE);
Alexander Couzens6a161492020-07-12 13:45:50 +02001651
1652 if (gss->num_ip4_local && gss->num_ip4_remote) {
Harald Welte1262c4f2021-01-19 20:58:33 +01001653 vty_out(vty, "%sLocal IPv4 Endpoints:%s", prefix, VTY_NEWLINE);
Alexander Couzens6a161492020-07-12 13:45:50 +02001654 for (i = 0; i < gss->num_ip4_local; i++)
Harald Welte1262c4f2021-01-19 20:58:33 +01001655 vty_dump_sns_ip4(vty, prefix, &gss->ip4_local[i]);
Alexander Couzens6a161492020-07-12 13:45:50 +02001656
Harald Welte1262c4f2021-01-19 20:58:33 +01001657 vty_out(vty, "%sRemote IPv4 Endpoints:%s", prefix, VTY_NEWLINE);
Alexander Couzens6a161492020-07-12 13:45:50 +02001658 for (i = 0; i < gss->num_ip4_remote; i++)
Harald Welte1262c4f2021-01-19 20:58:33 +01001659 vty_dump_sns_ip4(vty, prefix, &gss->ip4_remote[i]);
Alexander Couzens6a161492020-07-12 13:45:50 +02001660 }
1661
1662 if (gss->num_ip6_local && gss->num_ip6_remote) {
Harald Welte1262c4f2021-01-19 20:58:33 +01001663 vty_out(vty, "%sLocal IPv6 Endpoints:%s", prefix, VTY_NEWLINE);
Alexander Couzens6a161492020-07-12 13:45:50 +02001664 for (i = 0; i < gss->num_ip6_local; i++)
Harald Welte1262c4f2021-01-19 20:58:33 +01001665 vty_dump_sns_ip6(vty, prefix, &gss->ip6_local[i]);
Alexander Couzens6a161492020-07-12 13:45:50 +02001666
Harald Welte1262c4f2021-01-19 20:58:33 +01001667 vty_out(vty, "%sRemote IPv6 Endpoints:%s", prefix, VTY_NEWLINE);
Alexander Couzens6a161492020-07-12 13:45:50 +02001668 for (i = 0; i < gss->num_ip6_remote; i++)
Harald Welte1262c4f2021-01-19 20:58:33 +01001669 vty_dump_sns_ip6(vty, prefix, &gss->ip6_remote[i]);
Alexander Couzens6a161492020-07-12 13:45:50 +02001670 }
1671}
1672
Alexander Couzens412bc342020-11-19 05:24:37 +01001673/*! write IP-SNS to a vty
1674 * \param[in] vty VTY to which the state shall be printed
1675 * \param[in] nse NS Entity whose IP-SNS state shall be printed */
Alexander Couzens8dfc24c2021-01-25 16:09:23 +01001676void ns2_sns_write_vty(struct vty *vty, const struct gprs_ns2_nse *nse)
Alexander Couzens412bc342020-11-19 05:24:37 +01001677{
1678 struct ns2_sns_state *gss;
1679 struct osmo_sockaddr_str addr_str;
1680 struct sns_endpoint *endpoint;
1681
1682 if (!nse->bss_sns_fi)
1683 return;
1684
1685 gss = (struct ns2_sns_state *) nse->bss_sns_fi->priv;
1686 llist_for_each_entry(endpoint, &gss->sns_endpoints, list) {
Vadim Yanitskiyd8b70032021-01-05 14:24:09 +01001687 /* It's unlikely that an error happens, but let's better be safe. */
1688 if (osmo_sockaddr_str_from_sockaddr(&addr_str, &endpoint->saddr.u.sas) != 0)
1689 addr_str = (struct osmo_sockaddr_str) { .ip = "<INVALID>" };
Alexander Couzens5fa431c2021-02-08 23:21:54 +01001690 vty_out(vty, " ip-sns-remote %s %u%s", addr_str.ip, addr_str.port, VTY_NEWLINE);
Alexander Couzens412bc342020-11-19 05:24:37 +01001691 }
1692}
1693
Alexander Couzense769f522020-12-07 07:37:07 +01001694static struct sns_endpoint *ns2_get_sns_endpoint(struct ns2_sns_state *state,
1695 const struct osmo_sockaddr *saddr)
1696{
1697 struct sns_endpoint *endpoint;
1698
1699 llist_for_each_entry(endpoint, &state->sns_endpoints, list) {
1700 if (!osmo_sockaddr_cmp(saddr, &endpoint->saddr))
1701 return endpoint;
1702 }
1703
1704 return NULL;
1705}
1706
1707/*! gprs_ns2_sns_add_endpoint
1708 * \param[in] nse
1709 * \param[in] sockaddr
1710 * \return
1711 */
1712int gprs_ns2_sns_add_endpoint(struct gprs_ns2_nse *nse,
1713 const struct osmo_sockaddr *saddr)
1714{
1715 struct ns2_sns_state *gss;
1716 struct sns_endpoint *endpoint;
1717 bool do_selection = false;
1718
1719 if (nse->ll != GPRS_NS2_LL_UDP) {
1720 return -EINVAL;
1721 }
1722
Alexander Couzens138b96f2021-01-25 16:23:29 +01001723 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
Alexander Couzense769f522020-12-07 07:37:07 +01001724 return -EINVAL;
1725 }
1726
1727 gss = nse->bss_sns_fi->priv;
1728
1729 if (ns2_get_sns_endpoint(gss, saddr))
1730 return -EADDRINUSE;
1731
1732 endpoint = talloc_zero(nse->bss_sns_fi->priv, struct sns_endpoint);
1733 if (!endpoint)
1734 return -ENOMEM;
1735
1736 endpoint->saddr = *saddr;
1737 if (llist_empty(&gss->sns_endpoints))
1738 do_selection = true;
1739
1740 llist_add_tail(&endpoint->list, &gss->sns_endpoints);
1741 if (do_selection)
Alexander Couzens67725e22021-02-15 02:37:03 +01001742 osmo_fsm_inst_dispatch(nse->bss_sns_fi, GPRS_SNS_EV_REQ_SELECT_ENDPOINT, NULL);
Alexander Couzense769f522020-12-07 07:37:07 +01001743
1744 return 0;
1745}
1746
1747/*! gprs_ns2_sns_del_endpoint
1748 * \param[in] nse
1749 * \param[in] sockaddr
1750 * \return 0 on success, otherwise < 0
1751 */
1752int gprs_ns2_sns_del_endpoint(struct gprs_ns2_nse *nse,
1753 const struct osmo_sockaddr *saddr)
1754{
1755 struct ns2_sns_state *gss;
1756 struct sns_endpoint *endpoint;
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 endpoint = ns2_get_sns_endpoint(gss, saddr);
1768 if (!endpoint)
1769 return -ENOENT;
1770
1771 /* if this is an unused SNS endpoint it's done */
1772 if (gss->initial != endpoint) {
1773 llist_del(&endpoint->list);
1774 talloc_free(endpoint);
1775 return 0;
1776 }
1777
Alexander Couzens67725e22021-02-15 02:37:03 +01001778 /* gprs_ns2_free_nsvcs() will trigger GPRS_SNS_EV_REQ_NO_NSVC on the last NS-VC
Alexander Couzense769f522020-12-07 07:37:07 +01001779 * and restart SNS SIZE procedure which selects a new initial */
Harald Weltef2949742021-01-20 14:54:14 +01001780 LOGNSE(nse, LOGL_INFO, "Current in-use SNS endpoint is being removed."
Alexander Couzense769f522020-12-07 07:37:07 +01001781 "Closing all NS-VC and restart SNS-SIZE procedure"
1782 "with a remaining SNS endpoint.\n");
1783
1784 /* Continue with the next endpoint in the list.
1785 * Special case if the endpoint is at the start or end of the list */
1786 if (endpoint->list.prev == &gss->sns_endpoints ||
1787 endpoint->list.next == &gss->sns_endpoints)
1788 gss->initial = NULL;
1789 else
1790 gss->initial = llist_entry(endpoint->list.next->prev,
1791 struct sns_endpoint,
1792 list);
1793
1794 llist_del(&endpoint->list);
1795 gprs_ns2_free_nsvcs(nse);
1796 talloc_free(endpoint);
1797
1798 return 0;
1799}
1800
1801/*! gprs_ns2_sns_count
1802 * \param[in] nse NS Entity whose IP-SNS endpoints shall be printed
1803 * \return the count of endpoints or < 0 if NSE doesn't contain sns.
1804 */
1805int gprs_ns2_sns_count(struct gprs_ns2_nse *nse)
1806{
1807 struct ns2_sns_state *gss;
1808 struct sns_endpoint *endpoint;
1809 int count = 0;
1810
1811 if (nse->ll != GPRS_NS2_LL_UDP) {
1812 return -EINVAL;
1813 }
1814
Alexander Couzens138b96f2021-01-25 16:23:29 +01001815 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
Alexander Couzense769f522020-12-07 07:37:07 +01001816 return -EINVAL;
1817 }
1818
1819 gss = nse->bss_sns_fi->priv;
1820 llist_for_each_entry(endpoint, &gss->sns_endpoints, list)
1821 count++;
1822
1823 return count;
1824}
1825
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01001826void ns2_sns_notify_alive(struct gprs_ns2_nse *nse, struct gprs_ns2_vc *nsvc, bool alive)
1827{
1828 struct ns2_sns_state *gss;
1829 struct gprs_ns2_vc *tmp;
1830
1831 if (!nse->bss_sns_fi)
1832 return;
1833
1834 gss = nse->bss_sns_fi->priv;
1835 if(nse->bss_sns_fi->state != GPRS_SNS_ST_CONFIGURED)
1836 return;
1837
1838 if (alive == gss->alive)
1839 return;
1840
1841 /* check if this is the current SNS NS-VC */
1842 if (nsvc == gss->sns_nsvc) {
1843 /* only replace the SNS NS-VC if there are other alive NS-VC.
1844 * There aren't any other alive NS-VC when the SNS fsm just reached CONFIGURED
1845 * and couldn't confirm yet if the NS-VC comes up */
1846 if (gss->alive && !alive)
1847 ns2_sns_replace_nsvc(nsvc);
1848 }
1849
1850 if (alive) {
1851 gss->alive = true;
Alexander Couzens67725e22021-02-15 02:37:03 +01001852 osmo_fsm_inst_dispatch(nse->bss_sns_fi, GPRS_SNS_EV_REQ_NSVC_ALIVE, NULL);
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01001853 } else {
1854 /* is there at least another alive nsvc? */
1855 llist_for_each_entry(tmp, &nse->nsvc, list) {
1856 if (ns2_vc_is_unblocked(tmp))
1857 return;
1858 }
1859
1860 /* all NS-VC have failed */
1861 gss->alive = false;
Alexander Couzens67725e22021-02-15 02:37:03 +01001862 osmo_fsm_inst_dispatch(nse->bss_sns_fi, GPRS_SNS_EV_REQ_NO_NSVC, NULL);
Alexander Couzensbe7cecc2021-02-03 18:25:27 +01001863 }
1864}
1865
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001866int gprs_ns2_sns_add_bind(struct gprs_ns2_nse *nse,
1867 struct gprs_ns2_vc_bind *bind)
1868{
1869 struct ns2_sns_state *gss;
1870 struct ns2_sns_bind *tmp;
1871
1872 OSMO_ASSERT(nse->bss_sns_fi);
1873 gss = nse->bss_sns_fi->priv;
1874
1875 if (!gprs_ns2_is_ip_bind(bind)) {
1876 return -EINVAL;
1877 }
1878
1879 if (!llist_empty(&gss->binds)) {
1880 llist_for_each_entry(tmp, &gss->binds, list) {
1881 if (tmp->bind == bind)
1882 return -EALREADY;
1883 }
1884 }
1885
1886 tmp = talloc_zero(gss, struct ns2_sns_bind);
1887 if (!tmp)
1888 return -ENOMEM;
1889 tmp->bind = bind;
1890 llist_add_tail(&tmp->list, &gss->binds);
1891
1892 osmo_fsm_inst_dispatch(nse->bss_sns_fi, GPRS_SNS_EV_REQ_ADD_BIND, tmp);
1893 return 0;
1894}
1895
1896/* Remove a bind from the SNS. All assosiated NSVC must be removed. */
1897int gprs_ns2_sns_del_bind(struct gprs_ns2_nse *nse,
1898 struct gprs_ns2_vc_bind *bind)
1899{
1900 struct ns2_sns_state *gss;
1901 struct ns2_sns_bind *tmp, *tmp2;
1902 bool found = false;
1903
1904 if (!nse->bss_sns_fi)
1905 return -EINVAL;
1906
1907 gss = nse->bss_sns_fi->priv;
1908 if (gss->initial_bind && gss->initial_bind->bind == bind) {
1909 if (gss->initial_bind->list.prev == &gss->binds)
1910 gss->initial_bind = NULL;
1911 else
1912 gss->initial_bind = llist_entry(gss->initial_bind->list.prev, struct ns2_sns_bind, list);
1913 }
1914
1915 llist_for_each_entry_safe(tmp, tmp2, &gss->binds, list) {
1916 if (tmp->bind == bind) {
1917 llist_del(&tmp->list);
1918 found = true;
1919 }
1920 }
1921
1922 if (!found)
1923 return -ENOENT;
1924
1925 osmo_fsm_inst_dispatch(nse->bss_sns_fi, GPRS_SNS_EV_REQ_DELETE_BIND, tmp);
1926 return 0;
1927}
1928
Alexander Couzensc4704762021-02-08 23:13:12 +01001929/* Update SNS weights
1930 * \param[in] nsvc the NSVC which should be updated
1931 */
1932void ns2_sns_update_weights(struct gprs_ns2_vc_bind *bind)
1933{
1934 /* TODO: implement weights after binds per sns implemented */
1935}
1936
Alexander Couzens6a161492020-07-12 13:45:50 +02001937/* initialize osmo_ctx on main tread */
1938static __attribute__((constructor)) void on_dso_load_ctx(void)
1939{
1940 OSMO_ASSERT(osmo_fsm_register(&gprs_ns2_sns_bss_fsm) == 0);
1941}