blob: 90d97b6a7bfe83b839c520c2e8b80d5708d081cb [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
Alexander Couzens7a7b20b2021-01-18 10:47:33 +0100258static void ns2_clear_ipv46_entries(struct ns2_sns_state *gss)
259{
260 TALLOC_FREE(gss->ip4_local);
261 TALLOC_FREE(gss->ip4_remote);
262 TALLOC_FREE(gss->ip6_local);
263 TALLOC_FREE(gss->ip6_remote);
264
265 gss->num_ip4_local = 0;
266 gss->num_ip4_remote = 0;
267 gss->num_ip6_local = 0;
268 gss->num_ip6_remote = 0;
269}
270
Daniel Willmanncf8371a2021-01-16 15:13:51 +0100271static void ns2_vc_create_ip(struct osmo_fsm_inst *fi, struct gprs_ns2_nse *nse, const struct osmo_sockaddr *remote,
272 uint8_t sig_weight, uint8_t data_weight)
Alexander Couzens6a161492020-07-12 13:45:50 +0200273{
274 struct gprs_ns2_inst *nsi = nse->nsi;
275 struct gprs_ns2_vc *nsvc;
276 struct gprs_ns2_vc_bind *bind;
Daniel Willmanncf8371a2021-01-16 15:13:51 +0100277
278 /* for every bind, create a connection if bind type == IP */
279 llist_for_each_entry(bind, &nsi->binding, list) {
280 if (bind->ll != GPRS_NS2_LL_UDP)
281 continue;
282 /* ignore failed connection */
283 nsvc = gprs_ns2_ip_connect_inactive(bind,
284 remote,
285 nse, 0);
286 if (!nsvc) {
287 LOGPFSML(fi, LOGL_ERROR, "SNS-CONFIG: Failed to create NSVC\n");
288 continue;
289 }
290
291 nsvc->sig_weight = sig_weight;
292 nsvc->data_weight = data_weight;
293 }
294}
295
296static void ns2_nsvc_create_ip4(struct osmo_fsm_inst *fi,
297 struct gprs_ns2_nse *nse,
298 const struct gprs_ns_ie_ip4_elem *ip4)
299{
Alexander Couzensc068d862020-10-12 04:11:51 +0200300 struct osmo_sockaddr remote = { };
Alexander Couzens6a161492020-07-12 13:45:50 +0200301 /* copy over. Both data structures use network byte order */
302 remote.u.sin.sin_family = AF_INET;
303 remote.u.sin.sin_addr.s_addr = ip4->ip_addr;
304 remote.u.sin.sin_port = ip4->udp_port;
305
Daniel Willmanncf8371a2021-01-16 15:13:51 +0100306 ns2_vc_create_ip(fi, nse, &remote, ip4->sig_weight, ip4->data_weight);
Alexander Couzens6a161492020-07-12 13:45:50 +0200307}
308
309static void ns2_nsvc_create_ip6(struct osmo_fsm_inst *fi,
310 struct gprs_ns2_nse *nse,
311 const struct gprs_ns_ie_ip6_elem *ip6)
312{
Alexander Couzens6a161492020-07-12 13:45:50 +0200313 struct osmo_sockaddr remote = {};
314 /* copy over. Both data structures use network byte order */
315 remote.u.sin6.sin6_family = AF_INET6;
316 remote.u.sin6.sin6_addr = ip6->ip_addr;
317 remote.u.sin6.sin6_port = ip6->udp_port;
318
Daniel Willmanncf8371a2021-01-16 15:13:51 +0100319 ns2_vc_create_ip(fi, nse, &remote, ip6->sig_weight, ip6->data_weight);
Alexander Couzens6a161492020-07-12 13:45:50 +0200320}
321
322
323static int create_missing_nsvcs(struct osmo_fsm_inst *fi)
324{
325 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
326 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
327 struct gprs_ns2_vc *nsvc;
328 struct gprs_ns2_vc_bind *bind;
329 struct osmo_sockaddr remote = { };
330 unsigned int i;
331
332 for (i = 0; i < gss->num_ip4_remote; i++) {
333 const struct gprs_ns_ie_ip4_elem *ip4 = &gss->ip4_remote[i];
334
335 remote.u.sin.sin_family = AF_INET;
336 remote.u.sin.sin_addr.s_addr = ip4->ip_addr;
337 remote.u.sin.sin_port = ip4->udp_port;
338
339 llist_for_each_entry(bind, &nse->nsi->binding, list) {
340 bool found = false;
Daniel Willmann967e2c12021-01-14 16:58:17 +0100341 if (bind->ll != GPRS_NS2_LL_UDP)
342 continue;
Alexander Couzens6a161492020-07-12 13:45:50 +0200343
344 llist_for_each_entry(nsvc, &nse->nsvc, list) {
345 if (nsvc->bind != bind)
346 continue;
347
Alexander Couzensc4229a42020-10-11 20:58:04 +0200348 if (!osmo_sockaddr_cmp(&remote, gprs_ns2_ip_vc_remote(nsvc))) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200349 found = true;
350 break;
351 }
352 }
353
354 if (!found) {
355 nsvc = gprs_ns2_ip_connect_inactive(bind, &remote, nse, 0);
356 if (!nsvc) {
357 /* TODO: add to a list to send back a NS-STATUS */
358 continue;
359 }
360 }
361
362 /* update data / signalling weight */
363 nsvc->data_weight = ip4->data_weight;
364 nsvc->sig_weight = ip4->sig_weight;
365 nsvc->sns_only = false;
366 }
367 }
368
369 for (i = 0; i < gss->num_ip6_remote; i++) {
370 const struct gprs_ns_ie_ip6_elem *ip6 = &gss->ip6_remote[i];
371
372 remote.u.sin6.sin6_family = AF_INET6;
373 remote.u.sin6.sin6_addr = ip6->ip_addr;
374 remote.u.sin6.sin6_port = ip6->udp_port;
375
376 llist_for_each_entry(bind, &nse->nsi->binding, list) {
377 bool found = false;
Daniel Willmann967e2c12021-01-14 16:58:17 +0100378 if (bind->ll != GPRS_NS2_LL_UDP)
379 continue;
Alexander Couzens6a161492020-07-12 13:45:50 +0200380
381 llist_for_each_entry(nsvc, &nse->nsvc, list) {
382 if (nsvc->bind != bind)
383 continue;
384
Alexander Couzensc4229a42020-10-11 20:58:04 +0200385 if (!osmo_sockaddr_cmp(&remote, gprs_ns2_ip_vc_remote(nsvc))) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200386 found = true;
387 break;
388 }
389 }
390
391 if (!found) {
392 nsvc = gprs_ns2_ip_connect_inactive(bind, &remote, nse, 0);
393 if (!nsvc) {
394 /* TODO: add to a list to send back a NS-STATUS */
395 continue;
396 }
397 }
398
399 /* update data / signalling weight */
400 nsvc->data_weight = ip6->data_weight;
401 nsvc->sig_weight = ip6->sig_weight;
402 nsvc->sns_only = false;
403 }
404 }
405
406
407 return 0;
408}
409
410/* Add a given remote IPv4 element to gprs_sns_state */
411static int add_remote_ip4_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip4_elem *ip4)
412{
413 unsigned int i;
414
415 if (gss->num_ip4_remote >= gss->num_max_ip4_remote)
416 return -NS_CAUSE_INVAL_NR_NS_VC;
417
418 /* check for duplicates */
419 for (i = 0; i < gss->num_ip4_remote; i++) {
420 if (memcmp(&gss->ip4_remote[i], ip4, sizeof(*ip4)))
421 continue;
422 /* TODO: log message duplicate */
423 /* TODO: check if this is the correct cause code */
424 return -NS_CAUSE_PROTO_ERR_UNSPEC;
425 }
426
427 gss->ip4_remote = talloc_realloc(gss, gss->ip4_remote, struct gprs_ns_ie_ip4_elem,
428 gss->num_ip4_remote+1);
429 gss->ip4_remote[gss->num_ip4_remote] = *ip4;
430 gss->num_ip4_remote += 1;
431 return 0;
432}
433
434/* Remove a given remote IPv4 element from gprs_sns_state */
435static int remove_remote_ip4_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip4_elem *ip4)
436{
437 unsigned int i;
438
439 for (i = 0; i < gss->num_ip4_remote; i++) {
440 if (memcmp(&gss->ip4_remote[i], ip4, sizeof(*ip4)))
441 continue;
442 /* all array elements < i remain as they are; all > i are shifted left by one */
443 memmove(&gss->ip4_remote[i], &gss->ip4_remote[i+1], gss->num_ip4_remote-i-1);
444 gss->num_ip4_remote -= 1;
445 return 0;
446 }
447 return -1;
448}
449
450/* update the weights for specified remote IPv4 */
451static int update_remote_ip4_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip4_elem *ip4)
452{
453 unsigned int i;
454
455 for (i = 0; i < gss->num_ip4_remote; i++) {
456 if (gss->ip4_remote[i].ip_addr != ip4->ip_addr ||
457 gss->ip4_remote[i].udp_port != ip4->udp_port)
458 continue;
459
460 gss->ip4_remote[i].sig_weight = ip4->sig_weight;
461 gss->ip4_remote[i].data_weight = ip4->data_weight;
462 return 0;
463 }
464 return -1;
465}
466
467/* Add a given remote IPv6 element to gprs_sns_state */
468static int add_remote_ip6_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip6_elem *ip6)
469{
470 if (gss->num_ip6_remote >= gss->num_max_ip6_remote)
471 return -NS_CAUSE_INVAL_NR_NS_VC;
472
473 gss->ip6_remote = talloc_realloc(gss, gss->ip6_remote, struct gprs_ns_ie_ip6_elem,
474 gss->num_ip6_remote+1);
475 gss->ip6_remote[gss->num_ip6_remote] = *ip6;
476 gss->num_ip6_remote += 1;
477 return 0;
478}
479
480/* Remove a given remote IPv6 element from gprs_sns_state */
481static int remove_remote_ip6_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip6_elem *ip6)
482{
483 unsigned int i;
484
485 for (i = 0; i < gss->num_ip6_remote; i++) {
486 if (memcmp(&gss->ip6_remote[i], ip6, sizeof(*ip6)))
487 continue;
488 /* all array elements < i remain as they are; all > i are shifted left by one */
489 memmove(&gss->ip6_remote[i], &gss->ip6_remote[i+1], gss->num_ip6_remote-i-1);
490 gss->num_ip6_remote -= 1;
491 return 0;
492 }
493 return -1;
494}
495
496/* update the weights for specified remote IPv6 */
497static int update_remote_ip6_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip6_elem *ip6)
498{
499 unsigned int i;
500
501 for (i = 0; i < gss->num_ip6_remote; i++) {
502 if (memcmp(&gss->ip6_remote[i].ip_addr, &ip6->ip_addr, sizeof(ip6->ip_addr)) ||
503 gss->ip6_remote[i].udp_port != ip6->udp_port)
504 continue;
505 gss->ip6_remote[i].sig_weight = ip6->sig_weight;
506 gss->ip6_remote[i].data_weight = ip6->data_weight;
507 return 0;
508 }
509 return -1;
510}
511
512static 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)
513{
514 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
515 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
516 struct gprs_ns2_vc *nsvc;
517 struct osmo_sockaddr sa = {};
Alexander Couzens9a4cf272020-10-11 20:48:04 +0200518 const struct osmo_sockaddr *remote;
Alexander Couzens6a161492020-07-12 13:45:50 +0200519 uint8_t new_signal;
520 uint8_t new_data;
521
522 /* TODO: Upon receiving an SNS-CHANGEWEIGHT PDU, if the resulting sum of the
523 * signalling weights of all the peer IP endpoints configured for this NSE is
524 * equal to zero or if the resulting sum of the data weights of all the peer IP
525 * endpoints configured for this NSE is equal to zero, the BSS/SGSN shall send an
526 * SNS-ACK PDU with a cause code of "Invalid weights". */
527
528 if (ip4) {
529 if (update_remote_ip4_elem(gss, ip4))
530 return -NS_CAUSE_UNKN_IP_EP;
531
532 /* copy over. Both data structures use network byte order */
533 sa.u.sin.sin_addr.s_addr = ip4->ip_addr;
534 sa.u.sin.sin_port = ip4->udp_port;
535 sa.u.sin.sin_family = AF_INET;
536 new_signal = ip4->sig_weight;
537 new_data = ip4->data_weight;
538 } else if (ip6) {
539 if (update_remote_ip6_elem(gss, ip6))
540 return -NS_CAUSE_UNKN_IP_EP;
541
542 /* copy over. Both data structures use network byte order */
543 sa.u.sin6.sin6_addr = ip6->ip_addr;
544 sa.u.sin6.sin6_port = ip6->udp_port;
545 sa.u.sin6.sin6_family = AF_INET6;
546 new_signal = ip6->sig_weight;
547 new_data = ip6->data_weight;
548 } else {
549 OSMO_ASSERT(false);
550 }
551
552 llist_for_each_entry(nsvc, &nse->nsvc, list) {
Alexander Couzensc4229a42020-10-11 20:58:04 +0200553 remote = gprs_ns2_ip_vc_remote(nsvc);
Alexander Couzens6a161492020-07-12 13:45:50 +0200554 /* all nsvc in NSE should be IP/UDP nsvc */
555 OSMO_ASSERT(remote);
556
557 if (osmo_sockaddr_cmp(&sa, remote))
558 continue;
559
560 LOGPFSML(fi, LOGL_INFO, "CHANGE-WEIGHT NS-VC %s data_weight %u->%u, sig_weight %u->%u\n",
561 gprs_ns2_ll_str(nsvc), nsvc->data_weight, new_data,
562 nsvc->sig_weight, new_signal);
563
564 nsvc->data_weight = new_data;
565 nsvc->sig_weight = new_signal;
566 }
567
568 return 0;
569}
570
571static int do_sns_delete(struct osmo_fsm_inst *fi,
572 const struct gprs_ns_ie_ip4_elem *ip4,
573 const struct gprs_ns_ie_ip6_elem *ip6)
574{
575 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
576 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
577 struct gprs_ns2_vc *nsvc, *tmp;
Alexander Couzens9a4cf272020-10-11 20:48:04 +0200578 const struct osmo_sockaddr *remote;
Alexander Couzens6a161492020-07-12 13:45:50 +0200579 struct osmo_sockaddr sa = {};
580
581 if (ip4) {
582 if (remove_remote_ip4_elem(gss, ip4) < 0)
583 return -NS_CAUSE_UNKN_IP_EP;
584 /* copy over. Both data structures use network byte order */
585 sa.u.sin.sin_addr.s_addr = ip4->ip_addr;
586 sa.u.sin.sin_port = ip4->udp_port;
587 sa.u.sin.sin_family = AF_INET;
588 } else if (ip6) {
589 if (remove_remote_ip6_elem(gss, ip6))
590 return -NS_CAUSE_UNKN_IP_EP;
591
592 /* copy over. Both data structures use network byte order */
593 sa.u.sin6.sin6_addr = ip6->ip_addr;
594 sa.u.sin6.sin6_port = ip6->udp_port;
595 sa.u.sin6.sin6_family = AF_INET6;
596 } else {
597 OSMO_ASSERT(false);
598 }
599
600 llist_for_each_entry_safe(nsvc, tmp, &nse->nsvc, list) {
Alexander Couzensc4229a42020-10-11 20:58:04 +0200601 remote = gprs_ns2_ip_vc_remote(nsvc);
Alexander Couzens6a161492020-07-12 13:45:50 +0200602 /* all nsvc in NSE should be IP/UDP nsvc */
603 OSMO_ASSERT(remote);
604 if (osmo_sockaddr_cmp(&sa, remote))
605 continue;
606
607 LOGPFSML(fi, LOGL_INFO, "DELETE NS-VC %s\n", gprs_ns2_ll_str(nsvc));
608 gprs_ns2_free_nsvc(nsvc);
609 }
610
611 return 0;
612}
613
614static int do_sns_add(struct osmo_fsm_inst *fi,
615 const struct gprs_ns_ie_ip4_elem *ip4,
616 const struct gprs_ns_ie_ip6_elem *ip6)
617{
618 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
619 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
620 struct gprs_ns2_vc *nsvc;
621 int rc = 0;
622
623 /* Upon receiving an SNS-ADD PDU, if the consequent number of IPv4 endpoints
624 * exceeds the number of IPv4 endpoints supported by the NSE, the NSE shall send
625 * an SNS-ACK PDU with a cause code set to "Invalid number of IP4 Endpoints". */
626 switch (gss->ip) {
627 case IPv4:
628 rc = add_remote_ip4_elem(gss, ip4);
629 break;
630 case IPv6:
631 rc = add_remote_ip6_elem(gss, ip6);
632 break;
633 default:
634 /* the gss->ip is initialized with the bss */
635 OSMO_ASSERT(false);
636 }
637
638 if (rc)
639 return rc;
640
641 /* Upon receiving an SNS-ADD PDU containing an already configured IP endpoint the
642 * NSE shall send an SNS-ACK PDU with the cause code "Protocol error -
643 * unspecified" */
644 switch (gss->ip) {
645 case IPv4:
646 nsvc = nsvc_by_ip4_elem(nse, ip4);
647 if (nsvc) {
648 /* the nsvc should be already in sync with the ip4 / ip6 elements */
649 return -NS_CAUSE_PROTO_ERR_UNSPEC;
650 }
651
652 /* TODO: failure case */
653 ns2_nsvc_create_ip4(fi, nse, ip4);
654 break;
655 case IPv6:
656 nsvc = nsvc_by_ip6_elem(nse, ip6);
657 if (nsvc) {
658 /* the nsvc should be already in sync with the ip4 / ip6 elements */
659 return -NS_CAUSE_PROTO_ERR_UNSPEC;
660 }
661
662 /* TODO: failure case */
663 ns2_nsvc_create_ip6(fi, nse, ip6);
664 break;
665 }
666
667 gprs_ns2_start_alive_all_nsvcs(nse);
668
669 return 0;
670}
671
672
673static void ns2_sns_st_unconfigured(struct osmo_fsm_inst *fi, uint32_t event, void *data)
674{
Alexander Couzense769f522020-12-07 07:37:07 +0100675 /* empty state - SNS Select will start by ns2_sns_st_all_action() */
Alexander Couzens6a161492020-07-12 13:45:50 +0200676}
677
678static void ns2_sns_st_size(struct osmo_fsm_inst *fi, uint32_t event, void *data)
679{
680 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
681 struct gprs_ns2_inst *nsi = nse->nsi;
682 struct tlv_parsed *tp = NULL;
683
684 switch (event) {
685 case GPRS_SNS_EV_SIZE_ACK:
686 tp = data;
687 if (TLVP_VAL_MINLEN(tp, NS_IE_CAUSE, 1)) {
688 LOGPFSML(fi, LOGL_ERROR, "SNS-SIZE-ACK with cause %s\n",
689 gprs_ns2_cause_str(*TLVP_VAL(tp, NS_IE_CAUSE)));
690 /* TODO: What to do? */
691 } else {
692 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIG_BSS,
693 nsi->timeout[NS_TOUT_TSNS_PROV], 2);
694 }
695 break;
696 default:
697 OSMO_ASSERT(0);
698 }
699}
700
Alexander Couzense769f522020-12-07 07:37:07 +0100701/* setup all dynamic SNS settings, create a new nsvc and send the SIZE */
Alexander Couzens6a161492020-07-12 13:45:50 +0200702static void ns2_sns_st_size_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
703{
704 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
Alexander Couzense769f522020-12-07 07:37:07 +0100705 struct gprs_ns_ie_ip4_elem *ip4_elems;
706 struct gprs_ns_ie_ip6_elem *ip6_elems;
707 struct gprs_ns2_vc_bind *bind;
708 struct gprs_ns2_inst *nsi = gss->nse->nsi;
709 struct osmo_sockaddr *remote;
710 const struct osmo_sockaddr *sa;
711 struct osmo_sockaddr local;
712 int count;
Alexander Couzens6a161492020-07-12 13:45:50 +0200713
Alexander Couzense769f522020-12-07 07:37:07 +0100714 /* on a generic failure, the timer callback will recover */
Alexander Couzens6a161492020-07-12 13:45:50 +0200715 if (old_state != GPRS_SNS_ST_UNCONFIGURED)
Daniel Willmann15c09a82020-11-03 23:05:43 +0100716 ns2_prim_status_ind(gss->nse, NULL, 0, NS_AFF_CAUSE_SNS_FAILURE);
Alexander Couzens6a161492020-07-12 13:45:50 +0200717
Alexander Couzens7a7b20b2021-01-18 10:47:33 +0100718 ns2_clear_ipv46_entries(gss);
719
Alexander Couzense769f522020-12-07 07:37:07 +0100720 /* no initial available */
721 if (!gss->initial)
722 return;
723
724 remote = &gss->initial->saddr;
725
726 /* count how many bindings are available (only UDP binds) */
727 count = ns2_ip_count_bind(nsi, remote);
728 if (count == 0) {
729 /* TODO: logging */
730 return;
731 }
732
Alexander Couzens81ae0aa2020-12-07 05:49:43 +0100733 bind = ns2_ip_get_bind_by_index(nsi, remote, gss->bind_offset);
Alexander Couzense769f522020-12-07 07:37:07 +0100734 if (!bind) {
Alexander Couzens81ae0aa2020-12-07 05:49:43 +0100735 if (gss->bind_offset) {
736 gss->bind_offset = 0;
737 bind = ns2_ip_get_bind_by_index(nsi, remote, gss->bind_offset);
738 }
739
740 if (!bind)
741 return;
Alexander Couzense769f522020-12-07 07:37:07 +0100742 }
743
744 /* setup the NSVC */
745 if (!gss->sns_nsvc) {
746 gss->sns_nsvc = gprs_ns2_ip_bind_connect(bind, gss->nse, remote);
747 if (!gss->sns_nsvc)
748 return;
749 gss->sns_nsvc->sns_only = true;
750 }
751
752 switch (gss->ip) {
753 case IPv4:
754 ip4_elems = talloc_zero_size(fi, sizeof(struct gprs_ns_ie_ip4_elem) * count);
755 if (!ip4_elems)
756 return;
757
758 gss->ip4_local = ip4_elems;
759
760 llist_for_each_entry(bind, &nsi->binding, list) {
761 if (!gprs_ns2_is_ip_bind(bind))
762 continue;
763
764 sa = gprs_ns2_ip_bind_sockaddr(bind);
765 if (!sa)
766 continue;
767
768 if (sa->u.sas.ss_family != AF_INET)
769 continue;
770
771 /* check if this is an specific bind */
772 if (sa->u.sin.sin_addr.s_addr == 0) {
773 if (osmo_sockaddr_local_ip(&local, remote))
774 continue;
775
776 ip4_elems->ip_addr = local.u.sin.sin_addr.s_addr;
777 } else {
778 ip4_elems->ip_addr = sa->u.sin.sin_addr.s_addr;
779 }
780
781 ip4_elems->udp_port = sa->u.sin.sin_port;
782 ip4_elems->sig_weight = 2;
783 ip4_elems->data_weight = 1;
784 ip4_elems++;
785 }
786
787 gss->num_ip4_local = count;
788 gss->num_max_ip4_remote = 4;
789 gss->num_max_nsvcs = OSMO_MAX(gss->num_max_ip4_remote * gss->num_ip4_local, 8);
790 break;
791 case IPv6:
792 /* IPv6 */
793 ip6_elems = talloc_zero_size(fi, sizeof(struct gprs_ns_ie_ip6_elem) * count);
794 if (!ip6_elems)
795 return;
796
797 gss->ip6_local = ip6_elems;
798
799 llist_for_each_entry(bind, &nsi->binding, list) {
800 if (!gprs_ns2_is_ip_bind(bind))
801 continue;
802
803 sa = gprs_ns2_ip_bind_sockaddr(bind);
804 if (!sa)
805 continue;
806
807 if (sa->u.sas.ss_family != AF_INET6)
808 continue;
809
810 /* check if this is an specific bind */
811 if (IN6_IS_ADDR_UNSPECIFIED(&sa->u.sin6.sin6_addr)) {
812 if (osmo_sockaddr_local_ip(&local, remote))
813 continue;
814
815 ip6_elems->ip_addr = local.u.sin6.sin6_addr;
816 } else {
817 ip6_elems->ip_addr = sa->u.sin6.sin6_addr;
818 }
819
820 ip6_elems->udp_port = sa->u.sin.sin_port;
821 ip6_elems->sig_weight = 2;
822 ip6_elems->data_weight = 1;
823
824 ip6_elems++;
825 }
826 gss->num_ip6_local = count;
827 gss->num_max_ip6_remote = 4;
828 gss->num_max_nsvcs = OSMO_MAX(gss->num_max_ip6_remote * gss->num_ip6_local, 8);
829 break;
830 }
831
Alexander Couzens6a161492020-07-12 13:45:50 +0200832 if (gss->num_max_ip4_remote > 0)
833 ns2_tx_sns_size(gss->sns_nsvc, true, gss->num_max_nsvcs, gss->num_max_ip4_remote, -1);
834 else
835 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 +0200836}
837
838static void ns2_sns_st_config_bss(struct osmo_fsm_inst *fi, uint32_t event, void *data)
839{
840 struct tlv_parsed *tp = NULL;
841
842 switch (event) {
843 case GPRS_SNS_EV_CONFIG_ACK:
844 tp = (struct tlv_parsed *) data;
845 if (TLVP_VAL_MINLEN(tp, NS_IE_CAUSE, 1)) {
846 LOGPFSML(fi, LOGL_ERROR, "SNS-CONFIG-ACK with cause %s\n",
847 gprs_ns2_cause_str(*TLVP_VAL(tp, NS_IE_CAUSE)));
848 /* TODO: What to do? */
849 } else {
850 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIG_SGSN, 0, 0);
851 }
852 break;
853 default:
854 OSMO_ASSERT(0);
855 }
856}
857
858static void ns2_sns_st_config_bss_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
859{
860 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
861 /* Transmit SNS-CONFIG */
Alexander Couzens6a161492020-07-12 13:45:50 +0200862 switch (gss->ip) {
863 case IPv4:
864 ns2_tx_sns_config(gss->sns_nsvc, true,
Alexander Couzense78207f2020-12-07 06:19:29 +0100865 gss->ip4_local, gss->num_ip4_local,
866 NULL, 0);
Alexander Couzens6a161492020-07-12 13:45:50 +0200867 break;
868 case IPv6:
869 ns2_tx_sns_config(gss->sns_nsvc, true,
Alexander Couzense78207f2020-12-07 06:19:29 +0100870 NULL, 0,
871 gss->ip6_local, gss->num_ip6_local);
Alexander Couzens6a161492020-07-12 13:45:50 +0200872 break;
873 }
874}
875
876
877static void ns_sns_st_config_sgsn_ip4(struct osmo_fsm_inst *fi, uint32_t event, void *data)
878{
879 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
880 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
881 const struct gprs_ns_ie_ip4_elem *v4_list;
882 unsigned int num_v4;
883 struct tlv_parsed *tp = NULL;
884
885 uint8_t cause;
886
887 tp = (struct tlv_parsed *) data;
888
889 if (!TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
890 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
891 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
892 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
893 return;
894 }
895 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
896 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
897 /* realloc to the new size */
898 gss->ip4_remote = talloc_realloc(gss, gss->ip4_remote,
899 struct gprs_ns_ie_ip4_elem,
900 gss->num_ip4_remote+num_v4);
901 /* append the new entries to the end of the list */
902 memcpy(&gss->ip4_remote[gss->num_ip4_remote], v4_list, num_v4*sizeof(*v4_list));
903 gss->num_ip4_remote += num_v4;
904
905 LOGPFSML(fi, LOGL_INFO, "Rx SNS-CONFIG: Remote IPv4 list now %u entries\n",
906 gss->num_ip4_remote);
907 if (event == GPRS_SNS_EV_CONFIG_END) {
908 /* check if sum of data / sig weights == 0 */
909 if (ip4_weight_sum_data(gss->ip4_remote, gss->num_ip4_remote) == 0 ||
910 ip4_weight_sum_sig(gss->ip4_remote, gss->num_ip4_remote) == 0) {
911 cause = NS_CAUSE_INVAL_WEIGH;
912 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
913 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
914 return;
915 }
916 create_missing_nsvcs(fi);
917 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
918 /* start the test procedure on ALL NSVCs! */
919 gprs_ns2_start_alive_all_nsvcs(nse);
920 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIGURED, 0, 0);
921 } else {
922 /* just send CONFIG-ACK */
923 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
924 }
925}
926
927static void ns_sns_st_config_sgsn_ip6(struct osmo_fsm_inst *fi, uint32_t event, void *data)
928{
929 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
930 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
931 const struct gprs_ns_ie_ip6_elem *v6_list;
932 unsigned int num_v6;
933 struct tlv_parsed *tp = NULL;
934
935 uint8_t cause;
936
937 tp = (struct tlv_parsed *) data;
938
939 if (!TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
940 cause = NS_CAUSE_INVAL_NR_IPv6_EP;
941 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
942 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
943 return;
944 }
945 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
946 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
947 /* realloc to the new size */
948 gss->ip6_remote = talloc_realloc(gss, gss->ip6_remote,
949 struct gprs_ns_ie_ip6_elem,
950 gss->num_ip6_remote+num_v6);
951 /* append the new entries to the end of the list */
952 memcpy(&gss->ip6_remote[gss->num_ip6_remote], v6_list, num_v6*sizeof(*v6_list));
953 gss->num_ip6_remote += num_v6;
954
955 LOGPFSML(fi, LOGL_INFO, "Rx SNS-CONFIG: Remote IPv6 list now %u entries\n",
956 gss->num_ip6_remote);
957 if (event == GPRS_SNS_EV_CONFIG_END) {
958 /* check if sum of data / sig weights == 0 */
959 if (ip6_weight_sum_data(gss->ip6_remote, gss->num_ip6_remote) == 0 ||
960 ip6_weight_sum_sig(gss->ip6_remote, gss->num_ip6_remote) == 0) {
961 cause = NS_CAUSE_INVAL_WEIGH;
962 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
963 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
964 return;
965 }
966 create_missing_nsvcs(fi);
967 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
968 /* start the test procedure on ALL NSVCs! */
969 gprs_ns2_start_alive_all_nsvcs(nse);
970 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIGURED, 0, 0);
971 } else {
972 /* just send CONFIG-ACK */
973 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
974 }
975}
976
977static void ns2_sns_st_config_sgsn(struct osmo_fsm_inst *fi, uint32_t event, void *data)
978{
979 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
980
981 switch (event) {
982 case GPRS_SNS_EV_CONFIG_END:
983 case GPRS_SNS_EV_CONFIG:
984
985#if 0 /* part of incoming SNS-SIZE (doesn't happen on BSS side */
986 if (TLVP_PRESENT(tp, NS_IE_RESET_FLAG)) {
987 /* reset all existing config */
988 if (gss->ip4_remote)
989 talloc_free(gss->ip4_remote);
990 gss->num_ip4_remote = 0;
991 }
992#endif
993 /* TODO: reject IPv6 elements on IPv4 mode and vice versa */
994 switch (gss->ip) {
995 case IPv4:
996 ns_sns_st_config_sgsn_ip4(fi, event, data);
997 break;
998 case IPv6:
999 ns_sns_st_config_sgsn_ip6(fi, event, data);
1000 break;
1001 default:
1002 OSMO_ASSERT(0);
1003 }
1004 break;
1005 default:
1006 OSMO_ASSERT(0);
1007 }
1008}
1009
1010/* called when receiving GPRS_SNS_EV_ADD in state configure */
1011static void ns2_sns_st_configured_add(struct osmo_fsm_inst *fi,
1012 struct ns2_sns_state *gss,
1013 struct tlv_parsed *tp)
1014{
1015 const struct gprs_ns_ie_ip4_elem *v4_list = NULL;
1016 const struct gprs_ns_ie_ip6_elem *v6_list = NULL;
1017 int num_v4 = 0, num_v6 = 0;
1018 uint8_t trans_id, cause = 0xff;
Harald Welte7da6ace2020-09-18 09:48:05 +02001019 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +02001020 int rc = 0;
1021
1022 /* TODO: refactor EV_ADD/CHANGE/REMOVE by
1023 * check uniqueness within the lists (no doublicate entries)
1024 * check not-known-by-us and sent back a list of unknown/known values
1025 * (abnormal behaviour according to 48.016)
1026 */
1027
1028 trans_id = *TLVP_VAL(tp, NS_IE_TRANS_ID);
1029 if (gss->ip == IPv4) {
1030 if (!TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
1031 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
1032 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1033 return;
1034 }
1035
1036 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
1037 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001038 for (i = 0; i < num_v4; i++) {
1039 unsigned int j;
Alexander Couzens6a161492020-07-12 13:45:50 +02001040 rc = do_sns_add(fi, &v4_list[i], NULL);
1041 if (rc < 0) {
1042 /* rollback/undo to restore previous state */
Harald Welte7da6ace2020-09-18 09:48:05 +02001043 for (j = 0; j < i; j++)
Alexander Couzens6a161492020-07-12 13:45:50 +02001044 do_sns_delete(fi, &v4_list[j], NULL);
1045 cause = -rc;
1046 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1047 break;
1048 }
1049 }
1050 } else { /* IPv6 */
1051 if (!TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
1052 cause = NS_CAUSE_INVAL_NR_IPv6_EP;
1053 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1054 return;
1055 }
1056
1057 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
1058 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001059 for (i = 0; i < num_v6; i++) {
1060 unsigned int j;
Alexander Couzens6a161492020-07-12 13:45:50 +02001061 rc = do_sns_add(fi, NULL, &v6_list[i]);
1062 if (rc < 0) {
1063 /* rollback/undo to restore previous state */
Harald Welte7da6ace2020-09-18 09:48:05 +02001064 for (j = 0; j < i; j++)
Alexander Couzens6a161492020-07-12 13:45:50 +02001065 do_sns_delete(fi, NULL, &v6_list[j]);
1066 cause = -rc;
1067 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1068 break;
1069 }
1070 }
1071 }
1072
1073 /* TODO: correct behaviour is to answer to the *same* NSVC from which the SNS_ADD was received */
1074 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, NULL, v4_list, num_v4, v6_list, num_v6);
1075}
1076
1077static void ns2_sns_st_configured_delete(struct osmo_fsm_inst *fi,
1078 struct ns2_sns_state *gss,
1079 struct tlv_parsed *tp)
1080{
1081 const struct gprs_ns_ie_ip4_elem *v4_list = NULL;
1082 const struct gprs_ns_ie_ip6_elem *v6_list = NULL;
1083 int num_v4 = 0, num_v6 = 0;
1084 uint8_t trans_id, cause = 0xff;
Harald Welte7da6ace2020-09-18 09:48:05 +02001085 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +02001086 int rc = 0;
1087
1088 /* TODO: split up delete into v4 + v6
1089 * TODO: check if IPv4_LIST or IP_ADDR(v4) is present on IPv6 and vice versa
1090 * TODO: check if IPv4_LIST/IPv6_LIST and IP_ADDR is present at the same time
1091 */
1092 trans_id = *TLVP_VAL(tp, NS_IE_TRANS_ID);
1093 if (gss->ip == IPv4) {
1094 if (TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
1095 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
1096 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001097 for ( i = 0; i < num_v4; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001098 rc = do_sns_delete(fi, &v4_list[i], NULL);
1099 if (rc < 0) {
1100 cause = -rc;
1101 /* continue to delete others */
1102 }
1103 }
1104 if (cause != 0xff) {
1105 /* TODO: create list of not-deleted and return it */
1106 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1107 return;
1108 }
1109
1110 } else if (TLVP_PRESENT(tp, NS_IE_IP_ADDR) && TLVP_LEN(tp, NS_IE_IP_ADDR) == 5) {
1111 /* delete all NS-VCs for given IPv4 address */
1112 const uint8_t *ie = TLVP_VAL(tp, NS_IE_IP_ADDR);
1113 struct gprs_ns_ie_ip4_elem *ip4_remote;
1114 uint32_t ip_addr = *(uint32_t *)(ie+1);
1115 if (ie[0] != 0x01) { /* Address Type != IPv4 */
1116 cause = NS_CAUSE_UNKN_IP_ADDR;
1117 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1118 return;
1119 }
1120 /* make a copy as do_sns_delete() will change the array underneath us */
1121 ip4_remote = talloc_memdup(fi, gss->ip4_remote,
1122 gss->num_ip4_remote * sizeof(*v4_list));
Harald Welte7da6ace2020-09-18 09:48:05 +02001123 for (i = 0; i < gss->num_ip4_remote; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001124 if (ip4_remote[i].ip_addr == ip_addr) {
1125 rc = do_sns_delete(fi, &ip4_remote[i], NULL);
1126 if (rc < 0) {
1127 cause = -rc;
1128 /* continue to delete others */
1129 }
1130 }
1131 }
1132 talloc_free(ip4_remote);
1133 if (cause != 0xff) {
1134 /* TODO: create list of not-deleted and return it */
1135 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1136 return;
1137 }
1138 } else {
1139 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
1140 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1141 return;
1142 }
1143 } else { /* IPv6 */
1144 if (TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
1145 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
1146 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001147 for (i = 0; i < num_v6; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001148 rc = do_sns_delete(fi, NULL, &v6_list[i]);
1149 if (rc < 0) {
1150 cause = -rc;
1151 /* continue to delete others */
1152 }
1153 }
1154 if (cause != 0xff) {
1155 /* TODO: create list of not-deleted and return it */
1156 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1157 return;
1158 }
1159 } else if (TLVP_PRES_LEN(tp, NS_IE_IP_ADDR, 17)) {
1160 /* delete all NS-VCs for given IPv4 address */
1161 const uint8_t *ie = TLVP_VAL(tp, NS_IE_IP_ADDR);
1162 struct gprs_ns_ie_ip6_elem *ip6_remote;
1163 struct in6_addr ip6_addr;
Harald Welte7da6ace2020-09-18 09:48:05 +02001164 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +02001165 if (ie[0] != 0x02) { /* Address Type != IPv6 */
1166 cause = NS_CAUSE_UNKN_IP_ADDR;
1167 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1168 return;
1169 }
1170 memcpy(&ip6_addr, (ie+1), sizeof(struct in6_addr));
1171 /* make a copy as do_sns_delete() will change the array underneath us */
1172 ip6_remote = talloc_memdup(fi, gss->ip6_remote,
1173 gss->num_ip6_remote * sizeof(*v4_list));
Harald Welte7da6ace2020-09-18 09:48:05 +02001174 for (i = 0; i < gss->num_ip6_remote; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001175 if (!memcmp(&ip6_remote[i].ip_addr, &ip6_addr, sizeof(struct in6_addr))) {
1176 rc = do_sns_delete(fi, NULL, &ip6_remote[i]);
1177 if (rc < 0) {
1178 cause = -rc;
1179 /* continue to delete others */
1180 }
1181 }
1182 }
1183
1184 talloc_free(ip6_remote);
1185 if (cause != 0xff) {
1186 /* TODO: create list of not-deleted and return it */
1187 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1188 return;
1189 }
1190 } else {
1191 cause = NS_CAUSE_INVAL_NR_IPv6_EP;
1192 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1193 return;
1194 }
1195 }
1196 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, NULL, v4_list, num_v4, v6_list, num_v6);
1197}
1198
1199static void ns2_sns_st_configured_change(struct osmo_fsm_inst *fi,
1200 struct ns2_sns_state *gss,
1201 struct tlv_parsed *tp)
1202{
1203 const struct gprs_ns_ie_ip4_elem *v4_list = NULL;
1204 const struct gprs_ns_ie_ip6_elem *v6_list = NULL;
1205 int num_v4 = 0, num_v6 = 0;
1206 uint8_t trans_id, cause = 0xff;
1207 int rc = 0;
Harald Welte7da6ace2020-09-18 09:48:05 +02001208 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +02001209
1210 trans_id = *TLVP_VAL(tp, NS_IE_TRANS_ID);
1211 if (TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
1212 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
1213 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001214 for (i = 0; i < num_v4; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001215 rc = do_sns_change_weight(fi, &v4_list[i], NULL);
1216 if (rc < 0) {
1217 cause = -rc;
1218 /* continue to others */
1219 }
1220 }
1221 if (cause != 0xff) {
1222 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1223 return;
1224 }
1225 } else if (TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
1226 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
1227 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001228 for (i = 0; i < num_v6; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001229 rc = do_sns_change_weight(fi, NULL, &v6_list[i]);
1230 if (rc < 0) {
1231 cause = -rc;
1232 /* continue to others */
1233 }
1234 }
1235 if (cause != 0xff) {
1236 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1237 return;
1238 }
1239 } else {
1240 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
1241 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1242 return;
1243 }
1244 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, NULL, v4_list, num_v4, v6_list, num_v6);
1245}
1246
1247static void ns2_sns_st_configured(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1248{
1249 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
1250 struct tlv_parsed *tp = data;
1251
1252 switch (event) {
1253 case GPRS_SNS_EV_ADD:
1254 ns2_sns_st_configured_add(fi, gss, tp);
1255 break;
1256 case GPRS_SNS_EV_DELETE:
1257 ns2_sns_st_configured_delete(fi, gss, tp);
1258 break;
1259 case GPRS_SNS_EV_CHANGE_WEIGHT:
1260 ns2_sns_st_configured_change(fi, gss, tp);
1261 break;
1262 }
1263}
1264
1265static void ns2_sns_st_configured_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
1266{
1267 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
Daniel Willmann15c09a82020-11-03 23:05:43 +01001268 ns2_prim_status_ind(nse, NULL, 0, NS_AFF_CAUSE_SNS_CONFIGURED);
Alexander Couzens6a161492020-07-12 13:45:50 +02001269}
1270
1271static const struct osmo_fsm_state ns2_sns_bss_states[] = {
1272 [GPRS_SNS_ST_UNCONFIGURED] = {
Alexander Couzense769f522020-12-07 07:37:07 +01001273 .in_event_mask = 0, /* handled by all_state_action */
Alexander Couzens6a161492020-07-12 13:45:50 +02001274 .out_state_mask = S(GPRS_SNS_ST_SIZE),
1275 .name = "UNCONFIGURED",
1276 .action = ns2_sns_st_unconfigured,
1277 },
1278 [GPRS_SNS_ST_SIZE] = {
1279 .in_event_mask = S(GPRS_SNS_EV_SIZE_ACK),
1280 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
1281 S(GPRS_SNS_ST_SIZE) |
1282 S(GPRS_SNS_ST_CONFIG_BSS),
1283 .name = "SIZE",
1284 .action = ns2_sns_st_size,
1285 .onenter = ns2_sns_st_size_onenter,
1286 },
1287 [GPRS_SNS_ST_CONFIG_BSS] = {
1288 .in_event_mask = S(GPRS_SNS_EV_CONFIG_ACK),
1289 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
1290 S(GPRS_SNS_ST_CONFIG_BSS) |
1291 S(GPRS_SNS_ST_CONFIG_SGSN) |
1292 S(GPRS_SNS_ST_SIZE),
1293 .name = "CONFIG_BSS",
1294 .action = ns2_sns_st_config_bss,
1295 .onenter = ns2_sns_st_config_bss_onenter,
1296 },
1297 [GPRS_SNS_ST_CONFIG_SGSN] = {
1298 .in_event_mask = S(GPRS_SNS_EV_CONFIG) |
1299 S(GPRS_SNS_EV_CONFIG_END),
1300 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
1301 S(GPRS_SNS_ST_CONFIG_SGSN) |
1302 S(GPRS_SNS_ST_CONFIGURED) |
1303 S(GPRS_SNS_ST_SIZE),
1304 .name = "CONFIG_SGSN",
1305 .action = ns2_sns_st_config_sgsn,
1306 },
1307 [GPRS_SNS_ST_CONFIGURED] = {
1308 .in_event_mask = S(GPRS_SNS_EV_ADD) |
1309 S(GPRS_SNS_EV_DELETE) |
1310 S(GPRS_SNS_EV_CHANGE_WEIGHT),
Alexander Couzense03d8632020-12-06 03:31:44 +01001311 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
1312 S(GPRS_SNS_ST_SIZE),
Alexander Couzens6a161492020-07-12 13:45:50 +02001313 .name = "CONFIGURED",
1314 .action = ns2_sns_st_configured,
1315 .onenter = ns2_sns_st_configured_onenter,
1316 },
1317};
1318
1319static int ns2_sns_fsm_bss_timer_cb(struct osmo_fsm_inst *fi)
1320{
Alexander Couzens90ee9632020-12-07 06:18:32 +01001321 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
Alexander Couzens6a161492020-07-12 13:45:50 +02001322 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
1323 struct gprs_ns2_inst *nsi = nse->nsi;
1324
Alexander Couzens90ee9632020-12-07 06:18:32 +01001325 gss->N++;
Alexander Couzens6a161492020-07-12 13:45:50 +02001326 switch (fi->T) {
1327 case 1:
Alexander Couzensa367d082020-12-21 14:06:24 +01001328 if (gss->N >= nsi->timeout[NS_TOUT_TSNS_SIZE_RETRIES]) {
1329 LOGPFSML(fi, LOGL_ERROR, "NSE %d: Size retries failed. Selecting next IP-SNS endpoint.\n", nse->nsei);
Alexander Couzens90ee9632020-12-07 06:18:32 +01001330 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_SELECT_ENDPOINT, NULL);
Alexander Couzensa367d082020-12-21 14:06:24 +01001331 } else {
Alexander Couzenscc65a252020-12-21 14:03:58 +01001332 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_SIZE, nsi->timeout[NS_TOUT_TSNS_PROV], 1);
Alexander Couzensa367d082020-12-21 14:06:24 +01001333 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001334 break;
1335 case 2:
Alexander Couzensa367d082020-12-21 14:06:24 +01001336 if (gss->N >= nsi->timeout[NS_TOUT_TSNS_CONFIG_RETRIES]) {
1337 LOGPFSML(fi, LOGL_ERROR, "NSE %d: Config retries failed. Selecting next IP-SNS endpoint.\n", nse->nsei);
Alexander Couzens90ee9632020-12-07 06:18:32 +01001338 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_SELECT_ENDPOINT, NULL);
Alexander Couzensa367d082020-12-21 14:06:24 +01001339 } else {
Alexander Couzenscc65a252020-12-21 14:03:58 +01001340 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 +01001341 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001342 break;
1343 }
1344 return 0;
1345}
1346
1347static void ns2_sns_st_all_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1348{
Alexander Couzense769f522020-12-07 07:37:07 +01001349 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
Alexander Couzens6a161492020-07-12 13:45:50 +02001350 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
1351
1352 /* reset when receiving GPRS_SNS_EV_NO_NSVC */
Alexander Couzense769f522020-12-07 07:37:07 +01001353 switch (event) {
1354 case GPRS_SNS_EV_NO_NSVC:
Alexander Couzens3ad73362020-12-21 13:53:00 +01001355 /* ignore reselection running */
1356 if (gss->reselection_running)
1357 break;
1358
1359 LOGPFSML(fi, LOGL_ERROR, "NSE %d: no remaining NSVC, resetting SNS FSM\n", nse->nsei);
1360 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_SELECT_ENDPOINT, NULL);
Alexander Couzense769f522020-12-07 07:37:07 +01001361 break;
1362 case GPRS_SNS_EV_SELECT_ENDPOINT:
1363 /* tear down previous state
1364 * gprs_ns2_free_nsvcs() will trigger NO_NSVC, prevent this from triggering a reselection */
1365 gss->reselection_running = true;
1366 gprs_ns2_free_nsvcs(nse);
Alexander Couzens7a7b20b2021-01-18 10:47:33 +01001367 ns2_clear_ipv46_entries(gss);
Alexander Couzense769f522020-12-07 07:37:07 +01001368
1369 /* Choose the next sns endpoint. */
1370 if (llist_empty(&gss->sns_endpoints)) {
1371 gss->initial = NULL;
1372 ns2_prim_status_ind(gss->nse, NULL, 0, NS_AFF_CAUSE_SNS_NO_ENDPOINTS);
1373 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 3);
1374 return;
1375 } else if (!gss->initial) {
1376 gss->initial = llist_first_entry(&gss->sns_endpoints, struct sns_endpoint, list);
Alexander Couzens81ae0aa2020-12-07 05:49:43 +01001377 gss->bind_offset = 0;
Alexander Couzense769f522020-12-07 07:37:07 +01001378 } else if (gss->initial->list.next == &gss->sns_endpoints) {
1379 /* last entry, continue with first */
1380 gss->initial = llist_first_entry(&gss->sns_endpoints, struct sns_endpoint, list);
Alexander Couzens81ae0aa2020-12-07 05:49:43 +01001381 gss->bind_offset++;
1382 gss->bind_offset %= ns2_ip_count_bind(nse->nsi, &gss->initial->saddr);
Alexander Couzense769f522020-12-07 07:37:07 +01001383 } else {
1384 /* next element is an entry */
1385 gss->initial = llist_entry(gss->initial->list.next, struct sns_endpoint, list);
1386 }
1387
1388 gss->reselection_running = false;
1389 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_SIZE, nse->nsi->timeout[NS_TOUT_TSNS_PROV], 1);
1390 break;
1391 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001392}
1393
1394static struct osmo_fsm gprs_ns2_sns_bss_fsm = {
1395 .name = "GPRS-NS2-SNS-BSS",
1396 .states = ns2_sns_bss_states,
1397 .num_states = ARRAY_SIZE(ns2_sns_bss_states),
Alexander Couzense769f522020-12-07 07:37:07 +01001398 .allstate_event_mask = S(GPRS_SNS_EV_NO_NSVC) |
1399 S(GPRS_SNS_EV_SELECT_ENDPOINT),
Alexander Couzens6a161492020-07-12 13:45:50 +02001400 .allstate_action = ns2_sns_st_all_action,
1401 .cleanup = NULL,
1402 .timer_cb = ns2_sns_fsm_bss_timer_cb,
1403 /* .log_subsys = DNS, "is not constant" */
1404 .event_names = gprs_sns_event_names,
1405 .pre_term = NULL,
1406 .log_subsys = DLNS,
1407};
1408
Harald Welte5bef2cc2020-09-18 22:33:24 +02001409/*! Allocate an IP-SNS FSM for the BSS side.
1410 * \param[in] nse NS Entity in which the FSM runs
1411 * \param[in] id string identifier
1412 * \retruns FSM instance on success; NULL on error */
Alexander Couzens6a161492020-07-12 13:45:50 +02001413struct osmo_fsm_inst *ns2_sns_bss_fsm_alloc(struct gprs_ns2_nse *nse,
1414 const char *id)
1415{
1416 struct osmo_fsm_inst *fi;
1417 struct ns2_sns_state *gss;
1418
1419 fi = osmo_fsm_inst_alloc(&gprs_ns2_sns_bss_fsm, nse, NULL, LOGL_DEBUG, id);
1420 if (!fi)
1421 return fi;
1422
1423 gss = talloc_zero(fi, struct ns2_sns_state);
1424 if (!gss)
1425 goto err;
1426
1427 fi->priv = gss;
1428 gss->nse = nse;
Alexander Couzense769f522020-12-07 07:37:07 +01001429 INIT_LLIST_HEAD(&gss->sns_endpoints);
Alexander Couzens6a161492020-07-12 13:45:50 +02001430
1431 return fi;
1432err:
1433 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
1434 return NULL;
1435}
1436
Harald Welte5bef2cc2020-09-18 22:33:24 +02001437/*! main entry point for receiving SNS messages from the network.
1438 * \param[in] nsvc NS-VC on which the message was received
1439 * \param[in] msg message buffer of the IP-SNS message
1440 * \param[in] tp parsed TLV structure of message
1441 * \retruns 0 on success; negative on error */
Alexander Couzens6a161492020-07-12 13:45:50 +02001442int gprs_ns2_sns_rx(struct gprs_ns2_vc *nsvc, struct msgb *msg, struct tlv_parsed *tp)
1443{
1444 struct gprs_ns2_nse *nse = nsvc->nse;
1445 struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h;
1446 uint16_t nsei = nsvc->nse->nsei;
1447 struct osmo_fsm_inst *fi;
1448
1449 if (!nse->bss_sns_fi) {
Harald Weltef2949742021-01-20 14:54:14 +01001450 LOGNSVC(nsvc, LOGL_NOTICE, "Rx %s for NS Instance that has no SNS!\n",
1451 get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
Alexander Couzens6a161492020-07-12 13:45:50 +02001452 return -EINVAL;
1453 }
1454
Alexander Couzens6a161492020-07-12 13:45:50 +02001455 /* FIXME: how to resolve SNS FSM Instance by NSEI (SGSN)? */
1456 fi = nse->bss_sns_fi;
1457
Harald Weltef2949742021-01-20 14:54:14 +01001458 LOGPFSML(fi, LOGL_DEBUG, "NSEI=%u Rx SNS PDU type %s\n", nsei,
1459 get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
1460
Alexander Couzens6a161492020-07-12 13:45:50 +02001461 switch (nsh->pdu_type) {
1462 case SNS_PDUT_SIZE:
1463 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_SIZE, tp);
1464 break;
1465 case SNS_PDUT_SIZE_ACK:
1466 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_SIZE_ACK, tp);
1467 break;
1468 case SNS_PDUT_CONFIG:
1469 if (nsh->data[0] & 0x01)
1470 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_CONFIG_END, tp);
1471 else
1472 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_CONFIG, tp);
1473 break;
1474 case SNS_PDUT_CONFIG_ACK:
1475 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_CONFIG_ACK, tp);
1476 break;
1477 case SNS_PDUT_ADD:
1478 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_ADD, tp);
1479 break;
1480 case SNS_PDUT_DELETE:
1481 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_DELETE, tp);
1482 break;
1483 case SNS_PDUT_CHANGE_WEIGHT:
1484 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_CHANGE_WEIGHT, tp);
1485 break;
1486 case SNS_PDUT_ACK:
Harald Weltef2949742021-01-20 14:54:14 +01001487 LOGPFSML(fi, LOGL_NOTICE, "NSEI=%u Rx unsupported SNS PDU type %s\n", nsei,
1488 get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
Alexander Couzens6a161492020-07-12 13:45:50 +02001489 break;
1490 default:
Harald Weltef2949742021-01-20 14:54:14 +01001491 LOGPFSML(fi, LOGL_ERROR, "NSEI=%u Rx unknown SNS PDU type %s\n", nsei,
1492 get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
Alexander Couzens6a161492020-07-12 13:45:50 +02001493 return -EINVAL;
1494 }
1495
1496 return 0;
1497}
1498
1499#include <osmocom/vty/vty.h>
1500#include <osmocom/vty/misc.h>
1501
Harald Welte1262c4f2021-01-19 20:58:33 +01001502static 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 +02001503{
1504 struct in_addr in = { .s_addr = ip4->ip_addr };
Harald Welte1262c4f2021-01-19 20:58:33 +01001505 vty_out(vty, "%s %s:%u, Signalling Weight: %u, Data Weight: %u%s", prefix,
Alexander Couzens6a161492020-07-12 13:45:50 +02001506 inet_ntoa(in), ntohs(ip4->udp_port), ip4->sig_weight, ip4->data_weight, VTY_NEWLINE);
1507}
1508
Harald Welte1262c4f2021-01-19 20:58:33 +01001509static 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 +02001510{
1511 char ip_addr[INET6_ADDRSTRLEN] = {};
1512 if (!inet_ntop(AF_INET6, &ip6->ip_addr, ip_addr, (INET6_ADDRSTRLEN)))
1513 strcpy(ip_addr, "Invalid IPv6");
1514
Harald Welte1262c4f2021-01-19 20:58:33 +01001515 vty_out(vty, "%s %s:%u, Signalling Weight: %u, Data Weight: %u%s", prefix,
Alexander Couzens6a161492020-07-12 13:45:50 +02001516 ip_addr, ntohs(ip6->udp_port), ip6->sig_weight, ip6->data_weight, VTY_NEWLINE);
1517}
1518
Harald Welte5bef2cc2020-09-18 22:33:24 +02001519/*! Dump the IP-SNS state to a vty.
1520 * \param[in] vty VTY to which the state shall be printed
Harald Welte1262c4f2021-01-19 20:58:33 +01001521 * \param[in] prefix prefix to print at start of each line (typically indenting)
Harald Welte5bef2cc2020-09-18 22:33:24 +02001522 * \param[in] nse NS Entity whose IP-SNS state shall be printed
1523 * \param[in] stats Whether or not statistics shall also be printed */
Harald Welte1262c4f2021-01-19 20:58:33 +01001524void gprs_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 +02001525{
1526 struct ns2_sns_state *gss;
1527 unsigned int i;
1528
1529 if (!nse->bss_sns_fi)
1530 return;
1531
Harald Welte1262c4f2021-01-19 20:58:33 +01001532 vty_out_fsm_inst2(vty, prefix, nse->bss_sns_fi);
Alexander Couzens6a161492020-07-12 13:45:50 +02001533 gss = (struct ns2_sns_state *) nse->bss_sns_fi->priv;
1534
Harald Welte1262c4f2021-01-19 20:58:33 +01001535 vty_out(vty, "%sMaximum number of remote NS-VCs: %zu, IPv4 Endpoints: %zu, IPv6 Endpoints: %zu%s",
1536 prefix, gss->num_max_nsvcs, gss->num_max_ip4_remote, gss->num_max_ip6_remote, VTY_NEWLINE);
Alexander Couzens6a161492020-07-12 13:45:50 +02001537
1538 if (gss->num_ip4_local && gss->num_ip4_remote) {
Harald Welte1262c4f2021-01-19 20:58:33 +01001539 vty_out(vty, "%sLocal IPv4 Endpoints:%s", prefix, VTY_NEWLINE);
Alexander Couzens6a161492020-07-12 13:45:50 +02001540 for (i = 0; i < gss->num_ip4_local; i++)
Harald Welte1262c4f2021-01-19 20:58:33 +01001541 vty_dump_sns_ip4(vty, prefix, &gss->ip4_local[i]);
Alexander Couzens6a161492020-07-12 13:45:50 +02001542
Harald Welte1262c4f2021-01-19 20:58:33 +01001543 vty_out(vty, "%sRemote IPv4 Endpoints:%s", prefix, VTY_NEWLINE);
Alexander Couzens6a161492020-07-12 13:45:50 +02001544 for (i = 0; i < gss->num_ip4_remote; i++)
Harald Welte1262c4f2021-01-19 20:58:33 +01001545 vty_dump_sns_ip4(vty, prefix, &gss->ip4_remote[i]);
Alexander Couzens6a161492020-07-12 13:45:50 +02001546 }
1547
1548 if (gss->num_ip6_local && gss->num_ip6_remote) {
Harald Welte1262c4f2021-01-19 20:58:33 +01001549 vty_out(vty, "%sLocal IPv6 Endpoints:%s", prefix, VTY_NEWLINE);
Alexander Couzens6a161492020-07-12 13:45:50 +02001550 for (i = 0; i < gss->num_ip6_local; i++)
Harald Welte1262c4f2021-01-19 20:58:33 +01001551 vty_dump_sns_ip6(vty, prefix, &gss->ip6_local[i]);
Alexander Couzens6a161492020-07-12 13:45:50 +02001552
Harald Welte1262c4f2021-01-19 20:58:33 +01001553 vty_out(vty, "%sRemote IPv6 Endpoints:%s", prefix, VTY_NEWLINE);
Alexander Couzens6a161492020-07-12 13:45:50 +02001554 for (i = 0; i < gss->num_ip6_remote; i++)
Harald Welte1262c4f2021-01-19 20:58:33 +01001555 vty_dump_sns_ip6(vty, prefix, &gss->ip6_remote[i]);
Alexander Couzens6a161492020-07-12 13:45:50 +02001556 }
1557}
1558
Alexander Couzens412bc342020-11-19 05:24:37 +01001559/*! write IP-SNS to a vty
1560 * \param[in] vty VTY to which the state shall be printed
1561 * \param[in] nse NS Entity whose IP-SNS state shall be printed */
1562void gprs_ns2_sns_write_vty(struct vty *vty, const struct gprs_ns2_nse *nse)
1563{
1564 struct ns2_sns_state *gss;
1565 struct osmo_sockaddr_str addr_str;
1566 struct sns_endpoint *endpoint;
1567
1568 if (!nse->bss_sns_fi)
1569 return;
1570
1571 gss = (struct ns2_sns_state *) nse->bss_sns_fi->priv;
1572 llist_for_each_entry(endpoint, &gss->sns_endpoints, list) {
Vadim Yanitskiyd8b70032021-01-05 14:24:09 +01001573 /* It's unlikely that an error happens, but let's better be safe. */
1574 if (osmo_sockaddr_str_from_sockaddr(&addr_str, &endpoint->saddr.u.sas) != 0)
1575 addr_str = (struct osmo_sockaddr_str) { .ip = "<INVALID>" };
Alexander Couzens412bc342020-11-19 05:24:37 +01001576 vty_out(vty, " ip-sns %s %u%s", addr_str.ip, addr_str.port, VTY_NEWLINE);
1577 }
1578}
1579
Alexander Couzense769f522020-12-07 07:37:07 +01001580static struct sns_endpoint *ns2_get_sns_endpoint(struct ns2_sns_state *state,
1581 const struct osmo_sockaddr *saddr)
1582{
1583 struct sns_endpoint *endpoint;
1584
1585 llist_for_each_entry(endpoint, &state->sns_endpoints, list) {
1586 if (!osmo_sockaddr_cmp(saddr, &endpoint->saddr))
1587 return endpoint;
1588 }
1589
1590 return NULL;
1591}
1592
1593/*! gprs_ns2_sns_add_endpoint
1594 * \param[in] nse
1595 * \param[in] sockaddr
1596 * \return
1597 */
1598int gprs_ns2_sns_add_endpoint(struct gprs_ns2_nse *nse,
1599 const struct osmo_sockaddr *saddr)
1600{
1601 struct ns2_sns_state *gss;
1602 struct sns_endpoint *endpoint;
1603 bool do_selection = false;
1604
1605 if (nse->ll != GPRS_NS2_LL_UDP) {
1606 return -EINVAL;
1607 }
1608
1609 if (nse->dialect != NS2_DIALECT_SNS) {
1610 return -EINVAL;
1611 }
1612
1613 gss = nse->bss_sns_fi->priv;
1614
1615 if (ns2_get_sns_endpoint(gss, saddr))
1616 return -EADDRINUSE;
1617
1618 endpoint = talloc_zero(nse->bss_sns_fi->priv, struct sns_endpoint);
1619 if (!endpoint)
1620 return -ENOMEM;
1621
1622 endpoint->saddr = *saddr;
1623 if (llist_empty(&gss->sns_endpoints))
1624 do_selection = true;
1625
1626 llist_add_tail(&endpoint->list, &gss->sns_endpoints);
1627 if (do_selection)
1628 osmo_fsm_inst_dispatch(nse->bss_sns_fi, GPRS_SNS_EV_SELECT_ENDPOINT, NULL);
1629
1630 return 0;
1631}
1632
1633/*! gprs_ns2_sns_del_endpoint
1634 * \param[in] nse
1635 * \param[in] sockaddr
1636 * \return 0 on success, otherwise < 0
1637 */
1638int gprs_ns2_sns_del_endpoint(struct gprs_ns2_nse *nse,
1639 const struct osmo_sockaddr *saddr)
1640{
1641 struct ns2_sns_state *gss;
1642 struct sns_endpoint *endpoint;
1643
1644 if (nse->ll != GPRS_NS2_LL_UDP) {
1645 return -EINVAL;
1646 }
1647
1648 if (nse->dialect != NS2_DIALECT_SNS) {
1649 return -EINVAL;
1650 }
1651
1652 gss = nse->bss_sns_fi->priv;
1653 endpoint = ns2_get_sns_endpoint(gss, saddr);
1654 if (!endpoint)
1655 return -ENOENT;
1656
1657 /* if this is an unused SNS endpoint it's done */
1658 if (gss->initial != endpoint) {
1659 llist_del(&endpoint->list);
1660 talloc_free(endpoint);
1661 return 0;
1662 }
1663
1664 /* gprs_ns2_free_nsvcs() will trigger GPRS_SNS_EV_NO_NSVC on the last NS-VC
1665 * and restart SNS SIZE procedure which selects a new initial */
Harald Weltef2949742021-01-20 14:54:14 +01001666 LOGNSE(nse, LOGL_INFO, "Current in-use SNS endpoint is being removed."
Alexander Couzense769f522020-12-07 07:37:07 +01001667 "Closing all NS-VC and restart SNS-SIZE procedure"
1668 "with a remaining SNS endpoint.\n");
1669
1670 /* Continue with the next endpoint in the list.
1671 * Special case if the endpoint is at the start or end of the list */
1672 if (endpoint->list.prev == &gss->sns_endpoints ||
1673 endpoint->list.next == &gss->sns_endpoints)
1674 gss->initial = NULL;
1675 else
1676 gss->initial = llist_entry(endpoint->list.next->prev,
1677 struct sns_endpoint,
1678 list);
1679
1680 llist_del(&endpoint->list);
1681 gprs_ns2_free_nsvcs(nse);
1682 talloc_free(endpoint);
1683
1684 return 0;
1685}
1686
1687/*! gprs_ns2_sns_count
1688 * \param[in] nse NS Entity whose IP-SNS endpoints shall be printed
1689 * \return the count of endpoints or < 0 if NSE doesn't contain sns.
1690 */
1691int gprs_ns2_sns_count(struct gprs_ns2_nse *nse)
1692{
1693 struct ns2_sns_state *gss;
1694 struct sns_endpoint *endpoint;
1695 int count = 0;
1696
1697 if (nse->ll != GPRS_NS2_LL_UDP) {
1698 return -EINVAL;
1699 }
1700
1701 if (nse->dialect != NS2_DIALECT_SNS) {
1702 return -EINVAL;
1703 }
1704
1705 gss = nse->bss_sns_fi->priv;
1706 llist_for_each_entry(endpoint, &gss->sns_endpoints, list)
1707 count++;
1708
1709 return count;
1710}
1711
Alexander Couzens6a161492020-07-12 13:45:50 +02001712/* initialize osmo_ctx on main tread */
1713static __attribute__((constructor)) void on_dso_load_ctx(void)
1714{
1715 OSMO_ASSERT(osmo_fsm_register(&gprs_ns2_sns_bss_fsm) == 0);
1716}