blob: ceff11518eca9c8e7800140bc783a05cca2d5524 [file] [log] [blame]
Alexander Couzens6a161492020-07-12 13:45:50 +02001/*! \file gprs_ns2_sns.c
2 * NS Sub-Network Service Protocol implementation
3 * 3GPP TS 08.16 version 8.0.1 Release 1999 / ETSI TS 101 299 V8.0.1 (2002-05)
4 * as well as its successor 3GPP TS 48.016 */
5
6/* (C) 2018 by Harald Welte <laforge@gnumonks.org>
7 * (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
8 * Author: Alexander Couzens <lynxis@fe80.eu>
9 *
10 * All Rights Reserved
11 *
12 * SPDX-License-Identifier: GPL-2.0+
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program. If not, see <http://www.gnu.org/licenses/>.
26 *
27 */
28
29/* The BSS NSE only has one SGSN IP address configured, and it will use the SNS procedures
30 * to communicated its local IPs/ports as well as all the SGSN side IPs/ports and
31 * associated weights. The BSS then uses this to establish a full mesh
32 * of NSVCs between all BSS-side IPs/ports and SGSN-side IPs/ports.
33 *
34 * Known limitation/expectation/bugs:
35 * - No concurrent dual stack. It supports either IPv4 or IPv6, but not both at the same time.
36 * - SNS Add/Change/Delete: Doesn't answer on the same NSVC as received SNS ADD/CHANGE/DELETE PDUs.
37 * - SNS Add/Change/Delete: Doesn't communicated the failed IPv4/IPv6 entries on the SNS_ACK.
38 */
39
40#include <errno.h>
41
42#include <netinet/in.h>
43#include <arpa/inet.h>
44#include <stdint.h>
45
46#include <osmocom/core/fsm.h>
47#include <osmocom/core/msgb.h>
48#include <osmocom/core/socket.h>
Alexander Couzens412bc342020-11-19 05:24:37 +010049#include <osmocom/core/sockaddr_str.h>
Alexander Couzens6a161492020-07-12 13:45:50 +020050#include <osmocom/gsm/tlv.h>
51#include <osmocom/gprs/gprs_msgb.h>
52#include <osmocom/gprs/gprs_ns2.h>
53#include <osmocom/gprs/protocol/gsm_08_16.h>
54
55#include "gprs_ns2_internal.h"
56
57#define S(x) (1 << (x))
58
59enum ns2_sns_type {
60 IPv4,
61 IPv6,
62};
63
64enum gprs_sns_bss_state {
65 GPRS_SNS_ST_UNCONFIGURED,
66 GPRS_SNS_ST_SIZE, /*!< SNS-SIZE procedure ongoing */
67 GPRS_SNS_ST_CONFIG_BSS, /*!< SNS-CONFIG procedure (BSS->SGSN) ongoing */
68 GPRS_SNS_ST_CONFIG_SGSN, /*!< SNS-CONFIG procedure (SGSN->BSS) ongoing */
69 GPRS_SNS_ST_CONFIGURED,
70};
71
72enum gprs_sns_event {
Alexander Couzense769f522020-12-07 07:37:07 +010073 GPRS_SNS_EV_SELECT_ENDPOINT, /*!< Select a SNS endpoint from the list */
Alexander Couzens6a161492020-07-12 13:45:50 +020074 GPRS_SNS_EV_SIZE,
75 GPRS_SNS_EV_SIZE_ACK,
76 GPRS_SNS_EV_CONFIG,
77 GPRS_SNS_EV_CONFIG_END, /*!< SNS-CONFIG with end flag received */
78 GPRS_SNS_EV_CONFIG_ACK,
79 GPRS_SNS_EV_ADD,
80 GPRS_SNS_EV_DELETE,
81 GPRS_SNS_EV_CHANGE_WEIGHT,
82 GPRS_SNS_EV_NO_NSVC,
83};
84
85static const struct value_string gprs_sns_event_names[] = {
Alexander Couzense769f522020-12-07 07:37:07 +010086 { GPRS_SNS_EV_SELECT_ENDPOINT, "SELECT_ENDPOINT" },
Alexander Couzens6a161492020-07-12 13:45:50 +020087 { GPRS_SNS_EV_SIZE, "SIZE" },
88 { GPRS_SNS_EV_SIZE_ACK, "SIZE_ACK" },
89 { GPRS_SNS_EV_CONFIG, "CONFIG" },
90 { GPRS_SNS_EV_CONFIG_END, "CONFIG_END" },
91 { GPRS_SNS_EV_CONFIG_ACK, "CONFIG_ACK" },
92 { GPRS_SNS_EV_ADD, "ADD" },
93 { GPRS_SNS_EV_DELETE, "DELETE" },
94 { GPRS_SNS_EV_CHANGE_WEIGHT, "CHANGE_WEIGHT" },
Pau Espin Pedrol0a446a12020-10-27 13:30:08 +010095 { GPRS_SNS_EV_NO_NSVC, "NO_NSVC" },
Alexander Couzens6a161492020-07-12 13:45:50 +020096 { 0, NULL }
97};
98
Alexander Couzense769f522020-12-07 07:37:07 +010099struct sns_endpoint {
100 struct llist_head list;
101 struct osmo_sockaddr saddr;
102};
103
Alexander Couzens6a161492020-07-12 13:45:50 +0200104struct ns2_sns_state {
105 struct gprs_ns2_nse *nse;
106
107 enum ns2_sns_type ip;
108
Alexander Couzense769f522020-12-07 07:37:07 +0100109 /* holds the list of initial SNS endpoints */
110 struct llist_head sns_endpoints;
111 /* prevent recursive reselection */
112 bool reselection_running;
113
114 /* The current initial SNS endpoints.
115 * The initial connection will be moved into the NSE
116 * if configured via SNS. Otherwise it will be removed
117 * in configured state. */
118 struct sns_endpoint *initial;
Alexander Couzens6a161492020-07-12 13:45:50 +0200119 /* all SNS PDU will be sent over this nsvc */
120 struct gprs_ns2_vc *sns_nsvc;
Alexander Couzens81ae0aa2020-12-07 05:49:43 +0100121 /* iterate over the binds after all remote has been tested */
122 int bind_offset;
Alexander Couzens90ee9632020-12-07 06:18:32 +0100123 /* timer N */
124 int N;
Alexander Couzens6a161492020-07-12 13:45:50 +0200125
126 /* local configuration to send to the remote end */
127 struct gprs_ns_ie_ip4_elem *ip4_local;
128 size_t num_ip4_local;
129
130 /* local configuration to send to the remote end */
131 struct gprs_ns_ie_ip6_elem *ip6_local;
132 size_t num_ip6_local;
133
134 /* local configuration about our capabilities in terms of connections to
135 * remote (SGSN) side */
136 size_t num_max_nsvcs;
137 size_t num_max_ip4_remote;
138 size_t num_max_ip6_remote;
139
140 /* remote configuration as received */
141 struct gprs_ns_ie_ip4_elem *ip4_remote;
142 unsigned int num_ip4_remote;
143
144 /* remote configuration as received */
145 struct gprs_ns_ie_ip6_elem *ip6_remote;
146 unsigned int num_ip6_remote;
147};
148
149static inline struct gprs_ns2_nse *nse_inst_from_fi(struct osmo_fsm_inst *fi)
150{
151 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
152 return gss->nse;
153}
154
155/* helper function to compute the sum of all (data or signaling) weights */
156static int ip4_weight_sum(const struct gprs_ns_ie_ip4_elem *ip4, unsigned int num,
157 bool data_weight)
158{
159 unsigned int i;
160 int weight_sum = 0;
161
162 for (i = 0; i < num; i++) {
163 if (data_weight)
164 weight_sum += ip4[i].data_weight;
165 else
166 weight_sum += ip4[i].sig_weight;
167 }
168 return weight_sum;
169}
170#define ip4_weight_sum_data(x,y) ip4_weight_sum(x, y, true)
171#define ip4_weight_sum_sig(x,y) ip4_weight_sum(x, y, false)
172
173/* helper function to compute the sum of all (data or signaling) weights */
174static int ip6_weight_sum(const struct gprs_ns_ie_ip6_elem *ip6, unsigned int num,
175 bool data_weight)
176{
177 unsigned int i;
178 int weight_sum = 0;
179
180 for (i = 0; i < num; i++) {
181 if (data_weight)
182 weight_sum += ip6[i].data_weight;
183 else
184 weight_sum += ip6[i].sig_weight;
185 }
186 return weight_sum;
187}
188#define ip6_weight_sum_data(x,y) ip6_weight_sum(x, y, true)
189#define ip6_weight_sum_sig(x,y) ip6_weight_sum(x, y, false)
190
191static struct gprs_ns2_vc *nsvc_by_ip4_elem(struct gprs_ns2_nse *nse,
192 const struct gprs_ns_ie_ip4_elem *ip4)
193{
194 struct osmo_sockaddr sa;
195 /* copy over. Both data structures use network byte order */
196 sa.u.sin.sin_addr.s_addr = ip4->ip_addr;
197 sa.u.sin.sin_port = ip4->udp_port;
198 sa.u.sin.sin_family = AF_INET;
199
Alexander Couzens38b19e82020-09-23 23:56:37 +0200200 return gprs_ns2_nsvc_by_sockaddr_nse(nse, &sa);
Alexander Couzens6a161492020-07-12 13:45:50 +0200201}
202
203static struct gprs_ns2_vc *nsvc_by_ip6_elem(struct gprs_ns2_nse *nse,
204 const struct gprs_ns_ie_ip6_elem *ip6)
205{
206 struct osmo_sockaddr sa;
207 /* copy over. Both data structures use network byte order */
208 sa.u.sin6.sin6_addr = ip6->ip_addr;
209 sa.u.sin6.sin6_port = ip6->udp_port;
210 sa.u.sin6.sin6_family = AF_INET;
211
Alexander Couzens38b19e82020-09-23 23:56:37 +0200212 return gprs_ns2_nsvc_by_sockaddr_nse(nse, &sa);
Alexander Couzens6a161492020-07-12 13:45:50 +0200213}
214
Alexander Couzens125298f2020-10-11 21:22:42 +0200215/*! Return the initial SNS remote socket address
216 * \param nse NS Entity
217 * \return address of the initial SNS connection; NULL in case of error
218 */
219const struct osmo_sockaddr *gprs_ns2_nse_sns_remote(struct gprs_ns2_nse *nse)
220{
221 struct ns2_sns_state *gss;
222
223 if (!nse->bss_sns_fi)
224 return NULL;
225
226 gss = (struct ns2_sns_state *) nse->bss_sns_fi->priv;
Alexander Couzense769f522020-12-07 07:37:07 +0100227 return &gss->initial->saddr;
Alexander Couzens125298f2020-10-11 21:22:42 +0200228}
229
Alexander Couzens6a161492020-07-12 13:45:50 +0200230/*! called when a nsvc is beeing freed */
231void ns2_sns_free_nsvc(struct gprs_ns2_vc *nsvc)
232{
233 struct gprs_ns2_nse *nse;
234 struct gprs_ns2_vc *tmp;
235 struct ns2_sns_state *gss;
236 struct osmo_fsm_inst *fi = nsvc->nse->bss_sns_fi;
237
238 if (!fi)
239 return;
240
241 gss = (struct ns2_sns_state *) fi->priv;
242 if (nsvc != gss->sns_nsvc)
243 return;
244
245 nse = nsvc->nse;
246 if (nse->alive) {
247 /* choose a different sns nsvc */
248 llist_for_each_entry(tmp, &nse->nsvc, list) {
249 if (gprs_ns2_vc_is_unblocked(tmp))
250 gss->sns_nsvc = tmp;
251 }
252 } else {
Alexander Couzens6a161492020-07-12 13:45:50 +0200253 gss->sns_nsvc = NULL;
254 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_NO_NSVC, NULL);
255 }
256}
257
Daniel Willmanncf8371a2021-01-16 15:13:51 +0100258static void ns2_vc_create_ip(struct osmo_fsm_inst *fi, struct gprs_ns2_nse *nse, const struct osmo_sockaddr *remote,
259 uint8_t sig_weight, uint8_t data_weight)
Alexander Couzens6a161492020-07-12 13:45:50 +0200260{
261 struct gprs_ns2_inst *nsi = nse->nsi;
262 struct gprs_ns2_vc *nsvc;
263 struct gprs_ns2_vc_bind *bind;
Daniel Willmanncf8371a2021-01-16 15:13:51 +0100264
265 /* for every bind, create a connection if bind type == IP */
266 llist_for_each_entry(bind, &nsi->binding, list) {
267 if (bind->ll != GPRS_NS2_LL_UDP)
268 continue;
269 /* ignore failed connection */
270 nsvc = gprs_ns2_ip_connect_inactive(bind,
271 remote,
272 nse, 0);
273 if (!nsvc) {
274 LOGPFSML(fi, LOGL_ERROR, "SNS-CONFIG: Failed to create NSVC\n");
275 continue;
276 }
277
278 nsvc->sig_weight = sig_weight;
279 nsvc->data_weight = data_weight;
280 }
281}
282
283static void ns2_nsvc_create_ip4(struct osmo_fsm_inst *fi,
284 struct gprs_ns2_nse *nse,
285 const struct gprs_ns_ie_ip4_elem *ip4)
286{
Alexander Couzensc068d862020-10-12 04:11:51 +0200287 struct osmo_sockaddr remote = { };
Alexander Couzens6a161492020-07-12 13:45:50 +0200288 /* copy over. Both data structures use network byte order */
289 remote.u.sin.sin_family = AF_INET;
290 remote.u.sin.sin_addr.s_addr = ip4->ip_addr;
291 remote.u.sin.sin_port = ip4->udp_port;
292
Daniel Willmanncf8371a2021-01-16 15:13:51 +0100293 ns2_vc_create_ip(fi, nse, &remote, ip4->sig_weight, ip4->data_weight);
Alexander Couzens6a161492020-07-12 13:45:50 +0200294}
295
296static void ns2_nsvc_create_ip6(struct osmo_fsm_inst *fi,
297 struct gprs_ns2_nse *nse,
298 const struct gprs_ns_ie_ip6_elem *ip6)
299{
Alexander Couzens6a161492020-07-12 13:45:50 +0200300 struct osmo_sockaddr remote = {};
301 /* copy over. Both data structures use network byte order */
302 remote.u.sin6.sin6_family = AF_INET6;
303 remote.u.sin6.sin6_addr = ip6->ip_addr;
304 remote.u.sin6.sin6_port = ip6->udp_port;
305
Daniel Willmanncf8371a2021-01-16 15:13:51 +0100306 ns2_vc_create_ip(fi, nse, &remote, ip6->sig_weight, ip6->data_weight);
Alexander Couzens6a161492020-07-12 13:45:50 +0200307}
308
309
310static int create_missing_nsvcs(struct osmo_fsm_inst *fi)
311{
312 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
313 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
314 struct gprs_ns2_vc *nsvc;
315 struct gprs_ns2_vc_bind *bind;
316 struct osmo_sockaddr remote = { };
317 unsigned int i;
318
319 for (i = 0; i < gss->num_ip4_remote; i++) {
320 const struct gprs_ns_ie_ip4_elem *ip4 = &gss->ip4_remote[i];
321
322 remote.u.sin.sin_family = AF_INET;
323 remote.u.sin.sin_addr.s_addr = ip4->ip_addr;
324 remote.u.sin.sin_port = ip4->udp_port;
325
326 llist_for_each_entry(bind, &nse->nsi->binding, list) {
327 bool found = false;
Daniel Willmann967e2c12021-01-14 16:58:17 +0100328 if (bind->ll != GPRS_NS2_LL_UDP)
329 continue;
Alexander Couzens6a161492020-07-12 13:45:50 +0200330
331 llist_for_each_entry(nsvc, &nse->nsvc, list) {
332 if (nsvc->bind != bind)
333 continue;
334
Alexander Couzensc4229a42020-10-11 20:58:04 +0200335 if (!osmo_sockaddr_cmp(&remote, gprs_ns2_ip_vc_remote(nsvc))) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200336 found = true;
337 break;
338 }
339 }
340
341 if (!found) {
342 nsvc = gprs_ns2_ip_connect_inactive(bind, &remote, nse, 0);
343 if (!nsvc) {
344 /* TODO: add to a list to send back a NS-STATUS */
345 continue;
346 }
347 }
348
349 /* update data / signalling weight */
350 nsvc->data_weight = ip4->data_weight;
351 nsvc->sig_weight = ip4->sig_weight;
352 nsvc->sns_only = false;
353 }
354 }
355
356 for (i = 0; i < gss->num_ip6_remote; i++) {
357 const struct gprs_ns_ie_ip6_elem *ip6 = &gss->ip6_remote[i];
358
359 remote.u.sin6.sin6_family = AF_INET6;
360 remote.u.sin6.sin6_addr = ip6->ip_addr;
361 remote.u.sin6.sin6_port = ip6->udp_port;
362
363 llist_for_each_entry(bind, &nse->nsi->binding, list) {
364 bool found = false;
Daniel Willmann967e2c12021-01-14 16:58:17 +0100365 if (bind->ll != GPRS_NS2_LL_UDP)
366 continue;
Alexander Couzens6a161492020-07-12 13:45:50 +0200367
368 llist_for_each_entry(nsvc, &nse->nsvc, list) {
369 if (nsvc->bind != bind)
370 continue;
371
Alexander Couzensc4229a42020-10-11 20:58:04 +0200372 if (!osmo_sockaddr_cmp(&remote, gprs_ns2_ip_vc_remote(nsvc))) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200373 found = true;
374 break;
375 }
376 }
377
378 if (!found) {
379 nsvc = gprs_ns2_ip_connect_inactive(bind, &remote, nse, 0);
380 if (!nsvc) {
381 /* TODO: add to a list to send back a NS-STATUS */
382 continue;
383 }
384 }
385
386 /* update data / signalling weight */
387 nsvc->data_weight = ip6->data_weight;
388 nsvc->sig_weight = ip6->sig_weight;
389 nsvc->sns_only = false;
390 }
391 }
392
393
394 return 0;
395}
396
397/* Add a given remote IPv4 element to gprs_sns_state */
398static int add_remote_ip4_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip4_elem *ip4)
399{
400 unsigned int i;
401
402 if (gss->num_ip4_remote >= gss->num_max_ip4_remote)
403 return -NS_CAUSE_INVAL_NR_NS_VC;
404
405 /* check for duplicates */
406 for (i = 0; i < gss->num_ip4_remote; i++) {
407 if (memcmp(&gss->ip4_remote[i], ip4, sizeof(*ip4)))
408 continue;
409 /* TODO: log message duplicate */
410 /* TODO: check if this is the correct cause code */
411 return -NS_CAUSE_PROTO_ERR_UNSPEC;
412 }
413
414 gss->ip4_remote = talloc_realloc(gss, gss->ip4_remote, struct gprs_ns_ie_ip4_elem,
415 gss->num_ip4_remote+1);
416 gss->ip4_remote[gss->num_ip4_remote] = *ip4;
417 gss->num_ip4_remote += 1;
418 return 0;
419}
420
421/* Remove a given remote IPv4 element from gprs_sns_state */
422static int remove_remote_ip4_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip4_elem *ip4)
423{
424 unsigned int i;
425
426 for (i = 0; i < gss->num_ip4_remote; i++) {
427 if (memcmp(&gss->ip4_remote[i], ip4, sizeof(*ip4)))
428 continue;
429 /* all array elements < i remain as they are; all > i are shifted left by one */
430 memmove(&gss->ip4_remote[i], &gss->ip4_remote[i+1], gss->num_ip4_remote-i-1);
431 gss->num_ip4_remote -= 1;
432 return 0;
433 }
434 return -1;
435}
436
437/* update the weights for specified remote IPv4 */
438static int update_remote_ip4_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip4_elem *ip4)
439{
440 unsigned int i;
441
442 for (i = 0; i < gss->num_ip4_remote; i++) {
443 if (gss->ip4_remote[i].ip_addr != ip4->ip_addr ||
444 gss->ip4_remote[i].udp_port != ip4->udp_port)
445 continue;
446
447 gss->ip4_remote[i].sig_weight = ip4->sig_weight;
448 gss->ip4_remote[i].data_weight = ip4->data_weight;
449 return 0;
450 }
451 return -1;
452}
453
454/* Add a given remote IPv6 element to gprs_sns_state */
455static int add_remote_ip6_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip6_elem *ip6)
456{
457 if (gss->num_ip6_remote >= gss->num_max_ip6_remote)
458 return -NS_CAUSE_INVAL_NR_NS_VC;
459
460 gss->ip6_remote = talloc_realloc(gss, gss->ip6_remote, struct gprs_ns_ie_ip6_elem,
461 gss->num_ip6_remote+1);
462 gss->ip6_remote[gss->num_ip6_remote] = *ip6;
463 gss->num_ip6_remote += 1;
464 return 0;
465}
466
467/* Remove a given remote IPv6 element from gprs_sns_state */
468static int remove_remote_ip6_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip6_elem *ip6)
469{
470 unsigned int i;
471
472 for (i = 0; i < gss->num_ip6_remote; i++) {
473 if (memcmp(&gss->ip6_remote[i], ip6, sizeof(*ip6)))
474 continue;
475 /* all array elements < i remain as they are; all > i are shifted left by one */
476 memmove(&gss->ip6_remote[i], &gss->ip6_remote[i+1], gss->num_ip6_remote-i-1);
477 gss->num_ip6_remote -= 1;
478 return 0;
479 }
480 return -1;
481}
482
483/* update the weights for specified remote IPv6 */
484static int update_remote_ip6_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip6_elem *ip6)
485{
486 unsigned int i;
487
488 for (i = 0; i < gss->num_ip6_remote; i++) {
489 if (memcmp(&gss->ip6_remote[i].ip_addr, &ip6->ip_addr, sizeof(ip6->ip_addr)) ||
490 gss->ip6_remote[i].udp_port != ip6->udp_port)
491 continue;
492 gss->ip6_remote[i].sig_weight = ip6->sig_weight;
493 gss->ip6_remote[i].data_weight = ip6->data_weight;
494 return 0;
495 }
496 return -1;
497}
498
499static 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)
500{
501 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
502 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
503 struct gprs_ns2_vc *nsvc;
504 struct osmo_sockaddr sa = {};
Alexander Couzens9a4cf272020-10-11 20:48:04 +0200505 const struct osmo_sockaddr *remote;
Alexander Couzens6a161492020-07-12 13:45:50 +0200506 uint8_t new_signal;
507 uint8_t new_data;
508
509 /* TODO: Upon receiving an SNS-CHANGEWEIGHT PDU, if the resulting sum of the
510 * signalling weights of all the peer IP endpoints configured for this NSE is
511 * equal to zero or if the resulting sum of the data weights of all the peer IP
512 * endpoints configured for this NSE is equal to zero, the BSS/SGSN shall send an
513 * SNS-ACK PDU with a cause code of "Invalid weights". */
514
515 if (ip4) {
516 if (update_remote_ip4_elem(gss, ip4))
517 return -NS_CAUSE_UNKN_IP_EP;
518
519 /* copy over. Both data structures use network byte order */
520 sa.u.sin.sin_addr.s_addr = ip4->ip_addr;
521 sa.u.sin.sin_port = ip4->udp_port;
522 sa.u.sin.sin_family = AF_INET;
523 new_signal = ip4->sig_weight;
524 new_data = ip4->data_weight;
525 } else if (ip6) {
526 if (update_remote_ip6_elem(gss, ip6))
527 return -NS_CAUSE_UNKN_IP_EP;
528
529 /* copy over. Both data structures use network byte order */
530 sa.u.sin6.sin6_addr = ip6->ip_addr;
531 sa.u.sin6.sin6_port = ip6->udp_port;
532 sa.u.sin6.sin6_family = AF_INET6;
533 new_signal = ip6->sig_weight;
534 new_data = ip6->data_weight;
535 } else {
536 OSMO_ASSERT(false);
537 }
538
539 llist_for_each_entry(nsvc, &nse->nsvc, list) {
Alexander Couzensc4229a42020-10-11 20:58:04 +0200540 remote = gprs_ns2_ip_vc_remote(nsvc);
Alexander Couzens6a161492020-07-12 13:45:50 +0200541 /* all nsvc in NSE should be IP/UDP nsvc */
542 OSMO_ASSERT(remote);
543
544 if (osmo_sockaddr_cmp(&sa, remote))
545 continue;
546
547 LOGPFSML(fi, LOGL_INFO, "CHANGE-WEIGHT NS-VC %s data_weight %u->%u, sig_weight %u->%u\n",
548 gprs_ns2_ll_str(nsvc), nsvc->data_weight, new_data,
549 nsvc->sig_weight, new_signal);
550
551 nsvc->data_weight = new_data;
552 nsvc->sig_weight = new_signal;
553 }
554
555 return 0;
556}
557
558static int do_sns_delete(struct osmo_fsm_inst *fi,
559 const struct gprs_ns_ie_ip4_elem *ip4,
560 const struct gprs_ns_ie_ip6_elem *ip6)
561{
562 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
563 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
564 struct gprs_ns2_vc *nsvc, *tmp;
Alexander Couzens9a4cf272020-10-11 20:48:04 +0200565 const struct osmo_sockaddr *remote;
Alexander Couzens6a161492020-07-12 13:45:50 +0200566 struct osmo_sockaddr sa = {};
567
568 if (ip4) {
569 if (remove_remote_ip4_elem(gss, ip4) < 0)
570 return -NS_CAUSE_UNKN_IP_EP;
571 /* copy over. Both data structures use network byte order */
572 sa.u.sin.sin_addr.s_addr = ip4->ip_addr;
573 sa.u.sin.sin_port = ip4->udp_port;
574 sa.u.sin.sin_family = AF_INET;
575 } else if (ip6) {
576 if (remove_remote_ip6_elem(gss, ip6))
577 return -NS_CAUSE_UNKN_IP_EP;
578
579 /* copy over. Both data structures use network byte order */
580 sa.u.sin6.sin6_addr = ip6->ip_addr;
581 sa.u.sin6.sin6_port = ip6->udp_port;
582 sa.u.sin6.sin6_family = AF_INET6;
583 } else {
584 OSMO_ASSERT(false);
585 }
586
587 llist_for_each_entry_safe(nsvc, tmp, &nse->nsvc, list) {
Alexander Couzensc4229a42020-10-11 20:58:04 +0200588 remote = gprs_ns2_ip_vc_remote(nsvc);
Alexander Couzens6a161492020-07-12 13:45:50 +0200589 /* all nsvc in NSE should be IP/UDP nsvc */
590 OSMO_ASSERT(remote);
591 if (osmo_sockaddr_cmp(&sa, remote))
592 continue;
593
594 LOGPFSML(fi, LOGL_INFO, "DELETE NS-VC %s\n", gprs_ns2_ll_str(nsvc));
595 gprs_ns2_free_nsvc(nsvc);
596 }
597
598 return 0;
599}
600
601static int do_sns_add(struct osmo_fsm_inst *fi,
602 const struct gprs_ns_ie_ip4_elem *ip4,
603 const struct gprs_ns_ie_ip6_elem *ip6)
604{
605 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
606 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
607 struct gprs_ns2_vc *nsvc;
608 int rc = 0;
609
610 /* Upon receiving an SNS-ADD PDU, if the consequent number of IPv4 endpoints
611 * exceeds the number of IPv4 endpoints supported by the NSE, the NSE shall send
612 * an SNS-ACK PDU with a cause code set to "Invalid number of IP4 Endpoints". */
613 switch (gss->ip) {
614 case IPv4:
615 rc = add_remote_ip4_elem(gss, ip4);
616 break;
617 case IPv6:
618 rc = add_remote_ip6_elem(gss, ip6);
619 break;
620 default:
621 /* the gss->ip is initialized with the bss */
622 OSMO_ASSERT(false);
623 }
624
625 if (rc)
626 return rc;
627
628 /* Upon receiving an SNS-ADD PDU containing an already configured IP endpoint the
629 * NSE shall send an SNS-ACK PDU with the cause code "Protocol error -
630 * unspecified" */
631 switch (gss->ip) {
632 case IPv4:
633 nsvc = nsvc_by_ip4_elem(nse, ip4);
634 if (nsvc) {
635 /* the nsvc should be already in sync with the ip4 / ip6 elements */
636 return -NS_CAUSE_PROTO_ERR_UNSPEC;
637 }
638
639 /* TODO: failure case */
640 ns2_nsvc_create_ip4(fi, nse, ip4);
641 break;
642 case IPv6:
643 nsvc = nsvc_by_ip6_elem(nse, ip6);
644 if (nsvc) {
645 /* the nsvc should be already in sync with the ip4 / ip6 elements */
646 return -NS_CAUSE_PROTO_ERR_UNSPEC;
647 }
648
649 /* TODO: failure case */
650 ns2_nsvc_create_ip6(fi, nse, ip6);
651 break;
652 }
653
654 gprs_ns2_start_alive_all_nsvcs(nse);
655
656 return 0;
657}
658
659
660static void ns2_sns_st_unconfigured(struct osmo_fsm_inst *fi, uint32_t event, void *data)
661{
Alexander Couzense769f522020-12-07 07:37:07 +0100662 /* empty state - SNS Select will start by ns2_sns_st_all_action() */
Alexander Couzens6a161492020-07-12 13:45:50 +0200663}
664
665static void ns2_sns_st_size(struct osmo_fsm_inst *fi, uint32_t event, void *data)
666{
667 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
668 struct gprs_ns2_inst *nsi = nse->nsi;
669 struct tlv_parsed *tp = NULL;
670
671 switch (event) {
672 case GPRS_SNS_EV_SIZE_ACK:
673 tp = data;
674 if (TLVP_VAL_MINLEN(tp, NS_IE_CAUSE, 1)) {
675 LOGPFSML(fi, LOGL_ERROR, "SNS-SIZE-ACK with cause %s\n",
676 gprs_ns2_cause_str(*TLVP_VAL(tp, NS_IE_CAUSE)));
677 /* TODO: What to do? */
678 } else {
679 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIG_BSS,
680 nsi->timeout[NS_TOUT_TSNS_PROV], 2);
681 }
682 break;
683 default:
684 OSMO_ASSERT(0);
685 }
686}
687
Alexander Couzense769f522020-12-07 07:37:07 +0100688/* setup all dynamic SNS settings, create a new nsvc and send the SIZE */
Alexander Couzens6a161492020-07-12 13:45:50 +0200689static void ns2_sns_st_size_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
690{
691 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
Alexander Couzense769f522020-12-07 07:37:07 +0100692 struct gprs_ns_ie_ip4_elem *ip4_elems;
693 struct gprs_ns_ie_ip6_elem *ip6_elems;
694 struct gprs_ns2_vc_bind *bind;
695 struct gprs_ns2_inst *nsi = gss->nse->nsi;
696 struct osmo_sockaddr *remote;
697 const struct osmo_sockaddr *sa;
698 struct osmo_sockaddr local;
699 int count;
Alexander Couzens6a161492020-07-12 13:45:50 +0200700
Alexander Couzense769f522020-12-07 07:37:07 +0100701 /* on a generic failure, the timer callback will recover */
Alexander Couzens6a161492020-07-12 13:45:50 +0200702 if (old_state != GPRS_SNS_ST_UNCONFIGURED)
Daniel Willmann15c09a82020-11-03 23:05:43 +0100703 ns2_prim_status_ind(gss->nse, NULL, 0, NS_AFF_CAUSE_SNS_FAILURE);
Alexander Couzens6a161492020-07-12 13:45:50 +0200704
Alexander Couzense769f522020-12-07 07:37:07 +0100705 /* no initial available */
706 if (!gss->initial)
707 return;
708
709 remote = &gss->initial->saddr;
710
711 /* count how many bindings are available (only UDP binds) */
712 count = ns2_ip_count_bind(nsi, remote);
713 if (count == 0) {
714 /* TODO: logging */
715 return;
716 }
717
Alexander Couzens81ae0aa2020-12-07 05:49:43 +0100718 bind = ns2_ip_get_bind_by_index(nsi, remote, gss->bind_offset);
Alexander Couzense769f522020-12-07 07:37:07 +0100719 if (!bind) {
Alexander Couzens81ae0aa2020-12-07 05:49:43 +0100720 if (gss->bind_offset) {
721 gss->bind_offset = 0;
722 bind = ns2_ip_get_bind_by_index(nsi, remote, gss->bind_offset);
723 }
724
725 if (!bind)
726 return;
Alexander Couzense769f522020-12-07 07:37:07 +0100727 }
728
729 /* setup the NSVC */
730 if (!gss->sns_nsvc) {
731 gss->sns_nsvc = gprs_ns2_ip_bind_connect(bind, gss->nse, remote);
732 if (!gss->sns_nsvc)
733 return;
734 gss->sns_nsvc->sns_only = true;
735 }
736
737 switch (gss->ip) {
738 case IPv4:
739 ip4_elems = talloc_zero_size(fi, sizeof(struct gprs_ns_ie_ip4_elem) * count);
740 if (!ip4_elems)
741 return;
742
743 gss->ip4_local = ip4_elems;
744
745 llist_for_each_entry(bind, &nsi->binding, list) {
746 if (!gprs_ns2_is_ip_bind(bind))
747 continue;
748
749 sa = gprs_ns2_ip_bind_sockaddr(bind);
750 if (!sa)
751 continue;
752
753 if (sa->u.sas.ss_family != AF_INET)
754 continue;
755
756 /* check if this is an specific bind */
757 if (sa->u.sin.sin_addr.s_addr == 0) {
758 if (osmo_sockaddr_local_ip(&local, remote))
759 continue;
760
761 ip4_elems->ip_addr = local.u.sin.sin_addr.s_addr;
762 } else {
763 ip4_elems->ip_addr = sa->u.sin.sin_addr.s_addr;
764 }
765
766 ip4_elems->udp_port = sa->u.sin.sin_port;
767 ip4_elems->sig_weight = 2;
768 ip4_elems->data_weight = 1;
769 ip4_elems++;
770 }
771
772 gss->num_ip4_local = count;
773 gss->num_max_ip4_remote = 4;
774 gss->num_max_nsvcs = OSMO_MAX(gss->num_max_ip4_remote * gss->num_ip4_local, 8);
775 break;
776 case IPv6:
777 /* IPv6 */
778 ip6_elems = talloc_zero_size(fi, sizeof(struct gprs_ns_ie_ip6_elem) * count);
779 if (!ip6_elems)
780 return;
781
782 gss->ip6_local = ip6_elems;
783
784 llist_for_each_entry(bind, &nsi->binding, list) {
785 if (!gprs_ns2_is_ip_bind(bind))
786 continue;
787
788 sa = gprs_ns2_ip_bind_sockaddr(bind);
789 if (!sa)
790 continue;
791
792 if (sa->u.sas.ss_family != AF_INET6)
793 continue;
794
795 /* check if this is an specific bind */
796 if (IN6_IS_ADDR_UNSPECIFIED(&sa->u.sin6.sin6_addr)) {
797 if (osmo_sockaddr_local_ip(&local, remote))
798 continue;
799
800 ip6_elems->ip_addr = local.u.sin6.sin6_addr;
801 } else {
802 ip6_elems->ip_addr = sa->u.sin6.sin6_addr;
803 }
804
805 ip6_elems->udp_port = sa->u.sin.sin_port;
806 ip6_elems->sig_weight = 2;
807 ip6_elems->data_weight = 1;
808
809 ip6_elems++;
810 }
811 gss->num_ip6_local = count;
812 gss->num_max_ip6_remote = 4;
813 gss->num_max_nsvcs = OSMO_MAX(gss->num_max_ip6_remote * gss->num_ip6_local, 8);
814 break;
815 }
816
Alexander Couzens6a161492020-07-12 13:45:50 +0200817 if (gss->num_max_ip4_remote > 0)
818 ns2_tx_sns_size(gss->sns_nsvc, true, gss->num_max_nsvcs, gss->num_max_ip4_remote, -1);
819 else
820 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 +0200821}
822
823static void ns2_sns_st_config_bss(struct osmo_fsm_inst *fi, uint32_t event, void *data)
824{
825 struct tlv_parsed *tp = NULL;
826
827 switch (event) {
828 case GPRS_SNS_EV_CONFIG_ACK:
829 tp = (struct tlv_parsed *) data;
830 if (TLVP_VAL_MINLEN(tp, NS_IE_CAUSE, 1)) {
831 LOGPFSML(fi, LOGL_ERROR, "SNS-CONFIG-ACK with cause %s\n",
832 gprs_ns2_cause_str(*TLVP_VAL(tp, NS_IE_CAUSE)));
833 /* TODO: What to do? */
834 } else {
835 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIG_SGSN, 0, 0);
836 }
837 break;
838 default:
839 OSMO_ASSERT(0);
840 }
841}
842
843static void ns2_sns_st_config_bss_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
844{
845 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
846 /* Transmit SNS-CONFIG */
Alexander Couzens6a161492020-07-12 13:45:50 +0200847 switch (gss->ip) {
848 case IPv4:
849 ns2_tx_sns_config(gss->sns_nsvc, true,
Alexander Couzense78207f2020-12-07 06:19:29 +0100850 gss->ip4_local, gss->num_ip4_local,
851 NULL, 0);
Alexander Couzens6a161492020-07-12 13:45:50 +0200852 break;
853 case IPv6:
854 ns2_tx_sns_config(gss->sns_nsvc, true,
Alexander Couzense78207f2020-12-07 06:19:29 +0100855 NULL, 0,
856 gss->ip6_local, gss->num_ip6_local);
Alexander Couzens6a161492020-07-12 13:45:50 +0200857 break;
858 }
859}
860
861
862static void ns_sns_st_config_sgsn_ip4(struct osmo_fsm_inst *fi, uint32_t event, void *data)
863{
864 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
865 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
866 const struct gprs_ns_ie_ip4_elem *v4_list;
867 unsigned int num_v4;
868 struct tlv_parsed *tp = NULL;
869
870 uint8_t cause;
871
872 tp = (struct tlv_parsed *) data;
873
874 if (!TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
875 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
876 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
877 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
878 return;
879 }
880 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
881 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
882 /* realloc to the new size */
883 gss->ip4_remote = talloc_realloc(gss, gss->ip4_remote,
884 struct gprs_ns_ie_ip4_elem,
885 gss->num_ip4_remote+num_v4);
886 /* append the new entries to the end of the list */
887 memcpy(&gss->ip4_remote[gss->num_ip4_remote], v4_list, num_v4*sizeof(*v4_list));
888 gss->num_ip4_remote += num_v4;
889
890 LOGPFSML(fi, LOGL_INFO, "Rx SNS-CONFIG: Remote IPv4 list now %u entries\n",
891 gss->num_ip4_remote);
892 if (event == GPRS_SNS_EV_CONFIG_END) {
893 /* check if sum of data / sig weights == 0 */
894 if (ip4_weight_sum_data(gss->ip4_remote, gss->num_ip4_remote) == 0 ||
895 ip4_weight_sum_sig(gss->ip4_remote, gss->num_ip4_remote) == 0) {
896 cause = NS_CAUSE_INVAL_WEIGH;
897 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
898 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
899 return;
900 }
901 create_missing_nsvcs(fi);
902 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
903 /* start the test procedure on ALL NSVCs! */
904 gprs_ns2_start_alive_all_nsvcs(nse);
905 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIGURED, 0, 0);
906 } else {
907 /* just send CONFIG-ACK */
908 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
909 }
910}
911
912static void ns_sns_st_config_sgsn_ip6(struct osmo_fsm_inst *fi, uint32_t event, void *data)
913{
914 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
915 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
916 const struct gprs_ns_ie_ip6_elem *v6_list;
917 unsigned int num_v6;
918 struct tlv_parsed *tp = NULL;
919
920 uint8_t cause;
921
922 tp = (struct tlv_parsed *) data;
923
924 if (!TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
925 cause = NS_CAUSE_INVAL_NR_IPv6_EP;
926 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
927 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
928 return;
929 }
930 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
931 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
932 /* realloc to the new size */
933 gss->ip6_remote = talloc_realloc(gss, gss->ip6_remote,
934 struct gprs_ns_ie_ip6_elem,
935 gss->num_ip6_remote+num_v6);
936 /* append the new entries to the end of the list */
937 memcpy(&gss->ip6_remote[gss->num_ip6_remote], v6_list, num_v6*sizeof(*v6_list));
938 gss->num_ip6_remote += num_v6;
939
940 LOGPFSML(fi, LOGL_INFO, "Rx SNS-CONFIG: Remote IPv6 list now %u entries\n",
941 gss->num_ip6_remote);
942 if (event == GPRS_SNS_EV_CONFIG_END) {
943 /* check if sum of data / sig weights == 0 */
944 if (ip6_weight_sum_data(gss->ip6_remote, gss->num_ip6_remote) == 0 ||
945 ip6_weight_sum_sig(gss->ip6_remote, gss->num_ip6_remote) == 0) {
946 cause = NS_CAUSE_INVAL_WEIGH;
947 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
948 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
949 return;
950 }
951 create_missing_nsvcs(fi);
952 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
953 /* start the test procedure on ALL NSVCs! */
954 gprs_ns2_start_alive_all_nsvcs(nse);
955 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIGURED, 0, 0);
956 } else {
957 /* just send CONFIG-ACK */
958 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
959 }
960}
961
962static void ns2_sns_st_config_sgsn(struct osmo_fsm_inst *fi, uint32_t event, void *data)
963{
964 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
965
966 switch (event) {
967 case GPRS_SNS_EV_CONFIG_END:
968 case GPRS_SNS_EV_CONFIG:
969
970#if 0 /* part of incoming SNS-SIZE (doesn't happen on BSS side */
971 if (TLVP_PRESENT(tp, NS_IE_RESET_FLAG)) {
972 /* reset all existing config */
973 if (gss->ip4_remote)
974 talloc_free(gss->ip4_remote);
975 gss->num_ip4_remote = 0;
976 }
977#endif
978 /* TODO: reject IPv6 elements on IPv4 mode and vice versa */
979 switch (gss->ip) {
980 case IPv4:
981 ns_sns_st_config_sgsn_ip4(fi, event, data);
982 break;
983 case IPv6:
984 ns_sns_st_config_sgsn_ip6(fi, event, data);
985 break;
986 default:
987 OSMO_ASSERT(0);
988 }
989 break;
990 default:
991 OSMO_ASSERT(0);
992 }
993}
994
995/* called when receiving GPRS_SNS_EV_ADD in state configure */
996static void ns2_sns_st_configured_add(struct osmo_fsm_inst *fi,
997 struct ns2_sns_state *gss,
998 struct tlv_parsed *tp)
999{
1000 const struct gprs_ns_ie_ip4_elem *v4_list = NULL;
1001 const struct gprs_ns_ie_ip6_elem *v6_list = NULL;
1002 int num_v4 = 0, num_v6 = 0;
1003 uint8_t trans_id, cause = 0xff;
Harald Welte7da6ace2020-09-18 09:48:05 +02001004 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +02001005 int rc = 0;
1006
1007 /* TODO: refactor EV_ADD/CHANGE/REMOVE by
1008 * check uniqueness within the lists (no doublicate entries)
1009 * check not-known-by-us and sent back a list of unknown/known values
1010 * (abnormal behaviour according to 48.016)
1011 */
1012
1013 trans_id = *TLVP_VAL(tp, NS_IE_TRANS_ID);
1014 if (gss->ip == IPv4) {
1015 if (!TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
1016 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
1017 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1018 return;
1019 }
1020
1021 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
1022 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001023 for (i = 0; i < num_v4; i++) {
1024 unsigned int j;
Alexander Couzens6a161492020-07-12 13:45:50 +02001025 rc = do_sns_add(fi, &v4_list[i], NULL);
1026 if (rc < 0) {
1027 /* rollback/undo to restore previous state */
Harald Welte7da6ace2020-09-18 09:48:05 +02001028 for (j = 0; j < i; j++)
Alexander Couzens6a161492020-07-12 13:45:50 +02001029 do_sns_delete(fi, &v4_list[j], NULL);
1030 cause = -rc;
1031 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1032 break;
1033 }
1034 }
1035 } else { /* IPv6 */
1036 if (!TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
1037 cause = NS_CAUSE_INVAL_NR_IPv6_EP;
1038 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1039 return;
1040 }
1041
1042 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
1043 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001044 for (i = 0; i < num_v6; i++) {
1045 unsigned int j;
Alexander Couzens6a161492020-07-12 13:45:50 +02001046 rc = do_sns_add(fi, NULL, &v6_list[i]);
1047 if (rc < 0) {
1048 /* rollback/undo to restore previous state */
Harald Welte7da6ace2020-09-18 09:48:05 +02001049 for (j = 0; j < i; j++)
Alexander Couzens6a161492020-07-12 13:45:50 +02001050 do_sns_delete(fi, NULL, &v6_list[j]);
1051 cause = -rc;
1052 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1053 break;
1054 }
1055 }
1056 }
1057
1058 /* TODO: correct behaviour is to answer to the *same* NSVC from which the SNS_ADD was received */
1059 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, NULL, v4_list, num_v4, v6_list, num_v6);
1060}
1061
1062static void ns2_sns_st_configured_delete(struct osmo_fsm_inst *fi,
1063 struct ns2_sns_state *gss,
1064 struct tlv_parsed *tp)
1065{
1066 const struct gprs_ns_ie_ip4_elem *v4_list = NULL;
1067 const struct gprs_ns_ie_ip6_elem *v6_list = NULL;
1068 int num_v4 = 0, num_v6 = 0;
1069 uint8_t trans_id, cause = 0xff;
Harald Welte7da6ace2020-09-18 09:48:05 +02001070 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +02001071 int rc = 0;
1072
1073 /* TODO: split up delete into v4 + v6
1074 * TODO: check if IPv4_LIST or IP_ADDR(v4) is present on IPv6 and vice versa
1075 * TODO: check if IPv4_LIST/IPv6_LIST and IP_ADDR is present at the same time
1076 */
1077 trans_id = *TLVP_VAL(tp, NS_IE_TRANS_ID);
1078 if (gss->ip == IPv4) {
1079 if (TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
1080 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
1081 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001082 for ( i = 0; i < num_v4; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001083 rc = do_sns_delete(fi, &v4_list[i], NULL);
1084 if (rc < 0) {
1085 cause = -rc;
1086 /* continue to delete others */
1087 }
1088 }
1089 if (cause != 0xff) {
1090 /* TODO: create list of not-deleted and return it */
1091 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1092 return;
1093 }
1094
1095 } else if (TLVP_PRESENT(tp, NS_IE_IP_ADDR) && TLVP_LEN(tp, NS_IE_IP_ADDR) == 5) {
1096 /* delete all NS-VCs for given IPv4 address */
1097 const uint8_t *ie = TLVP_VAL(tp, NS_IE_IP_ADDR);
1098 struct gprs_ns_ie_ip4_elem *ip4_remote;
1099 uint32_t ip_addr = *(uint32_t *)(ie+1);
1100 if (ie[0] != 0x01) { /* Address Type != IPv4 */
1101 cause = NS_CAUSE_UNKN_IP_ADDR;
1102 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1103 return;
1104 }
1105 /* make a copy as do_sns_delete() will change the array underneath us */
1106 ip4_remote = talloc_memdup(fi, gss->ip4_remote,
1107 gss->num_ip4_remote * sizeof(*v4_list));
Harald Welte7da6ace2020-09-18 09:48:05 +02001108 for (i = 0; i < gss->num_ip4_remote; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001109 if (ip4_remote[i].ip_addr == ip_addr) {
1110 rc = do_sns_delete(fi, &ip4_remote[i], NULL);
1111 if (rc < 0) {
1112 cause = -rc;
1113 /* continue to delete others */
1114 }
1115 }
1116 }
1117 talloc_free(ip4_remote);
1118 if (cause != 0xff) {
1119 /* TODO: create list of not-deleted and return it */
1120 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1121 return;
1122 }
1123 } else {
1124 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
1125 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1126 return;
1127 }
1128 } else { /* IPv6 */
1129 if (TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
1130 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
1131 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001132 for (i = 0; i < num_v6; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001133 rc = do_sns_delete(fi, NULL, &v6_list[i]);
1134 if (rc < 0) {
1135 cause = -rc;
1136 /* continue to delete others */
1137 }
1138 }
1139 if (cause != 0xff) {
1140 /* TODO: create list of not-deleted and return it */
1141 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1142 return;
1143 }
1144 } else if (TLVP_PRES_LEN(tp, NS_IE_IP_ADDR, 17)) {
1145 /* delete all NS-VCs for given IPv4 address */
1146 const uint8_t *ie = TLVP_VAL(tp, NS_IE_IP_ADDR);
1147 struct gprs_ns_ie_ip6_elem *ip6_remote;
1148 struct in6_addr ip6_addr;
Harald Welte7da6ace2020-09-18 09:48:05 +02001149 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +02001150 if (ie[0] != 0x02) { /* Address Type != IPv6 */
1151 cause = NS_CAUSE_UNKN_IP_ADDR;
1152 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1153 return;
1154 }
1155 memcpy(&ip6_addr, (ie+1), sizeof(struct in6_addr));
1156 /* make a copy as do_sns_delete() will change the array underneath us */
1157 ip6_remote = talloc_memdup(fi, gss->ip6_remote,
1158 gss->num_ip6_remote * sizeof(*v4_list));
Harald Welte7da6ace2020-09-18 09:48:05 +02001159 for (i = 0; i < gss->num_ip6_remote; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001160 if (!memcmp(&ip6_remote[i].ip_addr, &ip6_addr, sizeof(struct in6_addr))) {
1161 rc = do_sns_delete(fi, NULL, &ip6_remote[i]);
1162 if (rc < 0) {
1163 cause = -rc;
1164 /* continue to delete others */
1165 }
1166 }
1167 }
1168
1169 talloc_free(ip6_remote);
1170 if (cause != 0xff) {
1171 /* TODO: create list of not-deleted and return it */
1172 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1173 return;
1174 }
1175 } else {
1176 cause = NS_CAUSE_INVAL_NR_IPv6_EP;
1177 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1178 return;
1179 }
1180 }
1181 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, NULL, v4_list, num_v4, v6_list, num_v6);
1182}
1183
1184static void ns2_sns_st_configured_change(struct osmo_fsm_inst *fi,
1185 struct ns2_sns_state *gss,
1186 struct tlv_parsed *tp)
1187{
1188 const struct gprs_ns_ie_ip4_elem *v4_list = NULL;
1189 const struct gprs_ns_ie_ip6_elem *v6_list = NULL;
1190 int num_v4 = 0, num_v6 = 0;
1191 uint8_t trans_id, cause = 0xff;
1192 int rc = 0;
Harald Welte7da6ace2020-09-18 09:48:05 +02001193 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +02001194
1195 trans_id = *TLVP_VAL(tp, NS_IE_TRANS_ID);
1196 if (TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
1197 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
1198 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001199 for (i = 0; i < num_v4; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001200 rc = do_sns_change_weight(fi, &v4_list[i], NULL);
1201 if (rc < 0) {
1202 cause = -rc;
1203 /* continue to others */
1204 }
1205 }
1206 if (cause != 0xff) {
1207 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1208 return;
1209 }
1210 } else if (TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
1211 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
1212 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001213 for (i = 0; i < num_v6; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001214 rc = do_sns_change_weight(fi, NULL, &v6_list[i]);
1215 if (rc < 0) {
1216 cause = -rc;
1217 /* continue to others */
1218 }
1219 }
1220 if (cause != 0xff) {
1221 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1222 return;
1223 }
1224 } else {
1225 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
1226 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1227 return;
1228 }
1229 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, NULL, v4_list, num_v4, v6_list, num_v6);
1230}
1231
1232static void ns2_sns_st_configured(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1233{
1234 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
1235 struct tlv_parsed *tp = data;
1236
1237 switch (event) {
1238 case GPRS_SNS_EV_ADD:
1239 ns2_sns_st_configured_add(fi, gss, tp);
1240 break;
1241 case GPRS_SNS_EV_DELETE:
1242 ns2_sns_st_configured_delete(fi, gss, tp);
1243 break;
1244 case GPRS_SNS_EV_CHANGE_WEIGHT:
1245 ns2_sns_st_configured_change(fi, gss, tp);
1246 break;
1247 }
1248}
1249
1250static void ns2_sns_st_configured_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
1251{
1252 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
Daniel Willmann15c09a82020-11-03 23:05:43 +01001253 ns2_prim_status_ind(nse, NULL, 0, NS_AFF_CAUSE_SNS_CONFIGURED);
Alexander Couzens6a161492020-07-12 13:45:50 +02001254}
1255
1256static const struct osmo_fsm_state ns2_sns_bss_states[] = {
1257 [GPRS_SNS_ST_UNCONFIGURED] = {
Alexander Couzense769f522020-12-07 07:37:07 +01001258 .in_event_mask = 0, /* handled by all_state_action */
Alexander Couzens6a161492020-07-12 13:45:50 +02001259 .out_state_mask = S(GPRS_SNS_ST_SIZE),
1260 .name = "UNCONFIGURED",
1261 .action = ns2_sns_st_unconfigured,
1262 },
1263 [GPRS_SNS_ST_SIZE] = {
1264 .in_event_mask = S(GPRS_SNS_EV_SIZE_ACK),
1265 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
1266 S(GPRS_SNS_ST_SIZE) |
1267 S(GPRS_SNS_ST_CONFIG_BSS),
1268 .name = "SIZE",
1269 .action = ns2_sns_st_size,
1270 .onenter = ns2_sns_st_size_onenter,
1271 },
1272 [GPRS_SNS_ST_CONFIG_BSS] = {
1273 .in_event_mask = S(GPRS_SNS_EV_CONFIG_ACK),
1274 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
1275 S(GPRS_SNS_ST_CONFIG_BSS) |
1276 S(GPRS_SNS_ST_CONFIG_SGSN) |
1277 S(GPRS_SNS_ST_SIZE),
1278 .name = "CONFIG_BSS",
1279 .action = ns2_sns_st_config_bss,
1280 .onenter = ns2_sns_st_config_bss_onenter,
1281 },
1282 [GPRS_SNS_ST_CONFIG_SGSN] = {
1283 .in_event_mask = S(GPRS_SNS_EV_CONFIG) |
1284 S(GPRS_SNS_EV_CONFIG_END),
1285 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
1286 S(GPRS_SNS_ST_CONFIG_SGSN) |
1287 S(GPRS_SNS_ST_CONFIGURED) |
1288 S(GPRS_SNS_ST_SIZE),
1289 .name = "CONFIG_SGSN",
1290 .action = ns2_sns_st_config_sgsn,
1291 },
1292 [GPRS_SNS_ST_CONFIGURED] = {
1293 .in_event_mask = S(GPRS_SNS_EV_ADD) |
1294 S(GPRS_SNS_EV_DELETE) |
1295 S(GPRS_SNS_EV_CHANGE_WEIGHT),
Alexander Couzense03d8632020-12-06 03:31:44 +01001296 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
1297 S(GPRS_SNS_ST_SIZE),
Alexander Couzens6a161492020-07-12 13:45:50 +02001298 .name = "CONFIGURED",
1299 .action = ns2_sns_st_configured,
1300 .onenter = ns2_sns_st_configured_onenter,
1301 },
1302};
1303
1304static int ns2_sns_fsm_bss_timer_cb(struct osmo_fsm_inst *fi)
1305{
Alexander Couzens90ee9632020-12-07 06:18:32 +01001306 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
Alexander Couzens6a161492020-07-12 13:45:50 +02001307 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
1308 struct gprs_ns2_inst *nsi = nse->nsi;
1309
Alexander Couzens90ee9632020-12-07 06:18:32 +01001310 gss->N++;
Alexander Couzens6a161492020-07-12 13:45:50 +02001311 switch (fi->T) {
1312 case 1:
Alexander Couzensa367d082020-12-21 14:06:24 +01001313 if (gss->N >= nsi->timeout[NS_TOUT_TSNS_SIZE_RETRIES]) {
1314 LOGPFSML(fi, LOGL_ERROR, "NSE %d: Size retries failed. Selecting next IP-SNS endpoint.\n", nse->nsei);
Alexander Couzens90ee9632020-12-07 06:18:32 +01001315 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_SELECT_ENDPOINT, NULL);
Alexander Couzensa367d082020-12-21 14:06:24 +01001316 } else {
Alexander Couzenscc65a252020-12-21 14:03:58 +01001317 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_SIZE, nsi->timeout[NS_TOUT_TSNS_PROV], 1);
Alexander Couzensa367d082020-12-21 14:06:24 +01001318 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001319 break;
1320 case 2:
Alexander Couzensa367d082020-12-21 14:06:24 +01001321 if (gss->N >= nsi->timeout[NS_TOUT_TSNS_CONFIG_RETRIES]) {
1322 LOGPFSML(fi, LOGL_ERROR, "NSE %d: Config retries failed. Selecting next IP-SNS endpoint.\n", nse->nsei);
Alexander Couzens90ee9632020-12-07 06:18:32 +01001323 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_SELECT_ENDPOINT, NULL);
Alexander Couzensa367d082020-12-21 14:06:24 +01001324 } else {
Alexander Couzenscc65a252020-12-21 14:03:58 +01001325 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIG_BSS, nsi->timeout[NS_TOUT_TSNS_PROV], 2);
Alexander Couzensa367d082020-12-21 14:06:24 +01001326 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001327 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:
Alexander Couzens3ad73362020-12-21 13:53:00 +01001340 /* ignore reselection running */
1341 if (gss->reselection_running)
1342 break;
1343
1344 LOGPFSML(fi, LOGL_ERROR, "NSE %d: no remaining NSVC, resetting SNS FSM\n", nse->nsei);
1345 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_SELECT_ENDPOINT, NULL);
Alexander Couzense769f522020-12-07 07:37:07 +01001346 break;
1347 case GPRS_SNS_EV_SELECT_ENDPOINT:
1348 /* tear down previous state
1349 * gprs_ns2_free_nsvcs() will trigger NO_NSVC, prevent this from triggering a reselection */
1350 gss->reselection_running = true;
1351 gprs_ns2_free_nsvcs(nse);
1352
1353 /* Choose the next sns endpoint. */
1354 if (llist_empty(&gss->sns_endpoints)) {
1355 gss->initial = NULL;
1356 ns2_prim_status_ind(gss->nse, NULL, 0, NS_AFF_CAUSE_SNS_NO_ENDPOINTS);
1357 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 3);
1358 return;
1359 } else if (!gss->initial) {
1360 gss->initial = llist_first_entry(&gss->sns_endpoints, struct sns_endpoint, list);
Alexander Couzens81ae0aa2020-12-07 05:49:43 +01001361 gss->bind_offset = 0;
Alexander Couzense769f522020-12-07 07:37:07 +01001362 } else if (gss->initial->list.next == &gss->sns_endpoints) {
1363 /* last entry, continue with first */
1364 gss->initial = llist_first_entry(&gss->sns_endpoints, struct sns_endpoint, list);
Alexander Couzens81ae0aa2020-12-07 05:49:43 +01001365 gss->bind_offset++;
1366 gss->bind_offset %= ns2_ip_count_bind(nse->nsi, &gss->initial->saddr);
Alexander Couzense769f522020-12-07 07:37:07 +01001367 } else {
1368 /* next element is an entry */
1369 gss->initial = llist_entry(gss->initial->list.next, struct sns_endpoint, list);
1370 }
1371
1372 gss->reselection_running = false;
1373 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_SIZE, nse->nsi->timeout[NS_TOUT_TSNS_PROV], 1);
1374 break;
1375 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001376}
1377
1378static struct osmo_fsm gprs_ns2_sns_bss_fsm = {
1379 .name = "GPRS-NS2-SNS-BSS",
1380 .states = ns2_sns_bss_states,
1381 .num_states = ARRAY_SIZE(ns2_sns_bss_states),
Alexander Couzense769f522020-12-07 07:37:07 +01001382 .allstate_event_mask = S(GPRS_SNS_EV_NO_NSVC) |
1383 S(GPRS_SNS_EV_SELECT_ENDPOINT),
Alexander Couzens6a161492020-07-12 13:45:50 +02001384 .allstate_action = ns2_sns_st_all_action,
1385 .cleanup = NULL,
1386 .timer_cb = ns2_sns_fsm_bss_timer_cb,
1387 /* .log_subsys = DNS, "is not constant" */
1388 .event_names = gprs_sns_event_names,
1389 .pre_term = NULL,
1390 .log_subsys = DLNS,
1391};
1392
Harald Welte5bef2cc2020-09-18 22:33:24 +02001393/*! Allocate an IP-SNS FSM for the BSS side.
1394 * \param[in] nse NS Entity in which the FSM runs
1395 * \param[in] id string identifier
1396 * \retruns FSM instance on success; NULL on error */
Alexander Couzens6a161492020-07-12 13:45:50 +02001397struct osmo_fsm_inst *ns2_sns_bss_fsm_alloc(struct gprs_ns2_nse *nse,
1398 const char *id)
1399{
1400 struct osmo_fsm_inst *fi;
1401 struct ns2_sns_state *gss;
1402
1403 fi = osmo_fsm_inst_alloc(&gprs_ns2_sns_bss_fsm, nse, NULL, LOGL_DEBUG, id);
1404 if (!fi)
1405 return fi;
1406
1407 gss = talloc_zero(fi, struct ns2_sns_state);
1408 if (!gss)
1409 goto err;
1410
1411 fi->priv = gss;
1412 gss->nse = nse;
Alexander Couzense769f522020-12-07 07:37:07 +01001413 INIT_LLIST_HEAD(&gss->sns_endpoints);
Alexander Couzens6a161492020-07-12 13:45:50 +02001414
1415 return fi;
1416err:
1417 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
1418 return NULL;
1419}
1420
Harald Welte5bef2cc2020-09-18 22:33:24 +02001421/*! main entry point for receiving SNS messages from the network.
1422 * \param[in] nsvc NS-VC on which the message was received
1423 * \param[in] msg message buffer of the IP-SNS message
1424 * \param[in] tp parsed TLV structure of message
1425 * \retruns 0 on success; negative on error */
Alexander Couzens6a161492020-07-12 13:45:50 +02001426int gprs_ns2_sns_rx(struct gprs_ns2_vc *nsvc, struct msgb *msg, struct tlv_parsed *tp)
1427{
1428 struct gprs_ns2_nse *nse = nsvc->nse;
1429 struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h;
1430 uint16_t nsei = nsvc->nse->nsei;
1431 struct osmo_fsm_inst *fi;
1432
1433 if (!nse->bss_sns_fi) {
1434 LOGP(DLNS, LOGL_NOTICE, "NSEI=%u Rx %s for NS Instance that has no SNS!\n",
1435 nsvc->nse->nsei, get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
1436 return -EINVAL;
1437 }
1438
1439 LOGP(DLNS, LOGL_DEBUG, "NSEI=%u Rx SNS PDU type %s\n", nsei,
1440 get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
1441
1442 /* FIXME: how to resolve SNS FSM Instance by NSEI (SGSN)? */
1443 fi = nse->bss_sns_fi;
1444
1445 switch (nsh->pdu_type) {
1446 case SNS_PDUT_SIZE:
1447 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_SIZE, tp);
1448 break;
1449 case SNS_PDUT_SIZE_ACK:
1450 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_SIZE_ACK, tp);
1451 break;
1452 case SNS_PDUT_CONFIG:
1453 if (nsh->data[0] & 0x01)
1454 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_CONFIG_END, tp);
1455 else
1456 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_CONFIG, tp);
1457 break;
1458 case SNS_PDUT_CONFIG_ACK:
1459 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_CONFIG_ACK, tp);
1460 break;
1461 case SNS_PDUT_ADD:
1462 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_ADD, tp);
1463 break;
1464 case SNS_PDUT_DELETE:
1465 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_DELETE, tp);
1466 break;
1467 case SNS_PDUT_CHANGE_WEIGHT:
1468 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_CHANGE_WEIGHT, tp);
1469 break;
1470 case SNS_PDUT_ACK:
1471 LOGP(DLNS, LOGL_NOTICE, "NSEI=%u Rx unsupported SNS PDU type %s\n", nsei,
1472 get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
1473 break;
1474 default:
1475 LOGP(DLNS, LOGL_ERROR, "NSEI=%u Rx unknown SNS PDU type %s\n", nsei,
1476 get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
1477 return -EINVAL;
1478 }
1479
1480 return 0;
1481}
1482
1483#include <osmocom/vty/vty.h>
1484#include <osmocom/vty/misc.h>
1485
1486static void vty_dump_sns_ip4(struct vty *vty, const struct gprs_ns_ie_ip4_elem *ip4)
1487{
1488 struct in_addr in = { .s_addr = ip4->ip_addr };
1489 vty_out(vty, " %s:%u, Signalling Weight: %u, Data Weight: %u%s",
1490 inet_ntoa(in), ntohs(ip4->udp_port), ip4->sig_weight, ip4->data_weight, VTY_NEWLINE);
1491}
1492
1493static void vty_dump_sns_ip6(struct vty *vty, const struct gprs_ns_ie_ip6_elem *ip6)
1494{
1495 char ip_addr[INET6_ADDRSTRLEN] = {};
1496 if (!inet_ntop(AF_INET6, &ip6->ip_addr, ip_addr, (INET6_ADDRSTRLEN)))
1497 strcpy(ip_addr, "Invalid IPv6");
1498
1499 vty_out(vty, " %s:%u, Signalling Weight: %u, Data Weight: %u%s",
1500 ip_addr, ntohs(ip6->udp_port), ip6->sig_weight, ip6->data_weight, VTY_NEWLINE);
1501}
1502
Harald Welte5bef2cc2020-09-18 22:33:24 +02001503/*! Dump the IP-SNS state to a vty.
1504 * \param[in] vty VTY to which the state shall be printed
1505 * \param[in] nse NS Entity whose IP-SNS state shall be printed
1506 * \param[in] stats Whether or not statistics shall also be printed */
Alexander Couzens6a161492020-07-12 13:45:50 +02001507void gprs_ns2_sns_dump_vty(struct vty *vty, const struct gprs_ns2_nse *nse, bool stats)
1508{
1509 struct ns2_sns_state *gss;
1510 unsigned int i;
1511
1512 if (!nse->bss_sns_fi)
1513 return;
1514
1515 vty_out_fsm_inst(vty, nse->bss_sns_fi);
1516 gss = (struct ns2_sns_state *) nse->bss_sns_fi->priv;
1517
1518 vty_out(vty, "Maximum number of remote NS-VCs: %zu, IPv4 Endpoints: %zu, IPv6 Endpoints: %zu%s",
1519 gss->num_max_nsvcs, gss->num_max_ip4_remote, gss->num_max_ip6_remote, VTY_NEWLINE);
1520
1521 if (gss->num_ip4_local && gss->num_ip4_remote) {
1522 vty_out(vty, "Local IPv4 Endpoints:%s", VTY_NEWLINE);
1523 for (i = 0; i < gss->num_ip4_local; i++)
1524 vty_dump_sns_ip4(vty, &gss->ip4_local[i]);
1525
1526 vty_out(vty, "Remote IPv4 Endpoints:%s", VTY_NEWLINE);
1527 for (i = 0; i < gss->num_ip4_remote; i++)
1528 vty_dump_sns_ip4(vty, &gss->ip4_remote[i]);
1529 }
1530
1531 if (gss->num_ip6_local && gss->num_ip6_remote) {
1532 vty_out(vty, "Local IPv6 Endpoints:%s", VTY_NEWLINE);
1533 for (i = 0; i < gss->num_ip6_local; i++)
1534 vty_dump_sns_ip6(vty, &gss->ip6_local[i]);
1535
1536 vty_out(vty, "Remote IPv6 Endpoints:%s", VTY_NEWLINE);
1537 for (i = 0; i < gss->num_ip6_remote; i++)
1538 vty_dump_sns_ip6(vty, &gss->ip6_remote[i]);
1539 }
1540}
1541
Alexander Couzens412bc342020-11-19 05:24:37 +01001542/*! write IP-SNS to a vty
1543 * \param[in] vty VTY to which the state shall be printed
1544 * \param[in] nse NS Entity whose IP-SNS state shall be printed */
1545void gprs_ns2_sns_write_vty(struct vty *vty, const struct gprs_ns2_nse *nse)
1546{
1547 struct ns2_sns_state *gss;
1548 struct osmo_sockaddr_str addr_str;
1549 struct sns_endpoint *endpoint;
1550
1551 if (!nse->bss_sns_fi)
1552 return;
1553
1554 gss = (struct ns2_sns_state *) nse->bss_sns_fi->priv;
1555 llist_for_each_entry(endpoint, &gss->sns_endpoints, list) {
Vadim Yanitskiyd8b70032021-01-05 14:24:09 +01001556 /* It's unlikely that an error happens, but let's better be safe. */
1557 if (osmo_sockaddr_str_from_sockaddr(&addr_str, &endpoint->saddr.u.sas) != 0)
1558 addr_str = (struct osmo_sockaddr_str) { .ip = "<INVALID>" };
Alexander Couzens412bc342020-11-19 05:24:37 +01001559 vty_out(vty, " ip-sns %s %u%s", addr_str.ip, addr_str.port, VTY_NEWLINE);
1560 }
1561}
1562
Alexander Couzense769f522020-12-07 07:37:07 +01001563static struct sns_endpoint *ns2_get_sns_endpoint(struct ns2_sns_state *state,
1564 const struct osmo_sockaddr *saddr)
1565{
1566 struct sns_endpoint *endpoint;
1567
1568 llist_for_each_entry(endpoint, &state->sns_endpoints, list) {
1569 if (!osmo_sockaddr_cmp(saddr, &endpoint->saddr))
1570 return endpoint;
1571 }
1572
1573 return NULL;
1574}
1575
1576/*! gprs_ns2_sns_add_endpoint
1577 * \param[in] nse
1578 * \param[in] sockaddr
1579 * \return
1580 */
1581int gprs_ns2_sns_add_endpoint(struct gprs_ns2_nse *nse,
1582 const struct osmo_sockaddr *saddr)
1583{
1584 struct ns2_sns_state *gss;
1585 struct sns_endpoint *endpoint;
1586 bool do_selection = false;
1587
1588 if (nse->ll != GPRS_NS2_LL_UDP) {
1589 return -EINVAL;
1590 }
1591
1592 if (nse->dialect != NS2_DIALECT_SNS) {
1593 return -EINVAL;
1594 }
1595
1596 gss = nse->bss_sns_fi->priv;
1597
1598 if (ns2_get_sns_endpoint(gss, saddr))
1599 return -EADDRINUSE;
1600
1601 endpoint = talloc_zero(nse->bss_sns_fi->priv, struct sns_endpoint);
1602 if (!endpoint)
1603 return -ENOMEM;
1604
1605 endpoint->saddr = *saddr;
1606 if (llist_empty(&gss->sns_endpoints))
1607 do_selection = true;
1608
1609 llist_add_tail(&endpoint->list, &gss->sns_endpoints);
1610 if (do_selection)
1611 osmo_fsm_inst_dispatch(nse->bss_sns_fi, GPRS_SNS_EV_SELECT_ENDPOINT, NULL);
1612
1613 return 0;
1614}
1615
1616/*! gprs_ns2_sns_del_endpoint
1617 * \param[in] nse
1618 * \param[in] sockaddr
1619 * \return 0 on success, otherwise < 0
1620 */
1621int gprs_ns2_sns_del_endpoint(struct gprs_ns2_nse *nse,
1622 const struct osmo_sockaddr *saddr)
1623{
1624 struct ns2_sns_state *gss;
1625 struct sns_endpoint *endpoint;
1626
1627 if (nse->ll != GPRS_NS2_LL_UDP) {
1628 return -EINVAL;
1629 }
1630
1631 if (nse->dialect != NS2_DIALECT_SNS) {
1632 return -EINVAL;
1633 }
1634
1635 gss = nse->bss_sns_fi->priv;
1636 endpoint = ns2_get_sns_endpoint(gss, saddr);
1637 if (!endpoint)
1638 return -ENOENT;
1639
1640 /* if this is an unused SNS endpoint it's done */
1641 if (gss->initial != endpoint) {
1642 llist_del(&endpoint->list);
1643 talloc_free(endpoint);
1644 return 0;
1645 }
1646
1647 /* gprs_ns2_free_nsvcs() will trigger GPRS_SNS_EV_NO_NSVC on the last NS-VC
1648 * and restart SNS SIZE procedure which selects a new initial */
1649 LOGP(DLNS, LOGL_INFO, "Current in-use SNS endpoint is being removed."
1650 "Closing all NS-VC and restart SNS-SIZE procedure"
1651 "with a remaining SNS endpoint.\n");
1652
1653 /* Continue with the next endpoint in the list.
1654 * Special case if the endpoint is at the start or end of the list */
1655 if (endpoint->list.prev == &gss->sns_endpoints ||
1656 endpoint->list.next == &gss->sns_endpoints)
1657 gss->initial = NULL;
1658 else
1659 gss->initial = llist_entry(endpoint->list.next->prev,
1660 struct sns_endpoint,
1661 list);
1662
1663 llist_del(&endpoint->list);
1664 gprs_ns2_free_nsvcs(nse);
1665 talloc_free(endpoint);
1666
1667 return 0;
1668}
1669
1670/*! gprs_ns2_sns_count
1671 * \param[in] nse NS Entity whose IP-SNS endpoints shall be printed
1672 * \return the count of endpoints or < 0 if NSE doesn't contain sns.
1673 */
1674int gprs_ns2_sns_count(struct gprs_ns2_nse *nse)
1675{
1676 struct ns2_sns_state *gss;
1677 struct sns_endpoint *endpoint;
1678 int count = 0;
1679
1680 if (nse->ll != GPRS_NS2_LL_UDP) {
1681 return -EINVAL;
1682 }
1683
1684 if (nse->dialect != NS2_DIALECT_SNS) {
1685 return -EINVAL;
1686 }
1687
1688 gss = nse->bss_sns_fi->priv;
1689 llist_for_each_entry(endpoint, &gss->sns_endpoints, list)
1690 count++;
1691
1692 return count;
1693}
1694
Alexander Couzens6a161492020-07-12 13:45:50 +02001695/* initialize osmo_ctx on main tread */
1696static __attribute__((constructor)) void on_dso_load_ctx(void)
1697{
1698 OSMO_ASSERT(osmo_fsm_register(&gprs_ns2_sns_bss_fsm) == 0);
1699}