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