blob: 2cb4293414cbe133e9fda208cf76a770dae14db6 [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) {
273 /* ignore failed connection */
274 nsvc = gprs_ns2_ip_connect_inactive(bind,
275 &remote,
276 nse, 0);
277 if (!nsvc) {
278 LOGPFSML(fi, LOGL_ERROR, "SNS-CONFIG: Failed to create NSVC\n");
279 continue;
280 }
281
282 nsvc->sig_weight = ip4->sig_weight;
283 nsvc->data_weight = ip4->data_weight;
284 }
285}
286
287static void ns2_nsvc_create_ip6(struct osmo_fsm_inst *fi,
288 struct gprs_ns2_nse *nse,
289 const struct gprs_ns_ie_ip6_elem *ip6)
290{
291 struct gprs_ns2_inst *nsi = nse->nsi;
292 struct gprs_ns2_vc *nsvc;
293 struct gprs_ns2_vc_bind *bind;
294 struct osmo_sockaddr remote = {};
295 /* copy over. Both data structures use network byte order */
296 remote.u.sin6.sin6_family = AF_INET6;
297 remote.u.sin6.sin6_addr = ip6->ip_addr;
298 remote.u.sin6.sin6_port = ip6->udp_port;
299
300 /* for every bind, create a connection if bind type == IP */
301 llist_for_each_entry(bind, &nsi->binding, list) {
302 /* ignore failed connection */
303 nsvc = gprs_ns2_ip_connect_inactive(bind,
304 &remote,
305 nse, 0);
306 if (!nsvc) {
307 LOGPFSML(fi, LOGL_ERROR, "SNS-CONFIG: Failed to create NSVC\n");
308 continue;
309 }
310
311 nsvc->sig_weight = ip6->sig_weight;
312 nsvc->data_weight = ip6->data_weight;
313 }
314}
315
316
317static int create_missing_nsvcs(struct osmo_fsm_inst *fi)
318{
319 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
320 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
321 struct gprs_ns2_vc *nsvc;
322 struct gprs_ns2_vc_bind *bind;
323 struct osmo_sockaddr remote = { };
324 unsigned int i;
325
326 for (i = 0; i < gss->num_ip4_remote; i++) {
327 const struct gprs_ns_ie_ip4_elem *ip4 = &gss->ip4_remote[i];
328
329 remote.u.sin.sin_family = AF_INET;
330 remote.u.sin.sin_addr.s_addr = ip4->ip_addr;
331 remote.u.sin.sin_port = ip4->udp_port;
332
333 llist_for_each_entry(bind, &nse->nsi->binding, list) {
334 bool found = false;
335
336 llist_for_each_entry(nsvc, &nse->nsvc, list) {
337 if (nsvc->bind != bind)
338 continue;
339
Alexander Couzensc4229a42020-10-11 20:58:04 +0200340 if (!osmo_sockaddr_cmp(&remote, gprs_ns2_ip_vc_remote(nsvc))) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200341 found = true;
342 break;
343 }
344 }
345
346 if (!found) {
347 nsvc = gprs_ns2_ip_connect_inactive(bind, &remote, nse, 0);
348 if (!nsvc) {
349 /* TODO: add to a list to send back a NS-STATUS */
350 continue;
351 }
352 }
353
354 /* update data / signalling weight */
355 nsvc->data_weight = ip4->data_weight;
356 nsvc->sig_weight = ip4->sig_weight;
357 nsvc->sns_only = false;
358 }
359 }
360
361 for (i = 0; i < gss->num_ip6_remote; i++) {
362 const struct gprs_ns_ie_ip6_elem *ip6 = &gss->ip6_remote[i];
363
364 remote.u.sin6.sin6_family = AF_INET6;
365 remote.u.sin6.sin6_addr = ip6->ip_addr;
366 remote.u.sin6.sin6_port = ip6->udp_port;
367
368 llist_for_each_entry(bind, &nse->nsi->binding, list) {
369 bool found = false;
370
371 llist_for_each_entry(nsvc, &nse->nsvc, list) {
372 if (nsvc->bind != bind)
373 continue;
374
Alexander Couzensc4229a42020-10-11 20:58:04 +0200375 if (!osmo_sockaddr_cmp(&remote, gprs_ns2_ip_vc_remote(nsvc))) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200376 found = true;
377 break;
378 }
379 }
380
381 if (!found) {
382 nsvc = gprs_ns2_ip_connect_inactive(bind, &remote, nse, 0);
383 if (!nsvc) {
384 /* TODO: add to a list to send back a NS-STATUS */
385 continue;
386 }
387 }
388
389 /* update data / signalling weight */
390 nsvc->data_weight = ip6->data_weight;
391 nsvc->sig_weight = ip6->sig_weight;
392 nsvc->sns_only = false;
393 }
394 }
395
396
397 return 0;
398}
399
400/* Add a given remote IPv4 element to gprs_sns_state */
401static int add_remote_ip4_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip4_elem *ip4)
402{
403 unsigned int i;
404
405 if (gss->num_ip4_remote >= gss->num_max_ip4_remote)
406 return -NS_CAUSE_INVAL_NR_NS_VC;
407
408 /* check for duplicates */
409 for (i = 0; i < gss->num_ip4_remote; i++) {
410 if (memcmp(&gss->ip4_remote[i], ip4, sizeof(*ip4)))
411 continue;
412 /* TODO: log message duplicate */
413 /* TODO: check if this is the correct cause code */
414 return -NS_CAUSE_PROTO_ERR_UNSPEC;
415 }
416
417 gss->ip4_remote = talloc_realloc(gss, gss->ip4_remote, struct gprs_ns_ie_ip4_elem,
418 gss->num_ip4_remote+1);
419 gss->ip4_remote[gss->num_ip4_remote] = *ip4;
420 gss->num_ip4_remote += 1;
421 return 0;
422}
423
424/* Remove a given remote IPv4 element from gprs_sns_state */
425static int remove_remote_ip4_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip4_elem *ip4)
426{
427 unsigned int i;
428
429 for (i = 0; i < gss->num_ip4_remote; i++) {
430 if (memcmp(&gss->ip4_remote[i], ip4, sizeof(*ip4)))
431 continue;
432 /* all array elements < i remain as they are; all > i are shifted left by one */
433 memmove(&gss->ip4_remote[i], &gss->ip4_remote[i+1], gss->num_ip4_remote-i-1);
434 gss->num_ip4_remote -= 1;
435 return 0;
436 }
437 return -1;
438}
439
440/* update the weights for specified remote IPv4 */
441static int update_remote_ip4_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip4_elem *ip4)
442{
443 unsigned int i;
444
445 for (i = 0; i < gss->num_ip4_remote; i++) {
446 if (gss->ip4_remote[i].ip_addr != ip4->ip_addr ||
447 gss->ip4_remote[i].udp_port != ip4->udp_port)
448 continue;
449
450 gss->ip4_remote[i].sig_weight = ip4->sig_weight;
451 gss->ip4_remote[i].data_weight = ip4->data_weight;
452 return 0;
453 }
454 return -1;
455}
456
457/* Add a given remote IPv6 element to gprs_sns_state */
458static int add_remote_ip6_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip6_elem *ip6)
459{
460 if (gss->num_ip6_remote >= gss->num_max_ip6_remote)
461 return -NS_CAUSE_INVAL_NR_NS_VC;
462
463 gss->ip6_remote = talloc_realloc(gss, gss->ip6_remote, struct gprs_ns_ie_ip6_elem,
464 gss->num_ip6_remote+1);
465 gss->ip6_remote[gss->num_ip6_remote] = *ip6;
466 gss->num_ip6_remote += 1;
467 return 0;
468}
469
470/* Remove a given remote IPv6 element from gprs_sns_state */
471static int remove_remote_ip6_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip6_elem *ip6)
472{
473 unsigned int i;
474
475 for (i = 0; i < gss->num_ip6_remote; i++) {
476 if (memcmp(&gss->ip6_remote[i], ip6, sizeof(*ip6)))
477 continue;
478 /* all array elements < i remain as they are; all > i are shifted left by one */
479 memmove(&gss->ip6_remote[i], &gss->ip6_remote[i+1], gss->num_ip6_remote-i-1);
480 gss->num_ip6_remote -= 1;
481 return 0;
482 }
483 return -1;
484}
485
486/* update the weights for specified remote IPv6 */
487static int update_remote_ip6_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip6_elem *ip6)
488{
489 unsigned int i;
490
491 for (i = 0; i < gss->num_ip6_remote; i++) {
492 if (memcmp(&gss->ip6_remote[i].ip_addr, &ip6->ip_addr, sizeof(ip6->ip_addr)) ||
493 gss->ip6_remote[i].udp_port != ip6->udp_port)
494 continue;
495 gss->ip6_remote[i].sig_weight = ip6->sig_weight;
496 gss->ip6_remote[i].data_weight = ip6->data_weight;
497 return 0;
498 }
499 return -1;
500}
501
502static 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)
503{
504 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
505 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
506 struct gprs_ns2_vc *nsvc;
507 struct osmo_sockaddr sa = {};
Alexander Couzens9a4cf272020-10-11 20:48:04 +0200508 const struct osmo_sockaddr *remote;
Alexander Couzens6a161492020-07-12 13:45:50 +0200509 uint8_t new_signal;
510 uint8_t new_data;
511
512 /* TODO: Upon receiving an SNS-CHANGEWEIGHT PDU, if the resulting sum of the
513 * signalling weights of all the peer IP endpoints configured for this NSE is
514 * equal to zero or if the resulting sum of the data weights of all the peer IP
515 * endpoints configured for this NSE is equal to zero, the BSS/SGSN shall send an
516 * SNS-ACK PDU with a cause code of "Invalid weights". */
517
518 if (ip4) {
519 if (update_remote_ip4_elem(gss, ip4))
520 return -NS_CAUSE_UNKN_IP_EP;
521
522 /* copy over. Both data structures use network byte order */
523 sa.u.sin.sin_addr.s_addr = ip4->ip_addr;
524 sa.u.sin.sin_port = ip4->udp_port;
525 sa.u.sin.sin_family = AF_INET;
526 new_signal = ip4->sig_weight;
527 new_data = ip4->data_weight;
528 } else if (ip6) {
529 if (update_remote_ip6_elem(gss, ip6))
530 return -NS_CAUSE_UNKN_IP_EP;
531
532 /* copy over. Both data structures use network byte order */
533 sa.u.sin6.sin6_addr = ip6->ip_addr;
534 sa.u.sin6.sin6_port = ip6->udp_port;
535 sa.u.sin6.sin6_family = AF_INET6;
536 new_signal = ip6->sig_weight;
537 new_data = ip6->data_weight;
538 } else {
539 OSMO_ASSERT(false);
540 }
541
542 llist_for_each_entry(nsvc, &nse->nsvc, list) {
Alexander Couzensc4229a42020-10-11 20:58:04 +0200543 remote = gprs_ns2_ip_vc_remote(nsvc);
Alexander Couzens6a161492020-07-12 13:45:50 +0200544 /* all nsvc in NSE should be IP/UDP nsvc */
545 OSMO_ASSERT(remote);
546
547 if (osmo_sockaddr_cmp(&sa, remote))
548 continue;
549
550 LOGPFSML(fi, LOGL_INFO, "CHANGE-WEIGHT NS-VC %s data_weight %u->%u, sig_weight %u->%u\n",
551 gprs_ns2_ll_str(nsvc), nsvc->data_weight, new_data,
552 nsvc->sig_weight, new_signal);
553
554 nsvc->data_weight = new_data;
555 nsvc->sig_weight = new_signal;
556 }
557
558 return 0;
559}
560
561static int do_sns_delete(struct osmo_fsm_inst *fi,
562 const struct gprs_ns_ie_ip4_elem *ip4,
563 const struct gprs_ns_ie_ip6_elem *ip6)
564{
565 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
566 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
567 struct gprs_ns2_vc *nsvc, *tmp;
Alexander Couzens9a4cf272020-10-11 20:48:04 +0200568 const struct osmo_sockaddr *remote;
Alexander Couzens6a161492020-07-12 13:45:50 +0200569 struct osmo_sockaddr sa = {};
570
571 if (ip4) {
572 if (remove_remote_ip4_elem(gss, ip4) < 0)
573 return -NS_CAUSE_UNKN_IP_EP;
574 /* copy over. Both data structures use network byte order */
575 sa.u.sin.sin_addr.s_addr = ip4->ip_addr;
576 sa.u.sin.sin_port = ip4->udp_port;
577 sa.u.sin.sin_family = AF_INET;
578 } else if (ip6) {
579 if (remove_remote_ip6_elem(gss, ip6))
580 return -NS_CAUSE_UNKN_IP_EP;
581
582 /* copy over. Both data structures use network byte order */
583 sa.u.sin6.sin6_addr = ip6->ip_addr;
584 sa.u.sin6.sin6_port = ip6->udp_port;
585 sa.u.sin6.sin6_family = AF_INET6;
586 } else {
587 OSMO_ASSERT(false);
588 }
589
590 llist_for_each_entry_safe(nsvc, tmp, &nse->nsvc, list) {
Alexander Couzensc4229a42020-10-11 20:58:04 +0200591 remote = gprs_ns2_ip_vc_remote(nsvc);
Alexander Couzens6a161492020-07-12 13:45:50 +0200592 /* all nsvc in NSE should be IP/UDP nsvc */
593 OSMO_ASSERT(remote);
594 if (osmo_sockaddr_cmp(&sa, remote))
595 continue;
596
597 LOGPFSML(fi, LOGL_INFO, "DELETE NS-VC %s\n", gprs_ns2_ll_str(nsvc));
598 gprs_ns2_free_nsvc(nsvc);
599 }
600
601 return 0;
602}
603
604static int do_sns_add(struct osmo_fsm_inst *fi,
605 const struct gprs_ns_ie_ip4_elem *ip4,
606 const struct gprs_ns_ie_ip6_elem *ip6)
607{
608 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
609 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
610 struct gprs_ns2_vc *nsvc;
611 int rc = 0;
612
613 /* Upon receiving an SNS-ADD PDU, if the consequent number of IPv4 endpoints
614 * exceeds the number of IPv4 endpoints supported by the NSE, the NSE shall send
615 * an SNS-ACK PDU with a cause code set to "Invalid number of IP4 Endpoints". */
616 switch (gss->ip) {
617 case IPv4:
618 rc = add_remote_ip4_elem(gss, ip4);
619 break;
620 case IPv6:
621 rc = add_remote_ip6_elem(gss, ip6);
622 break;
623 default:
624 /* the gss->ip is initialized with the bss */
625 OSMO_ASSERT(false);
626 }
627
628 if (rc)
629 return rc;
630
631 /* Upon receiving an SNS-ADD PDU containing an already configured IP endpoint the
632 * NSE shall send an SNS-ACK PDU with the cause code "Protocol error -
633 * unspecified" */
634 switch (gss->ip) {
635 case IPv4:
636 nsvc = nsvc_by_ip4_elem(nse, ip4);
637 if (nsvc) {
638 /* the nsvc should be already in sync with the ip4 / ip6 elements */
639 return -NS_CAUSE_PROTO_ERR_UNSPEC;
640 }
641
642 /* TODO: failure case */
643 ns2_nsvc_create_ip4(fi, nse, ip4);
644 break;
645 case IPv6:
646 nsvc = nsvc_by_ip6_elem(nse, ip6);
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_ip6(fi, nse, ip6);
654 break;
655 }
656
657 gprs_ns2_start_alive_all_nsvcs(nse);
658
659 return 0;
660}
661
662
663static void ns2_sns_st_unconfigured(struct osmo_fsm_inst *fi, uint32_t event, void *data)
664{
Alexander Couzense769f522020-12-07 07:37:07 +0100665 /* empty state - SNS Select will start by ns2_sns_st_all_action() */
Alexander Couzens6a161492020-07-12 13:45:50 +0200666}
667
668static void ns2_sns_st_size(struct osmo_fsm_inst *fi, uint32_t event, void *data)
669{
670 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
671 struct gprs_ns2_inst *nsi = nse->nsi;
672 struct tlv_parsed *tp = NULL;
673
674 switch (event) {
675 case GPRS_SNS_EV_SIZE_ACK:
676 tp = data;
677 if (TLVP_VAL_MINLEN(tp, NS_IE_CAUSE, 1)) {
678 LOGPFSML(fi, LOGL_ERROR, "SNS-SIZE-ACK with cause %s\n",
679 gprs_ns2_cause_str(*TLVP_VAL(tp, NS_IE_CAUSE)));
680 /* TODO: What to do? */
681 } else {
682 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIG_BSS,
683 nsi->timeout[NS_TOUT_TSNS_PROV], 2);
684 }
685 break;
686 default:
687 OSMO_ASSERT(0);
688 }
689}
690
Alexander Couzense769f522020-12-07 07:37:07 +0100691/* setup all dynamic SNS settings, create a new nsvc and send the SIZE */
Alexander Couzens6a161492020-07-12 13:45:50 +0200692static void ns2_sns_st_size_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
693{
694 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
Alexander Couzense769f522020-12-07 07:37:07 +0100695 struct gprs_ns_ie_ip4_elem *ip4_elems;
696 struct gprs_ns_ie_ip6_elem *ip6_elems;
697 struct gprs_ns2_vc_bind *bind;
698 struct gprs_ns2_inst *nsi = gss->nse->nsi;
699 struct osmo_sockaddr *remote;
700 const struct osmo_sockaddr *sa;
701 struct osmo_sockaddr local;
702 int count;
Alexander Couzens6a161492020-07-12 13:45:50 +0200703
Alexander Couzense769f522020-12-07 07:37:07 +0100704 /* on a generic failure, the timer callback will recover */
Alexander Couzens6a161492020-07-12 13:45:50 +0200705 if (old_state != GPRS_SNS_ST_UNCONFIGURED)
Daniel Willmann15c09a82020-11-03 23:05:43 +0100706 ns2_prim_status_ind(gss->nse, NULL, 0, NS_AFF_CAUSE_SNS_FAILURE);
Alexander Couzens6a161492020-07-12 13:45:50 +0200707
Alexander Couzense769f522020-12-07 07:37:07 +0100708 /* no initial available */
709 if (!gss->initial)
710 return;
711
712 remote = &gss->initial->saddr;
713
714 /* count how many bindings are available (only UDP binds) */
715 count = ns2_ip_count_bind(nsi, remote);
716 if (count == 0) {
717 /* TODO: logging */
718 return;
719 }
720
Alexander Couzens81ae0aa2020-12-07 05:49:43 +0100721 bind = ns2_ip_get_bind_by_index(nsi, remote, gss->bind_offset);
Alexander Couzense769f522020-12-07 07:37:07 +0100722 if (!bind) {
Alexander Couzens81ae0aa2020-12-07 05:49:43 +0100723 if (gss->bind_offset) {
724 gss->bind_offset = 0;
725 bind = ns2_ip_get_bind_by_index(nsi, remote, gss->bind_offset);
726 }
727
728 if (!bind)
729 return;
Alexander Couzense769f522020-12-07 07:37:07 +0100730 }
731
732 /* setup the NSVC */
733 if (!gss->sns_nsvc) {
734 gss->sns_nsvc = gprs_ns2_ip_bind_connect(bind, gss->nse, remote);
735 if (!gss->sns_nsvc)
736 return;
737 gss->sns_nsvc->sns_only = true;
738 }
739
740 switch (gss->ip) {
741 case IPv4:
742 ip4_elems = talloc_zero_size(fi, sizeof(struct gprs_ns_ie_ip4_elem) * count);
743 if (!ip4_elems)
744 return;
745
746 gss->ip4_local = ip4_elems;
747
748 llist_for_each_entry(bind, &nsi->binding, list) {
749 if (!gprs_ns2_is_ip_bind(bind))
750 continue;
751
752 sa = gprs_ns2_ip_bind_sockaddr(bind);
753 if (!sa)
754 continue;
755
756 if (sa->u.sas.ss_family != AF_INET)
757 continue;
758
759 /* check if this is an specific bind */
760 if (sa->u.sin.sin_addr.s_addr == 0) {
761 if (osmo_sockaddr_local_ip(&local, remote))
762 continue;
763
764 ip4_elems->ip_addr = local.u.sin.sin_addr.s_addr;
765 } else {
766 ip4_elems->ip_addr = sa->u.sin.sin_addr.s_addr;
767 }
768
769 ip4_elems->udp_port = sa->u.sin.sin_port;
770 ip4_elems->sig_weight = 2;
771 ip4_elems->data_weight = 1;
772 ip4_elems++;
773 }
774
775 gss->num_ip4_local = count;
776 gss->num_max_ip4_remote = 4;
777 gss->num_max_nsvcs = OSMO_MAX(gss->num_max_ip4_remote * gss->num_ip4_local, 8);
778 break;
779 case IPv6:
780 /* IPv6 */
781 ip6_elems = talloc_zero_size(fi, sizeof(struct gprs_ns_ie_ip6_elem) * count);
782 if (!ip6_elems)
783 return;
784
785 gss->ip6_local = ip6_elems;
786
787 llist_for_each_entry(bind, &nsi->binding, list) {
788 if (!gprs_ns2_is_ip_bind(bind))
789 continue;
790
791 sa = gprs_ns2_ip_bind_sockaddr(bind);
792 if (!sa)
793 continue;
794
795 if (sa->u.sas.ss_family != AF_INET6)
796 continue;
797
798 /* check if this is an specific bind */
799 if (IN6_IS_ADDR_UNSPECIFIED(&sa->u.sin6.sin6_addr)) {
800 if (osmo_sockaddr_local_ip(&local, remote))
801 continue;
802
803 ip6_elems->ip_addr = local.u.sin6.sin6_addr;
804 } else {
805 ip6_elems->ip_addr = sa->u.sin6.sin6_addr;
806 }
807
808 ip6_elems->udp_port = sa->u.sin.sin_port;
809 ip6_elems->sig_weight = 2;
810 ip6_elems->data_weight = 1;
811
812 ip6_elems++;
813 }
814 gss->num_ip6_local = count;
815 gss->num_max_ip6_remote = 4;
816 gss->num_max_nsvcs = OSMO_MAX(gss->num_max_ip6_remote * gss->num_ip6_local, 8);
817 break;
818 }
819
Alexander Couzens6a161492020-07-12 13:45:50 +0200820 if (gss->num_max_ip4_remote > 0)
821 ns2_tx_sns_size(gss->sns_nsvc, true, gss->num_max_nsvcs, gss->num_max_ip4_remote, -1);
822 else
823 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 +0200824}
825
826static void ns2_sns_st_config_bss(struct osmo_fsm_inst *fi, uint32_t event, void *data)
827{
828 struct tlv_parsed *tp = NULL;
829
830 switch (event) {
831 case GPRS_SNS_EV_CONFIG_ACK:
832 tp = (struct tlv_parsed *) data;
833 if (TLVP_VAL_MINLEN(tp, NS_IE_CAUSE, 1)) {
834 LOGPFSML(fi, LOGL_ERROR, "SNS-CONFIG-ACK with cause %s\n",
835 gprs_ns2_cause_str(*TLVP_VAL(tp, NS_IE_CAUSE)));
836 /* TODO: What to do? */
837 } else {
838 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIG_SGSN, 0, 0);
839 }
840 break;
841 default:
842 OSMO_ASSERT(0);
843 }
844}
845
846static void ns2_sns_st_config_bss_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
847{
848 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
849 /* Transmit SNS-CONFIG */
Alexander Couzens6a161492020-07-12 13:45:50 +0200850 switch (gss->ip) {
851 case IPv4:
852 ns2_tx_sns_config(gss->sns_nsvc, true,
Alexander Couzense78207f2020-12-07 06:19:29 +0100853 gss->ip4_local, gss->num_ip4_local,
854 NULL, 0);
Alexander Couzens6a161492020-07-12 13:45:50 +0200855 break;
856 case IPv6:
857 ns2_tx_sns_config(gss->sns_nsvc, true,
Alexander Couzense78207f2020-12-07 06:19:29 +0100858 NULL, 0,
859 gss->ip6_local, gss->num_ip6_local);
Alexander Couzens6a161492020-07-12 13:45:50 +0200860 break;
861 }
862}
863
864
865static void ns_sns_st_config_sgsn_ip4(struct osmo_fsm_inst *fi, uint32_t event, void *data)
866{
867 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
868 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
869 const struct gprs_ns_ie_ip4_elem *v4_list;
870 unsigned int num_v4;
871 struct tlv_parsed *tp = NULL;
872
873 uint8_t cause;
874
875 tp = (struct tlv_parsed *) data;
876
877 if (!TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
878 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
879 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
880 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
881 return;
882 }
883 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
884 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
885 /* realloc to the new size */
886 gss->ip4_remote = talloc_realloc(gss, gss->ip4_remote,
887 struct gprs_ns_ie_ip4_elem,
888 gss->num_ip4_remote+num_v4);
889 /* append the new entries to the end of the list */
890 memcpy(&gss->ip4_remote[gss->num_ip4_remote], v4_list, num_v4*sizeof(*v4_list));
891 gss->num_ip4_remote += num_v4;
892
893 LOGPFSML(fi, LOGL_INFO, "Rx SNS-CONFIG: Remote IPv4 list now %u entries\n",
894 gss->num_ip4_remote);
895 if (event == GPRS_SNS_EV_CONFIG_END) {
896 /* check if sum of data / sig weights == 0 */
897 if (ip4_weight_sum_data(gss->ip4_remote, gss->num_ip4_remote) == 0 ||
898 ip4_weight_sum_sig(gss->ip4_remote, gss->num_ip4_remote) == 0) {
899 cause = NS_CAUSE_INVAL_WEIGH;
900 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
901 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
902 return;
903 }
904 create_missing_nsvcs(fi);
905 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
906 /* start the test procedure on ALL NSVCs! */
907 gprs_ns2_start_alive_all_nsvcs(nse);
908 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIGURED, 0, 0);
909 } else {
910 /* just send CONFIG-ACK */
911 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
912 }
913}
914
915static void ns_sns_st_config_sgsn_ip6(struct osmo_fsm_inst *fi, uint32_t event, void *data)
916{
917 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
918 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
919 const struct gprs_ns_ie_ip6_elem *v6_list;
920 unsigned int num_v6;
921 struct tlv_parsed *tp = NULL;
922
923 uint8_t cause;
924
925 tp = (struct tlv_parsed *) data;
926
927 if (!TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
928 cause = NS_CAUSE_INVAL_NR_IPv6_EP;
929 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
930 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
931 return;
932 }
933 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
934 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
935 /* realloc to the new size */
936 gss->ip6_remote = talloc_realloc(gss, gss->ip6_remote,
937 struct gprs_ns_ie_ip6_elem,
938 gss->num_ip6_remote+num_v6);
939 /* append the new entries to the end of the list */
940 memcpy(&gss->ip6_remote[gss->num_ip6_remote], v6_list, num_v6*sizeof(*v6_list));
941 gss->num_ip6_remote += num_v6;
942
943 LOGPFSML(fi, LOGL_INFO, "Rx SNS-CONFIG: Remote IPv6 list now %u entries\n",
944 gss->num_ip6_remote);
945 if (event == GPRS_SNS_EV_CONFIG_END) {
946 /* check if sum of data / sig weights == 0 */
947 if (ip6_weight_sum_data(gss->ip6_remote, gss->num_ip6_remote) == 0 ||
948 ip6_weight_sum_sig(gss->ip6_remote, gss->num_ip6_remote) == 0) {
949 cause = NS_CAUSE_INVAL_WEIGH;
950 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
951 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
952 return;
953 }
954 create_missing_nsvcs(fi);
955 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
956 /* start the test procedure on ALL NSVCs! */
957 gprs_ns2_start_alive_all_nsvcs(nse);
958 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIGURED, 0, 0);
959 } else {
960 /* just send CONFIG-ACK */
961 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
962 }
963}
964
965static void ns2_sns_st_config_sgsn(struct osmo_fsm_inst *fi, uint32_t event, void *data)
966{
967 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
968
969 switch (event) {
970 case GPRS_SNS_EV_CONFIG_END:
971 case GPRS_SNS_EV_CONFIG:
972
973#if 0 /* part of incoming SNS-SIZE (doesn't happen on BSS side */
974 if (TLVP_PRESENT(tp, NS_IE_RESET_FLAG)) {
975 /* reset all existing config */
976 if (gss->ip4_remote)
977 talloc_free(gss->ip4_remote);
978 gss->num_ip4_remote = 0;
979 }
980#endif
981 /* TODO: reject IPv6 elements on IPv4 mode and vice versa */
982 switch (gss->ip) {
983 case IPv4:
984 ns_sns_st_config_sgsn_ip4(fi, event, data);
985 break;
986 case IPv6:
987 ns_sns_st_config_sgsn_ip6(fi, event, data);
988 break;
989 default:
990 OSMO_ASSERT(0);
991 }
992 break;
993 default:
994 OSMO_ASSERT(0);
995 }
996}
997
998/* called when receiving GPRS_SNS_EV_ADD in state configure */
999static void ns2_sns_st_configured_add(struct osmo_fsm_inst *fi,
1000 struct ns2_sns_state *gss,
1001 struct tlv_parsed *tp)
1002{
1003 const struct gprs_ns_ie_ip4_elem *v4_list = NULL;
1004 const struct gprs_ns_ie_ip6_elem *v6_list = NULL;
1005 int num_v4 = 0, num_v6 = 0;
1006 uint8_t trans_id, cause = 0xff;
Harald Welte7da6ace2020-09-18 09:48:05 +02001007 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +02001008 int rc = 0;
1009
1010 /* TODO: refactor EV_ADD/CHANGE/REMOVE by
1011 * check uniqueness within the lists (no doublicate entries)
1012 * check not-known-by-us and sent back a list of unknown/known values
1013 * (abnormal behaviour according to 48.016)
1014 */
1015
1016 trans_id = *TLVP_VAL(tp, NS_IE_TRANS_ID);
1017 if (gss->ip == IPv4) {
1018 if (!TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
1019 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
1020 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1021 return;
1022 }
1023
1024 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
1025 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001026 for (i = 0; i < num_v4; i++) {
1027 unsigned int j;
Alexander Couzens6a161492020-07-12 13:45:50 +02001028 rc = do_sns_add(fi, &v4_list[i], NULL);
1029 if (rc < 0) {
1030 /* rollback/undo to restore previous state */
Harald Welte7da6ace2020-09-18 09:48:05 +02001031 for (j = 0; j < i; j++)
Alexander Couzens6a161492020-07-12 13:45:50 +02001032 do_sns_delete(fi, &v4_list[j], NULL);
1033 cause = -rc;
1034 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1035 break;
1036 }
1037 }
1038 } else { /* IPv6 */
1039 if (!TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
1040 cause = NS_CAUSE_INVAL_NR_IPv6_EP;
1041 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1042 return;
1043 }
1044
1045 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
1046 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001047 for (i = 0; i < num_v6; i++) {
1048 unsigned int j;
Alexander Couzens6a161492020-07-12 13:45:50 +02001049 rc = do_sns_add(fi, NULL, &v6_list[i]);
1050 if (rc < 0) {
1051 /* rollback/undo to restore previous state */
Harald Welte7da6ace2020-09-18 09:48:05 +02001052 for (j = 0; j < i; j++)
Alexander Couzens6a161492020-07-12 13:45:50 +02001053 do_sns_delete(fi, NULL, &v6_list[j]);
1054 cause = -rc;
1055 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1056 break;
1057 }
1058 }
1059 }
1060
1061 /* TODO: correct behaviour is to answer to the *same* NSVC from which the SNS_ADD was received */
1062 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, NULL, v4_list, num_v4, v6_list, num_v6);
1063}
1064
1065static void ns2_sns_st_configured_delete(struct osmo_fsm_inst *fi,
1066 struct ns2_sns_state *gss,
1067 struct tlv_parsed *tp)
1068{
1069 const struct gprs_ns_ie_ip4_elem *v4_list = NULL;
1070 const struct gprs_ns_ie_ip6_elem *v6_list = NULL;
1071 int num_v4 = 0, num_v6 = 0;
1072 uint8_t trans_id, cause = 0xff;
Harald Welte7da6ace2020-09-18 09:48:05 +02001073 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +02001074 int rc = 0;
1075
1076 /* TODO: split up delete into v4 + v6
1077 * TODO: check if IPv4_LIST or IP_ADDR(v4) is present on IPv6 and vice versa
1078 * TODO: check if IPv4_LIST/IPv6_LIST and IP_ADDR is present at the same time
1079 */
1080 trans_id = *TLVP_VAL(tp, NS_IE_TRANS_ID);
1081 if (gss->ip == IPv4) {
1082 if (TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
1083 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
1084 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001085 for ( i = 0; i < num_v4; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001086 rc = do_sns_delete(fi, &v4_list[i], NULL);
1087 if (rc < 0) {
1088 cause = -rc;
1089 /* continue to delete others */
1090 }
1091 }
1092 if (cause != 0xff) {
1093 /* TODO: create list of not-deleted and return it */
1094 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1095 return;
1096 }
1097
1098 } else if (TLVP_PRESENT(tp, NS_IE_IP_ADDR) && TLVP_LEN(tp, NS_IE_IP_ADDR) == 5) {
1099 /* delete all NS-VCs for given IPv4 address */
1100 const uint8_t *ie = TLVP_VAL(tp, NS_IE_IP_ADDR);
1101 struct gprs_ns_ie_ip4_elem *ip4_remote;
1102 uint32_t ip_addr = *(uint32_t *)(ie+1);
1103 if (ie[0] != 0x01) { /* Address Type != IPv4 */
1104 cause = NS_CAUSE_UNKN_IP_ADDR;
1105 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1106 return;
1107 }
1108 /* make a copy as do_sns_delete() will change the array underneath us */
1109 ip4_remote = talloc_memdup(fi, gss->ip4_remote,
1110 gss->num_ip4_remote * sizeof(*v4_list));
Harald Welte7da6ace2020-09-18 09:48:05 +02001111 for (i = 0; i < gss->num_ip4_remote; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001112 if (ip4_remote[i].ip_addr == ip_addr) {
1113 rc = do_sns_delete(fi, &ip4_remote[i], NULL);
1114 if (rc < 0) {
1115 cause = -rc;
1116 /* continue to delete others */
1117 }
1118 }
1119 }
1120 talloc_free(ip4_remote);
1121 if (cause != 0xff) {
1122 /* TODO: create list of not-deleted and return it */
1123 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1124 return;
1125 }
1126 } else {
1127 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
1128 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1129 return;
1130 }
1131 } else { /* IPv6 */
1132 if (TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
1133 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
1134 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001135 for (i = 0; i < num_v6; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001136 rc = do_sns_delete(fi, NULL, &v6_list[i]);
1137 if (rc < 0) {
1138 cause = -rc;
1139 /* continue to delete others */
1140 }
1141 }
1142 if (cause != 0xff) {
1143 /* TODO: create list of not-deleted and return it */
1144 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1145 return;
1146 }
1147 } else if (TLVP_PRES_LEN(tp, NS_IE_IP_ADDR, 17)) {
1148 /* delete all NS-VCs for given IPv4 address */
1149 const uint8_t *ie = TLVP_VAL(tp, NS_IE_IP_ADDR);
1150 struct gprs_ns_ie_ip6_elem *ip6_remote;
1151 struct in6_addr ip6_addr;
Harald Welte7da6ace2020-09-18 09:48:05 +02001152 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +02001153 if (ie[0] != 0x02) { /* Address Type != IPv6 */
1154 cause = NS_CAUSE_UNKN_IP_ADDR;
1155 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1156 return;
1157 }
1158 memcpy(&ip6_addr, (ie+1), sizeof(struct in6_addr));
1159 /* make a copy as do_sns_delete() will change the array underneath us */
1160 ip6_remote = talloc_memdup(fi, gss->ip6_remote,
1161 gss->num_ip6_remote * sizeof(*v4_list));
Harald Welte7da6ace2020-09-18 09:48:05 +02001162 for (i = 0; i < gss->num_ip6_remote; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001163 if (!memcmp(&ip6_remote[i].ip_addr, &ip6_addr, sizeof(struct in6_addr))) {
1164 rc = do_sns_delete(fi, NULL, &ip6_remote[i]);
1165 if (rc < 0) {
1166 cause = -rc;
1167 /* continue to delete others */
1168 }
1169 }
1170 }
1171
1172 talloc_free(ip6_remote);
1173 if (cause != 0xff) {
1174 /* TODO: create list of not-deleted and return it */
1175 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1176 return;
1177 }
1178 } else {
1179 cause = NS_CAUSE_INVAL_NR_IPv6_EP;
1180 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1181 return;
1182 }
1183 }
1184 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, NULL, v4_list, num_v4, v6_list, num_v6);
1185}
1186
1187static void ns2_sns_st_configured_change(struct osmo_fsm_inst *fi,
1188 struct ns2_sns_state *gss,
1189 struct tlv_parsed *tp)
1190{
1191 const struct gprs_ns_ie_ip4_elem *v4_list = NULL;
1192 const struct gprs_ns_ie_ip6_elem *v6_list = NULL;
1193 int num_v4 = 0, num_v6 = 0;
1194 uint8_t trans_id, cause = 0xff;
1195 int rc = 0;
Harald Welte7da6ace2020-09-18 09:48:05 +02001196 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +02001197
1198 trans_id = *TLVP_VAL(tp, NS_IE_TRANS_ID);
1199 if (TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
1200 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
1201 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001202 for (i = 0; i < num_v4; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001203 rc = do_sns_change_weight(fi, &v4_list[i], NULL);
1204 if (rc < 0) {
1205 cause = -rc;
1206 /* continue to others */
1207 }
1208 }
1209 if (cause != 0xff) {
1210 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1211 return;
1212 }
1213 } else if (TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
1214 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
1215 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001216 for (i = 0; i < num_v6; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001217 rc = do_sns_change_weight(fi, NULL, &v6_list[i]);
1218 if (rc < 0) {
1219 cause = -rc;
1220 /* continue to others */
1221 }
1222 }
1223 if (cause != 0xff) {
1224 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1225 return;
1226 }
1227 } else {
1228 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
1229 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1230 return;
1231 }
1232 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, NULL, v4_list, num_v4, v6_list, num_v6);
1233}
1234
1235static void ns2_sns_st_configured(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1236{
1237 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
1238 struct tlv_parsed *tp = data;
1239
1240 switch (event) {
1241 case GPRS_SNS_EV_ADD:
1242 ns2_sns_st_configured_add(fi, gss, tp);
1243 break;
1244 case GPRS_SNS_EV_DELETE:
1245 ns2_sns_st_configured_delete(fi, gss, tp);
1246 break;
1247 case GPRS_SNS_EV_CHANGE_WEIGHT:
1248 ns2_sns_st_configured_change(fi, gss, tp);
1249 break;
1250 }
1251}
1252
1253static void ns2_sns_st_configured_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
1254{
1255 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
Daniel Willmann15c09a82020-11-03 23:05:43 +01001256 ns2_prim_status_ind(nse, NULL, 0, NS_AFF_CAUSE_SNS_CONFIGURED);
Alexander Couzens6a161492020-07-12 13:45:50 +02001257}
1258
1259static const struct osmo_fsm_state ns2_sns_bss_states[] = {
1260 [GPRS_SNS_ST_UNCONFIGURED] = {
Alexander Couzense769f522020-12-07 07:37:07 +01001261 .in_event_mask = 0, /* handled by all_state_action */
Alexander Couzens6a161492020-07-12 13:45:50 +02001262 .out_state_mask = S(GPRS_SNS_ST_SIZE),
1263 .name = "UNCONFIGURED",
1264 .action = ns2_sns_st_unconfigured,
1265 },
1266 [GPRS_SNS_ST_SIZE] = {
1267 .in_event_mask = S(GPRS_SNS_EV_SIZE_ACK),
1268 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
1269 S(GPRS_SNS_ST_SIZE) |
1270 S(GPRS_SNS_ST_CONFIG_BSS),
1271 .name = "SIZE",
1272 .action = ns2_sns_st_size,
1273 .onenter = ns2_sns_st_size_onenter,
1274 },
1275 [GPRS_SNS_ST_CONFIG_BSS] = {
1276 .in_event_mask = S(GPRS_SNS_EV_CONFIG_ACK),
1277 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
1278 S(GPRS_SNS_ST_CONFIG_BSS) |
1279 S(GPRS_SNS_ST_CONFIG_SGSN) |
1280 S(GPRS_SNS_ST_SIZE),
1281 .name = "CONFIG_BSS",
1282 .action = ns2_sns_st_config_bss,
1283 .onenter = ns2_sns_st_config_bss_onenter,
1284 },
1285 [GPRS_SNS_ST_CONFIG_SGSN] = {
1286 .in_event_mask = S(GPRS_SNS_EV_CONFIG) |
1287 S(GPRS_SNS_EV_CONFIG_END),
1288 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
1289 S(GPRS_SNS_ST_CONFIG_SGSN) |
1290 S(GPRS_SNS_ST_CONFIGURED) |
1291 S(GPRS_SNS_ST_SIZE),
1292 .name = "CONFIG_SGSN",
1293 .action = ns2_sns_st_config_sgsn,
1294 },
1295 [GPRS_SNS_ST_CONFIGURED] = {
1296 .in_event_mask = S(GPRS_SNS_EV_ADD) |
1297 S(GPRS_SNS_EV_DELETE) |
1298 S(GPRS_SNS_EV_CHANGE_WEIGHT),
Alexander Couzense03d8632020-12-06 03:31:44 +01001299 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
1300 S(GPRS_SNS_ST_SIZE),
Alexander Couzens6a161492020-07-12 13:45:50 +02001301 .name = "CONFIGURED",
1302 .action = ns2_sns_st_configured,
1303 .onenter = ns2_sns_st_configured_onenter,
1304 },
1305};
1306
1307static int ns2_sns_fsm_bss_timer_cb(struct osmo_fsm_inst *fi)
1308{
Alexander Couzens90ee9632020-12-07 06:18:32 +01001309 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
Alexander Couzens6a161492020-07-12 13:45:50 +02001310 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
1311 struct gprs_ns2_inst *nsi = nse->nsi;
1312
Alexander Couzens90ee9632020-12-07 06:18:32 +01001313 gss->N++;
Alexander Couzens6a161492020-07-12 13:45:50 +02001314 switch (fi->T) {
1315 case 1:
Alexander Couzensa367d082020-12-21 14:06:24 +01001316 if (gss->N >= nsi->timeout[NS_TOUT_TSNS_SIZE_RETRIES]) {
1317 LOGPFSML(fi, LOGL_ERROR, "NSE %d: Size retries failed. Selecting next IP-SNS endpoint.\n", nse->nsei);
Alexander Couzens90ee9632020-12-07 06:18:32 +01001318 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_SELECT_ENDPOINT, NULL);
Alexander Couzensa367d082020-12-21 14:06:24 +01001319 } else {
Alexander Couzenscc65a252020-12-21 14:03:58 +01001320 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_SIZE, nsi->timeout[NS_TOUT_TSNS_PROV], 1);
Alexander Couzensa367d082020-12-21 14:06:24 +01001321 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001322 break;
1323 case 2:
Alexander Couzensa367d082020-12-21 14:06:24 +01001324 if (gss->N >= nsi->timeout[NS_TOUT_TSNS_CONFIG_RETRIES]) {
1325 LOGPFSML(fi, LOGL_ERROR, "NSE %d: Config 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_CONFIG_BSS, nsi->timeout[NS_TOUT_TSNS_PROV], 2);
Alexander Couzensa367d082020-12-21 14:06:24 +01001329 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001330 break;
1331 }
1332 return 0;
1333}
1334
1335static void ns2_sns_st_all_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1336{
Alexander Couzense769f522020-12-07 07:37:07 +01001337 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
Alexander Couzens6a161492020-07-12 13:45:50 +02001338 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
1339
1340 /* reset when receiving GPRS_SNS_EV_NO_NSVC */
Alexander Couzense769f522020-12-07 07:37:07 +01001341 switch (event) {
1342 case GPRS_SNS_EV_NO_NSVC:
Alexander Couzens3ad73362020-12-21 13:53:00 +01001343 /* ignore reselection running */
1344 if (gss->reselection_running)
1345 break;
1346
1347 LOGPFSML(fi, LOGL_ERROR, "NSE %d: no remaining NSVC, resetting SNS FSM\n", nse->nsei);
1348 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_SELECT_ENDPOINT, NULL);
Alexander Couzense769f522020-12-07 07:37:07 +01001349 break;
1350 case GPRS_SNS_EV_SELECT_ENDPOINT:
1351 /* tear down previous state
1352 * gprs_ns2_free_nsvcs() will trigger NO_NSVC, prevent this from triggering a reselection */
1353 gss->reselection_running = true;
1354 gprs_ns2_free_nsvcs(nse);
1355
1356 /* Choose the next sns endpoint. */
1357 if (llist_empty(&gss->sns_endpoints)) {
1358 gss->initial = NULL;
1359 ns2_prim_status_ind(gss->nse, NULL, 0, NS_AFF_CAUSE_SNS_NO_ENDPOINTS);
1360 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 3);
1361 return;
1362 } else if (!gss->initial) {
1363 gss->initial = llist_first_entry(&gss->sns_endpoints, struct sns_endpoint, list);
Alexander Couzens81ae0aa2020-12-07 05:49:43 +01001364 gss->bind_offset = 0;
Alexander Couzense769f522020-12-07 07:37:07 +01001365 } else if (gss->initial->list.next == &gss->sns_endpoints) {
1366 /* last entry, continue with first */
1367 gss->initial = llist_first_entry(&gss->sns_endpoints, struct sns_endpoint, list);
Alexander Couzens81ae0aa2020-12-07 05:49:43 +01001368 gss->bind_offset++;
1369 gss->bind_offset %= ns2_ip_count_bind(nse->nsi, &gss->initial->saddr);
Alexander Couzense769f522020-12-07 07:37:07 +01001370 } else {
1371 /* next element is an entry */
1372 gss->initial = llist_entry(gss->initial->list.next, struct sns_endpoint, list);
1373 }
1374
1375 gss->reselection_running = false;
1376 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_SIZE, nse->nsi->timeout[NS_TOUT_TSNS_PROV], 1);
1377 break;
1378 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001379}
1380
1381static struct osmo_fsm gprs_ns2_sns_bss_fsm = {
1382 .name = "GPRS-NS2-SNS-BSS",
1383 .states = ns2_sns_bss_states,
1384 .num_states = ARRAY_SIZE(ns2_sns_bss_states),
Alexander Couzense769f522020-12-07 07:37:07 +01001385 .allstate_event_mask = S(GPRS_SNS_EV_NO_NSVC) |
1386 S(GPRS_SNS_EV_SELECT_ENDPOINT),
Alexander Couzens6a161492020-07-12 13:45:50 +02001387 .allstate_action = ns2_sns_st_all_action,
1388 .cleanup = NULL,
1389 .timer_cb = ns2_sns_fsm_bss_timer_cb,
1390 /* .log_subsys = DNS, "is not constant" */
1391 .event_names = gprs_sns_event_names,
1392 .pre_term = NULL,
1393 .log_subsys = DLNS,
1394};
1395
Harald Welte5bef2cc2020-09-18 22:33:24 +02001396/*! Allocate an IP-SNS FSM for the BSS side.
1397 * \param[in] nse NS Entity in which the FSM runs
1398 * \param[in] id string identifier
1399 * \retruns FSM instance on success; NULL on error */
Alexander Couzens6a161492020-07-12 13:45:50 +02001400struct osmo_fsm_inst *ns2_sns_bss_fsm_alloc(struct gprs_ns2_nse *nse,
1401 const char *id)
1402{
1403 struct osmo_fsm_inst *fi;
1404 struct ns2_sns_state *gss;
1405
1406 fi = osmo_fsm_inst_alloc(&gprs_ns2_sns_bss_fsm, nse, NULL, LOGL_DEBUG, id);
1407 if (!fi)
1408 return fi;
1409
1410 gss = talloc_zero(fi, struct ns2_sns_state);
1411 if (!gss)
1412 goto err;
1413
1414 fi->priv = gss;
1415 gss->nse = nse;
Alexander Couzense769f522020-12-07 07:37:07 +01001416 INIT_LLIST_HEAD(&gss->sns_endpoints);
Alexander Couzens6a161492020-07-12 13:45:50 +02001417
1418 return fi;
1419err:
1420 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
1421 return NULL;
1422}
1423
Harald Welte5bef2cc2020-09-18 22:33:24 +02001424/*! main entry point for receiving SNS messages from the network.
1425 * \param[in] nsvc NS-VC on which the message was received
1426 * \param[in] msg message buffer of the IP-SNS message
1427 * \param[in] tp parsed TLV structure of message
1428 * \retruns 0 on success; negative on error */
Alexander Couzens6a161492020-07-12 13:45:50 +02001429int gprs_ns2_sns_rx(struct gprs_ns2_vc *nsvc, struct msgb *msg, struct tlv_parsed *tp)
1430{
1431 struct gprs_ns2_nse *nse = nsvc->nse;
1432 struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h;
1433 uint16_t nsei = nsvc->nse->nsei;
1434 struct osmo_fsm_inst *fi;
1435
1436 if (!nse->bss_sns_fi) {
1437 LOGP(DLNS, LOGL_NOTICE, "NSEI=%u Rx %s for NS Instance that has no SNS!\n",
1438 nsvc->nse->nsei, get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
1439 return -EINVAL;
1440 }
1441
1442 LOGP(DLNS, LOGL_DEBUG, "NSEI=%u Rx SNS PDU type %s\n", nsei,
1443 get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
1444
1445 /* FIXME: how to resolve SNS FSM Instance by NSEI (SGSN)? */
1446 fi = nse->bss_sns_fi;
1447
1448 switch (nsh->pdu_type) {
1449 case SNS_PDUT_SIZE:
1450 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_SIZE, tp);
1451 break;
1452 case SNS_PDUT_SIZE_ACK:
1453 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_SIZE_ACK, tp);
1454 break;
1455 case SNS_PDUT_CONFIG:
1456 if (nsh->data[0] & 0x01)
1457 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_CONFIG_END, tp);
1458 else
1459 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_CONFIG, tp);
1460 break;
1461 case SNS_PDUT_CONFIG_ACK:
1462 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_CONFIG_ACK, tp);
1463 break;
1464 case SNS_PDUT_ADD:
1465 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_ADD, tp);
1466 break;
1467 case SNS_PDUT_DELETE:
1468 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_DELETE, tp);
1469 break;
1470 case SNS_PDUT_CHANGE_WEIGHT:
1471 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_CHANGE_WEIGHT, tp);
1472 break;
1473 case SNS_PDUT_ACK:
1474 LOGP(DLNS, LOGL_NOTICE, "NSEI=%u Rx unsupported SNS PDU type %s\n", nsei,
1475 get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
1476 break;
1477 default:
1478 LOGP(DLNS, LOGL_ERROR, "NSEI=%u Rx unknown SNS PDU type %s\n", nsei,
1479 get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
1480 return -EINVAL;
1481 }
1482
1483 return 0;
1484}
1485
1486#include <osmocom/vty/vty.h>
1487#include <osmocom/vty/misc.h>
1488
1489static void vty_dump_sns_ip4(struct vty *vty, const struct gprs_ns_ie_ip4_elem *ip4)
1490{
1491 struct in_addr in = { .s_addr = ip4->ip_addr };
1492 vty_out(vty, " %s:%u, Signalling Weight: %u, Data Weight: %u%s",
1493 inet_ntoa(in), ntohs(ip4->udp_port), ip4->sig_weight, ip4->data_weight, VTY_NEWLINE);
1494}
1495
1496static void vty_dump_sns_ip6(struct vty *vty, const struct gprs_ns_ie_ip6_elem *ip6)
1497{
1498 char ip_addr[INET6_ADDRSTRLEN] = {};
1499 if (!inet_ntop(AF_INET6, &ip6->ip_addr, ip_addr, (INET6_ADDRSTRLEN)))
1500 strcpy(ip_addr, "Invalid IPv6");
1501
1502 vty_out(vty, " %s:%u, Signalling Weight: %u, Data Weight: %u%s",
1503 ip_addr, ntohs(ip6->udp_port), ip6->sig_weight, ip6->data_weight, VTY_NEWLINE);
1504}
1505
Harald Welte5bef2cc2020-09-18 22:33:24 +02001506/*! Dump the IP-SNS state to a vty.
1507 * \param[in] vty VTY to which the state shall be printed
1508 * \param[in] nse NS Entity whose IP-SNS state shall be printed
1509 * \param[in] stats Whether or not statistics shall also be printed */
Alexander Couzens6a161492020-07-12 13:45:50 +02001510void gprs_ns2_sns_dump_vty(struct vty *vty, const struct gprs_ns2_nse *nse, bool stats)
1511{
1512 struct ns2_sns_state *gss;
1513 unsigned int i;
1514
1515 if (!nse->bss_sns_fi)
1516 return;
1517
1518 vty_out_fsm_inst(vty, nse->bss_sns_fi);
1519 gss = (struct ns2_sns_state *) nse->bss_sns_fi->priv;
1520
1521 vty_out(vty, "Maximum number of remote NS-VCs: %zu, IPv4 Endpoints: %zu, IPv6 Endpoints: %zu%s",
1522 gss->num_max_nsvcs, gss->num_max_ip4_remote, gss->num_max_ip6_remote, VTY_NEWLINE);
1523
1524 if (gss->num_ip4_local && gss->num_ip4_remote) {
1525 vty_out(vty, "Local IPv4 Endpoints:%s", VTY_NEWLINE);
1526 for (i = 0; i < gss->num_ip4_local; i++)
1527 vty_dump_sns_ip4(vty, &gss->ip4_local[i]);
1528
1529 vty_out(vty, "Remote IPv4 Endpoints:%s", VTY_NEWLINE);
1530 for (i = 0; i < gss->num_ip4_remote; i++)
1531 vty_dump_sns_ip4(vty, &gss->ip4_remote[i]);
1532 }
1533
1534 if (gss->num_ip6_local && gss->num_ip6_remote) {
1535 vty_out(vty, "Local IPv6 Endpoints:%s", VTY_NEWLINE);
1536 for (i = 0; i < gss->num_ip6_local; i++)
1537 vty_dump_sns_ip6(vty, &gss->ip6_local[i]);
1538
1539 vty_out(vty, "Remote IPv6 Endpoints:%s", VTY_NEWLINE);
1540 for (i = 0; i < gss->num_ip6_remote; i++)
1541 vty_dump_sns_ip6(vty, &gss->ip6_remote[i]);
1542 }
1543}
1544
Alexander Couzens412bc342020-11-19 05:24:37 +01001545/*! write IP-SNS to a vty
1546 * \param[in] vty VTY to which the state shall be printed
1547 * \param[in] nse NS Entity whose IP-SNS state shall be printed */
1548void gprs_ns2_sns_write_vty(struct vty *vty, const struct gprs_ns2_nse *nse)
1549{
1550 struct ns2_sns_state *gss;
1551 struct osmo_sockaddr_str addr_str;
1552 struct sns_endpoint *endpoint;
1553
1554 if (!nse->bss_sns_fi)
1555 return;
1556
1557 gss = (struct ns2_sns_state *) nse->bss_sns_fi->priv;
1558 llist_for_each_entry(endpoint, &gss->sns_endpoints, list) {
Vadim Yanitskiyd8b70032021-01-05 14:24:09 +01001559 /* It's unlikely that an error happens, but let's better be safe. */
1560 if (osmo_sockaddr_str_from_sockaddr(&addr_str, &endpoint->saddr.u.sas) != 0)
1561 addr_str = (struct osmo_sockaddr_str) { .ip = "<INVALID>" };
Alexander Couzens412bc342020-11-19 05:24:37 +01001562 vty_out(vty, " ip-sns %s %u%s", addr_str.ip, addr_str.port, VTY_NEWLINE);
1563 }
1564}
1565
Alexander Couzense769f522020-12-07 07:37:07 +01001566static struct sns_endpoint *ns2_get_sns_endpoint(struct ns2_sns_state *state,
1567 const struct osmo_sockaddr *saddr)
1568{
1569 struct sns_endpoint *endpoint;
1570
1571 llist_for_each_entry(endpoint, &state->sns_endpoints, list) {
1572 if (!osmo_sockaddr_cmp(saddr, &endpoint->saddr))
1573 return endpoint;
1574 }
1575
1576 return NULL;
1577}
1578
1579/*! gprs_ns2_sns_add_endpoint
1580 * \param[in] nse
1581 * \param[in] sockaddr
1582 * \return
1583 */
1584int gprs_ns2_sns_add_endpoint(struct gprs_ns2_nse *nse,
1585 const struct osmo_sockaddr *saddr)
1586{
1587 struct ns2_sns_state *gss;
1588 struct sns_endpoint *endpoint;
1589 bool do_selection = false;
1590
1591 if (nse->ll != GPRS_NS2_LL_UDP) {
1592 return -EINVAL;
1593 }
1594
1595 if (nse->dialect != NS2_DIALECT_SNS) {
1596 return -EINVAL;
1597 }
1598
1599 gss = nse->bss_sns_fi->priv;
1600
1601 if (ns2_get_sns_endpoint(gss, saddr))
1602 return -EADDRINUSE;
1603
1604 endpoint = talloc_zero(nse->bss_sns_fi->priv, struct sns_endpoint);
1605 if (!endpoint)
1606 return -ENOMEM;
1607
1608 endpoint->saddr = *saddr;
1609 if (llist_empty(&gss->sns_endpoints))
1610 do_selection = true;
1611
1612 llist_add_tail(&endpoint->list, &gss->sns_endpoints);
1613 if (do_selection)
1614 osmo_fsm_inst_dispatch(nse->bss_sns_fi, GPRS_SNS_EV_SELECT_ENDPOINT, NULL);
1615
1616 return 0;
1617}
1618
1619/*! gprs_ns2_sns_del_endpoint
1620 * \param[in] nse
1621 * \param[in] sockaddr
1622 * \return 0 on success, otherwise < 0
1623 */
1624int gprs_ns2_sns_del_endpoint(struct gprs_ns2_nse *nse,
1625 const struct osmo_sockaddr *saddr)
1626{
1627 struct ns2_sns_state *gss;
1628 struct sns_endpoint *endpoint;
1629
1630 if (nse->ll != GPRS_NS2_LL_UDP) {
1631 return -EINVAL;
1632 }
1633
1634 if (nse->dialect != NS2_DIALECT_SNS) {
1635 return -EINVAL;
1636 }
1637
1638 gss = nse->bss_sns_fi->priv;
1639 endpoint = ns2_get_sns_endpoint(gss, saddr);
1640 if (!endpoint)
1641 return -ENOENT;
1642
1643 /* if this is an unused SNS endpoint it's done */
1644 if (gss->initial != endpoint) {
1645 llist_del(&endpoint->list);
1646 talloc_free(endpoint);
1647 return 0;
1648 }
1649
1650 /* gprs_ns2_free_nsvcs() will trigger GPRS_SNS_EV_NO_NSVC on the last NS-VC
1651 * and restart SNS SIZE procedure which selects a new initial */
1652 LOGP(DLNS, LOGL_INFO, "Current in-use SNS endpoint is being removed."
1653 "Closing all NS-VC and restart SNS-SIZE procedure"
1654 "with a remaining SNS endpoint.\n");
1655
1656 /* Continue with the next endpoint in the list.
1657 * Special case if the endpoint is at the start or end of the list */
1658 if (endpoint->list.prev == &gss->sns_endpoints ||
1659 endpoint->list.next == &gss->sns_endpoints)
1660 gss->initial = NULL;
1661 else
1662 gss->initial = llist_entry(endpoint->list.next->prev,
1663 struct sns_endpoint,
1664 list);
1665
1666 llist_del(&endpoint->list);
1667 gprs_ns2_free_nsvcs(nse);
1668 talloc_free(endpoint);
1669
1670 return 0;
1671}
1672
1673/*! gprs_ns2_sns_count
1674 * \param[in] nse NS Entity whose IP-SNS endpoints shall be printed
1675 * \return the count of endpoints or < 0 if NSE doesn't contain sns.
1676 */
1677int gprs_ns2_sns_count(struct gprs_ns2_nse *nse)
1678{
1679 struct ns2_sns_state *gss;
1680 struct sns_endpoint *endpoint;
1681 int count = 0;
1682
1683 if (nse->ll != GPRS_NS2_LL_UDP) {
1684 return -EINVAL;
1685 }
1686
1687 if (nse->dialect != NS2_DIALECT_SNS) {
1688 return -EINVAL;
1689 }
1690
1691 gss = nse->bss_sns_fi->priv;
1692 llist_for_each_entry(endpoint, &gss->sns_endpoints, list)
1693 count++;
1694
1695 return count;
1696}
1697
Alexander Couzens6a161492020-07-12 13:45:50 +02001698/* initialize osmo_ctx on main tread */
1699static __attribute__((constructor)) void on_dso_load_ctx(void)
1700{
1701 OSMO_ASSERT(osmo_fsm_register(&gprs_ns2_sns_bss_fsm) == 0);
1702}