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