blob: 195847755ec0ef227e4f942839cd27e11e9b3ea8 [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,
83};
84
85static const struct value_string gprs_sns_event_names[] = {
Alexander Couzense769f522020-12-07 07:37:07 +010086 { GPRS_SNS_EV_SELECT_ENDPOINT, "SELECT_ENDPOINT" },
Alexander Couzens6a161492020-07-12 13:45:50 +020087 { GPRS_SNS_EV_SIZE, "SIZE" },
88 { GPRS_SNS_EV_SIZE_ACK, "SIZE_ACK" },
89 { GPRS_SNS_EV_CONFIG, "CONFIG" },
90 { GPRS_SNS_EV_CONFIG_END, "CONFIG_END" },
91 { GPRS_SNS_EV_CONFIG_ACK, "CONFIG_ACK" },
92 { GPRS_SNS_EV_ADD, "ADD" },
93 { GPRS_SNS_EV_DELETE, "DELETE" },
94 { GPRS_SNS_EV_CHANGE_WEIGHT, "CHANGE_WEIGHT" },
Pau Espin Pedrol0a446a12020-10-27 13:30:08 +010095 { GPRS_SNS_EV_NO_NSVC, "NO_NSVC" },
Alexander Couzens6a161492020-07-12 13:45:50 +020096 { 0, NULL }
97};
98
Alexander Couzense769f522020-12-07 07:37:07 +010099struct sns_endpoint {
100 struct llist_head list;
101 struct osmo_sockaddr saddr;
102};
103
Alexander Couzens6a161492020-07-12 13:45:50 +0200104struct ns2_sns_state {
105 struct gprs_ns2_nse *nse;
106
107 enum ns2_sns_type ip;
108
Alexander Couzense769f522020-12-07 07:37:07 +0100109 /* holds the list of initial SNS endpoints */
110 struct llist_head sns_endpoints;
111 /* prevent recursive reselection */
112 bool reselection_running;
113
114 /* The current initial SNS endpoints.
115 * The initial connection will be moved into the NSE
116 * if configured via SNS. Otherwise it will be removed
117 * in configured state. */
118 struct sns_endpoint *initial;
Alexander Couzens6a161492020-07-12 13:45:50 +0200119 /* all SNS PDU will be sent over this nsvc */
120 struct gprs_ns2_vc *sns_nsvc;
Alexander Couzens81ae0aa2020-12-07 05:49:43 +0100121 /* iterate over the binds after all remote has been tested */
122 int bind_offset;
Alexander Couzens90ee9632020-12-07 06:18:32 +0100123 /* timer N */
124 int N;
Alexander Couzens6a161492020-07-12 13:45:50 +0200125
126 /* local configuration to send to the remote end */
127 struct gprs_ns_ie_ip4_elem *ip4_local;
128 size_t num_ip4_local;
129
130 /* local configuration to send to the remote end */
131 struct gprs_ns_ie_ip6_elem *ip6_local;
132 size_t num_ip6_local;
133
134 /* local configuration about our capabilities in terms of connections to
135 * remote (SGSN) side */
136 size_t num_max_nsvcs;
137 size_t num_max_ip4_remote;
138 size_t num_max_ip6_remote;
139
140 /* remote configuration as received */
141 struct gprs_ns_ie_ip4_elem *ip4_remote;
142 unsigned int num_ip4_remote;
143
144 /* remote configuration as received */
145 struct gprs_ns_ie_ip6_elem *ip6_remote;
146 unsigned int num_ip6_remote;
147};
148
149static inline struct gprs_ns2_nse *nse_inst_from_fi(struct osmo_fsm_inst *fi)
150{
151 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
152 return gss->nse;
153}
154
155/* helper function to compute the sum of all (data or signaling) weights */
156static int ip4_weight_sum(const struct gprs_ns_ie_ip4_elem *ip4, unsigned int num,
157 bool data_weight)
158{
159 unsigned int i;
160 int weight_sum = 0;
161
162 for (i = 0; i < num; i++) {
163 if (data_weight)
164 weight_sum += ip4[i].data_weight;
165 else
166 weight_sum += ip4[i].sig_weight;
167 }
168 return weight_sum;
169}
170#define ip4_weight_sum_data(x,y) ip4_weight_sum(x, y, true)
171#define ip4_weight_sum_sig(x,y) ip4_weight_sum(x, y, false)
172
173/* helper function to compute the sum of all (data or signaling) weights */
174static int ip6_weight_sum(const struct gprs_ns_ie_ip6_elem *ip6, unsigned int num,
175 bool data_weight)
176{
177 unsigned int i;
178 int weight_sum = 0;
179
180 for (i = 0; i < num; i++) {
181 if (data_weight)
182 weight_sum += ip6[i].data_weight;
183 else
184 weight_sum += ip6[i].sig_weight;
185 }
186 return weight_sum;
187}
188#define ip6_weight_sum_data(x,y) ip6_weight_sum(x, y, true)
189#define ip6_weight_sum_sig(x,y) ip6_weight_sum(x, y, false)
190
191static struct gprs_ns2_vc *nsvc_by_ip4_elem(struct gprs_ns2_nse *nse,
192 const struct gprs_ns_ie_ip4_elem *ip4)
193{
194 struct osmo_sockaddr sa;
195 /* copy over. Both data structures use network byte order */
196 sa.u.sin.sin_addr.s_addr = ip4->ip_addr;
197 sa.u.sin.sin_port = ip4->udp_port;
198 sa.u.sin.sin_family = AF_INET;
199
Alexander Couzens38b19e82020-09-23 23:56:37 +0200200 return gprs_ns2_nsvc_by_sockaddr_nse(nse, &sa);
Alexander Couzens6a161492020-07-12 13:45:50 +0200201}
202
203static struct gprs_ns2_vc *nsvc_by_ip6_elem(struct gprs_ns2_nse *nse,
204 const struct gprs_ns_ie_ip6_elem *ip6)
205{
206 struct osmo_sockaddr sa;
207 /* copy over. Both data structures use network byte order */
208 sa.u.sin6.sin6_addr = ip6->ip_addr;
209 sa.u.sin6.sin6_port = ip6->udp_port;
210 sa.u.sin6.sin6_family = AF_INET;
211
Alexander Couzens38b19e82020-09-23 23:56:37 +0200212 return gprs_ns2_nsvc_by_sockaddr_nse(nse, &sa);
Alexander Couzens6a161492020-07-12 13:45:50 +0200213}
214
Alexander Couzens125298f2020-10-11 21:22:42 +0200215/*! Return the initial SNS remote socket address
216 * \param nse NS Entity
217 * \return address of the initial SNS connection; NULL in case of error
218 */
219const struct osmo_sockaddr *gprs_ns2_nse_sns_remote(struct gprs_ns2_nse *nse)
220{
221 struct ns2_sns_state *gss;
222
223 if (!nse->bss_sns_fi)
224 return NULL;
225
226 gss = (struct ns2_sns_state *) nse->bss_sns_fi->priv;
Alexander Couzense769f522020-12-07 07:37:07 +0100227 return &gss->initial->saddr;
Alexander Couzens125298f2020-10-11 21:22:42 +0200228}
229
Alexander Couzens6a161492020-07-12 13:45:50 +0200230/*! called when a nsvc is beeing freed */
231void ns2_sns_free_nsvc(struct gprs_ns2_vc *nsvc)
232{
233 struct gprs_ns2_nse *nse;
234 struct gprs_ns2_vc *tmp;
235 struct ns2_sns_state *gss;
236 struct osmo_fsm_inst *fi = nsvc->nse->bss_sns_fi;
237
238 if (!fi)
239 return;
240
241 gss = (struct ns2_sns_state *) fi->priv;
242 if (nsvc != gss->sns_nsvc)
243 return;
244
245 nse = nsvc->nse;
246 if (nse->alive) {
247 /* choose a different sns nsvc */
248 llist_for_each_entry(tmp, &nse->nsvc, list) {
249 if (gprs_ns2_vc_is_unblocked(tmp))
250 gss->sns_nsvc = tmp;
251 }
252 } else {
Alexander Couzens6a161492020-07-12 13:45:50 +0200253 gss->sns_nsvc = NULL;
254 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_NO_NSVC, NULL);
255 }
256}
257
258static void ns2_nsvc_create_ip4(struct osmo_fsm_inst *fi,
259 struct gprs_ns2_nse *nse,
260 const struct gprs_ns_ie_ip4_elem *ip4)
261{
262 struct gprs_ns2_inst *nsi = nse->nsi;
263 struct gprs_ns2_vc *nsvc;
264 struct gprs_ns2_vc_bind *bind;
Alexander Couzensc068d862020-10-12 04:11:51 +0200265 struct osmo_sockaddr remote = { };
Alexander Couzens6a161492020-07-12 13:45:50 +0200266 /* copy over. Both data structures use network byte order */
267 remote.u.sin.sin_family = AF_INET;
268 remote.u.sin.sin_addr.s_addr = ip4->ip_addr;
269 remote.u.sin.sin_port = ip4->udp_port;
270
271 /* for every bind, create a connection if bind type == IP */
272 llist_for_each_entry(bind, &nsi->binding, list) {
Daniel Willmann967e2c12021-01-14 16:58:17 +0100273 if (bind->ll != GPRS_NS2_LL_UDP)
274 continue;
Alexander Couzens6a161492020-07-12 13:45:50 +0200275 /* ignore failed connection */
276 nsvc = gprs_ns2_ip_connect_inactive(bind,
277 &remote,
278 nse, 0);
279 if (!nsvc) {
280 LOGPFSML(fi, LOGL_ERROR, "SNS-CONFIG: Failed to create NSVC\n");
281 continue;
282 }
283
284 nsvc->sig_weight = ip4->sig_weight;
285 nsvc->data_weight = ip4->data_weight;
286 }
287}
288
289static void ns2_nsvc_create_ip6(struct osmo_fsm_inst *fi,
290 struct gprs_ns2_nse *nse,
291 const struct gprs_ns_ie_ip6_elem *ip6)
292{
293 struct gprs_ns2_inst *nsi = nse->nsi;
294 struct gprs_ns2_vc *nsvc;
295 struct gprs_ns2_vc_bind *bind;
296 struct osmo_sockaddr remote = {};
297 /* copy over. Both data structures use network byte order */
298 remote.u.sin6.sin6_family = AF_INET6;
299 remote.u.sin6.sin6_addr = ip6->ip_addr;
300 remote.u.sin6.sin6_port = ip6->udp_port;
301
302 /* for every bind, create a connection if bind type == IP */
303 llist_for_each_entry(bind, &nsi->binding, list) {
Daniel Willmann967e2c12021-01-14 16:58:17 +0100304 if (bind->ll != GPRS_NS2_LL_UDP)
305 continue;
Alexander Couzens6a161492020-07-12 13:45:50 +0200306 /* 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 = ip6->sig_weight;
316 nsvc->data_weight = ip6->data_weight;
317 }
318}
319
320
321static int create_missing_nsvcs(struct osmo_fsm_inst *fi)
322{
323 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
324 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
325 struct gprs_ns2_vc *nsvc;
326 struct gprs_ns2_vc_bind *bind;
327 struct osmo_sockaddr remote = { };
328 unsigned int i;
329
330 for (i = 0; i < gss->num_ip4_remote; i++) {
331 const struct gprs_ns_ie_ip4_elem *ip4 = &gss->ip4_remote[i];
332
333 remote.u.sin.sin_family = AF_INET;
334 remote.u.sin.sin_addr.s_addr = ip4->ip_addr;
335 remote.u.sin.sin_port = ip4->udp_port;
336
337 llist_for_each_entry(bind, &nse->nsi->binding, list) {
338 bool found = false;
Daniel Willmann967e2c12021-01-14 16:58:17 +0100339 if (bind->ll != GPRS_NS2_LL_UDP)
340 continue;
Alexander Couzens6a161492020-07-12 13:45:50 +0200341
342 llist_for_each_entry(nsvc, &nse->nsvc, list) {
343 if (nsvc->bind != bind)
344 continue;
345
Alexander Couzensc4229a42020-10-11 20:58:04 +0200346 if (!osmo_sockaddr_cmp(&remote, gprs_ns2_ip_vc_remote(nsvc))) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200347 found = true;
348 break;
349 }
350 }
351
352 if (!found) {
353 nsvc = gprs_ns2_ip_connect_inactive(bind, &remote, nse, 0);
354 if (!nsvc) {
355 /* TODO: add to a list to send back a NS-STATUS */
356 continue;
357 }
358 }
359
360 /* update data / signalling weight */
361 nsvc->data_weight = ip4->data_weight;
362 nsvc->sig_weight = ip4->sig_weight;
363 nsvc->sns_only = false;
364 }
365 }
366
367 for (i = 0; i < gss->num_ip6_remote; i++) {
368 const struct gprs_ns_ie_ip6_elem *ip6 = &gss->ip6_remote[i];
369
370 remote.u.sin6.sin6_family = AF_INET6;
371 remote.u.sin6.sin6_addr = ip6->ip_addr;
372 remote.u.sin6.sin6_port = ip6->udp_port;
373
374 llist_for_each_entry(bind, &nse->nsi->binding, list) {
375 bool found = false;
Daniel Willmann967e2c12021-01-14 16:58:17 +0100376 if (bind->ll != GPRS_NS2_LL_UDP)
377 continue;
Alexander Couzens6a161492020-07-12 13:45:50 +0200378
379 llist_for_each_entry(nsvc, &nse->nsvc, list) {
380 if (nsvc->bind != bind)
381 continue;
382
Alexander Couzensc4229a42020-10-11 20:58:04 +0200383 if (!osmo_sockaddr_cmp(&remote, gprs_ns2_ip_vc_remote(nsvc))) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200384 found = true;
385 break;
386 }
387 }
388
389 if (!found) {
390 nsvc = gprs_ns2_ip_connect_inactive(bind, &remote, nse, 0);
391 if (!nsvc) {
392 /* TODO: add to a list to send back a NS-STATUS */
393 continue;
394 }
395 }
396
397 /* update data / signalling weight */
398 nsvc->data_weight = ip6->data_weight;
399 nsvc->sig_weight = ip6->sig_weight;
400 nsvc->sns_only = false;
401 }
402 }
403
404
405 return 0;
406}
407
408/* Add a given remote IPv4 element to gprs_sns_state */
409static int add_remote_ip4_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip4_elem *ip4)
410{
411 unsigned int i;
412
413 if (gss->num_ip4_remote >= gss->num_max_ip4_remote)
414 return -NS_CAUSE_INVAL_NR_NS_VC;
415
416 /* check for duplicates */
417 for (i = 0; i < gss->num_ip4_remote; i++) {
418 if (memcmp(&gss->ip4_remote[i], ip4, sizeof(*ip4)))
419 continue;
420 /* TODO: log message duplicate */
421 /* TODO: check if this is the correct cause code */
422 return -NS_CAUSE_PROTO_ERR_UNSPEC;
423 }
424
425 gss->ip4_remote = talloc_realloc(gss, gss->ip4_remote, struct gprs_ns_ie_ip4_elem,
426 gss->num_ip4_remote+1);
427 gss->ip4_remote[gss->num_ip4_remote] = *ip4;
428 gss->num_ip4_remote += 1;
429 return 0;
430}
431
432/* Remove a given remote IPv4 element from gprs_sns_state */
433static int remove_remote_ip4_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip4_elem *ip4)
434{
435 unsigned int i;
436
437 for (i = 0; i < gss->num_ip4_remote; i++) {
438 if (memcmp(&gss->ip4_remote[i], ip4, sizeof(*ip4)))
439 continue;
440 /* all array elements < i remain as they are; all > i are shifted left by one */
441 memmove(&gss->ip4_remote[i], &gss->ip4_remote[i+1], gss->num_ip4_remote-i-1);
442 gss->num_ip4_remote -= 1;
443 return 0;
444 }
445 return -1;
446}
447
448/* update the weights for specified remote IPv4 */
449static int update_remote_ip4_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip4_elem *ip4)
450{
451 unsigned int i;
452
453 for (i = 0; i < gss->num_ip4_remote; i++) {
454 if (gss->ip4_remote[i].ip_addr != ip4->ip_addr ||
455 gss->ip4_remote[i].udp_port != ip4->udp_port)
456 continue;
457
458 gss->ip4_remote[i].sig_weight = ip4->sig_weight;
459 gss->ip4_remote[i].data_weight = ip4->data_weight;
460 return 0;
461 }
462 return -1;
463}
464
465/* Add a given remote IPv6 element to gprs_sns_state */
466static int add_remote_ip6_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip6_elem *ip6)
467{
468 if (gss->num_ip6_remote >= gss->num_max_ip6_remote)
469 return -NS_CAUSE_INVAL_NR_NS_VC;
470
471 gss->ip6_remote = talloc_realloc(gss, gss->ip6_remote, struct gprs_ns_ie_ip6_elem,
472 gss->num_ip6_remote+1);
473 gss->ip6_remote[gss->num_ip6_remote] = *ip6;
474 gss->num_ip6_remote += 1;
475 return 0;
476}
477
478/* Remove a given remote IPv6 element from gprs_sns_state */
479static int remove_remote_ip6_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip6_elem *ip6)
480{
481 unsigned int i;
482
483 for (i = 0; i < gss->num_ip6_remote; i++) {
484 if (memcmp(&gss->ip6_remote[i], ip6, sizeof(*ip6)))
485 continue;
486 /* all array elements < i remain as they are; all > i are shifted left by one */
487 memmove(&gss->ip6_remote[i], &gss->ip6_remote[i+1], gss->num_ip6_remote-i-1);
488 gss->num_ip6_remote -= 1;
489 return 0;
490 }
491 return -1;
492}
493
494/* update the weights for specified remote IPv6 */
495static int update_remote_ip6_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip6_elem *ip6)
496{
497 unsigned int i;
498
499 for (i = 0; i < gss->num_ip6_remote; i++) {
500 if (memcmp(&gss->ip6_remote[i].ip_addr, &ip6->ip_addr, sizeof(ip6->ip_addr)) ||
501 gss->ip6_remote[i].udp_port != ip6->udp_port)
502 continue;
503 gss->ip6_remote[i].sig_weight = ip6->sig_weight;
504 gss->ip6_remote[i].data_weight = ip6->data_weight;
505 return 0;
506 }
507 return -1;
508}
509
510static 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)
511{
512 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
513 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
514 struct gprs_ns2_vc *nsvc;
515 struct osmo_sockaddr sa = {};
Alexander Couzens9a4cf272020-10-11 20:48:04 +0200516 const struct osmo_sockaddr *remote;
Alexander Couzens6a161492020-07-12 13:45:50 +0200517 uint8_t new_signal;
518 uint8_t new_data;
519
520 /* TODO: Upon receiving an SNS-CHANGEWEIGHT PDU, if the resulting sum of the
521 * signalling weights of all the peer IP endpoints configured for this NSE is
522 * equal to zero or if the resulting sum of the data weights of all the peer IP
523 * endpoints configured for this NSE is equal to zero, the BSS/SGSN shall send an
524 * SNS-ACK PDU with a cause code of "Invalid weights". */
525
526 if (ip4) {
527 if (update_remote_ip4_elem(gss, ip4))
528 return -NS_CAUSE_UNKN_IP_EP;
529
530 /* copy over. Both data structures use network byte order */
531 sa.u.sin.sin_addr.s_addr = ip4->ip_addr;
532 sa.u.sin.sin_port = ip4->udp_port;
533 sa.u.sin.sin_family = AF_INET;
534 new_signal = ip4->sig_weight;
535 new_data = ip4->data_weight;
536 } else if (ip6) {
537 if (update_remote_ip6_elem(gss, ip6))
538 return -NS_CAUSE_UNKN_IP_EP;
539
540 /* copy over. Both data structures use network byte order */
541 sa.u.sin6.sin6_addr = ip6->ip_addr;
542 sa.u.sin6.sin6_port = ip6->udp_port;
543 sa.u.sin6.sin6_family = AF_INET6;
544 new_signal = ip6->sig_weight;
545 new_data = ip6->data_weight;
546 } else {
547 OSMO_ASSERT(false);
548 }
549
550 llist_for_each_entry(nsvc, &nse->nsvc, list) {
Alexander Couzensc4229a42020-10-11 20:58:04 +0200551 remote = gprs_ns2_ip_vc_remote(nsvc);
Alexander Couzens6a161492020-07-12 13:45:50 +0200552 /* all nsvc in NSE should be IP/UDP nsvc */
553 OSMO_ASSERT(remote);
554
555 if (osmo_sockaddr_cmp(&sa, remote))
556 continue;
557
558 LOGPFSML(fi, LOGL_INFO, "CHANGE-WEIGHT NS-VC %s data_weight %u->%u, sig_weight %u->%u\n",
559 gprs_ns2_ll_str(nsvc), nsvc->data_weight, new_data,
560 nsvc->sig_weight, new_signal);
561
562 nsvc->data_weight = new_data;
563 nsvc->sig_weight = new_signal;
564 }
565
566 return 0;
567}
568
569static int do_sns_delete(struct osmo_fsm_inst *fi,
570 const struct gprs_ns_ie_ip4_elem *ip4,
571 const struct gprs_ns_ie_ip6_elem *ip6)
572{
573 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
574 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
575 struct gprs_ns2_vc *nsvc, *tmp;
Alexander Couzens9a4cf272020-10-11 20:48:04 +0200576 const struct osmo_sockaddr *remote;
Alexander Couzens6a161492020-07-12 13:45:50 +0200577 struct osmo_sockaddr sa = {};
578
579 if (ip4) {
580 if (remove_remote_ip4_elem(gss, ip4) < 0)
581 return -NS_CAUSE_UNKN_IP_EP;
582 /* copy over. Both data structures use network byte order */
583 sa.u.sin.sin_addr.s_addr = ip4->ip_addr;
584 sa.u.sin.sin_port = ip4->udp_port;
585 sa.u.sin.sin_family = AF_INET;
586 } else if (ip6) {
587 if (remove_remote_ip6_elem(gss, ip6))
588 return -NS_CAUSE_UNKN_IP_EP;
589
590 /* copy over. Both data structures use network byte order */
591 sa.u.sin6.sin6_addr = ip6->ip_addr;
592 sa.u.sin6.sin6_port = ip6->udp_port;
593 sa.u.sin6.sin6_family = AF_INET6;
594 } else {
595 OSMO_ASSERT(false);
596 }
597
598 llist_for_each_entry_safe(nsvc, tmp, &nse->nsvc, list) {
Alexander Couzensc4229a42020-10-11 20:58:04 +0200599 remote = gprs_ns2_ip_vc_remote(nsvc);
Alexander Couzens6a161492020-07-12 13:45:50 +0200600 /* all nsvc in NSE should be IP/UDP nsvc */
601 OSMO_ASSERT(remote);
602 if (osmo_sockaddr_cmp(&sa, remote))
603 continue;
604
605 LOGPFSML(fi, LOGL_INFO, "DELETE NS-VC %s\n", gprs_ns2_ll_str(nsvc));
606 gprs_ns2_free_nsvc(nsvc);
607 }
608
609 return 0;
610}
611
612static int do_sns_add(struct osmo_fsm_inst *fi,
613 const struct gprs_ns_ie_ip4_elem *ip4,
614 const struct gprs_ns_ie_ip6_elem *ip6)
615{
616 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
617 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
618 struct gprs_ns2_vc *nsvc;
619 int rc = 0;
620
621 /* Upon receiving an SNS-ADD PDU, if the consequent number of IPv4 endpoints
622 * exceeds the number of IPv4 endpoints supported by the NSE, the NSE shall send
623 * an SNS-ACK PDU with a cause code set to "Invalid number of IP4 Endpoints". */
624 switch (gss->ip) {
625 case IPv4:
626 rc = add_remote_ip4_elem(gss, ip4);
627 break;
628 case IPv6:
629 rc = add_remote_ip6_elem(gss, ip6);
630 break;
631 default:
632 /* the gss->ip is initialized with the bss */
633 OSMO_ASSERT(false);
634 }
635
636 if (rc)
637 return rc;
638
639 /* Upon receiving an SNS-ADD PDU containing an already configured IP endpoint the
640 * NSE shall send an SNS-ACK PDU with the cause code "Protocol error -
641 * unspecified" */
642 switch (gss->ip) {
643 case IPv4:
644 nsvc = nsvc_by_ip4_elem(nse, ip4);
645 if (nsvc) {
646 /* the nsvc should be already in sync with the ip4 / ip6 elements */
647 return -NS_CAUSE_PROTO_ERR_UNSPEC;
648 }
649
650 /* TODO: failure case */
651 ns2_nsvc_create_ip4(fi, nse, ip4);
652 break;
653 case IPv6:
654 nsvc = nsvc_by_ip6_elem(nse, ip6);
655 if (nsvc) {
656 /* the nsvc should be already in sync with the ip4 / ip6 elements */
657 return -NS_CAUSE_PROTO_ERR_UNSPEC;
658 }
659
660 /* TODO: failure case */
661 ns2_nsvc_create_ip6(fi, nse, ip6);
662 break;
663 }
664
665 gprs_ns2_start_alive_all_nsvcs(nse);
666
667 return 0;
668}
669
670
671static void ns2_sns_st_unconfigured(struct osmo_fsm_inst *fi, uint32_t event, void *data)
672{
Alexander Couzense769f522020-12-07 07:37:07 +0100673 /* empty state - SNS Select will start by ns2_sns_st_all_action() */
Alexander Couzens6a161492020-07-12 13:45:50 +0200674}
675
676static void ns2_sns_st_size(struct osmo_fsm_inst *fi, uint32_t event, void *data)
677{
678 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
679 struct gprs_ns2_inst *nsi = nse->nsi;
680 struct tlv_parsed *tp = NULL;
681
682 switch (event) {
683 case GPRS_SNS_EV_SIZE_ACK:
684 tp = data;
685 if (TLVP_VAL_MINLEN(tp, NS_IE_CAUSE, 1)) {
686 LOGPFSML(fi, LOGL_ERROR, "SNS-SIZE-ACK with cause %s\n",
687 gprs_ns2_cause_str(*TLVP_VAL(tp, NS_IE_CAUSE)));
688 /* TODO: What to do? */
689 } else {
690 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIG_BSS,
691 nsi->timeout[NS_TOUT_TSNS_PROV], 2);
692 }
693 break;
694 default:
695 OSMO_ASSERT(0);
696 }
697}
698
Alexander Couzense769f522020-12-07 07:37:07 +0100699/* setup all dynamic SNS settings, create a new nsvc and send the SIZE */
Alexander Couzens6a161492020-07-12 13:45:50 +0200700static void ns2_sns_st_size_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
701{
702 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
Alexander Couzense769f522020-12-07 07:37:07 +0100703 struct gprs_ns_ie_ip4_elem *ip4_elems;
704 struct gprs_ns_ie_ip6_elem *ip6_elems;
705 struct gprs_ns2_vc_bind *bind;
706 struct gprs_ns2_inst *nsi = gss->nse->nsi;
707 struct osmo_sockaddr *remote;
708 const struct osmo_sockaddr *sa;
709 struct osmo_sockaddr local;
710 int count;
Alexander Couzens6a161492020-07-12 13:45:50 +0200711
Alexander Couzense769f522020-12-07 07:37:07 +0100712 /* on a generic failure, the timer callback will recover */
Alexander Couzens6a161492020-07-12 13:45:50 +0200713 if (old_state != GPRS_SNS_ST_UNCONFIGURED)
Daniel Willmann15c09a82020-11-03 23:05:43 +0100714 ns2_prim_status_ind(gss->nse, NULL, 0, NS_AFF_CAUSE_SNS_FAILURE);
Alexander Couzens6a161492020-07-12 13:45:50 +0200715
Alexander Couzense769f522020-12-07 07:37:07 +0100716 /* no initial available */
717 if (!gss->initial)
718 return;
719
720 remote = &gss->initial->saddr;
721
722 /* count how many bindings are available (only UDP binds) */
723 count = ns2_ip_count_bind(nsi, remote);
724 if (count == 0) {
725 /* TODO: logging */
726 return;
727 }
728
Alexander Couzens81ae0aa2020-12-07 05:49:43 +0100729 bind = ns2_ip_get_bind_by_index(nsi, remote, gss->bind_offset);
Alexander Couzense769f522020-12-07 07:37:07 +0100730 if (!bind) {
Alexander Couzens81ae0aa2020-12-07 05:49:43 +0100731 if (gss->bind_offset) {
732 gss->bind_offset = 0;
733 bind = ns2_ip_get_bind_by_index(nsi, remote, gss->bind_offset);
734 }
735
736 if (!bind)
737 return;
Alexander Couzense769f522020-12-07 07:37:07 +0100738 }
739
740 /* setup the NSVC */
741 if (!gss->sns_nsvc) {
742 gss->sns_nsvc = gprs_ns2_ip_bind_connect(bind, gss->nse, remote);
743 if (!gss->sns_nsvc)
744 return;
745 gss->sns_nsvc->sns_only = true;
746 }
747
748 switch (gss->ip) {
749 case IPv4:
750 ip4_elems = talloc_zero_size(fi, sizeof(struct gprs_ns_ie_ip4_elem) * count);
751 if (!ip4_elems)
752 return;
753
754 gss->ip4_local = ip4_elems;
755
756 llist_for_each_entry(bind, &nsi->binding, list) {
757 if (!gprs_ns2_is_ip_bind(bind))
758 continue;
759
760 sa = gprs_ns2_ip_bind_sockaddr(bind);
761 if (!sa)
762 continue;
763
764 if (sa->u.sas.ss_family != AF_INET)
765 continue;
766
767 /* check if this is an specific bind */
768 if (sa->u.sin.sin_addr.s_addr == 0) {
769 if (osmo_sockaddr_local_ip(&local, remote))
770 continue;
771
772 ip4_elems->ip_addr = local.u.sin.sin_addr.s_addr;
773 } else {
774 ip4_elems->ip_addr = sa->u.sin.sin_addr.s_addr;
775 }
776
777 ip4_elems->udp_port = sa->u.sin.sin_port;
778 ip4_elems->sig_weight = 2;
779 ip4_elems->data_weight = 1;
780 ip4_elems++;
781 }
782
783 gss->num_ip4_local = count;
784 gss->num_max_ip4_remote = 4;
785 gss->num_max_nsvcs = OSMO_MAX(gss->num_max_ip4_remote * gss->num_ip4_local, 8);
786 break;
787 case IPv6:
788 /* IPv6 */
789 ip6_elems = talloc_zero_size(fi, sizeof(struct gprs_ns_ie_ip6_elem) * count);
790 if (!ip6_elems)
791 return;
792
793 gss->ip6_local = ip6_elems;
794
795 llist_for_each_entry(bind, &nsi->binding, list) {
796 if (!gprs_ns2_is_ip_bind(bind))
797 continue;
798
799 sa = gprs_ns2_ip_bind_sockaddr(bind);
800 if (!sa)
801 continue;
802
803 if (sa->u.sas.ss_family != AF_INET6)
804 continue;
805
806 /* check if this is an specific bind */
807 if (IN6_IS_ADDR_UNSPECIFIED(&sa->u.sin6.sin6_addr)) {
808 if (osmo_sockaddr_local_ip(&local, remote))
809 continue;
810
811 ip6_elems->ip_addr = local.u.sin6.sin6_addr;
812 } else {
813 ip6_elems->ip_addr = sa->u.sin6.sin6_addr;
814 }
815
816 ip6_elems->udp_port = sa->u.sin.sin_port;
817 ip6_elems->sig_weight = 2;
818 ip6_elems->data_weight = 1;
819
820 ip6_elems++;
821 }
822 gss->num_ip6_local = count;
823 gss->num_max_ip6_remote = 4;
824 gss->num_max_nsvcs = OSMO_MAX(gss->num_max_ip6_remote * gss->num_ip6_local, 8);
825 break;
826 }
827
Alexander Couzens6a161492020-07-12 13:45:50 +0200828 if (gss->num_max_ip4_remote > 0)
829 ns2_tx_sns_size(gss->sns_nsvc, true, gss->num_max_nsvcs, gss->num_max_ip4_remote, -1);
830 else
831 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 +0200832}
833
834static void ns2_sns_st_config_bss(struct osmo_fsm_inst *fi, uint32_t event, void *data)
835{
836 struct tlv_parsed *tp = NULL;
837
838 switch (event) {
839 case GPRS_SNS_EV_CONFIG_ACK:
840 tp = (struct tlv_parsed *) data;
841 if (TLVP_VAL_MINLEN(tp, NS_IE_CAUSE, 1)) {
842 LOGPFSML(fi, LOGL_ERROR, "SNS-CONFIG-ACK with cause %s\n",
843 gprs_ns2_cause_str(*TLVP_VAL(tp, NS_IE_CAUSE)));
844 /* TODO: What to do? */
845 } else {
846 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIG_SGSN, 0, 0);
847 }
848 break;
849 default:
850 OSMO_ASSERT(0);
851 }
852}
853
854static void ns2_sns_st_config_bss_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
855{
856 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
857 /* Transmit SNS-CONFIG */
Alexander Couzens6a161492020-07-12 13:45:50 +0200858 switch (gss->ip) {
859 case IPv4:
860 ns2_tx_sns_config(gss->sns_nsvc, true,
Alexander Couzense78207f2020-12-07 06:19:29 +0100861 gss->ip4_local, gss->num_ip4_local,
862 NULL, 0);
Alexander Couzens6a161492020-07-12 13:45:50 +0200863 break;
864 case IPv6:
865 ns2_tx_sns_config(gss->sns_nsvc, true,
Alexander Couzense78207f2020-12-07 06:19:29 +0100866 NULL, 0,
867 gss->ip6_local, gss->num_ip6_local);
Alexander Couzens6a161492020-07-12 13:45:50 +0200868 break;
869 }
870}
871
872
873static void ns_sns_st_config_sgsn_ip4(struct osmo_fsm_inst *fi, uint32_t event, void *data)
874{
875 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
876 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
877 const struct gprs_ns_ie_ip4_elem *v4_list;
878 unsigned int num_v4;
879 struct tlv_parsed *tp = NULL;
880
881 uint8_t cause;
882
883 tp = (struct tlv_parsed *) data;
884
885 if (!TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
886 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
887 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
888 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
889 return;
890 }
891 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
892 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
893 /* realloc to the new size */
894 gss->ip4_remote = talloc_realloc(gss, gss->ip4_remote,
895 struct gprs_ns_ie_ip4_elem,
896 gss->num_ip4_remote+num_v4);
897 /* append the new entries to the end of the list */
898 memcpy(&gss->ip4_remote[gss->num_ip4_remote], v4_list, num_v4*sizeof(*v4_list));
899 gss->num_ip4_remote += num_v4;
900
901 LOGPFSML(fi, LOGL_INFO, "Rx SNS-CONFIG: Remote IPv4 list now %u entries\n",
902 gss->num_ip4_remote);
903 if (event == GPRS_SNS_EV_CONFIG_END) {
904 /* check if sum of data / sig weights == 0 */
905 if (ip4_weight_sum_data(gss->ip4_remote, gss->num_ip4_remote) == 0 ||
906 ip4_weight_sum_sig(gss->ip4_remote, gss->num_ip4_remote) == 0) {
907 cause = NS_CAUSE_INVAL_WEIGH;
908 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
909 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
910 return;
911 }
912 create_missing_nsvcs(fi);
913 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
914 /* start the test procedure on ALL NSVCs! */
915 gprs_ns2_start_alive_all_nsvcs(nse);
916 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIGURED, 0, 0);
917 } else {
918 /* just send CONFIG-ACK */
919 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
920 }
921}
922
923static void ns_sns_st_config_sgsn_ip6(struct osmo_fsm_inst *fi, uint32_t event, void *data)
924{
925 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
926 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
927 const struct gprs_ns_ie_ip6_elem *v6_list;
928 unsigned int num_v6;
929 struct tlv_parsed *tp = NULL;
930
931 uint8_t cause;
932
933 tp = (struct tlv_parsed *) data;
934
935 if (!TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
936 cause = NS_CAUSE_INVAL_NR_IPv6_EP;
937 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
938 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
939 return;
940 }
941 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
942 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
943 /* realloc to the new size */
944 gss->ip6_remote = talloc_realloc(gss, gss->ip6_remote,
945 struct gprs_ns_ie_ip6_elem,
946 gss->num_ip6_remote+num_v6);
947 /* append the new entries to the end of the list */
948 memcpy(&gss->ip6_remote[gss->num_ip6_remote], v6_list, num_v6*sizeof(*v6_list));
949 gss->num_ip6_remote += num_v6;
950
951 LOGPFSML(fi, LOGL_INFO, "Rx SNS-CONFIG: Remote IPv6 list now %u entries\n",
952 gss->num_ip6_remote);
953 if (event == GPRS_SNS_EV_CONFIG_END) {
954 /* check if sum of data / sig weights == 0 */
955 if (ip6_weight_sum_data(gss->ip6_remote, gss->num_ip6_remote) == 0 ||
956 ip6_weight_sum_sig(gss->ip6_remote, gss->num_ip6_remote) == 0) {
957 cause = NS_CAUSE_INVAL_WEIGH;
958 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
959 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
960 return;
961 }
962 create_missing_nsvcs(fi);
963 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
964 /* start the test procedure on ALL NSVCs! */
965 gprs_ns2_start_alive_all_nsvcs(nse);
966 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIGURED, 0, 0);
967 } else {
968 /* just send CONFIG-ACK */
969 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
970 }
971}
972
973static void ns2_sns_st_config_sgsn(struct osmo_fsm_inst *fi, uint32_t event, void *data)
974{
975 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
976
977 switch (event) {
978 case GPRS_SNS_EV_CONFIG_END:
979 case GPRS_SNS_EV_CONFIG:
980
981#if 0 /* part of incoming SNS-SIZE (doesn't happen on BSS side */
982 if (TLVP_PRESENT(tp, NS_IE_RESET_FLAG)) {
983 /* reset all existing config */
984 if (gss->ip4_remote)
985 talloc_free(gss->ip4_remote);
986 gss->num_ip4_remote = 0;
987 }
988#endif
989 /* TODO: reject IPv6 elements on IPv4 mode and vice versa */
990 switch (gss->ip) {
991 case IPv4:
992 ns_sns_st_config_sgsn_ip4(fi, event, data);
993 break;
994 case IPv6:
995 ns_sns_st_config_sgsn_ip6(fi, event, data);
996 break;
997 default:
998 OSMO_ASSERT(0);
999 }
1000 break;
1001 default:
1002 OSMO_ASSERT(0);
1003 }
1004}
1005
1006/* called when receiving GPRS_SNS_EV_ADD in state configure */
1007static void ns2_sns_st_configured_add(struct osmo_fsm_inst *fi,
1008 struct ns2_sns_state *gss,
1009 struct tlv_parsed *tp)
1010{
1011 const struct gprs_ns_ie_ip4_elem *v4_list = NULL;
1012 const struct gprs_ns_ie_ip6_elem *v6_list = NULL;
1013 int num_v4 = 0, num_v6 = 0;
1014 uint8_t trans_id, cause = 0xff;
Harald Welte7da6ace2020-09-18 09:48:05 +02001015 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +02001016 int rc = 0;
1017
1018 /* TODO: refactor EV_ADD/CHANGE/REMOVE by
1019 * check uniqueness within the lists (no doublicate entries)
1020 * check not-known-by-us and sent back a list of unknown/known values
1021 * (abnormal behaviour according to 48.016)
1022 */
1023
1024 trans_id = *TLVP_VAL(tp, NS_IE_TRANS_ID);
1025 if (gss->ip == IPv4) {
1026 if (!TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
1027 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
1028 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1029 return;
1030 }
1031
1032 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
1033 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001034 for (i = 0; i < num_v4; i++) {
1035 unsigned int j;
Alexander Couzens6a161492020-07-12 13:45:50 +02001036 rc = do_sns_add(fi, &v4_list[i], NULL);
1037 if (rc < 0) {
1038 /* rollback/undo to restore previous state */
Harald Welte7da6ace2020-09-18 09:48:05 +02001039 for (j = 0; j < i; j++)
Alexander Couzens6a161492020-07-12 13:45:50 +02001040 do_sns_delete(fi, &v4_list[j], NULL);
1041 cause = -rc;
1042 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1043 break;
1044 }
1045 }
1046 } else { /* IPv6 */
1047 if (!TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
1048 cause = NS_CAUSE_INVAL_NR_IPv6_EP;
1049 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1050 return;
1051 }
1052
1053 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
1054 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001055 for (i = 0; i < num_v6; i++) {
1056 unsigned int j;
Alexander Couzens6a161492020-07-12 13:45:50 +02001057 rc = do_sns_add(fi, NULL, &v6_list[i]);
1058 if (rc < 0) {
1059 /* rollback/undo to restore previous state */
Harald Welte7da6ace2020-09-18 09:48:05 +02001060 for (j = 0; j < i; j++)
Alexander Couzens6a161492020-07-12 13:45:50 +02001061 do_sns_delete(fi, NULL, &v6_list[j]);
1062 cause = -rc;
1063 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1064 break;
1065 }
1066 }
1067 }
1068
1069 /* TODO: correct behaviour is to answer to the *same* NSVC from which the SNS_ADD was received */
1070 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, NULL, v4_list, num_v4, v6_list, num_v6);
1071}
1072
1073static void ns2_sns_st_configured_delete(struct osmo_fsm_inst *fi,
1074 struct ns2_sns_state *gss,
1075 struct tlv_parsed *tp)
1076{
1077 const struct gprs_ns_ie_ip4_elem *v4_list = NULL;
1078 const struct gprs_ns_ie_ip6_elem *v6_list = NULL;
1079 int num_v4 = 0, num_v6 = 0;
1080 uint8_t trans_id, cause = 0xff;
Harald Welte7da6ace2020-09-18 09:48:05 +02001081 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +02001082 int rc = 0;
1083
1084 /* TODO: split up delete into v4 + v6
1085 * TODO: check if IPv4_LIST or IP_ADDR(v4) is present on IPv6 and vice versa
1086 * TODO: check if IPv4_LIST/IPv6_LIST and IP_ADDR is present at the same time
1087 */
1088 trans_id = *TLVP_VAL(tp, NS_IE_TRANS_ID);
1089 if (gss->ip == IPv4) {
1090 if (TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
1091 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
1092 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001093 for ( i = 0; i < num_v4; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001094 rc = do_sns_delete(fi, &v4_list[i], NULL);
1095 if (rc < 0) {
1096 cause = -rc;
1097 /* continue to delete others */
1098 }
1099 }
1100 if (cause != 0xff) {
1101 /* TODO: create list of not-deleted and return it */
1102 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1103 return;
1104 }
1105
1106 } else if (TLVP_PRESENT(tp, NS_IE_IP_ADDR) && TLVP_LEN(tp, NS_IE_IP_ADDR) == 5) {
1107 /* delete all NS-VCs for given IPv4 address */
1108 const uint8_t *ie = TLVP_VAL(tp, NS_IE_IP_ADDR);
1109 struct gprs_ns_ie_ip4_elem *ip4_remote;
1110 uint32_t ip_addr = *(uint32_t *)(ie+1);
1111 if (ie[0] != 0x01) { /* Address Type != IPv4 */
1112 cause = NS_CAUSE_UNKN_IP_ADDR;
1113 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1114 return;
1115 }
1116 /* make a copy as do_sns_delete() will change the array underneath us */
1117 ip4_remote = talloc_memdup(fi, gss->ip4_remote,
1118 gss->num_ip4_remote * sizeof(*v4_list));
Harald Welte7da6ace2020-09-18 09:48:05 +02001119 for (i = 0; i < gss->num_ip4_remote; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001120 if (ip4_remote[i].ip_addr == ip_addr) {
1121 rc = do_sns_delete(fi, &ip4_remote[i], NULL);
1122 if (rc < 0) {
1123 cause = -rc;
1124 /* continue to delete others */
1125 }
1126 }
1127 }
1128 talloc_free(ip4_remote);
1129 if (cause != 0xff) {
1130 /* TODO: create list of not-deleted and return it */
1131 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1132 return;
1133 }
1134 } else {
1135 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
1136 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1137 return;
1138 }
1139 } else { /* IPv6 */
1140 if (TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
1141 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
1142 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001143 for (i = 0; i < num_v6; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001144 rc = do_sns_delete(fi, NULL, &v6_list[i]);
1145 if (rc < 0) {
1146 cause = -rc;
1147 /* continue to delete others */
1148 }
1149 }
1150 if (cause != 0xff) {
1151 /* TODO: create list of not-deleted and return it */
1152 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1153 return;
1154 }
1155 } else if (TLVP_PRES_LEN(tp, NS_IE_IP_ADDR, 17)) {
1156 /* delete all NS-VCs for given IPv4 address */
1157 const uint8_t *ie = TLVP_VAL(tp, NS_IE_IP_ADDR);
1158 struct gprs_ns_ie_ip6_elem *ip6_remote;
1159 struct in6_addr ip6_addr;
Harald Welte7da6ace2020-09-18 09:48:05 +02001160 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +02001161 if (ie[0] != 0x02) { /* Address Type != IPv6 */
1162 cause = NS_CAUSE_UNKN_IP_ADDR;
1163 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1164 return;
1165 }
1166 memcpy(&ip6_addr, (ie+1), sizeof(struct in6_addr));
1167 /* make a copy as do_sns_delete() will change the array underneath us */
1168 ip6_remote = talloc_memdup(fi, gss->ip6_remote,
1169 gss->num_ip6_remote * sizeof(*v4_list));
Harald Welte7da6ace2020-09-18 09:48:05 +02001170 for (i = 0; i < gss->num_ip6_remote; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001171 if (!memcmp(&ip6_remote[i].ip_addr, &ip6_addr, sizeof(struct in6_addr))) {
1172 rc = do_sns_delete(fi, NULL, &ip6_remote[i]);
1173 if (rc < 0) {
1174 cause = -rc;
1175 /* continue to delete others */
1176 }
1177 }
1178 }
1179
1180 talloc_free(ip6_remote);
1181 if (cause != 0xff) {
1182 /* TODO: create list of not-deleted and return it */
1183 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1184 return;
1185 }
1186 } else {
1187 cause = NS_CAUSE_INVAL_NR_IPv6_EP;
1188 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1189 return;
1190 }
1191 }
1192 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, NULL, v4_list, num_v4, v6_list, num_v6);
1193}
1194
1195static void ns2_sns_st_configured_change(struct osmo_fsm_inst *fi,
1196 struct ns2_sns_state *gss,
1197 struct tlv_parsed *tp)
1198{
1199 const struct gprs_ns_ie_ip4_elem *v4_list = NULL;
1200 const struct gprs_ns_ie_ip6_elem *v6_list = NULL;
1201 int num_v4 = 0, num_v6 = 0;
1202 uint8_t trans_id, cause = 0xff;
1203 int rc = 0;
Harald Welte7da6ace2020-09-18 09:48:05 +02001204 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +02001205
1206 trans_id = *TLVP_VAL(tp, NS_IE_TRANS_ID);
1207 if (TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
1208 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
1209 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001210 for (i = 0; i < num_v4; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001211 rc = do_sns_change_weight(fi, &v4_list[i], NULL);
1212 if (rc < 0) {
1213 cause = -rc;
1214 /* continue to others */
1215 }
1216 }
1217 if (cause != 0xff) {
1218 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1219 return;
1220 }
1221 } else if (TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
1222 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
1223 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001224 for (i = 0; i < num_v6; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001225 rc = do_sns_change_weight(fi, NULL, &v6_list[i]);
1226 if (rc < 0) {
1227 cause = -rc;
1228 /* continue to others */
1229 }
1230 }
1231 if (cause != 0xff) {
1232 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1233 return;
1234 }
1235 } else {
1236 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
1237 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1238 return;
1239 }
1240 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, NULL, v4_list, num_v4, v6_list, num_v6);
1241}
1242
1243static void ns2_sns_st_configured(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1244{
1245 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
1246 struct tlv_parsed *tp = data;
1247
1248 switch (event) {
1249 case GPRS_SNS_EV_ADD:
1250 ns2_sns_st_configured_add(fi, gss, tp);
1251 break;
1252 case GPRS_SNS_EV_DELETE:
1253 ns2_sns_st_configured_delete(fi, gss, tp);
1254 break;
1255 case GPRS_SNS_EV_CHANGE_WEIGHT:
1256 ns2_sns_st_configured_change(fi, gss, tp);
1257 break;
1258 }
1259}
1260
1261static void ns2_sns_st_configured_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
1262{
1263 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
Daniel Willmann15c09a82020-11-03 23:05:43 +01001264 ns2_prim_status_ind(nse, NULL, 0, NS_AFF_CAUSE_SNS_CONFIGURED);
Alexander Couzens6a161492020-07-12 13:45:50 +02001265}
1266
1267static const struct osmo_fsm_state ns2_sns_bss_states[] = {
1268 [GPRS_SNS_ST_UNCONFIGURED] = {
Alexander Couzense769f522020-12-07 07:37:07 +01001269 .in_event_mask = 0, /* handled by all_state_action */
Alexander Couzens6a161492020-07-12 13:45:50 +02001270 .out_state_mask = S(GPRS_SNS_ST_SIZE),
1271 .name = "UNCONFIGURED",
1272 .action = ns2_sns_st_unconfigured,
1273 },
1274 [GPRS_SNS_ST_SIZE] = {
1275 .in_event_mask = S(GPRS_SNS_EV_SIZE_ACK),
1276 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
1277 S(GPRS_SNS_ST_SIZE) |
1278 S(GPRS_SNS_ST_CONFIG_BSS),
1279 .name = "SIZE",
1280 .action = ns2_sns_st_size,
1281 .onenter = ns2_sns_st_size_onenter,
1282 },
1283 [GPRS_SNS_ST_CONFIG_BSS] = {
1284 .in_event_mask = S(GPRS_SNS_EV_CONFIG_ACK),
1285 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
1286 S(GPRS_SNS_ST_CONFIG_BSS) |
1287 S(GPRS_SNS_ST_CONFIG_SGSN) |
1288 S(GPRS_SNS_ST_SIZE),
1289 .name = "CONFIG_BSS",
1290 .action = ns2_sns_st_config_bss,
1291 .onenter = ns2_sns_st_config_bss_onenter,
1292 },
1293 [GPRS_SNS_ST_CONFIG_SGSN] = {
1294 .in_event_mask = S(GPRS_SNS_EV_CONFIG) |
1295 S(GPRS_SNS_EV_CONFIG_END),
1296 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
1297 S(GPRS_SNS_ST_CONFIG_SGSN) |
1298 S(GPRS_SNS_ST_CONFIGURED) |
1299 S(GPRS_SNS_ST_SIZE),
1300 .name = "CONFIG_SGSN",
1301 .action = ns2_sns_st_config_sgsn,
1302 },
1303 [GPRS_SNS_ST_CONFIGURED] = {
1304 .in_event_mask = S(GPRS_SNS_EV_ADD) |
1305 S(GPRS_SNS_EV_DELETE) |
1306 S(GPRS_SNS_EV_CHANGE_WEIGHT),
Alexander Couzense03d8632020-12-06 03:31:44 +01001307 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
1308 S(GPRS_SNS_ST_SIZE),
Alexander Couzens6a161492020-07-12 13:45:50 +02001309 .name = "CONFIGURED",
1310 .action = ns2_sns_st_configured,
1311 .onenter = ns2_sns_st_configured_onenter,
1312 },
1313};
1314
1315static int ns2_sns_fsm_bss_timer_cb(struct osmo_fsm_inst *fi)
1316{
Alexander Couzens90ee9632020-12-07 06:18:32 +01001317 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
Alexander Couzens6a161492020-07-12 13:45:50 +02001318 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
1319 struct gprs_ns2_inst *nsi = nse->nsi;
1320
Alexander Couzens90ee9632020-12-07 06:18:32 +01001321 gss->N++;
Alexander Couzens6a161492020-07-12 13:45:50 +02001322 switch (fi->T) {
1323 case 1:
Alexander Couzensa367d082020-12-21 14:06:24 +01001324 if (gss->N >= nsi->timeout[NS_TOUT_TSNS_SIZE_RETRIES]) {
1325 LOGPFSML(fi, LOGL_ERROR, "NSE %d: Size retries failed. Selecting next IP-SNS endpoint.\n", nse->nsei);
Alexander Couzens90ee9632020-12-07 06:18:32 +01001326 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_SELECT_ENDPOINT, NULL);
Alexander Couzensa367d082020-12-21 14:06:24 +01001327 } else {
Alexander Couzenscc65a252020-12-21 14:03:58 +01001328 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_SIZE, nsi->timeout[NS_TOUT_TSNS_PROV], 1);
Alexander Couzensa367d082020-12-21 14:06:24 +01001329 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001330 break;
1331 case 2:
Alexander Couzensa367d082020-12-21 14:06:24 +01001332 if (gss->N >= nsi->timeout[NS_TOUT_TSNS_CONFIG_RETRIES]) {
1333 LOGPFSML(fi, LOGL_ERROR, "NSE %d: Config retries failed. Selecting next IP-SNS endpoint.\n", nse->nsei);
Alexander Couzens90ee9632020-12-07 06:18:32 +01001334 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_SELECT_ENDPOINT, NULL);
Alexander Couzensa367d082020-12-21 14:06:24 +01001335 } else {
Alexander Couzenscc65a252020-12-21 14:03:58 +01001336 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 +01001337 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001338 break;
1339 }
1340 return 0;
1341}
1342
1343static void ns2_sns_st_all_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1344{
Alexander Couzense769f522020-12-07 07:37:07 +01001345 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
Alexander Couzens6a161492020-07-12 13:45:50 +02001346 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
1347
1348 /* reset when receiving GPRS_SNS_EV_NO_NSVC */
Alexander Couzense769f522020-12-07 07:37:07 +01001349 switch (event) {
1350 case GPRS_SNS_EV_NO_NSVC:
Alexander Couzens3ad73362020-12-21 13:53:00 +01001351 /* ignore reselection running */
1352 if (gss->reselection_running)
1353 break;
1354
1355 LOGPFSML(fi, LOGL_ERROR, "NSE %d: no remaining NSVC, resetting SNS FSM\n", nse->nsei);
1356 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_SELECT_ENDPOINT, NULL);
Alexander Couzense769f522020-12-07 07:37:07 +01001357 break;
1358 case GPRS_SNS_EV_SELECT_ENDPOINT:
1359 /* tear down previous state
1360 * gprs_ns2_free_nsvcs() will trigger NO_NSVC, prevent this from triggering a reselection */
1361 gss->reselection_running = true;
1362 gprs_ns2_free_nsvcs(nse);
1363
1364 /* Choose the next sns endpoint. */
1365 if (llist_empty(&gss->sns_endpoints)) {
1366 gss->initial = NULL;
1367 ns2_prim_status_ind(gss->nse, NULL, 0, NS_AFF_CAUSE_SNS_NO_ENDPOINTS);
1368 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 3);
1369 return;
1370 } else if (!gss->initial) {
1371 gss->initial = llist_first_entry(&gss->sns_endpoints, struct sns_endpoint, list);
Alexander Couzens81ae0aa2020-12-07 05:49:43 +01001372 gss->bind_offset = 0;
Alexander Couzense769f522020-12-07 07:37:07 +01001373 } else if (gss->initial->list.next == &gss->sns_endpoints) {
1374 /* last entry, continue with first */
1375 gss->initial = llist_first_entry(&gss->sns_endpoints, struct sns_endpoint, list);
Alexander Couzens81ae0aa2020-12-07 05:49:43 +01001376 gss->bind_offset++;
1377 gss->bind_offset %= ns2_ip_count_bind(nse->nsi, &gss->initial->saddr);
Alexander Couzense769f522020-12-07 07:37:07 +01001378 } else {
1379 /* next element is an entry */
1380 gss->initial = llist_entry(gss->initial->list.next, struct sns_endpoint, list);
1381 }
1382
1383 gss->reselection_running = false;
1384 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_SIZE, nse->nsi->timeout[NS_TOUT_TSNS_PROV], 1);
1385 break;
1386 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001387}
1388
1389static struct osmo_fsm gprs_ns2_sns_bss_fsm = {
1390 .name = "GPRS-NS2-SNS-BSS",
1391 .states = ns2_sns_bss_states,
1392 .num_states = ARRAY_SIZE(ns2_sns_bss_states),
Alexander Couzense769f522020-12-07 07:37:07 +01001393 .allstate_event_mask = S(GPRS_SNS_EV_NO_NSVC) |
1394 S(GPRS_SNS_EV_SELECT_ENDPOINT),
Alexander Couzens6a161492020-07-12 13:45:50 +02001395 .allstate_action = ns2_sns_st_all_action,
1396 .cleanup = NULL,
1397 .timer_cb = ns2_sns_fsm_bss_timer_cb,
1398 /* .log_subsys = DNS, "is not constant" */
1399 .event_names = gprs_sns_event_names,
1400 .pre_term = NULL,
1401 .log_subsys = DLNS,
1402};
1403
Harald Welte5bef2cc2020-09-18 22:33:24 +02001404/*! Allocate an IP-SNS FSM for the BSS side.
1405 * \param[in] nse NS Entity in which the FSM runs
1406 * \param[in] id string identifier
1407 * \retruns FSM instance on success; NULL on error */
Alexander Couzens6a161492020-07-12 13:45:50 +02001408struct osmo_fsm_inst *ns2_sns_bss_fsm_alloc(struct gprs_ns2_nse *nse,
1409 const char *id)
1410{
1411 struct osmo_fsm_inst *fi;
1412 struct ns2_sns_state *gss;
1413
1414 fi = osmo_fsm_inst_alloc(&gprs_ns2_sns_bss_fsm, nse, NULL, LOGL_DEBUG, id);
1415 if (!fi)
1416 return fi;
1417
1418 gss = talloc_zero(fi, struct ns2_sns_state);
1419 if (!gss)
1420 goto err;
1421
1422 fi->priv = gss;
1423 gss->nse = nse;
Alexander Couzense769f522020-12-07 07:37:07 +01001424 INIT_LLIST_HEAD(&gss->sns_endpoints);
Alexander Couzens6a161492020-07-12 13:45:50 +02001425
1426 return fi;
1427err:
1428 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
1429 return NULL;
1430}
1431
Harald Welte5bef2cc2020-09-18 22:33:24 +02001432/*! main entry point for receiving SNS messages from the network.
1433 * \param[in] nsvc NS-VC on which the message was received
1434 * \param[in] msg message buffer of the IP-SNS message
1435 * \param[in] tp parsed TLV structure of message
1436 * \retruns 0 on success; negative on error */
Alexander Couzens6a161492020-07-12 13:45:50 +02001437int gprs_ns2_sns_rx(struct gprs_ns2_vc *nsvc, struct msgb *msg, struct tlv_parsed *tp)
1438{
1439 struct gprs_ns2_nse *nse = nsvc->nse;
1440 struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h;
1441 uint16_t nsei = nsvc->nse->nsei;
1442 struct osmo_fsm_inst *fi;
1443
1444 if (!nse->bss_sns_fi) {
1445 LOGP(DLNS, LOGL_NOTICE, "NSEI=%u Rx %s for NS Instance that has no SNS!\n",
1446 nsvc->nse->nsei, get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
1447 return -EINVAL;
1448 }
1449
1450 LOGP(DLNS, LOGL_DEBUG, "NSEI=%u Rx SNS PDU type %s\n", nsei,
1451 get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
1452
1453 /* FIXME: how to resolve SNS FSM Instance by NSEI (SGSN)? */
1454 fi = nse->bss_sns_fi;
1455
1456 switch (nsh->pdu_type) {
1457 case SNS_PDUT_SIZE:
1458 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_SIZE, tp);
1459 break;
1460 case SNS_PDUT_SIZE_ACK:
1461 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_SIZE_ACK, tp);
1462 break;
1463 case SNS_PDUT_CONFIG:
1464 if (nsh->data[0] & 0x01)
1465 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_CONFIG_END, tp);
1466 else
1467 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_CONFIG, tp);
1468 break;
1469 case SNS_PDUT_CONFIG_ACK:
1470 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_CONFIG_ACK, tp);
1471 break;
1472 case SNS_PDUT_ADD:
1473 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_ADD, tp);
1474 break;
1475 case SNS_PDUT_DELETE:
1476 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_DELETE, tp);
1477 break;
1478 case SNS_PDUT_CHANGE_WEIGHT:
1479 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_CHANGE_WEIGHT, tp);
1480 break;
1481 case SNS_PDUT_ACK:
1482 LOGP(DLNS, LOGL_NOTICE, "NSEI=%u Rx unsupported SNS PDU type %s\n", nsei,
1483 get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
1484 break;
1485 default:
1486 LOGP(DLNS, LOGL_ERROR, "NSEI=%u Rx unknown SNS PDU type %s\n", nsei,
1487 get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
1488 return -EINVAL;
1489 }
1490
1491 return 0;
1492}
1493
1494#include <osmocom/vty/vty.h>
1495#include <osmocom/vty/misc.h>
1496
1497static void vty_dump_sns_ip4(struct vty *vty, const struct gprs_ns_ie_ip4_elem *ip4)
1498{
1499 struct in_addr in = { .s_addr = ip4->ip_addr };
1500 vty_out(vty, " %s:%u, Signalling Weight: %u, Data Weight: %u%s",
1501 inet_ntoa(in), ntohs(ip4->udp_port), ip4->sig_weight, ip4->data_weight, VTY_NEWLINE);
1502}
1503
1504static void vty_dump_sns_ip6(struct vty *vty, const struct gprs_ns_ie_ip6_elem *ip6)
1505{
1506 char ip_addr[INET6_ADDRSTRLEN] = {};
1507 if (!inet_ntop(AF_INET6, &ip6->ip_addr, ip_addr, (INET6_ADDRSTRLEN)))
1508 strcpy(ip_addr, "Invalid IPv6");
1509
1510 vty_out(vty, " %s:%u, Signalling Weight: %u, Data Weight: %u%s",
1511 ip_addr, ntohs(ip6->udp_port), ip6->sig_weight, ip6->data_weight, VTY_NEWLINE);
1512}
1513
Harald Welte5bef2cc2020-09-18 22:33:24 +02001514/*! Dump the IP-SNS state to a vty.
1515 * \param[in] vty VTY to which the state shall be printed
1516 * \param[in] nse NS Entity whose IP-SNS state shall be printed
1517 * \param[in] stats Whether or not statistics shall also be printed */
Alexander Couzens6a161492020-07-12 13:45:50 +02001518void gprs_ns2_sns_dump_vty(struct vty *vty, const struct gprs_ns2_nse *nse, bool stats)
1519{
1520 struct ns2_sns_state *gss;
1521 unsigned int i;
1522
1523 if (!nse->bss_sns_fi)
1524 return;
1525
1526 vty_out_fsm_inst(vty, nse->bss_sns_fi);
1527 gss = (struct ns2_sns_state *) nse->bss_sns_fi->priv;
1528
1529 vty_out(vty, "Maximum number of remote NS-VCs: %zu, IPv4 Endpoints: %zu, IPv6 Endpoints: %zu%s",
1530 gss->num_max_nsvcs, gss->num_max_ip4_remote, gss->num_max_ip6_remote, VTY_NEWLINE);
1531
1532 if (gss->num_ip4_local && gss->num_ip4_remote) {
1533 vty_out(vty, "Local IPv4 Endpoints:%s", VTY_NEWLINE);
1534 for (i = 0; i < gss->num_ip4_local; i++)
1535 vty_dump_sns_ip4(vty, &gss->ip4_local[i]);
1536
1537 vty_out(vty, "Remote IPv4 Endpoints:%s", VTY_NEWLINE);
1538 for (i = 0; i < gss->num_ip4_remote; i++)
1539 vty_dump_sns_ip4(vty, &gss->ip4_remote[i]);
1540 }
1541
1542 if (gss->num_ip6_local && gss->num_ip6_remote) {
1543 vty_out(vty, "Local IPv6 Endpoints:%s", VTY_NEWLINE);
1544 for (i = 0; i < gss->num_ip6_local; i++)
1545 vty_dump_sns_ip6(vty, &gss->ip6_local[i]);
1546
1547 vty_out(vty, "Remote IPv6 Endpoints:%s", VTY_NEWLINE);
1548 for (i = 0; i < gss->num_ip6_remote; i++)
1549 vty_dump_sns_ip6(vty, &gss->ip6_remote[i]);
1550 }
1551}
1552
Alexander Couzens412bc342020-11-19 05:24:37 +01001553/*! write IP-SNS to a vty
1554 * \param[in] vty VTY to which the state shall be printed
1555 * \param[in] nse NS Entity whose IP-SNS state shall be printed */
1556void gprs_ns2_sns_write_vty(struct vty *vty, const struct gprs_ns2_nse *nse)
1557{
1558 struct ns2_sns_state *gss;
1559 struct osmo_sockaddr_str addr_str;
1560 struct sns_endpoint *endpoint;
1561
1562 if (!nse->bss_sns_fi)
1563 return;
1564
1565 gss = (struct ns2_sns_state *) nse->bss_sns_fi->priv;
1566 llist_for_each_entry(endpoint, &gss->sns_endpoints, list) {
Vadim Yanitskiyd8b70032021-01-05 14:24:09 +01001567 /* It's unlikely that an error happens, but let's better be safe. */
1568 if (osmo_sockaddr_str_from_sockaddr(&addr_str, &endpoint->saddr.u.sas) != 0)
1569 addr_str = (struct osmo_sockaddr_str) { .ip = "<INVALID>" };
Alexander Couzens412bc342020-11-19 05:24:37 +01001570 vty_out(vty, " ip-sns %s %u%s", addr_str.ip, addr_str.port, VTY_NEWLINE);
1571 }
1572}
1573
Alexander Couzense769f522020-12-07 07:37:07 +01001574static struct sns_endpoint *ns2_get_sns_endpoint(struct ns2_sns_state *state,
1575 const struct osmo_sockaddr *saddr)
1576{
1577 struct sns_endpoint *endpoint;
1578
1579 llist_for_each_entry(endpoint, &state->sns_endpoints, list) {
1580 if (!osmo_sockaddr_cmp(saddr, &endpoint->saddr))
1581 return endpoint;
1582 }
1583
1584 return NULL;
1585}
1586
1587/*! gprs_ns2_sns_add_endpoint
1588 * \param[in] nse
1589 * \param[in] sockaddr
1590 * \return
1591 */
1592int gprs_ns2_sns_add_endpoint(struct gprs_ns2_nse *nse,
1593 const struct osmo_sockaddr *saddr)
1594{
1595 struct ns2_sns_state *gss;
1596 struct sns_endpoint *endpoint;
1597 bool do_selection = false;
1598
1599 if (nse->ll != GPRS_NS2_LL_UDP) {
1600 return -EINVAL;
1601 }
1602
1603 if (nse->dialect != NS2_DIALECT_SNS) {
1604 return -EINVAL;
1605 }
1606
1607 gss = nse->bss_sns_fi->priv;
1608
1609 if (ns2_get_sns_endpoint(gss, saddr))
1610 return -EADDRINUSE;
1611
1612 endpoint = talloc_zero(nse->bss_sns_fi->priv, struct sns_endpoint);
1613 if (!endpoint)
1614 return -ENOMEM;
1615
1616 endpoint->saddr = *saddr;
1617 if (llist_empty(&gss->sns_endpoints))
1618 do_selection = true;
1619
1620 llist_add_tail(&endpoint->list, &gss->sns_endpoints);
1621 if (do_selection)
1622 osmo_fsm_inst_dispatch(nse->bss_sns_fi, GPRS_SNS_EV_SELECT_ENDPOINT, NULL);
1623
1624 return 0;
1625}
1626
1627/*! gprs_ns2_sns_del_endpoint
1628 * \param[in] nse
1629 * \param[in] sockaddr
1630 * \return 0 on success, otherwise < 0
1631 */
1632int gprs_ns2_sns_del_endpoint(struct gprs_ns2_nse *nse,
1633 const struct osmo_sockaddr *saddr)
1634{
1635 struct ns2_sns_state *gss;
1636 struct sns_endpoint *endpoint;
1637
1638 if (nse->ll != GPRS_NS2_LL_UDP) {
1639 return -EINVAL;
1640 }
1641
1642 if (nse->dialect != NS2_DIALECT_SNS) {
1643 return -EINVAL;
1644 }
1645
1646 gss = nse->bss_sns_fi->priv;
1647 endpoint = ns2_get_sns_endpoint(gss, saddr);
1648 if (!endpoint)
1649 return -ENOENT;
1650
1651 /* if this is an unused SNS endpoint it's done */
1652 if (gss->initial != endpoint) {
1653 llist_del(&endpoint->list);
1654 talloc_free(endpoint);
1655 return 0;
1656 }
1657
1658 /* gprs_ns2_free_nsvcs() will trigger GPRS_SNS_EV_NO_NSVC on the last NS-VC
1659 * and restart SNS SIZE procedure which selects a new initial */
1660 LOGP(DLNS, LOGL_INFO, "Current in-use SNS endpoint is being removed."
1661 "Closing all NS-VC and restart SNS-SIZE procedure"
1662 "with a remaining SNS endpoint.\n");
1663
1664 /* Continue with the next endpoint in the list.
1665 * Special case if the endpoint is at the start or end of the list */
1666 if (endpoint->list.prev == &gss->sns_endpoints ||
1667 endpoint->list.next == &gss->sns_endpoints)
1668 gss->initial = NULL;
1669 else
1670 gss->initial = llist_entry(endpoint->list.next->prev,
1671 struct sns_endpoint,
1672 list);
1673
1674 llist_del(&endpoint->list);
1675 gprs_ns2_free_nsvcs(nse);
1676 talloc_free(endpoint);
1677
1678 return 0;
1679}
1680
1681/*! gprs_ns2_sns_count
1682 * \param[in] nse NS Entity whose IP-SNS endpoints shall be printed
1683 * \return the count of endpoints or < 0 if NSE doesn't contain sns.
1684 */
1685int gprs_ns2_sns_count(struct gprs_ns2_nse *nse)
1686{
1687 struct ns2_sns_state *gss;
1688 struct sns_endpoint *endpoint;
1689 int count = 0;
1690
1691 if (nse->ll != GPRS_NS2_LL_UDP) {
1692 return -EINVAL;
1693 }
1694
1695 if (nse->dialect != NS2_DIALECT_SNS) {
1696 return -EINVAL;
1697 }
1698
1699 gss = nse->bss_sns_fi->priv;
1700 llist_for_each_entry(endpoint, &gss->sns_endpoints, list)
1701 count++;
1702
1703 return count;
1704}
1705
Alexander Couzens6a161492020-07-12 13:45:50 +02001706/* initialize osmo_ctx on main tread */
1707static __attribute__((constructor)) void on_dso_load_ctx(void)
1708{
1709 OSMO_ASSERT(osmo_fsm_register(&gprs_ns2_sns_bss_fsm) == 0);
1710}