blob: b7fbbf807dc14b423a5521ccfad17b6ed1324044 [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>
49#include <osmocom/gsm/tlv.h>
50#include <osmocom/gprs/gprs_msgb.h>
51#include <osmocom/gprs/gprs_ns2.h>
52#include <osmocom/gprs/protocol/gsm_08_16.h>
53
54#include "gprs_ns2_internal.h"
55
56#define S(x) (1 << (x))
57
58enum ns2_sns_type {
59 IPv4,
60 IPv6,
61};
62
63enum gprs_sns_bss_state {
64 GPRS_SNS_ST_UNCONFIGURED,
65 GPRS_SNS_ST_SIZE, /*!< SNS-SIZE procedure ongoing */
66 GPRS_SNS_ST_CONFIG_BSS, /*!< SNS-CONFIG procedure (BSS->SGSN) ongoing */
67 GPRS_SNS_ST_CONFIG_SGSN, /*!< SNS-CONFIG procedure (SGSN->BSS) ongoing */
68 GPRS_SNS_ST_CONFIGURED,
69};
70
71enum gprs_sns_event {
Alexander Couzense769f522020-12-07 07:37:07 +010072 GPRS_SNS_EV_SELECT_ENDPOINT, /*!< Select a SNS endpoint from the list */
Alexander Couzens6a161492020-07-12 13:45:50 +020073 GPRS_SNS_EV_SIZE,
74 GPRS_SNS_EV_SIZE_ACK,
75 GPRS_SNS_EV_CONFIG,
76 GPRS_SNS_EV_CONFIG_END, /*!< SNS-CONFIG with end flag received */
77 GPRS_SNS_EV_CONFIG_ACK,
78 GPRS_SNS_EV_ADD,
79 GPRS_SNS_EV_DELETE,
80 GPRS_SNS_EV_CHANGE_WEIGHT,
81 GPRS_SNS_EV_NO_NSVC,
82};
83
84static const struct value_string gprs_sns_event_names[] = {
Alexander Couzense769f522020-12-07 07:37:07 +010085 { GPRS_SNS_EV_SELECT_ENDPOINT, "SELECT_ENDPOINT" },
Alexander Couzens6a161492020-07-12 13:45:50 +020086 { GPRS_SNS_EV_SIZE, "SIZE" },
87 { GPRS_SNS_EV_SIZE_ACK, "SIZE_ACK" },
88 { GPRS_SNS_EV_CONFIG, "CONFIG" },
89 { GPRS_SNS_EV_CONFIG_END, "CONFIG_END" },
90 { GPRS_SNS_EV_CONFIG_ACK, "CONFIG_ACK" },
91 { GPRS_SNS_EV_ADD, "ADD" },
92 { GPRS_SNS_EV_DELETE, "DELETE" },
93 { GPRS_SNS_EV_CHANGE_WEIGHT, "CHANGE_WEIGHT" },
Pau Espin Pedrol0a446a12020-10-27 13:30:08 +010094 { GPRS_SNS_EV_NO_NSVC, "NO_NSVC" },
Alexander Couzens6a161492020-07-12 13:45:50 +020095 { 0, NULL }
96};
97
Alexander Couzense769f522020-12-07 07:37:07 +010098struct sns_endpoint {
99 struct llist_head list;
100 struct osmo_sockaddr saddr;
101};
102
Alexander Couzens6a161492020-07-12 13:45:50 +0200103struct ns2_sns_state {
104 struct gprs_ns2_nse *nse;
105
106 enum ns2_sns_type ip;
107
Alexander Couzense769f522020-12-07 07:37:07 +0100108 /* holds the list of initial SNS endpoints */
109 struct llist_head sns_endpoints;
110 /* prevent recursive reselection */
111 bool reselection_running;
112
113 /* The current initial SNS endpoints.
114 * The initial connection will be moved into the NSE
115 * if configured via SNS. Otherwise it will be removed
116 * in configured state. */
117 struct sns_endpoint *initial;
Alexander Couzens6a161492020-07-12 13:45:50 +0200118 /* all SNS PDU will be sent over this nsvc */
119 struct gprs_ns2_vc *sns_nsvc;
120
121 /* local configuration to send to the remote end */
122 struct gprs_ns_ie_ip4_elem *ip4_local;
123 size_t num_ip4_local;
124
125 /* local configuration to send to the remote end */
126 struct gprs_ns_ie_ip6_elem *ip6_local;
127 size_t num_ip6_local;
128
129 /* local configuration about our capabilities in terms of connections to
130 * remote (SGSN) side */
131 size_t num_max_nsvcs;
132 size_t num_max_ip4_remote;
133 size_t num_max_ip6_remote;
134
135 /* remote configuration as received */
136 struct gprs_ns_ie_ip4_elem *ip4_remote;
137 unsigned int num_ip4_remote;
138
139 /* remote configuration as received */
140 struct gprs_ns_ie_ip6_elem *ip6_remote;
141 unsigned int num_ip6_remote;
142};
143
144static inline struct gprs_ns2_nse *nse_inst_from_fi(struct osmo_fsm_inst *fi)
145{
146 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
147 return gss->nse;
148}
149
150/* helper function to compute the sum of all (data or signaling) weights */
151static int ip4_weight_sum(const struct gprs_ns_ie_ip4_elem *ip4, unsigned int num,
152 bool data_weight)
153{
154 unsigned int i;
155 int weight_sum = 0;
156
157 for (i = 0; i < num; i++) {
158 if (data_weight)
159 weight_sum += ip4[i].data_weight;
160 else
161 weight_sum += ip4[i].sig_weight;
162 }
163 return weight_sum;
164}
165#define ip4_weight_sum_data(x,y) ip4_weight_sum(x, y, true)
166#define ip4_weight_sum_sig(x,y) ip4_weight_sum(x, y, false)
167
168/* helper function to compute the sum of all (data or signaling) weights */
169static int ip6_weight_sum(const struct gprs_ns_ie_ip6_elem *ip6, unsigned int num,
170 bool data_weight)
171{
172 unsigned int i;
173 int weight_sum = 0;
174
175 for (i = 0; i < num; i++) {
176 if (data_weight)
177 weight_sum += ip6[i].data_weight;
178 else
179 weight_sum += ip6[i].sig_weight;
180 }
181 return weight_sum;
182}
183#define ip6_weight_sum_data(x,y) ip6_weight_sum(x, y, true)
184#define ip6_weight_sum_sig(x,y) ip6_weight_sum(x, y, false)
185
186static struct gprs_ns2_vc *nsvc_by_ip4_elem(struct gprs_ns2_nse *nse,
187 const struct gprs_ns_ie_ip4_elem *ip4)
188{
189 struct osmo_sockaddr sa;
190 /* copy over. Both data structures use network byte order */
191 sa.u.sin.sin_addr.s_addr = ip4->ip_addr;
192 sa.u.sin.sin_port = ip4->udp_port;
193 sa.u.sin.sin_family = AF_INET;
194
Alexander Couzens38b19e82020-09-23 23:56:37 +0200195 return gprs_ns2_nsvc_by_sockaddr_nse(nse, &sa);
Alexander Couzens6a161492020-07-12 13:45:50 +0200196}
197
198static struct gprs_ns2_vc *nsvc_by_ip6_elem(struct gprs_ns2_nse *nse,
199 const struct gprs_ns_ie_ip6_elem *ip6)
200{
201 struct osmo_sockaddr sa;
202 /* copy over. Both data structures use network byte order */
203 sa.u.sin6.sin6_addr = ip6->ip_addr;
204 sa.u.sin6.sin6_port = ip6->udp_port;
205 sa.u.sin6.sin6_family = AF_INET;
206
Alexander Couzens38b19e82020-09-23 23:56:37 +0200207 return gprs_ns2_nsvc_by_sockaddr_nse(nse, &sa);
Alexander Couzens6a161492020-07-12 13:45:50 +0200208}
209
Alexander Couzens125298f2020-10-11 21:22:42 +0200210/*! Return the initial SNS remote socket address
211 * \param nse NS Entity
212 * \return address of the initial SNS connection; NULL in case of error
213 */
214const struct osmo_sockaddr *gprs_ns2_nse_sns_remote(struct gprs_ns2_nse *nse)
215{
216 struct ns2_sns_state *gss;
217
218 if (!nse->bss_sns_fi)
219 return NULL;
220
221 gss = (struct ns2_sns_state *) nse->bss_sns_fi->priv;
Alexander Couzense769f522020-12-07 07:37:07 +0100222 return &gss->initial->saddr;
Alexander Couzens125298f2020-10-11 21:22:42 +0200223}
224
Alexander Couzens6a161492020-07-12 13:45:50 +0200225/*! called when a nsvc is beeing freed */
226void ns2_sns_free_nsvc(struct gprs_ns2_vc *nsvc)
227{
228 struct gprs_ns2_nse *nse;
229 struct gprs_ns2_vc *tmp;
230 struct ns2_sns_state *gss;
231 struct osmo_fsm_inst *fi = nsvc->nse->bss_sns_fi;
232
233 if (!fi)
234 return;
235
236 gss = (struct ns2_sns_state *) fi->priv;
237 if (nsvc != gss->sns_nsvc)
238 return;
239
240 nse = nsvc->nse;
241 if (nse->alive) {
242 /* choose a different sns nsvc */
243 llist_for_each_entry(tmp, &nse->nsvc, list) {
244 if (gprs_ns2_vc_is_unblocked(tmp))
245 gss->sns_nsvc = tmp;
246 }
247 } else {
Pau Espin Pedrol7fbe7cf2020-10-27 13:27:18 +0100248 LOGPFSML(fi, LOGL_ERROR, "NSE %d: no remaining NSVC, resetting SNS FSM\n", nse->nsei);
Alexander Couzens6a161492020-07-12 13:45:50 +0200249 gss->sns_nsvc = NULL;
250 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_NO_NSVC, NULL);
251 }
252}
253
254static void ns2_nsvc_create_ip4(struct osmo_fsm_inst *fi,
255 struct gprs_ns2_nse *nse,
256 const struct gprs_ns_ie_ip4_elem *ip4)
257{
258 struct gprs_ns2_inst *nsi = nse->nsi;
259 struct gprs_ns2_vc *nsvc;
260 struct gprs_ns2_vc_bind *bind;
Alexander Couzensc068d862020-10-12 04:11:51 +0200261 struct osmo_sockaddr remote = { };
Alexander Couzens6a161492020-07-12 13:45:50 +0200262 /* copy over. Both data structures use network byte order */
263 remote.u.sin.sin_family = AF_INET;
264 remote.u.sin.sin_addr.s_addr = ip4->ip_addr;
265 remote.u.sin.sin_port = ip4->udp_port;
266
267 /* for every bind, create a connection if bind type == IP */
268 llist_for_each_entry(bind, &nsi->binding, list) {
269 /* ignore failed connection */
270 nsvc = gprs_ns2_ip_connect_inactive(bind,
271 &remote,
272 nse, 0);
273 if (!nsvc) {
274 LOGPFSML(fi, LOGL_ERROR, "SNS-CONFIG: Failed to create NSVC\n");
275 continue;
276 }
277
278 nsvc->sig_weight = ip4->sig_weight;
279 nsvc->data_weight = ip4->data_weight;
280 }
281}
282
283static void ns2_nsvc_create_ip6(struct osmo_fsm_inst *fi,
284 struct gprs_ns2_nse *nse,
285 const struct gprs_ns_ie_ip6_elem *ip6)
286{
287 struct gprs_ns2_inst *nsi = nse->nsi;
288 struct gprs_ns2_vc *nsvc;
289 struct gprs_ns2_vc_bind *bind;
290 struct osmo_sockaddr remote = {};
291 /* copy over. Both data structures use network byte order */
292 remote.u.sin6.sin6_family = AF_INET6;
293 remote.u.sin6.sin6_addr = ip6->ip_addr;
294 remote.u.sin6.sin6_port = ip6->udp_port;
295
296 /* for every bind, create a connection if bind type == IP */
297 llist_for_each_entry(bind, &nsi->binding, list) {
298 /* ignore failed connection */
299 nsvc = gprs_ns2_ip_connect_inactive(bind,
300 &remote,
301 nse, 0);
302 if (!nsvc) {
303 LOGPFSML(fi, LOGL_ERROR, "SNS-CONFIG: Failed to create NSVC\n");
304 continue;
305 }
306
307 nsvc->sig_weight = ip6->sig_weight;
308 nsvc->data_weight = ip6->data_weight;
309 }
310}
311
312
313static int create_missing_nsvcs(struct osmo_fsm_inst *fi)
314{
315 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
316 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
317 struct gprs_ns2_vc *nsvc;
318 struct gprs_ns2_vc_bind *bind;
319 struct osmo_sockaddr remote = { };
320 unsigned int i;
321
322 for (i = 0; i < gss->num_ip4_remote; i++) {
323 const struct gprs_ns_ie_ip4_elem *ip4 = &gss->ip4_remote[i];
324
325 remote.u.sin.sin_family = AF_INET;
326 remote.u.sin.sin_addr.s_addr = ip4->ip_addr;
327 remote.u.sin.sin_port = ip4->udp_port;
328
329 llist_for_each_entry(bind, &nse->nsi->binding, list) {
330 bool found = false;
331
332 llist_for_each_entry(nsvc, &nse->nsvc, list) {
333 if (nsvc->bind != bind)
334 continue;
335
Alexander Couzensc4229a42020-10-11 20:58:04 +0200336 if (!osmo_sockaddr_cmp(&remote, gprs_ns2_ip_vc_remote(nsvc))) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200337 found = true;
338 break;
339 }
340 }
341
342 if (!found) {
343 nsvc = gprs_ns2_ip_connect_inactive(bind, &remote, nse, 0);
344 if (!nsvc) {
345 /* TODO: add to a list to send back a NS-STATUS */
346 continue;
347 }
348 }
349
350 /* update data / signalling weight */
351 nsvc->data_weight = ip4->data_weight;
352 nsvc->sig_weight = ip4->sig_weight;
353 nsvc->sns_only = false;
354 }
355 }
356
357 for (i = 0; i < gss->num_ip6_remote; i++) {
358 const struct gprs_ns_ie_ip6_elem *ip6 = &gss->ip6_remote[i];
359
360 remote.u.sin6.sin6_family = AF_INET6;
361 remote.u.sin6.sin6_addr = ip6->ip_addr;
362 remote.u.sin6.sin6_port = ip6->udp_port;
363
364 llist_for_each_entry(bind, &nse->nsi->binding, list) {
365 bool found = false;
366
367 llist_for_each_entry(nsvc, &nse->nsvc, list) {
368 if (nsvc->bind != bind)
369 continue;
370
Alexander Couzensc4229a42020-10-11 20:58:04 +0200371 if (!osmo_sockaddr_cmp(&remote, gprs_ns2_ip_vc_remote(nsvc))) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200372 found = true;
373 break;
374 }
375 }
376
377 if (!found) {
378 nsvc = gprs_ns2_ip_connect_inactive(bind, &remote, nse, 0);
379 if (!nsvc) {
380 /* TODO: add to a list to send back a NS-STATUS */
381 continue;
382 }
383 }
384
385 /* update data / signalling weight */
386 nsvc->data_weight = ip6->data_weight;
387 nsvc->sig_weight = ip6->sig_weight;
388 nsvc->sns_only = false;
389 }
390 }
391
392
393 return 0;
394}
395
396/* Add a given remote IPv4 element to gprs_sns_state */
397static int add_remote_ip4_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip4_elem *ip4)
398{
399 unsigned int i;
400
401 if (gss->num_ip4_remote >= gss->num_max_ip4_remote)
402 return -NS_CAUSE_INVAL_NR_NS_VC;
403
404 /* check for duplicates */
405 for (i = 0; i < gss->num_ip4_remote; i++) {
406 if (memcmp(&gss->ip4_remote[i], ip4, sizeof(*ip4)))
407 continue;
408 /* TODO: log message duplicate */
409 /* TODO: check if this is the correct cause code */
410 return -NS_CAUSE_PROTO_ERR_UNSPEC;
411 }
412
413 gss->ip4_remote = talloc_realloc(gss, gss->ip4_remote, struct gprs_ns_ie_ip4_elem,
414 gss->num_ip4_remote+1);
415 gss->ip4_remote[gss->num_ip4_remote] = *ip4;
416 gss->num_ip4_remote += 1;
417 return 0;
418}
419
420/* Remove a given remote IPv4 element from gprs_sns_state */
421static int remove_remote_ip4_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip4_elem *ip4)
422{
423 unsigned int i;
424
425 for (i = 0; i < gss->num_ip4_remote; i++) {
426 if (memcmp(&gss->ip4_remote[i], ip4, sizeof(*ip4)))
427 continue;
428 /* all array elements < i remain as they are; all > i are shifted left by one */
429 memmove(&gss->ip4_remote[i], &gss->ip4_remote[i+1], gss->num_ip4_remote-i-1);
430 gss->num_ip4_remote -= 1;
431 return 0;
432 }
433 return -1;
434}
435
436/* update the weights for specified remote IPv4 */
437static int update_remote_ip4_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip4_elem *ip4)
438{
439 unsigned int i;
440
441 for (i = 0; i < gss->num_ip4_remote; i++) {
442 if (gss->ip4_remote[i].ip_addr != ip4->ip_addr ||
443 gss->ip4_remote[i].udp_port != ip4->udp_port)
444 continue;
445
446 gss->ip4_remote[i].sig_weight = ip4->sig_weight;
447 gss->ip4_remote[i].data_weight = ip4->data_weight;
448 return 0;
449 }
450 return -1;
451}
452
453/* Add a given remote IPv6 element to gprs_sns_state */
454static int add_remote_ip6_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip6_elem *ip6)
455{
456 if (gss->num_ip6_remote >= gss->num_max_ip6_remote)
457 return -NS_CAUSE_INVAL_NR_NS_VC;
458
459 gss->ip6_remote = talloc_realloc(gss, gss->ip6_remote, struct gprs_ns_ie_ip6_elem,
460 gss->num_ip6_remote+1);
461 gss->ip6_remote[gss->num_ip6_remote] = *ip6;
462 gss->num_ip6_remote += 1;
463 return 0;
464}
465
466/* Remove a given remote IPv6 element from gprs_sns_state */
467static int remove_remote_ip6_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip6_elem *ip6)
468{
469 unsigned int i;
470
471 for (i = 0; i < gss->num_ip6_remote; i++) {
472 if (memcmp(&gss->ip6_remote[i], ip6, sizeof(*ip6)))
473 continue;
474 /* all array elements < i remain as they are; all > i are shifted left by one */
475 memmove(&gss->ip6_remote[i], &gss->ip6_remote[i+1], gss->num_ip6_remote-i-1);
476 gss->num_ip6_remote -= 1;
477 return 0;
478 }
479 return -1;
480}
481
482/* update the weights for specified remote IPv6 */
483static int update_remote_ip6_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip6_elem *ip6)
484{
485 unsigned int i;
486
487 for (i = 0; i < gss->num_ip6_remote; i++) {
488 if (memcmp(&gss->ip6_remote[i].ip_addr, &ip6->ip_addr, sizeof(ip6->ip_addr)) ||
489 gss->ip6_remote[i].udp_port != ip6->udp_port)
490 continue;
491 gss->ip6_remote[i].sig_weight = ip6->sig_weight;
492 gss->ip6_remote[i].data_weight = ip6->data_weight;
493 return 0;
494 }
495 return -1;
496}
497
498static 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)
499{
500 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
501 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
502 struct gprs_ns2_vc *nsvc;
503 struct osmo_sockaddr sa = {};
Alexander Couzens9a4cf272020-10-11 20:48:04 +0200504 const struct osmo_sockaddr *remote;
Alexander Couzens6a161492020-07-12 13:45:50 +0200505 uint8_t new_signal;
506 uint8_t new_data;
507
508 /* TODO: Upon receiving an SNS-CHANGEWEIGHT PDU, if the resulting sum of the
509 * signalling weights of all the peer IP endpoints configured for this NSE is
510 * equal to zero or if the resulting sum of the data weights of all the peer IP
511 * endpoints configured for this NSE is equal to zero, the BSS/SGSN shall send an
512 * SNS-ACK PDU with a cause code of "Invalid weights". */
513
514 if (ip4) {
515 if (update_remote_ip4_elem(gss, ip4))
516 return -NS_CAUSE_UNKN_IP_EP;
517
518 /* copy over. Both data structures use network byte order */
519 sa.u.sin.sin_addr.s_addr = ip4->ip_addr;
520 sa.u.sin.sin_port = ip4->udp_port;
521 sa.u.sin.sin_family = AF_INET;
522 new_signal = ip4->sig_weight;
523 new_data = ip4->data_weight;
524 } else if (ip6) {
525 if (update_remote_ip6_elem(gss, ip6))
526 return -NS_CAUSE_UNKN_IP_EP;
527
528 /* copy over. Both data structures use network byte order */
529 sa.u.sin6.sin6_addr = ip6->ip_addr;
530 sa.u.sin6.sin6_port = ip6->udp_port;
531 sa.u.sin6.sin6_family = AF_INET6;
532 new_signal = ip6->sig_weight;
533 new_data = ip6->data_weight;
534 } else {
535 OSMO_ASSERT(false);
536 }
537
538 llist_for_each_entry(nsvc, &nse->nsvc, list) {
Alexander Couzensc4229a42020-10-11 20:58:04 +0200539 remote = gprs_ns2_ip_vc_remote(nsvc);
Alexander Couzens6a161492020-07-12 13:45:50 +0200540 /* all nsvc in NSE should be IP/UDP nsvc */
541 OSMO_ASSERT(remote);
542
543 if (osmo_sockaddr_cmp(&sa, remote))
544 continue;
545
546 LOGPFSML(fi, LOGL_INFO, "CHANGE-WEIGHT NS-VC %s data_weight %u->%u, sig_weight %u->%u\n",
547 gprs_ns2_ll_str(nsvc), nsvc->data_weight, new_data,
548 nsvc->sig_weight, new_signal);
549
550 nsvc->data_weight = new_data;
551 nsvc->sig_weight = new_signal;
552 }
553
554 return 0;
555}
556
557static int do_sns_delete(struct osmo_fsm_inst *fi,
558 const struct gprs_ns_ie_ip4_elem *ip4,
559 const struct gprs_ns_ie_ip6_elem *ip6)
560{
561 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
562 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
563 struct gprs_ns2_vc *nsvc, *tmp;
Alexander Couzens9a4cf272020-10-11 20:48:04 +0200564 const struct osmo_sockaddr *remote;
Alexander Couzens6a161492020-07-12 13:45:50 +0200565 struct osmo_sockaddr sa = {};
566
567 if (ip4) {
568 if (remove_remote_ip4_elem(gss, ip4) < 0)
569 return -NS_CAUSE_UNKN_IP_EP;
570 /* copy over. Both data structures use network byte order */
571 sa.u.sin.sin_addr.s_addr = ip4->ip_addr;
572 sa.u.sin.sin_port = ip4->udp_port;
573 sa.u.sin.sin_family = AF_INET;
574 } else if (ip6) {
575 if (remove_remote_ip6_elem(gss, ip6))
576 return -NS_CAUSE_UNKN_IP_EP;
577
578 /* copy over. Both data structures use network byte order */
579 sa.u.sin6.sin6_addr = ip6->ip_addr;
580 sa.u.sin6.sin6_port = ip6->udp_port;
581 sa.u.sin6.sin6_family = AF_INET6;
582 } else {
583 OSMO_ASSERT(false);
584 }
585
586 llist_for_each_entry_safe(nsvc, tmp, &nse->nsvc, list) {
Alexander Couzensc4229a42020-10-11 20:58:04 +0200587 remote = gprs_ns2_ip_vc_remote(nsvc);
Alexander Couzens6a161492020-07-12 13:45:50 +0200588 /* all nsvc in NSE should be IP/UDP nsvc */
589 OSMO_ASSERT(remote);
590 if (osmo_sockaddr_cmp(&sa, remote))
591 continue;
592
593 LOGPFSML(fi, LOGL_INFO, "DELETE NS-VC %s\n", gprs_ns2_ll_str(nsvc));
594 gprs_ns2_free_nsvc(nsvc);
595 }
596
597 return 0;
598}
599
600static int do_sns_add(struct osmo_fsm_inst *fi,
601 const struct gprs_ns_ie_ip4_elem *ip4,
602 const struct gprs_ns_ie_ip6_elem *ip6)
603{
604 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
605 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
606 struct gprs_ns2_vc *nsvc;
607 int rc = 0;
608
609 /* Upon receiving an SNS-ADD PDU, if the consequent number of IPv4 endpoints
610 * exceeds the number of IPv4 endpoints supported by the NSE, the NSE shall send
611 * an SNS-ACK PDU with a cause code set to "Invalid number of IP4 Endpoints". */
612 switch (gss->ip) {
613 case IPv4:
614 rc = add_remote_ip4_elem(gss, ip4);
615 break;
616 case IPv6:
617 rc = add_remote_ip6_elem(gss, ip6);
618 break;
619 default:
620 /* the gss->ip is initialized with the bss */
621 OSMO_ASSERT(false);
622 }
623
624 if (rc)
625 return rc;
626
627 /* Upon receiving an SNS-ADD PDU containing an already configured IP endpoint the
628 * NSE shall send an SNS-ACK PDU with the cause code "Protocol error -
629 * unspecified" */
630 switch (gss->ip) {
631 case IPv4:
632 nsvc = nsvc_by_ip4_elem(nse, ip4);
633 if (nsvc) {
634 /* the nsvc should be already in sync with the ip4 / ip6 elements */
635 return -NS_CAUSE_PROTO_ERR_UNSPEC;
636 }
637
638 /* TODO: failure case */
639 ns2_nsvc_create_ip4(fi, nse, ip4);
640 break;
641 case IPv6:
642 nsvc = nsvc_by_ip6_elem(nse, ip6);
643 if (nsvc) {
644 /* the nsvc should be already in sync with the ip4 / ip6 elements */
645 return -NS_CAUSE_PROTO_ERR_UNSPEC;
646 }
647
648 /* TODO: failure case */
649 ns2_nsvc_create_ip6(fi, nse, ip6);
650 break;
651 }
652
653 gprs_ns2_start_alive_all_nsvcs(nse);
654
655 return 0;
656}
657
658
659static void ns2_sns_st_unconfigured(struct osmo_fsm_inst *fi, uint32_t event, void *data)
660{
Alexander Couzense769f522020-12-07 07:37:07 +0100661 /* empty state - SNS Select will start by ns2_sns_st_all_action() */
Alexander Couzens6a161492020-07-12 13:45:50 +0200662}
663
664static void ns2_sns_st_size(struct osmo_fsm_inst *fi, uint32_t event, void *data)
665{
666 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
667 struct gprs_ns2_inst *nsi = nse->nsi;
668 struct tlv_parsed *tp = NULL;
669
670 switch (event) {
671 case GPRS_SNS_EV_SIZE_ACK:
672 tp = data;
673 if (TLVP_VAL_MINLEN(tp, NS_IE_CAUSE, 1)) {
674 LOGPFSML(fi, LOGL_ERROR, "SNS-SIZE-ACK with cause %s\n",
675 gprs_ns2_cause_str(*TLVP_VAL(tp, NS_IE_CAUSE)));
676 /* TODO: What to do? */
677 } else {
678 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIG_BSS,
679 nsi->timeout[NS_TOUT_TSNS_PROV], 2);
680 }
681 break;
682 default:
683 OSMO_ASSERT(0);
684 }
685}
686
Alexander Couzense769f522020-12-07 07:37:07 +0100687/* setup all dynamic SNS settings, create a new nsvc and send the SIZE */
Alexander Couzens6a161492020-07-12 13:45:50 +0200688static void ns2_sns_st_size_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
689{
690 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
Alexander Couzense769f522020-12-07 07:37:07 +0100691 struct gprs_ns_ie_ip4_elem *ip4_elems;
692 struct gprs_ns_ie_ip6_elem *ip6_elems;
693 struct gprs_ns2_vc_bind *bind;
694 struct gprs_ns2_inst *nsi = gss->nse->nsi;
695 struct osmo_sockaddr *remote;
696 const struct osmo_sockaddr *sa;
697 struct osmo_sockaddr local;
698 int count;
Alexander Couzens6a161492020-07-12 13:45:50 +0200699
Alexander Couzense769f522020-12-07 07:37:07 +0100700 /* on a generic failure, the timer callback will recover */
Alexander Couzens6a161492020-07-12 13:45:50 +0200701 if (old_state != GPRS_SNS_ST_UNCONFIGURED)
Daniel Willmann15c09a82020-11-03 23:05:43 +0100702 ns2_prim_status_ind(gss->nse, NULL, 0, NS_AFF_CAUSE_SNS_FAILURE);
Alexander Couzens6a161492020-07-12 13:45:50 +0200703
Alexander Couzense769f522020-12-07 07:37:07 +0100704 /* no initial available */
705 if (!gss->initial)
706 return;
707
708 remote = &gss->initial->saddr;
709
710 /* count how many bindings are available (only UDP binds) */
711 count = ns2_ip_count_bind(nsi, remote);
712 if (count == 0) {
713 /* TODO: logging */
714 return;
715 }
716
717 bind = ns2_ip_get_bind_by_index(nsi, remote, 0);
718 if (!bind) {
719 return;
720 }
721
722 /* setup the NSVC */
723 if (!gss->sns_nsvc) {
724 gss->sns_nsvc = gprs_ns2_ip_bind_connect(bind, gss->nse, remote);
725 if (!gss->sns_nsvc)
726 return;
727 gss->sns_nsvc->sns_only = true;
728 }
729
730 switch (gss->ip) {
731 case IPv4:
732 ip4_elems = talloc_zero_size(fi, sizeof(struct gprs_ns_ie_ip4_elem) * count);
733 if (!ip4_elems)
734 return;
735
736 gss->ip4_local = ip4_elems;
737
738 llist_for_each_entry(bind, &nsi->binding, list) {
739 if (!gprs_ns2_is_ip_bind(bind))
740 continue;
741
742 sa = gprs_ns2_ip_bind_sockaddr(bind);
743 if (!sa)
744 continue;
745
746 if (sa->u.sas.ss_family != AF_INET)
747 continue;
748
749 /* check if this is an specific bind */
750 if (sa->u.sin.sin_addr.s_addr == 0) {
751 if (osmo_sockaddr_local_ip(&local, remote))
752 continue;
753
754 ip4_elems->ip_addr = local.u.sin.sin_addr.s_addr;
755 } else {
756 ip4_elems->ip_addr = sa->u.sin.sin_addr.s_addr;
757 }
758
759 ip4_elems->udp_port = sa->u.sin.sin_port;
760 ip4_elems->sig_weight = 2;
761 ip4_elems->data_weight = 1;
762 ip4_elems++;
763 }
764
765 gss->num_ip4_local = count;
766 gss->num_max_ip4_remote = 4;
767 gss->num_max_nsvcs = OSMO_MAX(gss->num_max_ip4_remote * gss->num_ip4_local, 8);
768 break;
769 case IPv6:
770 /* IPv6 */
771 ip6_elems = talloc_zero_size(fi, sizeof(struct gprs_ns_ie_ip6_elem) * count);
772 if (!ip6_elems)
773 return;
774
775 gss->ip6_local = ip6_elems;
776
777 llist_for_each_entry(bind, &nsi->binding, list) {
778 if (!gprs_ns2_is_ip_bind(bind))
779 continue;
780
781 sa = gprs_ns2_ip_bind_sockaddr(bind);
782 if (!sa)
783 continue;
784
785 if (sa->u.sas.ss_family != AF_INET6)
786 continue;
787
788 /* check if this is an specific bind */
789 if (IN6_IS_ADDR_UNSPECIFIED(&sa->u.sin6.sin6_addr)) {
790 if (osmo_sockaddr_local_ip(&local, remote))
791 continue;
792
793 ip6_elems->ip_addr = local.u.sin6.sin6_addr;
794 } else {
795 ip6_elems->ip_addr = sa->u.sin6.sin6_addr;
796 }
797
798 ip6_elems->udp_port = sa->u.sin.sin_port;
799 ip6_elems->sig_weight = 2;
800 ip6_elems->data_weight = 1;
801
802 ip6_elems++;
803 }
804 gss->num_ip6_local = count;
805 gss->num_max_ip6_remote = 4;
806 gss->num_max_nsvcs = OSMO_MAX(gss->num_max_ip6_remote * gss->num_ip6_local, 8);
807 break;
808 }
809
Alexander Couzens6a161492020-07-12 13:45:50 +0200810 if (gss->num_max_ip4_remote > 0)
811 ns2_tx_sns_size(gss->sns_nsvc, true, gss->num_max_nsvcs, gss->num_max_ip4_remote, -1);
812 else
813 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 +0200814}
815
816static void ns2_sns_st_config_bss(struct osmo_fsm_inst *fi, uint32_t event, void *data)
817{
818 struct tlv_parsed *tp = NULL;
819
820 switch (event) {
821 case GPRS_SNS_EV_CONFIG_ACK:
822 tp = (struct tlv_parsed *) data;
823 if (TLVP_VAL_MINLEN(tp, NS_IE_CAUSE, 1)) {
824 LOGPFSML(fi, LOGL_ERROR, "SNS-CONFIG-ACK with cause %s\n",
825 gprs_ns2_cause_str(*TLVP_VAL(tp, NS_IE_CAUSE)));
826 /* TODO: What to do? */
827 } else {
828 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIG_SGSN, 0, 0);
829 }
830 break;
831 default:
832 OSMO_ASSERT(0);
833 }
834}
835
836static void ns2_sns_st_config_bss_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
837{
838 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
839 /* Transmit SNS-CONFIG */
Alexander Couzens6a161492020-07-12 13:45:50 +0200840 switch (gss->ip) {
841 case IPv4:
842 ns2_tx_sns_config(gss->sns_nsvc, true,
Alexander Couzense78207f2020-12-07 06:19:29 +0100843 gss->ip4_local, gss->num_ip4_local,
844 NULL, 0);
Alexander Couzens6a161492020-07-12 13:45:50 +0200845 break;
846 case IPv6:
847 ns2_tx_sns_config(gss->sns_nsvc, true,
Alexander Couzense78207f2020-12-07 06:19:29 +0100848 NULL, 0,
849 gss->ip6_local, gss->num_ip6_local);
Alexander Couzens6a161492020-07-12 13:45:50 +0200850 break;
851 }
852}
853
854
855static void ns_sns_st_config_sgsn_ip4(struct osmo_fsm_inst *fi, uint32_t event, void *data)
856{
857 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
858 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
859 const struct gprs_ns_ie_ip4_elem *v4_list;
860 unsigned int num_v4;
861 struct tlv_parsed *tp = NULL;
862
863 uint8_t cause;
864
865 tp = (struct tlv_parsed *) data;
866
867 if (!TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
868 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
869 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
870 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
871 return;
872 }
873 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
874 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
875 /* realloc to the new size */
876 gss->ip4_remote = talloc_realloc(gss, gss->ip4_remote,
877 struct gprs_ns_ie_ip4_elem,
878 gss->num_ip4_remote+num_v4);
879 /* append the new entries to the end of the list */
880 memcpy(&gss->ip4_remote[gss->num_ip4_remote], v4_list, num_v4*sizeof(*v4_list));
881 gss->num_ip4_remote += num_v4;
882
883 LOGPFSML(fi, LOGL_INFO, "Rx SNS-CONFIG: Remote IPv4 list now %u entries\n",
884 gss->num_ip4_remote);
885 if (event == GPRS_SNS_EV_CONFIG_END) {
886 /* check if sum of data / sig weights == 0 */
887 if (ip4_weight_sum_data(gss->ip4_remote, gss->num_ip4_remote) == 0 ||
888 ip4_weight_sum_sig(gss->ip4_remote, gss->num_ip4_remote) == 0) {
889 cause = NS_CAUSE_INVAL_WEIGH;
890 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
891 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
892 return;
893 }
894 create_missing_nsvcs(fi);
895 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
896 /* start the test procedure on ALL NSVCs! */
897 gprs_ns2_start_alive_all_nsvcs(nse);
898 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIGURED, 0, 0);
899 } else {
900 /* just send CONFIG-ACK */
901 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
902 }
903}
904
905static void ns_sns_st_config_sgsn_ip6(struct osmo_fsm_inst *fi, uint32_t event, void *data)
906{
907 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
908 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
909 const struct gprs_ns_ie_ip6_elem *v6_list;
910 unsigned int num_v6;
911 struct tlv_parsed *tp = NULL;
912
913 uint8_t cause;
914
915 tp = (struct tlv_parsed *) data;
916
917 if (!TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
918 cause = NS_CAUSE_INVAL_NR_IPv6_EP;
919 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
920 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
921 return;
922 }
923 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
924 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
925 /* realloc to the new size */
926 gss->ip6_remote = talloc_realloc(gss, gss->ip6_remote,
927 struct gprs_ns_ie_ip6_elem,
928 gss->num_ip6_remote+num_v6);
929 /* append the new entries to the end of the list */
930 memcpy(&gss->ip6_remote[gss->num_ip6_remote], v6_list, num_v6*sizeof(*v6_list));
931 gss->num_ip6_remote += num_v6;
932
933 LOGPFSML(fi, LOGL_INFO, "Rx SNS-CONFIG: Remote IPv6 list now %u entries\n",
934 gss->num_ip6_remote);
935 if (event == GPRS_SNS_EV_CONFIG_END) {
936 /* check if sum of data / sig weights == 0 */
937 if (ip6_weight_sum_data(gss->ip6_remote, gss->num_ip6_remote) == 0 ||
938 ip6_weight_sum_sig(gss->ip6_remote, gss->num_ip6_remote) == 0) {
939 cause = NS_CAUSE_INVAL_WEIGH;
940 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
941 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
942 return;
943 }
944 create_missing_nsvcs(fi);
945 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
946 /* start the test procedure on ALL NSVCs! */
947 gprs_ns2_start_alive_all_nsvcs(nse);
948 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIGURED, 0, 0);
949 } else {
950 /* just send CONFIG-ACK */
951 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
952 }
953}
954
955static void ns2_sns_st_config_sgsn(struct osmo_fsm_inst *fi, uint32_t event, void *data)
956{
957 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
958
959 switch (event) {
960 case GPRS_SNS_EV_CONFIG_END:
961 case GPRS_SNS_EV_CONFIG:
962
963#if 0 /* part of incoming SNS-SIZE (doesn't happen on BSS side */
964 if (TLVP_PRESENT(tp, NS_IE_RESET_FLAG)) {
965 /* reset all existing config */
966 if (gss->ip4_remote)
967 talloc_free(gss->ip4_remote);
968 gss->num_ip4_remote = 0;
969 }
970#endif
971 /* TODO: reject IPv6 elements on IPv4 mode and vice versa */
972 switch (gss->ip) {
973 case IPv4:
974 ns_sns_st_config_sgsn_ip4(fi, event, data);
975 break;
976 case IPv6:
977 ns_sns_st_config_sgsn_ip6(fi, event, data);
978 break;
979 default:
980 OSMO_ASSERT(0);
981 }
982 break;
983 default:
984 OSMO_ASSERT(0);
985 }
986}
987
988/* called when receiving GPRS_SNS_EV_ADD in state configure */
989static void ns2_sns_st_configured_add(struct osmo_fsm_inst *fi,
990 struct ns2_sns_state *gss,
991 struct tlv_parsed *tp)
992{
993 const struct gprs_ns_ie_ip4_elem *v4_list = NULL;
994 const struct gprs_ns_ie_ip6_elem *v6_list = NULL;
995 int num_v4 = 0, num_v6 = 0;
996 uint8_t trans_id, cause = 0xff;
Harald Welte7da6ace2020-09-18 09:48:05 +0200997 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +0200998 int rc = 0;
999
1000 /* TODO: refactor EV_ADD/CHANGE/REMOVE by
1001 * check uniqueness within the lists (no doublicate entries)
1002 * check not-known-by-us and sent back a list of unknown/known values
1003 * (abnormal behaviour according to 48.016)
1004 */
1005
1006 trans_id = *TLVP_VAL(tp, NS_IE_TRANS_ID);
1007 if (gss->ip == IPv4) {
1008 if (!TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
1009 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
1010 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1011 return;
1012 }
1013
1014 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
1015 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001016 for (i = 0; i < num_v4; i++) {
1017 unsigned int j;
Alexander Couzens6a161492020-07-12 13:45:50 +02001018 rc = do_sns_add(fi, &v4_list[i], NULL);
1019 if (rc < 0) {
1020 /* rollback/undo to restore previous state */
Harald Welte7da6ace2020-09-18 09:48:05 +02001021 for (j = 0; j < i; j++)
Alexander Couzens6a161492020-07-12 13:45:50 +02001022 do_sns_delete(fi, &v4_list[j], NULL);
1023 cause = -rc;
1024 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1025 break;
1026 }
1027 }
1028 } else { /* IPv6 */
1029 if (!TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
1030 cause = NS_CAUSE_INVAL_NR_IPv6_EP;
1031 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1032 return;
1033 }
1034
1035 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
1036 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001037 for (i = 0; i < num_v6; i++) {
1038 unsigned int j;
Alexander Couzens6a161492020-07-12 13:45:50 +02001039 rc = do_sns_add(fi, NULL, &v6_list[i]);
1040 if (rc < 0) {
1041 /* rollback/undo to restore previous state */
Harald Welte7da6ace2020-09-18 09:48:05 +02001042 for (j = 0; j < i; j++)
Alexander Couzens6a161492020-07-12 13:45:50 +02001043 do_sns_delete(fi, NULL, &v6_list[j]);
1044 cause = -rc;
1045 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1046 break;
1047 }
1048 }
1049 }
1050
1051 /* TODO: correct behaviour is to answer to the *same* NSVC from which the SNS_ADD was received */
1052 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, NULL, v4_list, num_v4, v6_list, num_v6);
1053}
1054
1055static void ns2_sns_st_configured_delete(struct osmo_fsm_inst *fi,
1056 struct ns2_sns_state *gss,
1057 struct tlv_parsed *tp)
1058{
1059 const struct gprs_ns_ie_ip4_elem *v4_list = NULL;
1060 const struct gprs_ns_ie_ip6_elem *v6_list = NULL;
1061 int num_v4 = 0, num_v6 = 0;
1062 uint8_t trans_id, cause = 0xff;
Harald Welte7da6ace2020-09-18 09:48:05 +02001063 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +02001064 int rc = 0;
1065
1066 /* TODO: split up delete into v4 + v6
1067 * TODO: check if IPv4_LIST or IP_ADDR(v4) is present on IPv6 and vice versa
1068 * TODO: check if IPv4_LIST/IPv6_LIST and IP_ADDR is present at the same time
1069 */
1070 trans_id = *TLVP_VAL(tp, NS_IE_TRANS_ID);
1071 if (gss->ip == IPv4) {
1072 if (TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
1073 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
1074 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001075 for ( i = 0; i < num_v4; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001076 rc = do_sns_delete(fi, &v4_list[i], NULL);
1077 if (rc < 0) {
1078 cause = -rc;
1079 /* continue to delete others */
1080 }
1081 }
1082 if (cause != 0xff) {
1083 /* TODO: create list of not-deleted and return it */
1084 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1085 return;
1086 }
1087
1088 } else if (TLVP_PRESENT(tp, NS_IE_IP_ADDR) && TLVP_LEN(tp, NS_IE_IP_ADDR) == 5) {
1089 /* delete all NS-VCs for given IPv4 address */
1090 const uint8_t *ie = TLVP_VAL(tp, NS_IE_IP_ADDR);
1091 struct gprs_ns_ie_ip4_elem *ip4_remote;
1092 uint32_t ip_addr = *(uint32_t *)(ie+1);
1093 if (ie[0] != 0x01) { /* Address Type != IPv4 */
1094 cause = NS_CAUSE_UNKN_IP_ADDR;
1095 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1096 return;
1097 }
1098 /* make a copy as do_sns_delete() will change the array underneath us */
1099 ip4_remote = talloc_memdup(fi, gss->ip4_remote,
1100 gss->num_ip4_remote * sizeof(*v4_list));
Harald Welte7da6ace2020-09-18 09:48:05 +02001101 for (i = 0; i < gss->num_ip4_remote; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001102 if (ip4_remote[i].ip_addr == ip_addr) {
1103 rc = do_sns_delete(fi, &ip4_remote[i], NULL);
1104 if (rc < 0) {
1105 cause = -rc;
1106 /* continue to delete others */
1107 }
1108 }
1109 }
1110 talloc_free(ip4_remote);
1111 if (cause != 0xff) {
1112 /* TODO: create list of not-deleted and return it */
1113 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1114 return;
1115 }
1116 } else {
1117 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
1118 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1119 return;
1120 }
1121 } else { /* IPv6 */
1122 if (TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
1123 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
1124 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001125 for (i = 0; i < num_v6; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001126 rc = do_sns_delete(fi, NULL, &v6_list[i]);
1127 if (rc < 0) {
1128 cause = -rc;
1129 /* continue to delete others */
1130 }
1131 }
1132 if (cause != 0xff) {
1133 /* TODO: create list of not-deleted and return it */
1134 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1135 return;
1136 }
1137 } else if (TLVP_PRES_LEN(tp, NS_IE_IP_ADDR, 17)) {
1138 /* delete all NS-VCs for given IPv4 address */
1139 const uint8_t *ie = TLVP_VAL(tp, NS_IE_IP_ADDR);
1140 struct gprs_ns_ie_ip6_elem *ip6_remote;
1141 struct in6_addr ip6_addr;
Harald Welte7da6ace2020-09-18 09:48:05 +02001142 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +02001143 if (ie[0] != 0x02) { /* Address Type != IPv6 */
1144 cause = NS_CAUSE_UNKN_IP_ADDR;
1145 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1146 return;
1147 }
1148 memcpy(&ip6_addr, (ie+1), sizeof(struct in6_addr));
1149 /* make a copy as do_sns_delete() will change the array underneath us */
1150 ip6_remote = talloc_memdup(fi, gss->ip6_remote,
1151 gss->num_ip6_remote * sizeof(*v4_list));
Harald Welte7da6ace2020-09-18 09:48:05 +02001152 for (i = 0; i < gss->num_ip6_remote; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001153 if (!memcmp(&ip6_remote[i].ip_addr, &ip6_addr, sizeof(struct in6_addr))) {
1154 rc = do_sns_delete(fi, NULL, &ip6_remote[i]);
1155 if (rc < 0) {
1156 cause = -rc;
1157 /* continue to delete others */
1158 }
1159 }
1160 }
1161
1162 talloc_free(ip6_remote);
1163 if (cause != 0xff) {
1164 /* TODO: create list of not-deleted and return it */
1165 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1166 return;
1167 }
1168 } else {
1169 cause = NS_CAUSE_INVAL_NR_IPv6_EP;
1170 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1171 return;
1172 }
1173 }
1174 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, NULL, v4_list, num_v4, v6_list, num_v6);
1175}
1176
1177static void ns2_sns_st_configured_change(struct osmo_fsm_inst *fi,
1178 struct ns2_sns_state *gss,
1179 struct tlv_parsed *tp)
1180{
1181 const struct gprs_ns_ie_ip4_elem *v4_list = NULL;
1182 const struct gprs_ns_ie_ip6_elem *v6_list = NULL;
1183 int num_v4 = 0, num_v6 = 0;
1184 uint8_t trans_id, cause = 0xff;
1185 int rc = 0;
Harald Welte7da6ace2020-09-18 09:48:05 +02001186 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +02001187
1188 trans_id = *TLVP_VAL(tp, NS_IE_TRANS_ID);
1189 if (TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
1190 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
1191 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001192 for (i = 0; i < num_v4; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001193 rc = do_sns_change_weight(fi, &v4_list[i], NULL);
1194 if (rc < 0) {
1195 cause = -rc;
1196 /* continue to others */
1197 }
1198 }
1199 if (cause != 0xff) {
1200 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1201 return;
1202 }
1203 } else if (TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
1204 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
1205 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001206 for (i = 0; i < num_v6; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001207 rc = do_sns_change_weight(fi, NULL, &v6_list[i]);
1208 if (rc < 0) {
1209 cause = -rc;
1210 /* continue to others */
1211 }
1212 }
1213 if (cause != 0xff) {
1214 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1215 return;
1216 }
1217 } else {
1218 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
1219 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1220 return;
1221 }
1222 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, NULL, v4_list, num_v4, v6_list, num_v6);
1223}
1224
1225static void ns2_sns_st_configured(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1226{
1227 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
1228 struct tlv_parsed *tp = data;
1229
1230 switch (event) {
1231 case GPRS_SNS_EV_ADD:
1232 ns2_sns_st_configured_add(fi, gss, tp);
1233 break;
1234 case GPRS_SNS_EV_DELETE:
1235 ns2_sns_st_configured_delete(fi, gss, tp);
1236 break;
1237 case GPRS_SNS_EV_CHANGE_WEIGHT:
1238 ns2_sns_st_configured_change(fi, gss, tp);
1239 break;
1240 }
1241}
1242
1243static void ns2_sns_st_configured_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
1244{
1245 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
Daniel Willmann15c09a82020-11-03 23:05:43 +01001246 ns2_prim_status_ind(nse, NULL, 0, NS_AFF_CAUSE_SNS_CONFIGURED);
Alexander Couzens6a161492020-07-12 13:45:50 +02001247}
1248
1249static const struct osmo_fsm_state ns2_sns_bss_states[] = {
1250 [GPRS_SNS_ST_UNCONFIGURED] = {
Alexander Couzense769f522020-12-07 07:37:07 +01001251 .in_event_mask = 0, /* handled by all_state_action */
Alexander Couzens6a161492020-07-12 13:45:50 +02001252 .out_state_mask = S(GPRS_SNS_ST_SIZE),
1253 .name = "UNCONFIGURED",
1254 .action = ns2_sns_st_unconfigured,
1255 },
1256 [GPRS_SNS_ST_SIZE] = {
1257 .in_event_mask = S(GPRS_SNS_EV_SIZE_ACK),
1258 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
1259 S(GPRS_SNS_ST_SIZE) |
1260 S(GPRS_SNS_ST_CONFIG_BSS),
1261 .name = "SIZE",
1262 .action = ns2_sns_st_size,
1263 .onenter = ns2_sns_st_size_onenter,
1264 },
1265 [GPRS_SNS_ST_CONFIG_BSS] = {
1266 .in_event_mask = S(GPRS_SNS_EV_CONFIG_ACK),
1267 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
1268 S(GPRS_SNS_ST_CONFIG_BSS) |
1269 S(GPRS_SNS_ST_CONFIG_SGSN) |
1270 S(GPRS_SNS_ST_SIZE),
1271 .name = "CONFIG_BSS",
1272 .action = ns2_sns_st_config_bss,
1273 .onenter = ns2_sns_st_config_bss_onenter,
1274 },
1275 [GPRS_SNS_ST_CONFIG_SGSN] = {
1276 .in_event_mask = S(GPRS_SNS_EV_CONFIG) |
1277 S(GPRS_SNS_EV_CONFIG_END),
1278 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
1279 S(GPRS_SNS_ST_CONFIG_SGSN) |
1280 S(GPRS_SNS_ST_CONFIGURED) |
1281 S(GPRS_SNS_ST_SIZE),
1282 .name = "CONFIG_SGSN",
1283 .action = ns2_sns_st_config_sgsn,
1284 },
1285 [GPRS_SNS_ST_CONFIGURED] = {
1286 .in_event_mask = S(GPRS_SNS_EV_ADD) |
1287 S(GPRS_SNS_EV_DELETE) |
1288 S(GPRS_SNS_EV_CHANGE_WEIGHT),
Alexander Couzense03d8632020-12-06 03:31:44 +01001289 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
1290 S(GPRS_SNS_ST_SIZE),
Alexander Couzens6a161492020-07-12 13:45:50 +02001291 .name = "CONFIGURED",
1292 .action = ns2_sns_st_configured,
1293 .onenter = ns2_sns_st_configured_onenter,
1294 },
1295};
1296
1297static int ns2_sns_fsm_bss_timer_cb(struct osmo_fsm_inst *fi)
1298{
1299 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
1300 struct gprs_ns2_inst *nsi = nse->nsi;
1301
1302 switch (fi->T) {
1303 case 1:
1304 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_SIZE, nsi->timeout[NS_TOUT_TSNS_PROV], 1);
1305 break;
1306 case 2:
1307 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIG_BSS, nsi->timeout[NS_TOUT_TSNS_PROV], 2);
1308 break;
1309 }
1310 return 0;
1311}
1312
1313static void ns2_sns_st_all_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1314{
Alexander Couzense769f522020-12-07 07:37:07 +01001315 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
Alexander Couzens6a161492020-07-12 13:45:50 +02001316 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
1317
1318 /* reset when receiving GPRS_SNS_EV_NO_NSVC */
Alexander Couzense769f522020-12-07 07:37:07 +01001319 switch (event) {
1320 case GPRS_SNS_EV_NO_NSVC:
1321 if (!gss->reselection_running)
1322 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_SELECT_ENDPOINT, NULL);
1323 break;
1324 case GPRS_SNS_EV_SELECT_ENDPOINT:
1325 /* tear down previous state
1326 * gprs_ns2_free_nsvcs() will trigger NO_NSVC, prevent this from triggering a reselection */
1327 gss->reselection_running = true;
1328 gprs_ns2_free_nsvcs(nse);
1329
1330 /* Choose the next sns endpoint. */
1331 if (llist_empty(&gss->sns_endpoints)) {
1332 gss->initial = NULL;
1333 ns2_prim_status_ind(gss->nse, NULL, 0, NS_AFF_CAUSE_SNS_NO_ENDPOINTS);
1334 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 3);
1335 return;
1336 } else if (!gss->initial) {
1337 gss->initial = llist_first_entry(&gss->sns_endpoints, struct sns_endpoint, list);
1338 } else if (gss->initial->list.next == &gss->sns_endpoints) {
1339 /* last entry, continue with first */
1340 gss->initial = llist_first_entry(&gss->sns_endpoints, struct sns_endpoint, list);
1341 } else {
1342 /* next element is an entry */
1343 gss->initial = llist_entry(gss->initial->list.next, struct sns_endpoint, list);
1344 }
1345
1346 gss->reselection_running = false;
1347 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_SIZE, nse->nsi->timeout[NS_TOUT_TSNS_PROV], 1);
1348 break;
1349 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001350}
1351
1352static struct osmo_fsm gprs_ns2_sns_bss_fsm = {
1353 .name = "GPRS-NS2-SNS-BSS",
1354 .states = ns2_sns_bss_states,
1355 .num_states = ARRAY_SIZE(ns2_sns_bss_states),
Alexander Couzense769f522020-12-07 07:37:07 +01001356 .allstate_event_mask = S(GPRS_SNS_EV_NO_NSVC) |
1357 S(GPRS_SNS_EV_SELECT_ENDPOINT),
Alexander Couzens6a161492020-07-12 13:45:50 +02001358 .allstate_action = ns2_sns_st_all_action,
1359 .cleanup = NULL,
1360 .timer_cb = ns2_sns_fsm_bss_timer_cb,
1361 /* .log_subsys = DNS, "is not constant" */
1362 .event_names = gprs_sns_event_names,
1363 .pre_term = NULL,
1364 .log_subsys = DLNS,
1365};
1366
Harald Welte5bef2cc2020-09-18 22:33:24 +02001367/*! Allocate an IP-SNS FSM for the BSS side.
1368 * \param[in] nse NS Entity in which the FSM runs
1369 * \param[in] id string identifier
1370 * \retruns FSM instance on success; NULL on error */
Alexander Couzens6a161492020-07-12 13:45:50 +02001371struct osmo_fsm_inst *ns2_sns_bss_fsm_alloc(struct gprs_ns2_nse *nse,
1372 const char *id)
1373{
1374 struct osmo_fsm_inst *fi;
1375 struct ns2_sns_state *gss;
1376
1377 fi = osmo_fsm_inst_alloc(&gprs_ns2_sns_bss_fsm, nse, NULL, LOGL_DEBUG, id);
1378 if (!fi)
1379 return fi;
1380
1381 gss = talloc_zero(fi, struct ns2_sns_state);
1382 if (!gss)
1383 goto err;
1384
1385 fi->priv = gss;
1386 gss->nse = nse;
Alexander Couzense769f522020-12-07 07:37:07 +01001387 INIT_LLIST_HEAD(&gss->sns_endpoints);
Alexander Couzens6a161492020-07-12 13:45:50 +02001388
1389 return fi;
1390err:
1391 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
1392 return NULL;
1393}
1394
Harald Welte5bef2cc2020-09-18 22:33:24 +02001395/*! main entry point for receiving SNS messages from the network.
1396 * \param[in] nsvc NS-VC on which the message was received
1397 * \param[in] msg message buffer of the IP-SNS message
1398 * \param[in] tp parsed TLV structure of message
1399 * \retruns 0 on success; negative on error */
Alexander Couzens6a161492020-07-12 13:45:50 +02001400int gprs_ns2_sns_rx(struct gprs_ns2_vc *nsvc, struct msgb *msg, struct tlv_parsed *tp)
1401{
1402 struct gprs_ns2_nse *nse = nsvc->nse;
1403 struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h;
1404 uint16_t nsei = nsvc->nse->nsei;
1405 struct osmo_fsm_inst *fi;
1406
1407 if (!nse->bss_sns_fi) {
1408 LOGP(DLNS, LOGL_NOTICE, "NSEI=%u Rx %s for NS Instance that has no SNS!\n",
1409 nsvc->nse->nsei, get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
1410 return -EINVAL;
1411 }
1412
1413 LOGP(DLNS, LOGL_DEBUG, "NSEI=%u Rx SNS PDU type %s\n", nsei,
1414 get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
1415
1416 /* FIXME: how to resolve SNS FSM Instance by NSEI (SGSN)? */
1417 fi = nse->bss_sns_fi;
1418
1419 switch (nsh->pdu_type) {
1420 case SNS_PDUT_SIZE:
1421 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_SIZE, tp);
1422 break;
1423 case SNS_PDUT_SIZE_ACK:
1424 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_SIZE_ACK, tp);
1425 break;
1426 case SNS_PDUT_CONFIG:
1427 if (nsh->data[0] & 0x01)
1428 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_CONFIG_END, tp);
1429 else
1430 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_CONFIG, tp);
1431 break;
1432 case SNS_PDUT_CONFIG_ACK:
1433 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_CONFIG_ACK, tp);
1434 break;
1435 case SNS_PDUT_ADD:
1436 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_ADD, tp);
1437 break;
1438 case SNS_PDUT_DELETE:
1439 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_DELETE, tp);
1440 break;
1441 case SNS_PDUT_CHANGE_WEIGHT:
1442 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_CHANGE_WEIGHT, tp);
1443 break;
1444 case SNS_PDUT_ACK:
1445 LOGP(DLNS, LOGL_NOTICE, "NSEI=%u Rx unsupported SNS PDU type %s\n", nsei,
1446 get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
1447 break;
1448 default:
1449 LOGP(DLNS, LOGL_ERROR, "NSEI=%u Rx unknown SNS PDU type %s\n", nsei,
1450 get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
1451 return -EINVAL;
1452 }
1453
1454 return 0;
1455}
1456
1457#include <osmocom/vty/vty.h>
1458#include <osmocom/vty/misc.h>
1459
1460static void vty_dump_sns_ip4(struct vty *vty, const struct gprs_ns_ie_ip4_elem *ip4)
1461{
1462 struct in_addr in = { .s_addr = ip4->ip_addr };
1463 vty_out(vty, " %s:%u, Signalling Weight: %u, Data Weight: %u%s",
1464 inet_ntoa(in), ntohs(ip4->udp_port), ip4->sig_weight, ip4->data_weight, VTY_NEWLINE);
1465}
1466
1467static void vty_dump_sns_ip6(struct vty *vty, const struct gprs_ns_ie_ip6_elem *ip6)
1468{
1469 char ip_addr[INET6_ADDRSTRLEN] = {};
1470 if (!inet_ntop(AF_INET6, &ip6->ip_addr, ip_addr, (INET6_ADDRSTRLEN)))
1471 strcpy(ip_addr, "Invalid IPv6");
1472
1473 vty_out(vty, " %s:%u, Signalling Weight: %u, Data Weight: %u%s",
1474 ip_addr, ntohs(ip6->udp_port), ip6->sig_weight, ip6->data_weight, VTY_NEWLINE);
1475}
1476
Harald Welte5bef2cc2020-09-18 22:33:24 +02001477/*! Dump the IP-SNS state to a vty.
1478 * \param[in] vty VTY to which the state shall be printed
1479 * \param[in] nse NS Entity whose IP-SNS state shall be printed
1480 * \param[in] stats Whether or not statistics shall also be printed */
Alexander Couzens6a161492020-07-12 13:45:50 +02001481void gprs_ns2_sns_dump_vty(struct vty *vty, const struct gprs_ns2_nse *nse, bool stats)
1482{
1483 struct ns2_sns_state *gss;
1484 unsigned int i;
1485
1486 if (!nse->bss_sns_fi)
1487 return;
1488
1489 vty_out_fsm_inst(vty, nse->bss_sns_fi);
1490 gss = (struct ns2_sns_state *) nse->bss_sns_fi->priv;
1491
1492 vty_out(vty, "Maximum number of remote NS-VCs: %zu, IPv4 Endpoints: %zu, IPv6 Endpoints: %zu%s",
1493 gss->num_max_nsvcs, gss->num_max_ip4_remote, gss->num_max_ip6_remote, VTY_NEWLINE);
1494
1495 if (gss->num_ip4_local && gss->num_ip4_remote) {
1496 vty_out(vty, "Local IPv4 Endpoints:%s", VTY_NEWLINE);
1497 for (i = 0; i < gss->num_ip4_local; i++)
1498 vty_dump_sns_ip4(vty, &gss->ip4_local[i]);
1499
1500 vty_out(vty, "Remote IPv4 Endpoints:%s", VTY_NEWLINE);
1501 for (i = 0; i < gss->num_ip4_remote; i++)
1502 vty_dump_sns_ip4(vty, &gss->ip4_remote[i]);
1503 }
1504
1505 if (gss->num_ip6_local && gss->num_ip6_remote) {
1506 vty_out(vty, "Local IPv6 Endpoints:%s", VTY_NEWLINE);
1507 for (i = 0; i < gss->num_ip6_local; i++)
1508 vty_dump_sns_ip6(vty, &gss->ip6_local[i]);
1509
1510 vty_out(vty, "Remote IPv6 Endpoints:%s", VTY_NEWLINE);
1511 for (i = 0; i < gss->num_ip6_remote; i++)
1512 vty_dump_sns_ip6(vty, &gss->ip6_remote[i]);
1513 }
1514}
1515
Alexander Couzense769f522020-12-07 07:37:07 +01001516static struct sns_endpoint *ns2_get_sns_endpoint(struct ns2_sns_state *state,
1517 const struct osmo_sockaddr *saddr)
1518{
1519 struct sns_endpoint *endpoint;
1520
1521 llist_for_each_entry(endpoint, &state->sns_endpoints, list) {
1522 if (!osmo_sockaddr_cmp(saddr, &endpoint->saddr))
1523 return endpoint;
1524 }
1525
1526 return NULL;
1527}
1528
1529/*! gprs_ns2_sns_add_endpoint
1530 * \param[in] nse
1531 * \param[in] sockaddr
1532 * \return
1533 */
1534int gprs_ns2_sns_add_endpoint(struct gprs_ns2_nse *nse,
1535 const struct osmo_sockaddr *saddr)
1536{
1537 struct ns2_sns_state *gss;
1538 struct sns_endpoint *endpoint;
1539 bool do_selection = false;
1540
1541 if (nse->ll != GPRS_NS2_LL_UDP) {
1542 return -EINVAL;
1543 }
1544
1545 if (nse->dialect != NS2_DIALECT_SNS) {
1546 return -EINVAL;
1547 }
1548
1549 gss = nse->bss_sns_fi->priv;
1550
1551 if (ns2_get_sns_endpoint(gss, saddr))
1552 return -EADDRINUSE;
1553
1554 endpoint = talloc_zero(nse->bss_sns_fi->priv, struct sns_endpoint);
1555 if (!endpoint)
1556 return -ENOMEM;
1557
1558 endpoint->saddr = *saddr;
1559 if (llist_empty(&gss->sns_endpoints))
1560 do_selection = true;
1561
1562 llist_add_tail(&endpoint->list, &gss->sns_endpoints);
1563 if (do_selection)
1564 osmo_fsm_inst_dispatch(nse->bss_sns_fi, GPRS_SNS_EV_SELECT_ENDPOINT, NULL);
1565
1566 return 0;
1567}
1568
1569/*! gprs_ns2_sns_del_endpoint
1570 * \param[in] nse
1571 * \param[in] sockaddr
1572 * \return 0 on success, otherwise < 0
1573 */
1574int gprs_ns2_sns_del_endpoint(struct gprs_ns2_nse *nse,
1575 const struct osmo_sockaddr *saddr)
1576{
1577 struct ns2_sns_state *gss;
1578 struct sns_endpoint *endpoint;
1579
1580 if (nse->ll != GPRS_NS2_LL_UDP) {
1581 return -EINVAL;
1582 }
1583
1584 if (nse->dialect != NS2_DIALECT_SNS) {
1585 return -EINVAL;
1586 }
1587
1588 gss = nse->bss_sns_fi->priv;
1589 endpoint = ns2_get_sns_endpoint(gss, saddr);
1590 if (!endpoint)
1591 return -ENOENT;
1592
1593 /* if this is an unused SNS endpoint it's done */
1594 if (gss->initial != endpoint) {
1595 llist_del(&endpoint->list);
1596 talloc_free(endpoint);
1597 return 0;
1598 }
1599
1600 /* gprs_ns2_free_nsvcs() will trigger GPRS_SNS_EV_NO_NSVC on the last NS-VC
1601 * and restart SNS SIZE procedure which selects a new initial */
1602 LOGP(DLNS, LOGL_INFO, "Current in-use SNS endpoint is being removed."
1603 "Closing all NS-VC and restart SNS-SIZE procedure"
1604 "with a remaining SNS endpoint.\n");
1605
1606 /* Continue with the next endpoint in the list.
1607 * Special case if the endpoint is at the start or end of the list */
1608 if (endpoint->list.prev == &gss->sns_endpoints ||
1609 endpoint->list.next == &gss->sns_endpoints)
1610 gss->initial = NULL;
1611 else
1612 gss->initial = llist_entry(endpoint->list.next->prev,
1613 struct sns_endpoint,
1614 list);
1615
1616 llist_del(&endpoint->list);
1617 gprs_ns2_free_nsvcs(nse);
1618 talloc_free(endpoint);
1619
1620 return 0;
1621}
1622
1623/*! gprs_ns2_sns_count
1624 * \param[in] nse NS Entity whose IP-SNS endpoints shall be printed
1625 * \return the count of endpoints or < 0 if NSE doesn't contain sns.
1626 */
1627int gprs_ns2_sns_count(struct gprs_ns2_nse *nse)
1628{
1629 struct ns2_sns_state *gss;
1630 struct sns_endpoint *endpoint;
1631 int count = 0;
1632
1633 if (nse->ll != GPRS_NS2_LL_UDP) {
1634 return -EINVAL;
1635 }
1636
1637 if (nse->dialect != NS2_DIALECT_SNS) {
1638 return -EINVAL;
1639 }
1640
1641 gss = nse->bss_sns_fi->priv;
1642 llist_for_each_entry(endpoint, &gss->sns_endpoints, list)
1643 count++;
1644
1645 return count;
1646}
1647
Alexander Couzens6a161492020-07-12 13:45:50 +02001648/* initialize osmo_ctx on main tread */
1649static __attribute__((constructor)) void on_dso_load_ctx(void)
1650{
1651 OSMO_ASSERT(osmo_fsm_register(&gprs_ns2_sns_bss_fsm) == 0);
1652}