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