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