blob: 275622691d119bc21e70b14cbe04c10c63531c6c [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 {
72 GPRS_SNS_EV_START,
73 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[] = {
85 { GPRS_SNS_EV_START, "START" },
86 { 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" },
94 { 0, NULL }
95};
96
97struct ns2_sns_state {
98 struct gprs_ns2_nse *nse;
99
100 enum ns2_sns_type ip;
101
102 /* initial connection. the initial connection will be terminated
103 * in configured state or moved into NSE if valid */
104 struct osmo_sockaddr initial;
105 /* all SNS PDU will be sent over this nsvc */
106 struct gprs_ns2_vc *sns_nsvc;
107
108 /* local configuration to send to the remote end */
109 struct gprs_ns_ie_ip4_elem *ip4_local;
110 size_t num_ip4_local;
111
112 /* local configuration to send to the remote end */
113 struct gprs_ns_ie_ip6_elem *ip6_local;
114 size_t num_ip6_local;
115
116 /* local configuration about our capabilities in terms of connections to
117 * remote (SGSN) side */
118 size_t num_max_nsvcs;
119 size_t num_max_ip4_remote;
120 size_t num_max_ip6_remote;
121
122 /* remote configuration as received */
123 struct gprs_ns_ie_ip4_elem *ip4_remote;
124 unsigned int num_ip4_remote;
125
126 /* remote configuration as received */
127 struct gprs_ns_ie_ip6_elem *ip6_remote;
128 unsigned int num_ip6_remote;
129};
130
131static inline struct gprs_ns2_nse *nse_inst_from_fi(struct osmo_fsm_inst *fi)
132{
133 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
134 return gss->nse;
135}
136
137/* helper function to compute the sum of all (data or signaling) weights */
138static int ip4_weight_sum(const struct gprs_ns_ie_ip4_elem *ip4, unsigned int num,
139 bool data_weight)
140{
141 unsigned int i;
142 int weight_sum = 0;
143
144 for (i = 0; i < num; i++) {
145 if (data_weight)
146 weight_sum += ip4[i].data_weight;
147 else
148 weight_sum += ip4[i].sig_weight;
149 }
150 return weight_sum;
151}
152#define ip4_weight_sum_data(x,y) ip4_weight_sum(x, y, true)
153#define ip4_weight_sum_sig(x,y) ip4_weight_sum(x, y, false)
154
155/* helper function to compute the sum of all (data or signaling) weights */
156static int ip6_weight_sum(const struct gprs_ns_ie_ip6_elem *ip6, 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 += ip6[i].data_weight;
165 else
166 weight_sum += ip6[i].sig_weight;
167 }
168 return weight_sum;
169}
170#define ip6_weight_sum_data(x,y) ip6_weight_sum(x, y, true)
171#define ip6_weight_sum_sig(x,y) ip6_weight_sum(x, y, false)
172
173static struct gprs_ns2_vc *nsvc_by_ip4_elem(struct gprs_ns2_nse *nse,
174 const struct gprs_ns_ie_ip4_elem *ip4)
175{
176 struct osmo_sockaddr sa;
177 /* copy over. Both data structures use network byte order */
178 sa.u.sin.sin_addr.s_addr = ip4->ip_addr;
179 sa.u.sin.sin_port = ip4->udp_port;
180 sa.u.sin.sin_family = AF_INET;
181
Alexander Couzens38b19e82020-09-23 23:56:37 +0200182 return gprs_ns2_nsvc_by_sockaddr_nse(nse, &sa);
Alexander Couzens6a161492020-07-12 13:45:50 +0200183}
184
185static struct gprs_ns2_vc *nsvc_by_ip6_elem(struct gprs_ns2_nse *nse,
186 const struct gprs_ns_ie_ip6_elem *ip6)
187{
188 struct osmo_sockaddr sa;
189 /* copy over. Both data structures use network byte order */
190 sa.u.sin6.sin6_addr = ip6->ip_addr;
191 sa.u.sin6.sin6_port = ip6->udp_port;
192 sa.u.sin6.sin6_family = AF_INET;
193
Alexander Couzens38b19e82020-09-23 23:56:37 +0200194 return gprs_ns2_nsvc_by_sockaddr_nse(nse, &sa);
Alexander Couzens6a161492020-07-12 13:45:50 +0200195}
196
197/*! called when a nsvc is beeing freed */
198void ns2_sns_free_nsvc(struct gprs_ns2_vc *nsvc)
199{
200 struct gprs_ns2_nse *nse;
201 struct gprs_ns2_vc *tmp;
202 struct ns2_sns_state *gss;
203 struct osmo_fsm_inst *fi = nsvc->nse->bss_sns_fi;
204
205 if (!fi)
206 return;
207
208 gss = (struct ns2_sns_state *) fi->priv;
209 if (nsvc != gss->sns_nsvc)
210 return;
211
212 nse = nsvc->nse;
213 if (nse->alive) {
214 /* choose a different sns nsvc */
215 llist_for_each_entry(tmp, &nse->nsvc, list) {
216 if (gprs_ns2_vc_is_unblocked(tmp))
217 gss->sns_nsvc = tmp;
218 }
219 } else {
220 LOGPFSML(fi, LOGL_ERROR, "NSE %d: no remaining NSVC. Reseting SNS FSM.", nse->nsei);
221 gss->sns_nsvc = NULL;
222 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_NO_NSVC, NULL);
223 }
224}
225
226static void ns2_nsvc_create_ip4(struct osmo_fsm_inst *fi,
227 struct gprs_ns2_nse *nse,
228 const struct gprs_ns_ie_ip4_elem *ip4)
229{
230 struct gprs_ns2_inst *nsi = nse->nsi;
231 struct gprs_ns2_vc *nsvc;
232 struct gprs_ns2_vc_bind *bind;
Alexander Couzensc068d862020-10-12 04:11:51 +0200233 struct osmo_sockaddr remote = { };
Alexander Couzens6a161492020-07-12 13:45:50 +0200234 /* copy over. Both data structures use network byte order */
235 remote.u.sin.sin_family = AF_INET;
236 remote.u.sin.sin_addr.s_addr = ip4->ip_addr;
237 remote.u.sin.sin_port = ip4->udp_port;
238
239 /* for every bind, create a connection if bind type == IP */
240 llist_for_each_entry(bind, &nsi->binding, list) {
241 /* ignore failed connection */
242 nsvc = gprs_ns2_ip_connect_inactive(bind,
243 &remote,
244 nse, 0);
245 if (!nsvc) {
246 LOGPFSML(fi, LOGL_ERROR, "SNS-CONFIG: Failed to create NSVC\n");
247 continue;
248 }
249
250 nsvc->sig_weight = ip4->sig_weight;
251 nsvc->data_weight = ip4->data_weight;
252 }
253}
254
255static void ns2_nsvc_create_ip6(struct osmo_fsm_inst *fi,
256 struct gprs_ns2_nse *nse,
257 const struct gprs_ns_ie_ip6_elem *ip6)
258{
259 struct gprs_ns2_inst *nsi = nse->nsi;
260 struct gprs_ns2_vc *nsvc;
261 struct gprs_ns2_vc_bind *bind;
262 struct osmo_sockaddr remote = {};
263 /* copy over. Both data structures use network byte order */
264 remote.u.sin6.sin6_family = AF_INET6;
265 remote.u.sin6.sin6_addr = ip6->ip_addr;
266 remote.u.sin6.sin6_port = ip6->udp_port;
267
268 /* for every bind, create a connection if bind type == IP */
269 llist_for_each_entry(bind, &nsi->binding, list) {
270 /* ignore failed connection */
271 nsvc = gprs_ns2_ip_connect_inactive(bind,
272 &remote,
273 nse, 0);
274 if (!nsvc) {
275 LOGPFSML(fi, LOGL_ERROR, "SNS-CONFIG: Failed to create NSVC\n");
276 continue;
277 }
278
279 nsvc->sig_weight = ip6->sig_weight;
280 nsvc->data_weight = ip6->data_weight;
281 }
282}
283
284
285static int create_missing_nsvcs(struct osmo_fsm_inst *fi)
286{
287 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
288 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
289 struct gprs_ns2_vc *nsvc;
290 struct gprs_ns2_vc_bind *bind;
291 struct osmo_sockaddr remote = { };
292 unsigned int i;
293
294 for (i = 0; i < gss->num_ip4_remote; i++) {
295 const struct gprs_ns_ie_ip4_elem *ip4 = &gss->ip4_remote[i];
296
297 remote.u.sin.sin_family = AF_INET;
298 remote.u.sin.sin_addr.s_addr = ip4->ip_addr;
299 remote.u.sin.sin_port = ip4->udp_port;
300
301 llist_for_each_entry(bind, &nse->nsi->binding, list) {
302 bool found = false;
303
304 llist_for_each_entry(nsvc, &nse->nsvc, list) {
305 if (nsvc->bind != bind)
306 continue;
307
308 if (!osmo_sockaddr_cmp(&remote, gprs_ns2_ip_vc_sockaddr(nsvc))) {
309 found = true;
310 break;
311 }
312 }
313
314 if (!found) {
315 nsvc = gprs_ns2_ip_connect_inactive(bind, &remote, nse, 0);
316 if (!nsvc) {
317 /* TODO: add to a list to send back a NS-STATUS */
318 continue;
319 }
320 }
321
322 /* update data / signalling weight */
323 nsvc->data_weight = ip4->data_weight;
324 nsvc->sig_weight = ip4->sig_weight;
325 nsvc->sns_only = false;
326 }
327 }
328
329 for (i = 0; i < gss->num_ip6_remote; i++) {
330 const struct gprs_ns_ie_ip6_elem *ip6 = &gss->ip6_remote[i];
331
332 remote.u.sin6.sin6_family = AF_INET6;
333 remote.u.sin6.sin6_addr = ip6->ip_addr;
334 remote.u.sin6.sin6_port = ip6->udp_port;
335
336 llist_for_each_entry(bind, &nse->nsi->binding, list) {
337 bool found = false;
338
339 llist_for_each_entry(nsvc, &nse->nsvc, list) {
340 if (nsvc->bind != bind)
341 continue;
342
343 if (!osmo_sockaddr_cmp(&remote, gprs_ns2_ip_vc_sockaddr(nsvc))) {
344 found = true;
345 break;
346 }
347 }
348
349 if (!found) {
350 nsvc = gprs_ns2_ip_connect_inactive(bind, &remote, nse, 0);
351 if (!nsvc) {
352 /* TODO: add to a list to send back a NS-STATUS */
353 continue;
354 }
355 }
356
357 /* update data / signalling weight */
358 nsvc->data_weight = ip6->data_weight;
359 nsvc->sig_weight = ip6->sig_weight;
360 nsvc->sns_only = false;
361 }
362 }
363
364
365 return 0;
366}
367
368/* Add a given remote IPv4 element to gprs_sns_state */
369static int add_remote_ip4_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip4_elem *ip4)
370{
371 unsigned int i;
372
373 if (gss->num_ip4_remote >= gss->num_max_ip4_remote)
374 return -NS_CAUSE_INVAL_NR_NS_VC;
375
376 /* check for duplicates */
377 for (i = 0; i < gss->num_ip4_remote; i++) {
378 if (memcmp(&gss->ip4_remote[i], ip4, sizeof(*ip4)))
379 continue;
380 /* TODO: log message duplicate */
381 /* TODO: check if this is the correct cause code */
382 return -NS_CAUSE_PROTO_ERR_UNSPEC;
383 }
384
385 gss->ip4_remote = talloc_realloc(gss, gss->ip4_remote, struct gprs_ns_ie_ip4_elem,
386 gss->num_ip4_remote+1);
387 gss->ip4_remote[gss->num_ip4_remote] = *ip4;
388 gss->num_ip4_remote += 1;
389 return 0;
390}
391
392/* Remove a given remote IPv4 element from gprs_sns_state */
393static int remove_remote_ip4_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip4_elem *ip4)
394{
395 unsigned int i;
396
397 for (i = 0; i < gss->num_ip4_remote; i++) {
398 if (memcmp(&gss->ip4_remote[i], ip4, sizeof(*ip4)))
399 continue;
400 /* all array elements < i remain as they are; all > i are shifted left by one */
401 memmove(&gss->ip4_remote[i], &gss->ip4_remote[i+1], gss->num_ip4_remote-i-1);
402 gss->num_ip4_remote -= 1;
403 return 0;
404 }
405 return -1;
406}
407
408/* update the weights for specified remote IPv4 */
409static int update_remote_ip4_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip4_elem *ip4)
410{
411 unsigned int i;
412
413 for (i = 0; i < gss->num_ip4_remote; i++) {
414 if (gss->ip4_remote[i].ip_addr != ip4->ip_addr ||
415 gss->ip4_remote[i].udp_port != ip4->udp_port)
416 continue;
417
418 gss->ip4_remote[i].sig_weight = ip4->sig_weight;
419 gss->ip4_remote[i].data_weight = ip4->data_weight;
420 return 0;
421 }
422 return -1;
423}
424
425/* Add a given remote IPv6 element to gprs_sns_state */
426static int add_remote_ip6_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip6_elem *ip6)
427{
428 if (gss->num_ip6_remote >= gss->num_max_ip6_remote)
429 return -NS_CAUSE_INVAL_NR_NS_VC;
430
431 gss->ip6_remote = talloc_realloc(gss, gss->ip6_remote, struct gprs_ns_ie_ip6_elem,
432 gss->num_ip6_remote+1);
433 gss->ip6_remote[gss->num_ip6_remote] = *ip6;
434 gss->num_ip6_remote += 1;
435 return 0;
436}
437
438/* Remove a given remote IPv6 element from gprs_sns_state */
439static int remove_remote_ip6_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip6_elem *ip6)
440{
441 unsigned int i;
442
443 for (i = 0; i < gss->num_ip6_remote; i++) {
444 if (memcmp(&gss->ip6_remote[i], ip6, sizeof(*ip6)))
445 continue;
446 /* all array elements < i remain as they are; all > i are shifted left by one */
447 memmove(&gss->ip6_remote[i], &gss->ip6_remote[i+1], gss->num_ip6_remote-i-1);
448 gss->num_ip6_remote -= 1;
449 return 0;
450 }
451 return -1;
452}
453
454/* update the weights for specified remote IPv6 */
455static int update_remote_ip6_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip6_elem *ip6)
456{
457 unsigned int i;
458
459 for (i = 0; i < gss->num_ip6_remote; i++) {
460 if (memcmp(&gss->ip6_remote[i].ip_addr, &ip6->ip_addr, sizeof(ip6->ip_addr)) ||
461 gss->ip6_remote[i].udp_port != ip6->udp_port)
462 continue;
463 gss->ip6_remote[i].sig_weight = ip6->sig_weight;
464 gss->ip6_remote[i].data_weight = ip6->data_weight;
465 return 0;
466 }
467 return -1;
468}
469
470static 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)
471{
472 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
473 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
474 struct gprs_ns2_vc *nsvc;
475 struct osmo_sockaddr sa = {};
Alexander Couzens9a4cf272020-10-11 20:48:04 +0200476 const struct osmo_sockaddr *remote;
Alexander Couzens6a161492020-07-12 13:45:50 +0200477 uint8_t new_signal;
478 uint8_t new_data;
479
480 /* TODO: Upon receiving an SNS-CHANGEWEIGHT PDU, if the resulting sum of the
481 * signalling weights of all the peer IP endpoints configured for this NSE is
482 * equal to zero or if the resulting sum of the data weights of all the peer IP
483 * endpoints configured for this NSE is equal to zero, the BSS/SGSN shall send an
484 * SNS-ACK PDU with a cause code of "Invalid weights". */
485
486 if (ip4) {
487 if (update_remote_ip4_elem(gss, ip4))
488 return -NS_CAUSE_UNKN_IP_EP;
489
490 /* copy over. Both data structures use network byte order */
491 sa.u.sin.sin_addr.s_addr = ip4->ip_addr;
492 sa.u.sin.sin_port = ip4->udp_port;
493 sa.u.sin.sin_family = AF_INET;
494 new_signal = ip4->sig_weight;
495 new_data = ip4->data_weight;
496 } else if (ip6) {
497 if (update_remote_ip6_elem(gss, ip6))
498 return -NS_CAUSE_UNKN_IP_EP;
499
500 /* copy over. Both data structures use network byte order */
501 sa.u.sin6.sin6_addr = ip6->ip_addr;
502 sa.u.sin6.sin6_port = ip6->udp_port;
503 sa.u.sin6.sin6_family = AF_INET6;
504 new_signal = ip6->sig_weight;
505 new_data = ip6->data_weight;
506 } else {
507 OSMO_ASSERT(false);
508 }
509
510 llist_for_each_entry(nsvc, &nse->nsvc, list) {
511 remote = gprs_ns2_ip_vc_sockaddr(nsvc);
512 /* all nsvc in NSE should be IP/UDP nsvc */
513 OSMO_ASSERT(remote);
514
515 if (osmo_sockaddr_cmp(&sa, remote))
516 continue;
517
518 LOGPFSML(fi, LOGL_INFO, "CHANGE-WEIGHT NS-VC %s data_weight %u->%u, sig_weight %u->%u\n",
519 gprs_ns2_ll_str(nsvc), nsvc->data_weight, new_data,
520 nsvc->sig_weight, new_signal);
521
522 nsvc->data_weight = new_data;
523 nsvc->sig_weight = new_signal;
524 }
525
526 return 0;
527}
528
529static int do_sns_delete(struct osmo_fsm_inst *fi,
530 const struct gprs_ns_ie_ip4_elem *ip4,
531 const struct gprs_ns_ie_ip6_elem *ip6)
532{
533 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
534 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
535 struct gprs_ns2_vc *nsvc, *tmp;
Alexander Couzens9a4cf272020-10-11 20:48:04 +0200536 const struct osmo_sockaddr *remote;
Alexander Couzens6a161492020-07-12 13:45:50 +0200537 struct osmo_sockaddr sa = {};
538
539 if (ip4) {
540 if (remove_remote_ip4_elem(gss, ip4) < 0)
541 return -NS_CAUSE_UNKN_IP_EP;
542 /* copy over. Both data structures use network byte order */
543 sa.u.sin.sin_addr.s_addr = ip4->ip_addr;
544 sa.u.sin.sin_port = ip4->udp_port;
545 sa.u.sin.sin_family = AF_INET;
546 } else if (ip6) {
547 if (remove_remote_ip6_elem(gss, ip6))
548 return -NS_CAUSE_UNKN_IP_EP;
549
550 /* copy over. Both data structures use network byte order */
551 sa.u.sin6.sin6_addr = ip6->ip_addr;
552 sa.u.sin6.sin6_port = ip6->udp_port;
553 sa.u.sin6.sin6_family = AF_INET6;
554 } else {
555 OSMO_ASSERT(false);
556 }
557
558 llist_for_each_entry_safe(nsvc, tmp, &nse->nsvc, list) {
559 remote = gprs_ns2_ip_vc_sockaddr(nsvc);
560 /* all nsvc in NSE should be IP/UDP nsvc */
561 OSMO_ASSERT(remote);
562 if (osmo_sockaddr_cmp(&sa, remote))
563 continue;
564
565 LOGPFSML(fi, LOGL_INFO, "DELETE NS-VC %s\n", gprs_ns2_ll_str(nsvc));
566 gprs_ns2_free_nsvc(nsvc);
567 }
568
569 return 0;
570}
571
572static int do_sns_add(struct osmo_fsm_inst *fi,
573 const struct gprs_ns_ie_ip4_elem *ip4,
574 const struct gprs_ns_ie_ip6_elem *ip6)
575{
576 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
577 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
578 struct gprs_ns2_vc *nsvc;
579 int rc = 0;
580
581 /* Upon receiving an SNS-ADD PDU, if the consequent number of IPv4 endpoints
582 * exceeds the number of IPv4 endpoints supported by the NSE, the NSE shall send
583 * an SNS-ACK PDU with a cause code set to "Invalid number of IP4 Endpoints". */
584 switch (gss->ip) {
585 case IPv4:
586 rc = add_remote_ip4_elem(gss, ip4);
587 break;
588 case IPv6:
589 rc = add_remote_ip6_elem(gss, ip6);
590 break;
591 default:
592 /* the gss->ip is initialized with the bss */
593 OSMO_ASSERT(false);
594 }
595
596 if (rc)
597 return rc;
598
599 /* Upon receiving an SNS-ADD PDU containing an already configured IP endpoint the
600 * NSE shall send an SNS-ACK PDU with the cause code "Protocol error -
601 * unspecified" */
602 switch (gss->ip) {
603 case IPv4:
604 nsvc = nsvc_by_ip4_elem(nse, ip4);
605 if (nsvc) {
606 /* the nsvc should be already in sync with the ip4 / ip6 elements */
607 return -NS_CAUSE_PROTO_ERR_UNSPEC;
608 }
609
610 /* TODO: failure case */
611 ns2_nsvc_create_ip4(fi, nse, ip4);
612 break;
613 case IPv6:
614 nsvc = nsvc_by_ip6_elem(nse, ip6);
615 if (nsvc) {
616 /* the nsvc should be already in sync with the ip4 / ip6 elements */
617 return -NS_CAUSE_PROTO_ERR_UNSPEC;
618 }
619
620 /* TODO: failure case */
621 ns2_nsvc_create_ip6(fi, nse, ip6);
622 break;
623 }
624
625 gprs_ns2_start_alive_all_nsvcs(nse);
626
627 return 0;
628}
629
630
631static void ns2_sns_st_unconfigured(struct osmo_fsm_inst *fi, uint32_t event, void *data)
632{
633 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
634 struct gprs_ns2_inst *nsi = nse->nsi;
635
636 switch (event) {
637 case GPRS_SNS_EV_START:
638 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_SIZE, nsi->timeout[NS_TOUT_TSNS_PROV], 1);
639 break;
640 default:
641 OSMO_ASSERT(0);
642 }
643}
644
645static void ns2_sns_st_size(struct osmo_fsm_inst *fi, uint32_t event, void *data)
646{
647 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
648 struct gprs_ns2_inst *nsi = nse->nsi;
649 struct tlv_parsed *tp = NULL;
650
651 switch (event) {
652 case GPRS_SNS_EV_SIZE_ACK:
653 tp = data;
654 if (TLVP_VAL_MINLEN(tp, NS_IE_CAUSE, 1)) {
655 LOGPFSML(fi, LOGL_ERROR, "SNS-SIZE-ACK with cause %s\n",
656 gprs_ns2_cause_str(*TLVP_VAL(tp, NS_IE_CAUSE)));
657 /* TODO: What to do? */
658 } else {
659 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIG_BSS,
660 nsi->timeout[NS_TOUT_TSNS_PROV], 2);
661 }
662 break;
663 default:
664 OSMO_ASSERT(0);
665 }
666}
667
668static void ns2_sns_st_size_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
669{
670 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
671
672 if (old_state != GPRS_SNS_ST_UNCONFIGURED)
Alexander Couzensbf95f0f2020-10-01 22:56:03 +0200673 ns2_prim_status_ind(gss->nse, 0, NS_AFF_CAUSE_SNS_FAILURE);
Alexander Couzens6a161492020-07-12 13:45:50 +0200674
675 if (gss->num_max_ip4_remote > 0)
676 ns2_tx_sns_size(gss->sns_nsvc, true, gss->num_max_nsvcs, gss->num_max_ip4_remote, -1);
677 else
678 ns2_tx_sns_size(gss->sns_nsvc, true, gss->num_max_nsvcs, -1, gss->num_max_ip6_remote);
679
680}
681
682static void ns2_sns_st_config_bss(struct osmo_fsm_inst *fi, uint32_t event, void *data)
683{
684 struct tlv_parsed *tp = NULL;
685
686 switch (event) {
687 case GPRS_SNS_EV_CONFIG_ACK:
688 tp = (struct tlv_parsed *) data;
689 if (TLVP_VAL_MINLEN(tp, NS_IE_CAUSE, 1)) {
690 LOGPFSML(fi, LOGL_ERROR, "SNS-CONFIG-ACK with cause %s\n",
691 gprs_ns2_cause_str(*TLVP_VAL(tp, NS_IE_CAUSE)));
692 /* TODO: What to do? */
693 } else {
694 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIG_SGSN, 0, 0);
695 }
696 break;
697 default:
698 OSMO_ASSERT(0);
699 }
700}
701
702static void ns2_sns_st_config_bss_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
703{
704 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
705 /* Transmit SNS-CONFIG */
706 /* TODO: ipv6 */
707 switch (gss->ip) {
708 case IPv4:
709 ns2_tx_sns_config(gss->sns_nsvc, true,
710 gss->ip4_local, gss->num_ip4_local,
711 NULL, 0);
712 break;
713 case IPv6:
714 ns2_tx_sns_config(gss->sns_nsvc, true,
715 NULL, 0,
716 gss->ip6_local, gss->num_ip6_local);
717 break;
718 }
719}
720
721
722static void ns_sns_st_config_sgsn_ip4(struct osmo_fsm_inst *fi, uint32_t event, void *data)
723{
724 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
725 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
726 const struct gprs_ns_ie_ip4_elem *v4_list;
727 unsigned int num_v4;
728 struct tlv_parsed *tp = NULL;
729
730 uint8_t cause;
731
732 tp = (struct tlv_parsed *) data;
733
734 if (!TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
735 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
736 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
737 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
738 return;
739 }
740 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
741 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
742 /* realloc to the new size */
743 gss->ip4_remote = talloc_realloc(gss, gss->ip4_remote,
744 struct gprs_ns_ie_ip4_elem,
745 gss->num_ip4_remote+num_v4);
746 /* append the new entries to the end of the list */
747 memcpy(&gss->ip4_remote[gss->num_ip4_remote], v4_list, num_v4*sizeof(*v4_list));
748 gss->num_ip4_remote += num_v4;
749
750 LOGPFSML(fi, LOGL_INFO, "Rx SNS-CONFIG: Remote IPv4 list now %u entries\n",
751 gss->num_ip4_remote);
752 if (event == GPRS_SNS_EV_CONFIG_END) {
753 /* check if sum of data / sig weights == 0 */
754 if (ip4_weight_sum_data(gss->ip4_remote, gss->num_ip4_remote) == 0 ||
755 ip4_weight_sum_sig(gss->ip4_remote, gss->num_ip4_remote) == 0) {
756 cause = NS_CAUSE_INVAL_WEIGH;
757 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
758 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
759 return;
760 }
761 create_missing_nsvcs(fi);
762 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
763 /* start the test procedure on ALL NSVCs! */
764 gprs_ns2_start_alive_all_nsvcs(nse);
765 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIGURED, 0, 0);
766 } else {
767 /* just send CONFIG-ACK */
768 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
769 }
770}
771
772static void ns_sns_st_config_sgsn_ip6(struct osmo_fsm_inst *fi, uint32_t event, void *data)
773{
774 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
775 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
776 const struct gprs_ns_ie_ip6_elem *v6_list;
777 unsigned int num_v6;
778 struct tlv_parsed *tp = NULL;
779
780 uint8_t cause;
781
782 tp = (struct tlv_parsed *) data;
783
784 if (!TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
785 cause = NS_CAUSE_INVAL_NR_IPv6_EP;
786 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
787 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
788 return;
789 }
790 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
791 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
792 /* realloc to the new size */
793 gss->ip6_remote = talloc_realloc(gss, gss->ip6_remote,
794 struct gprs_ns_ie_ip6_elem,
795 gss->num_ip6_remote+num_v6);
796 /* append the new entries to the end of the list */
797 memcpy(&gss->ip6_remote[gss->num_ip6_remote], v6_list, num_v6*sizeof(*v6_list));
798 gss->num_ip6_remote += num_v6;
799
800 LOGPFSML(fi, LOGL_INFO, "Rx SNS-CONFIG: Remote IPv6 list now %u entries\n",
801 gss->num_ip6_remote);
802 if (event == GPRS_SNS_EV_CONFIG_END) {
803 /* check if sum of data / sig weights == 0 */
804 if (ip6_weight_sum_data(gss->ip6_remote, gss->num_ip6_remote) == 0 ||
805 ip6_weight_sum_sig(gss->ip6_remote, gss->num_ip6_remote) == 0) {
806 cause = NS_CAUSE_INVAL_WEIGH;
807 ns2_tx_sns_config_ack(gss->sns_nsvc, &cause);
808 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
809 return;
810 }
811 create_missing_nsvcs(fi);
812 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
813 /* start the test procedure on ALL NSVCs! */
814 gprs_ns2_start_alive_all_nsvcs(nse);
815 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIGURED, 0, 0);
816 } else {
817 /* just send CONFIG-ACK */
818 ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);
819 }
820}
821
822static void ns2_sns_st_config_sgsn(struct osmo_fsm_inst *fi, uint32_t event, void *data)
823{
824 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
825
826 switch (event) {
827 case GPRS_SNS_EV_CONFIG_END:
828 case GPRS_SNS_EV_CONFIG:
829
830#if 0 /* part of incoming SNS-SIZE (doesn't happen on BSS side */
831 if (TLVP_PRESENT(tp, NS_IE_RESET_FLAG)) {
832 /* reset all existing config */
833 if (gss->ip4_remote)
834 talloc_free(gss->ip4_remote);
835 gss->num_ip4_remote = 0;
836 }
837#endif
838 /* TODO: reject IPv6 elements on IPv4 mode and vice versa */
839 switch (gss->ip) {
840 case IPv4:
841 ns_sns_st_config_sgsn_ip4(fi, event, data);
842 break;
843 case IPv6:
844 ns_sns_st_config_sgsn_ip6(fi, event, data);
845 break;
846 default:
847 OSMO_ASSERT(0);
848 }
849 break;
850 default:
851 OSMO_ASSERT(0);
852 }
853}
854
855/* called when receiving GPRS_SNS_EV_ADD in state configure */
856static void ns2_sns_st_configured_add(struct osmo_fsm_inst *fi,
857 struct ns2_sns_state *gss,
858 struct tlv_parsed *tp)
859{
860 const struct gprs_ns_ie_ip4_elem *v4_list = NULL;
861 const struct gprs_ns_ie_ip6_elem *v6_list = NULL;
862 int num_v4 = 0, num_v6 = 0;
863 uint8_t trans_id, cause = 0xff;
Harald Welte7da6ace2020-09-18 09:48:05 +0200864 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +0200865 int rc = 0;
866
867 /* TODO: refactor EV_ADD/CHANGE/REMOVE by
868 * check uniqueness within the lists (no doublicate entries)
869 * check not-known-by-us and sent back a list of unknown/known values
870 * (abnormal behaviour according to 48.016)
871 */
872
873 trans_id = *TLVP_VAL(tp, NS_IE_TRANS_ID);
874 if (gss->ip == IPv4) {
875 if (!TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
876 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
877 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
878 return;
879 }
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);
Harald Welte7da6ace2020-09-18 09:48:05 +0200883 for (i = 0; i < num_v4; i++) {
884 unsigned int j;
Alexander Couzens6a161492020-07-12 13:45:50 +0200885 rc = do_sns_add(fi, &v4_list[i], NULL);
886 if (rc < 0) {
887 /* rollback/undo to restore previous state */
Harald Welte7da6ace2020-09-18 09:48:05 +0200888 for (j = 0; j < i; j++)
Alexander Couzens6a161492020-07-12 13:45:50 +0200889 do_sns_delete(fi, &v4_list[j], NULL);
890 cause = -rc;
891 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
892 break;
893 }
894 }
895 } else { /* IPv6 */
896 if (!TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
897 cause = NS_CAUSE_INVAL_NR_IPv6_EP;
898 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
899 return;
900 }
901
902 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
903 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
Harald Welte7da6ace2020-09-18 09:48:05 +0200904 for (i = 0; i < num_v6; i++) {
905 unsigned int j;
Alexander Couzens6a161492020-07-12 13:45:50 +0200906 rc = do_sns_add(fi, NULL, &v6_list[i]);
907 if (rc < 0) {
908 /* rollback/undo to restore previous state */
Harald Welte7da6ace2020-09-18 09:48:05 +0200909 for (j = 0; j < i; j++)
Alexander Couzens6a161492020-07-12 13:45:50 +0200910 do_sns_delete(fi, NULL, &v6_list[j]);
911 cause = -rc;
912 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
913 break;
914 }
915 }
916 }
917
918 /* TODO: correct behaviour is to answer to the *same* NSVC from which the SNS_ADD was received */
919 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, NULL, v4_list, num_v4, v6_list, num_v6);
920}
921
922static void ns2_sns_st_configured_delete(struct osmo_fsm_inst *fi,
923 struct ns2_sns_state *gss,
924 struct tlv_parsed *tp)
925{
926 const struct gprs_ns_ie_ip4_elem *v4_list = NULL;
927 const struct gprs_ns_ie_ip6_elem *v6_list = NULL;
928 int num_v4 = 0, num_v6 = 0;
929 uint8_t trans_id, cause = 0xff;
Harald Welte7da6ace2020-09-18 09:48:05 +0200930 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +0200931 int rc = 0;
932
933 /* TODO: split up delete into v4 + v6
934 * TODO: check if IPv4_LIST or IP_ADDR(v4) is present on IPv6 and vice versa
935 * TODO: check if IPv4_LIST/IPv6_LIST and IP_ADDR is present at the same time
936 */
937 trans_id = *TLVP_VAL(tp, NS_IE_TRANS_ID);
938 if (gss->ip == IPv4) {
939 if (TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
940 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
941 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
Harald Welte7da6ace2020-09-18 09:48:05 +0200942 for ( i = 0; i < num_v4; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200943 rc = do_sns_delete(fi, &v4_list[i], NULL);
944 if (rc < 0) {
945 cause = -rc;
946 /* continue to delete others */
947 }
948 }
949 if (cause != 0xff) {
950 /* TODO: create list of not-deleted and return it */
951 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
952 return;
953 }
954
955 } else if (TLVP_PRESENT(tp, NS_IE_IP_ADDR) && TLVP_LEN(tp, NS_IE_IP_ADDR) == 5) {
956 /* delete all NS-VCs for given IPv4 address */
957 const uint8_t *ie = TLVP_VAL(tp, NS_IE_IP_ADDR);
958 struct gprs_ns_ie_ip4_elem *ip4_remote;
959 uint32_t ip_addr = *(uint32_t *)(ie+1);
960 if (ie[0] != 0x01) { /* Address Type != IPv4 */
961 cause = NS_CAUSE_UNKN_IP_ADDR;
962 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
963 return;
964 }
965 /* make a copy as do_sns_delete() will change the array underneath us */
966 ip4_remote = talloc_memdup(fi, gss->ip4_remote,
967 gss->num_ip4_remote * sizeof(*v4_list));
Harald Welte7da6ace2020-09-18 09:48:05 +0200968 for (i = 0; i < gss->num_ip4_remote; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200969 if (ip4_remote[i].ip_addr == ip_addr) {
970 rc = do_sns_delete(fi, &ip4_remote[i], NULL);
971 if (rc < 0) {
972 cause = -rc;
973 /* continue to delete others */
974 }
975 }
976 }
977 talloc_free(ip4_remote);
978 if (cause != 0xff) {
979 /* TODO: create list of not-deleted and return it */
980 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
981 return;
982 }
983 } else {
984 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
985 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
986 return;
987 }
988 } else { /* IPv6 */
989 if (TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
990 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
991 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
Harald Welte7da6ace2020-09-18 09:48:05 +0200992 for (i = 0; i < num_v6; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200993 rc = do_sns_delete(fi, NULL, &v6_list[i]);
994 if (rc < 0) {
995 cause = -rc;
996 /* continue to delete others */
997 }
998 }
999 if (cause != 0xff) {
1000 /* TODO: create list of not-deleted and return it */
1001 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1002 return;
1003 }
1004 } else if (TLVP_PRES_LEN(tp, NS_IE_IP_ADDR, 17)) {
1005 /* delete all NS-VCs for given IPv4 address */
1006 const uint8_t *ie = TLVP_VAL(tp, NS_IE_IP_ADDR);
1007 struct gprs_ns_ie_ip6_elem *ip6_remote;
1008 struct in6_addr ip6_addr;
Harald Welte7da6ace2020-09-18 09:48:05 +02001009 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +02001010 if (ie[0] != 0x02) { /* Address Type != IPv6 */
1011 cause = NS_CAUSE_UNKN_IP_ADDR;
1012 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1013 return;
1014 }
1015 memcpy(&ip6_addr, (ie+1), sizeof(struct in6_addr));
1016 /* make a copy as do_sns_delete() will change the array underneath us */
1017 ip6_remote = talloc_memdup(fi, gss->ip6_remote,
1018 gss->num_ip6_remote * sizeof(*v4_list));
Harald Welte7da6ace2020-09-18 09:48:05 +02001019 for (i = 0; i < gss->num_ip6_remote; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001020 if (!memcmp(&ip6_remote[i].ip_addr, &ip6_addr, sizeof(struct in6_addr))) {
1021 rc = do_sns_delete(fi, NULL, &ip6_remote[i]);
1022 if (rc < 0) {
1023 cause = -rc;
1024 /* continue to delete others */
1025 }
1026 }
1027 }
1028
1029 talloc_free(ip6_remote);
1030 if (cause != 0xff) {
1031 /* TODO: create list of not-deleted and return it */
1032 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1033 return;
1034 }
1035 } else {
1036 cause = NS_CAUSE_INVAL_NR_IPv6_EP;
1037 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1038 return;
1039 }
1040 }
1041 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, NULL, v4_list, num_v4, v6_list, num_v6);
1042}
1043
1044static void ns2_sns_st_configured_change(struct osmo_fsm_inst *fi,
1045 struct ns2_sns_state *gss,
1046 struct tlv_parsed *tp)
1047{
1048 const struct gprs_ns_ie_ip4_elem *v4_list = NULL;
1049 const struct gprs_ns_ie_ip6_elem *v6_list = NULL;
1050 int num_v4 = 0, num_v6 = 0;
1051 uint8_t trans_id, cause = 0xff;
1052 int rc = 0;
Harald Welte7da6ace2020-09-18 09:48:05 +02001053 unsigned int i;
Alexander Couzens6a161492020-07-12 13:45:50 +02001054
1055 trans_id = *TLVP_VAL(tp, NS_IE_TRANS_ID);
1056 if (TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
1057 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
1058 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001059 for (i = 0; i < num_v4; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001060 rc = do_sns_change_weight(fi, &v4_list[i], NULL);
1061 if (rc < 0) {
1062 cause = -rc;
1063 /* continue to others */
1064 }
1065 }
1066 if (cause != 0xff) {
1067 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1068 return;
1069 }
1070 } else if (TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
1071 v6_list = (const struct gprs_ns_ie_ip6_elem *) TLVP_VAL(tp, NS_IE_IPv6_LIST);
1072 num_v6 = TLVP_LEN(tp, NS_IE_IPv6_LIST) / sizeof(*v6_list);
Harald Welte7da6ace2020-09-18 09:48:05 +02001073 for (i = 0; i < num_v6; i++) {
Alexander Couzens6a161492020-07-12 13:45:50 +02001074 rc = do_sns_change_weight(fi, NULL, &v6_list[i]);
1075 if (rc < 0) {
1076 cause = -rc;
1077 /* continue to others */
1078 }
1079 }
1080 if (cause != 0xff) {
1081 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1082 return;
1083 }
1084 } else {
1085 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
1086 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
1087 return;
1088 }
1089 ns2_tx_sns_ack(gss->sns_nsvc, trans_id, NULL, v4_list, num_v4, v6_list, num_v6);
1090}
1091
1092static void ns2_sns_st_configured(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1093{
1094 struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
1095 struct tlv_parsed *tp = data;
1096
1097 switch (event) {
1098 case GPRS_SNS_EV_ADD:
1099 ns2_sns_st_configured_add(fi, gss, tp);
1100 break;
1101 case GPRS_SNS_EV_DELETE:
1102 ns2_sns_st_configured_delete(fi, gss, tp);
1103 break;
1104 case GPRS_SNS_EV_CHANGE_WEIGHT:
1105 ns2_sns_st_configured_change(fi, gss, tp);
1106 break;
1107 }
1108}
1109
1110static void ns2_sns_st_configured_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
1111{
1112 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
Alexander Couzensbf95f0f2020-10-01 22:56:03 +02001113 ns2_prim_status_ind(nse, 0, NS_AFF_CAUSE_SNS_CONFIGURED);
Alexander Couzens6a161492020-07-12 13:45:50 +02001114}
1115
1116static const struct osmo_fsm_state ns2_sns_bss_states[] = {
1117 [GPRS_SNS_ST_UNCONFIGURED] = {
1118 .in_event_mask = S(GPRS_SNS_EV_START),
1119 .out_state_mask = S(GPRS_SNS_ST_SIZE),
1120 .name = "UNCONFIGURED",
1121 .action = ns2_sns_st_unconfigured,
1122 },
1123 [GPRS_SNS_ST_SIZE] = {
1124 .in_event_mask = S(GPRS_SNS_EV_SIZE_ACK),
1125 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
1126 S(GPRS_SNS_ST_SIZE) |
1127 S(GPRS_SNS_ST_CONFIG_BSS),
1128 .name = "SIZE",
1129 .action = ns2_sns_st_size,
1130 .onenter = ns2_sns_st_size_onenter,
1131 },
1132 [GPRS_SNS_ST_CONFIG_BSS] = {
1133 .in_event_mask = S(GPRS_SNS_EV_CONFIG_ACK),
1134 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
1135 S(GPRS_SNS_ST_CONFIG_BSS) |
1136 S(GPRS_SNS_ST_CONFIG_SGSN) |
1137 S(GPRS_SNS_ST_SIZE),
1138 .name = "CONFIG_BSS",
1139 .action = ns2_sns_st_config_bss,
1140 .onenter = ns2_sns_st_config_bss_onenter,
1141 },
1142 [GPRS_SNS_ST_CONFIG_SGSN] = {
1143 .in_event_mask = S(GPRS_SNS_EV_CONFIG) |
1144 S(GPRS_SNS_EV_CONFIG_END),
1145 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
1146 S(GPRS_SNS_ST_CONFIG_SGSN) |
1147 S(GPRS_SNS_ST_CONFIGURED) |
1148 S(GPRS_SNS_ST_SIZE),
1149 .name = "CONFIG_SGSN",
1150 .action = ns2_sns_st_config_sgsn,
1151 },
1152 [GPRS_SNS_ST_CONFIGURED] = {
1153 .in_event_mask = S(GPRS_SNS_EV_ADD) |
1154 S(GPRS_SNS_EV_DELETE) |
1155 S(GPRS_SNS_EV_CHANGE_WEIGHT),
1156 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED),
1157 .name = "CONFIGURED",
1158 .action = ns2_sns_st_configured,
1159 .onenter = ns2_sns_st_configured_onenter,
1160 },
1161};
1162
1163static int ns2_sns_fsm_bss_timer_cb(struct osmo_fsm_inst *fi)
1164{
1165 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
1166 struct gprs_ns2_inst *nsi = nse->nsi;
1167
1168 switch (fi->T) {
1169 case 1:
1170 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_SIZE, nsi->timeout[NS_TOUT_TSNS_PROV], 1);
1171 break;
1172 case 2:
1173 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIG_BSS, nsi->timeout[NS_TOUT_TSNS_PROV], 2);
1174 break;
1175 }
1176 return 0;
1177}
1178
1179static void ns2_sns_st_all_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1180{
1181 struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
1182
1183 /* reset when receiving GPRS_SNS_EV_NO_NSVC */
1184 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_SIZE, nse->nsi->timeout[NS_TOUT_TSNS_PROV], 3);
1185}
1186
1187static struct osmo_fsm gprs_ns2_sns_bss_fsm = {
1188 .name = "GPRS-NS2-SNS-BSS",
1189 .states = ns2_sns_bss_states,
1190 .num_states = ARRAY_SIZE(ns2_sns_bss_states),
1191 .allstate_event_mask = GPRS_SNS_EV_NO_NSVC,
1192 .allstate_action = ns2_sns_st_all_action,
1193 .cleanup = NULL,
1194 .timer_cb = ns2_sns_fsm_bss_timer_cb,
1195 /* .log_subsys = DNS, "is not constant" */
1196 .event_names = gprs_sns_event_names,
1197 .pre_term = NULL,
1198 .log_subsys = DLNS,
1199};
1200
Harald Welte5bef2cc2020-09-18 22:33:24 +02001201/*! Allocate an IP-SNS FSM for the BSS side.
1202 * \param[in] nse NS Entity in which the FSM runs
1203 * \param[in] id string identifier
1204 * \retruns FSM instance on success; NULL on error */
Alexander Couzens6a161492020-07-12 13:45:50 +02001205struct osmo_fsm_inst *ns2_sns_bss_fsm_alloc(struct gprs_ns2_nse *nse,
1206 const char *id)
1207{
1208 struct osmo_fsm_inst *fi;
1209 struct ns2_sns_state *gss;
1210
1211 fi = osmo_fsm_inst_alloc(&gprs_ns2_sns_bss_fsm, nse, NULL, LOGL_DEBUG, id);
1212 if (!fi)
1213 return fi;
1214
1215 gss = talloc_zero(fi, struct ns2_sns_state);
1216 if (!gss)
1217 goto err;
1218
1219 fi->priv = gss;
1220 gss->nse = nse;
1221
1222 return fi;
1223err:
1224 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
1225 return NULL;
1226}
1227
Harald Welte5bef2cc2020-09-18 22:33:24 +02001228/*! Start an IP-SNS FSM.
1229 * \param[in] nse NS Entity whose IP-SNS FSM shall be started
1230 * \param[in] nsvc Initial NS-VC
1231 * \param[in] remote remote (SGSN) address
1232 * \returns 0 on success; negative on error */
Vadim Yanitskiya07f25e2020-10-09 21:47:01 +07001233int ns2_sns_bss_fsm_start(struct gprs_ns2_nse *nse, struct gprs_ns2_vc *nsvc,
1234 const struct osmo_sockaddr *remote)
Alexander Couzens6a161492020-07-12 13:45:50 +02001235{
1236 struct osmo_fsm_inst *fi = nse->bss_sns_fi;
1237 struct ns2_sns_state *gss = (struct ns2_sns_state *) nse->bss_sns_fi->priv;
1238 struct gprs_ns_ie_ip4_elem *ip4_elems;
1239 struct gprs_ns_ie_ip6_elem *ip6_elems;
1240 struct gprs_ns2_vc_bind *bind;
1241 struct gprs_ns2_inst *nsi = nse->nsi;
Alexander Couzens9a4cf272020-10-11 20:48:04 +02001242 const struct osmo_sockaddr *sa;
1243 struct osmo_sockaddr local;
1244
Alexander Couzens6a161492020-07-12 13:45:50 +02001245 gss->ip = remote->u.sa.sa_family == AF_INET ? IPv4 : IPv6;
1246
1247 gss->initial = *remote;
1248 gss->sns_nsvc = nsvc;
1249 nsvc->sns_only = true;
1250
1251 int count = 0;
1252 llist_for_each_entry(bind, &nsi->binding, list) {
1253 if (!gprs_ns2_is_ip_bind(bind))
1254 continue;
1255
1256 sa = gprs_ns2_ip_bind_sockaddr(bind);
1257 if (!sa)
1258 continue;
1259
1260 if (sa->u.sa.sa_family == remote->u.sa.sa_family)
1261 count++;
1262 }
1263
1264 if (count == 0) {
1265 /* TODO: logging */
1266 goto err;
1267 }
1268
1269 switch (gss->ip) {
1270 case IPv4:
1271 ip4_elems = talloc_zero_size(fi, sizeof(struct gprs_ns_ie_ip4_elem) * count);
1272 if (!ip4_elems)
1273 goto err;
1274
1275 gss->ip4_local = ip4_elems;
1276
1277 llist_for_each_entry(bind, &nsi->binding, list) {
1278 if (!gprs_ns2_is_ip_bind(bind))
1279 continue;
1280
1281 sa = gprs_ns2_ip_bind_sockaddr(bind);
1282 if (!sa)
1283 continue;
1284
1285 if (sa->u.sas.ss_family != AF_INET)
1286 continue;
1287
1288 /* check if this is an specific bind */
1289 if (sa->u.sin.sin_addr.s_addr == 0) {
1290 if (osmo_sockaddr_local_ip(&local, remote))
1291 continue;
1292
1293 ip4_elems->ip_addr = local.u.sin.sin_addr.s_addr;
1294 } else {
1295 ip4_elems->ip_addr = sa->u.sin.sin_addr.s_addr;
1296 }
1297
1298 ip4_elems->udp_port = sa->u.sin.sin_port;
1299 ip4_elems->sig_weight = 2;
1300 ip4_elems->data_weight = 1;
1301 ip4_elems++;
1302 }
1303
1304 gss->num_ip4_local = count;
1305 gss->num_max_ip4_remote = 4;
1306 break;
1307 case IPv6:
1308 /* IPv6 */
1309 ip6_elems = talloc_zero_size(fi, sizeof(struct gprs_ns_ie_ip6_elem) * count);
1310 if (!ip6_elems)
1311 goto err;
1312
1313 gss->ip6_local = ip6_elems;
1314
1315 llist_for_each_entry(bind, &nsi->binding, list) {
1316 if (!gprs_ns2_is_ip_bind(bind))
1317 continue;
1318
1319 sa = gprs_ns2_ip_bind_sockaddr(bind);
1320 if (!sa)
1321 continue;
1322
1323 if (sa->u.sas.ss_family != AF_INET6)
1324 continue;
1325
1326 /* check if this is an specific bind */
1327 if (IN6_IS_ADDR_UNSPECIFIED(&sa->u.sin6.sin6_addr)) {
1328 if (osmo_sockaddr_local_ip(&local, remote))
1329 continue;
1330
1331 ip6_elems->ip_addr = local.u.sin6.sin6_addr;
1332 } else {
1333 ip6_elems->ip_addr = sa->u.sin6.sin6_addr;
1334 }
1335
1336 ip6_elems->udp_port = sa->u.sin.sin_port;
1337 ip6_elems->sig_weight = 2;
1338 ip6_elems->data_weight = 1;
1339
1340 ip6_elems++;
1341 }
1342 gss->num_ip6_local = count;
1343 gss->num_max_ip6_remote = 4;
1344 break;
1345 }
1346
1347 gss->num_max_nsvcs = 8;
1348
1349 return osmo_fsm_inst_dispatch(nse->bss_sns_fi, GPRS_SNS_EV_START, NULL);
1350
1351err:
1352 return -1;
1353}
1354
Harald Welte5bef2cc2020-09-18 22:33:24 +02001355/*! main entry point for receiving SNS messages from the network.
1356 * \param[in] nsvc NS-VC on which the message was received
1357 * \param[in] msg message buffer of the IP-SNS message
1358 * \param[in] tp parsed TLV structure of message
1359 * \retruns 0 on success; negative on error */
Alexander Couzens6a161492020-07-12 13:45:50 +02001360int gprs_ns2_sns_rx(struct gprs_ns2_vc *nsvc, struct msgb *msg, struct tlv_parsed *tp)
1361{
1362 struct gprs_ns2_nse *nse = nsvc->nse;
1363 struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h;
1364 uint16_t nsei = nsvc->nse->nsei;
1365 struct osmo_fsm_inst *fi;
1366
1367 if (!nse->bss_sns_fi) {
1368 LOGP(DLNS, LOGL_NOTICE, "NSEI=%u Rx %s for NS Instance that has no SNS!\n",
1369 nsvc->nse->nsei, get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
1370 return -EINVAL;
1371 }
1372
1373 LOGP(DLNS, LOGL_DEBUG, "NSEI=%u Rx SNS PDU type %s\n", nsei,
1374 get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
1375
1376 /* FIXME: how to resolve SNS FSM Instance by NSEI (SGSN)? */
1377 fi = nse->bss_sns_fi;
1378
1379 switch (nsh->pdu_type) {
1380 case SNS_PDUT_SIZE:
1381 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_SIZE, tp);
1382 break;
1383 case SNS_PDUT_SIZE_ACK:
1384 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_SIZE_ACK, tp);
1385 break;
1386 case SNS_PDUT_CONFIG:
1387 if (nsh->data[0] & 0x01)
1388 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_CONFIG_END, tp);
1389 else
1390 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_CONFIG, tp);
1391 break;
1392 case SNS_PDUT_CONFIG_ACK:
1393 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_CONFIG_ACK, tp);
1394 break;
1395 case SNS_PDUT_ADD:
1396 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_ADD, tp);
1397 break;
1398 case SNS_PDUT_DELETE:
1399 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_DELETE, tp);
1400 break;
1401 case SNS_PDUT_CHANGE_WEIGHT:
1402 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_CHANGE_WEIGHT, tp);
1403 break;
1404 case SNS_PDUT_ACK:
1405 LOGP(DLNS, LOGL_NOTICE, "NSEI=%u Rx unsupported SNS PDU type %s\n", nsei,
1406 get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
1407 break;
1408 default:
1409 LOGP(DLNS, LOGL_ERROR, "NSEI=%u Rx unknown SNS PDU type %s\n", nsei,
1410 get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
1411 return -EINVAL;
1412 }
1413
1414 return 0;
1415}
1416
1417#include <osmocom/vty/vty.h>
1418#include <osmocom/vty/misc.h>
1419
1420static void vty_dump_sns_ip4(struct vty *vty, const struct gprs_ns_ie_ip4_elem *ip4)
1421{
1422 struct in_addr in = { .s_addr = ip4->ip_addr };
1423 vty_out(vty, " %s:%u, Signalling Weight: %u, Data Weight: %u%s",
1424 inet_ntoa(in), ntohs(ip4->udp_port), ip4->sig_weight, ip4->data_weight, VTY_NEWLINE);
1425}
1426
1427static void vty_dump_sns_ip6(struct vty *vty, const struct gprs_ns_ie_ip6_elem *ip6)
1428{
1429 char ip_addr[INET6_ADDRSTRLEN] = {};
1430 if (!inet_ntop(AF_INET6, &ip6->ip_addr, ip_addr, (INET6_ADDRSTRLEN)))
1431 strcpy(ip_addr, "Invalid IPv6");
1432
1433 vty_out(vty, " %s:%u, Signalling Weight: %u, Data Weight: %u%s",
1434 ip_addr, ntohs(ip6->udp_port), ip6->sig_weight, ip6->data_weight, VTY_NEWLINE);
1435}
1436
Harald Welte5bef2cc2020-09-18 22:33:24 +02001437/*! Dump the IP-SNS state to a vty.
1438 * \param[in] vty VTY to which the state shall be printed
1439 * \param[in] nse NS Entity whose IP-SNS state shall be printed
1440 * \param[in] stats Whether or not statistics shall also be printed */
Alexander Couzens6a161492020-07-12 13:45:50 +02001441void gprs_ns2_sns_dump_vty(struct vty *vty, const struct gprs_ns2_nse *nse, bool stats)
1442{
1443 struct ns2_sns_state *gss;
1444 unsigned int i;
1445
1446 if (!nse->bss_sns_fi)
1447 return;
1448
1449 vty_out_fsm_inst(vty, nse->bss_sns_fi);
1450 gss = (struct ns2_sns_state *) nse->bss_sns_fi->priv;
1451
1452 vty_out(vty, "Maximum number of remote NS-VCs: %zu, IPv4 Endpoints: %zu, IPv6 Endpoints: %zu%s",
1453 gss->num_max_nsvcs, gss->num_max_ip4_remote, gss->num_max_ip6_remote, VTY_NEWLINE);
1454
1455 if (gss->num_ip4_local && gss->num_ip4_remote) {
1456 vty_out(vty, "Local IPv4 Endpoints:%s", VTY_NEWLINE);
1457 for (i = 0; i < gss->num_ip4_local; i++)
1458 vty_dump_sns_ip4(vty, &gss->ip4_local[i]);
1459
1460 vty_out(vty, "Remote IPv4 Endpoints:%s", VTY_NEWLINE);
1461 for (i = 0; i < gss->num_ip4_remote; i++)
1462 vty_dump_sns_ip4(vty, &gss->ip4_remote[i]);
1463 }
1464
1465 if (gss->num_ip6_local && gss->num_ip6_remote) {
1466 vty_out(vty, "Local IPv6 Endpoints:%s", VTY_NEWLINE);
1467 for (i = 0; i < gss->num_ip6_local; i++)
1468 vty_dump_sns_ip6(vty, &gss->ip6_local[i]);
1469
1470 vty_out(vty, "Remote IPv6 Endpoints:%s", VTY_NEWLINE);
1471 for (i = 0; i < gss->num_ip6_remote; i++)
1472 vty_dump_sns_ip6(vty, &gss->ip6_remote[i]);
1473 }
1474}
1475
1476/* initialize osmo_ctx on main tread */
1477static __attribute__((constructor)) void on_dso_load_ctx(void)
1478{
1479 OSMO_ASSERT(osmo_fsm_register(&gprs_ns2_sns_bss_fsm) == 0);
1480}